123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176 |
- /*
- * Thread-safe guest to host memory mapping
- *
- * Copyright 2012 Red Hat, Inc. and/or its affiliates
- *
- * Authors:
- * Stefan Hajnoczi <stefanha@redhat.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- *
- */
- #include "exec/address-spaces.h"
- #include "hostmem.h"
- static int hostmem_lookup_cmp(const void *phys_, const void *region_)
- {
- hwaddr phys = *(const hwaddr *)phys_;
- const HostMemRegion *region = region_;
- if (phys < region->guest_addr) {
- return -1;
- } else if (phys >= region->guest_addr + region->size) {
- return 1;
- } else {
- return 0;
- }
- }
- /**
- * Map guest physical address to host pointer
- */
- void *hostmem_lookup(HostMem *hostmem, hwaddr phys, hwaddr len, bool is_write)
- {
- HostMemRegion *region;
- void *host_addr = NULL;
- hwaddr offset_within_region;
- qemu_mutex_lock(&hostmem->current_regions_lock);
- region = bsearch(&phys, hostmem->current_regions,
- hostmem->num_current_regions,
- sizeof(hostmem->current_regions[0]),
- hostmem_lookup_cmp);
- if (!region) {
- goto out;
- }
- if (is_write && region->readonly) {
- goto out;
- }
- offset_within_region = phys - region->guest_addr;
- if (len <= region->size - offset_within_region) {
- host_addr = region->host_addr + offset_within_region;
- }
- out:
- qemu_mutex_unlock(&hostmem->current_regions_lock);
- return host_addr;
- }
- /**
- * Install new regions list
- */
- static void hostmem_listener_commit(MemoryListener *listener)
- {
- HostMem *hostmem = container_of(listener, HostMem, listener);
- qemu_mutex_lock(&hostmem->current_regions_lock);
- g_free(hostmem->current_regions);
- hostmem->current_regions = hostmem->new_regions;
- hostmem->num_current_regions = hostmem->num_new_regions;
- qemu_mutex_unlock(&hostmem->current_regions_lock);
- /* Reset new regions list */
- hostmem->new_regions = NULL;
- hostmem->num_new_regions = 0;
- }
- /**
- * Add a MemoryRegionSection to the new regions list
- */
- static void hostmem_append_new_region(HostMem *hostmem,
- MemoryRegionSection *section)
- {
- void *ram_ptr = memory_region_get_ram_ptr(section->mr);
- size_t num = hostmem->num_new_regions;
- size_t new_size = (num + 1) * sizeof(hostmem->new_regions[0]);
- hostmem->new_regions = g_realloc(hostmem->new_regions, new_size);
- hostmem->new_regions[num] = (HostMemRegion){
- .host_addr = ram_ptr + section->offset_within_region,
- .guest_addr = section->offset_within_address_space,
- .size = section->size,
- .readonly = section->readonly,
- };
- hostmem->num_new_regions++;
- }
- static void hostmem_listener_append_region(MemoryListener *listener,
- MemoryRegionSection *section)
- {
- HostMem *hostmem = container_of(listener, HostMem, listener);
- /* Ignore non-RAM regions, we may not be able to map them */
- if (!memory_region_is_ram(section->mr)) {
- return;
- }
- /* Ignore regions with dirty logging, we cannot mark them dirty */
- if (memory_region_is_logging(section->mr)) {
- return;
- }
- hostmem_append_new_region(hostmem, section);
- }
- /* We don't implement most MemoryListener callbacks, use these nop stubs */
- static void hostmem_listener_dummy(MemoryListener *listener)
- {
- }
- static void hostmem_listener_section_dummy(MemoryListener *listener,
- MemoryRegionSection *section)
- {
- }
- static void hostmem_listener_eventfd_dummy(MemoryListener *listener,
- MemoryRegionSection *section,
- bool match_data, uint64_t data,
- EventNotifier *e)
- {
- }
- static void hostmem_listener_coalesced_mmio_dummy(MemoryListener *listener,
- MemoryRegionSection *section,
- hwaddr addr, hwaddr len)
- {
- }
- void hostmem_init(HostMem *hostmem)
- {
- memset(hostmem, 0, sizeof(*hostmem));
- qemu_mutex_init(&hostmem->current_regions_lock);
- hostmem->listener = (MemoryListener){
- .begin = hostmem_listener_dummy,
- .commit = hostmem_listener_commit,
- .region_add = hostmem_listener_append_region,
- .region_del = hostmem_listener_section_dummy,
- .region_nop = hostmem_listener_append_region,
- .log_start = hostmem_listener_section_dummy,
- .log_stop = hostmem_listener_section_dummy,
- .log_sync = hostmem_listener_section_dummy,
- .log_global_start = hostmem_listener_dummy,
- .log_global_stop = hostmem_listener_dummy,
- .eventfd_add = hostmem_listener_eventfd_dummy,
- .eventfd_del = hostmem_listener_eventfd_dummy,
- .coalesced_mmio_add = hostmem_listener_coalesced_mmio_dummy,
- .coalesced_mmio_del = hostmem_listener_coalesced_mmio_dummy,
- .priority = 10,
- };
- memory_listener_register(&hostmem->listener, &address_space_memory);
- if (hostmem->num_new_regions > 0) {
- hostmem_listener_commit(&hostmem->listener);
- }
- }
- void hostmem_finalize(HostMem *hostmem)
- {
- memory_listener_unregister(&hostmem->listener);
- g_free(hostmem->new_regions);
- g_free(hostmem->current_regions);
- qemu_mutex_destroy(&hostmem->current_regions_lock);
- }
|