mmap-alloc.c 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. /*
  2. * Support for RAM backed by mmaped host memory.
  3. *
  4. * Copyright (c) 2015 Red Hat, Inc.
  5. *
  6. * Authors:
  7. * Michael S. Tsirkin <mst@redhat.com>
  8. *
  9. * This work is licensed under the terms of the GNU GPL, version 2 or
  10. * later. See the COPYING file in the top-level directory.
  11. */
  12. #include "qemu/osdep.h"
  13. #include <qemu/mmap-alloc.h>
  14. #define HUGETLBFS_MAGIC 0x958458f6
  15. #ifdef CONFIG_LINUX
  16. #include <sys/vfs.h>
  17. #endif
  18. size_t qemu_fd_getpagesize(int fd)
  19. {
  20. #ifdef CONFIG_LINUX
  21. struct statfs fs;
  22. int ret;
  23. if (fd != -1) {
  24. do {
  25. ret = fstatfs(fd, &fs);
  26. } while (ret != 0 && errno == EINTR);
  27. if (ret == 0 && fs.f_type == HUGETLBFS_MAGIC) {
  28. return fs.f_bsize;
  29. }
  30. }
  31. #endif
  32. return getpagesize();
  33. }
  34. void *qemu_ram_mmap(int fd, size_t size, size_t align, bool shared)
  35. {
  36. /*
  37. * Note: this always allocates at least one extra page of virtual address
  38. * space, even if size is already aligned.
  39. */
  40. size_t total = size + align;
  41. #if defined(__powerpc64__) && defined(__linux__)
  42. /* On ppc64 mappings in the same segment (aka slice) must share the same
  43. * page size. Since we will be re-allocating part of this segment
  44. * from the supplied fd, we should make sure to use the same page size, to
  45. * this end we mmap the supplied fd. In this case, set MAP_NORESERVE to
  46. * avoid allocating backing store memory.
  47. * We do this unless we are using the system page size, in which case
  48. * anonymous memory is OK.
  49. */
  50. int anonfd = fd == -1 || qemu_fd_getpagesize(fd) == getpagesize() ? -1 : fd;
  51. int flags = anonfd == -1 ? MAP_ANONYMOUS : MAP_NORESERVE;
  52. void *ptr = mmap(0, total, PROT_NONE, flags | MAP_PRIVATE, anonfd, 0);
  53. #else
  54. void *ptr = mmap(0, total, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
  55. #endif
  56. size_t offset = QEMU_ALIGN_UP((uintptr_t)ptr, align) - (uintptr_t)ptr;
  57. void *ptr1;
  58. if (ptr == MAP_FAILED) {
  59. return MAP_FAILED;
  60. }
  61. /* Make sure align is a power of 2 */
  62. assert(!(align & (align - 1)));
  63. /* Always align to host page size */
  64. assert(align >= getpagesize());
  65. ptr1 = mmap(ptr + offset, size, PROT_READ | PROT_WRITE,
  66. MAP_FIXED |
  67. (fd == -1 ? MAP_ANONYMOUS : 0) |
  68. (shared ? MAP_SHARED : MAP_PRIVATE),
  69. fd, 0);
  70. if (ptr1 == MAP_FAILED) {
  71. munmap(ptr, total);
  72. return MAP_FAILED;
  73. }
  74. ptr += offset;
  75. total -= offset;
  76. if (offset > 0) {
  77. munmap(ptr - offset, offset);
  78. }
  79. /*
  80. * Leave a single PROT_NONE page allocated after the RAM block, to serve as
  81. * a guard page guarding against potential buffer overflows.
  82. */
  83. if (total > size + getpagesize()) {
  84. munmap(ptr + size + getpagesize(), total - size - getpagesize());
  85. }
  86. return ptr;
  87. }
  88. void qemu_ram_munmap(void *ptr, size_t size)
  89. {
  90. if (ptr) {
  91. /* Unmap both the RAM block and the guard page */
  92. munmap(ptr, size + getpagesize());
  93. }
  94. }