hostmem.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. /*
  2. * Thread-safe guest to host memory mapping
  3. *
  4. * Copyright 2012 Red Hat, Inc. and/or its affiliates
  5. *
  6. * Authors:
  7. * Stefan Hajnoczi <stefanha@redhat.com>
  8. *
  9. * This work is licensed under the terms of the GNU GPL, version 2 or later.
  10. * See the COPYING file in the top-level directory.
  11. *
  12. */
  13. #include "exec/address-spaces.h"
  14. #include "hostmem.h"
  15. static int hostmem_lookup_cmp(const void *phys_, const void *region_)
  16. {
  17. hwaddr phys = *(const hwaddr *)phys_;
  18. const HostMemRegion *region = region_;
  19. if (phys < region->guest_addr) {
  20. return -1;
  21. } else if (phys >= region->guest_addr + region->size) {
  22. return 1;
  23. } else {
  24. return 0;
  25. }
  26. }
  27. /**
  28. * Map guest physical address to host pointer
  29. */
  30. void *hostmem_lookup(HostMem *hostmem, hwaddr phys, hwaddr len, bool is_write)
  31. {
  32. HostMemRegion *region;
  33. void *host_addr = NULL;
  34. hwaddr offset_within_region;
  35. qemu_mutex_lock(&hostmem->current_regions_lock);
  36. region = bsearch(&phys, hostmem->current_regions,
  37. hostmem->num_current_regions,
  38. sizeof(hostmem->current_regions[0]),
  39. hostmem_lookup_cmp);
  40. if (!region) {
  41. goto out;
  42. }
  43. if (is_write && region->readonly) {
  44. goto out;
  45. }
  46. offset_within_region = phys - region->guest_addr;
  47. if (len <= region->size - offset_within_region) {
  48. host_addr = region->host_addr + offset_within_region;
  49. }
  50. out:
  51. qemu_mutex_unlock(&hostmem->current_regions_lock);
  52. return host_addr;
  53. }
  54. /**
  55. * Install new regions list
  56. */
  57. static void hostmem_listener_commit(MemoryListener *listener)
  58. {
  59. HostMem *hostmem = container_of(listener, HostMem, listener);
  60. qemu_mutex_lock(&hostmem->current_regions_lock);
  61. g_free(hostmem->current_regions);
  62. hostmem->current_regions = hostmem->new_regions;
  63. hostmem->num_current_regions = hostmem->num_new_regions;
  64. qemu_mutex_unlock(&hostmem->current_regions_lock);
  65. /* Reset new regions list */
  66. hostmem->new_regions = NULL;
  67. hostmem->num_new_regions = 0;
  68. }
  69. /**
  70. * Add a MemoryRegionSection to the new regions list
  71. */
  72. static void hostmem_append_new_region(HostMem *hostmem,
  73. MemoryRegionSection *section)
  74. {
  75. void *ram_ptr = memory_region_get_ram_ptr(section->mr);
  76. size_t num = hostmem->num_new_regions;
  77. size_t new_size = (num + 1) * sizeof(hostmem->new_regions[0]);
  78. hostmem->new_regions = g_realloc(hostmem->new_regions, new_size);
  79. hostmem->new_regions[num] = (HostMemRegion){
  80. .host_addr = ram_ptr + section->offset_within_region,
  81. .guest_addr = section->offset_within_address_space,
  82. .size = section->size,
  83. .readonly = section->readonly,
  84. };
  85. hostmem->num_new_regions++;
  86. }
  87. static void hostmem_listener_append_region(MemoryListener *listener,
  88. MemoryRegionSection *section)
  89. {
  90. HostMem *hostmem = container_of(listener, HostMem, listener);
  91. /* Ignore non-RAM regions, we may not be able to map them */
  92. if (!memory_region_is_ram(section->mr)) {
  93. return;
  94. }
  95. /* Ignore regions with dirty logging, we cannot mark them dirty */
  96. if (memory_region_is_logging(section->mr)) {
  97. return;
  98. }
  99. hostmem_append_new_region(hostmem, section);
  100. }
  101. /* We don't implement most MemoryListener callbacks, use these nop stubs */
  102. static void hostmem_listener_dummy(MemoryListener *listener)
  103. {
  104. }
  105. static void hostmem_listener_section_dummy(MemoryListener *listener,
  106. MemoryRegionSection *section)
  107. {
  108. }
  109. static void hostmem_listener_eventfd_dummy(MemoryListener *listener,
  110. MemoryRegionSection *section,
  111. bool match_data, uint64_t data,
  112. EventNotifier *e)
  113. {
  114. }
  115. static void hostmem_listener_coalesced_mmio_dummy(MemoryListener *listener,
  116. MemoryRegionSection *section,
  117. hwaddr addr, hwaddr len)
  118. {
  119. }
  120. void hostmem_init(HostMem *hostmem)
  121. {
  122. memset(hostmem, 0, sizeof(*hostmem));
  123. qemu_mutex_init(&hostmem->current_regions_lock);
  124. hostmem->listener = (MemoryListener){
  125. .begin = hostmem_listener_dummy,
  126. .commit = hostmem_listener_commit,
  127. .region_add = hostmem_listener_append_region,
  128. .region_del = hostmem_listener_section_dummy,
  129. .region_nop = hostmem_listener_append_region,
  130. .log_start = hostmem_listener_section_dummy,
  131. .log_stop = hostmem_listener_section_dummy,
  132. .log_sync = hostmem_listener_section_dummy,
  133. .log_global_start = hostmem_listener_dummy,
  134. .log_global_stop = hostmem_listener_dummy,
  135. .eventfd_add = hostmem_listener_eventfd_dummy,
  136. .eventfd_del = hostmem_listener_eventfd_dummy,
  137. .coalesced_mmio_add = hostmem_listener_coalesced_mmio_dummy,
  138. .coalesced_mmio_del = hostmem_listener_coalesced_mmio_dummy,
  139. .priority = 10,
  140. };
  141. memory_listener_register(&hostmem->listener, &address_space_memory);
  142. if (hostmem->num_new_regions > 0) {
  143. hostmem_listener_commit(&hostmem->listener);
  144. }
  145. }
  146. void hostmem_finalize(HostMem *hostmem)
  147. {
  148. memory_listener_unregister(&hostmem->listener);
  149. g_free(hostmem->new_regions);
  150. g_free(hostmem->current_regions);
  151. qemu_mutex_destroy(&hostmem->current_regions_lock);
  152. }