diff options
author | Anthony Liguori <aliguori@us.ibm.com> | 2013-01-02 12:19:27 -0600 |
---|---|---|
committer | Anthony Liguori <aliguori@us.ibm.com> | 2013-01-02 12:19:27 -0600 |
commit | 217da7fdeb2a4c99c49f22f9dc64c8df2e3a4387 (patch) | |
tree | 8b5e91974d20566398b3a74d08392a26c13f2141 /hw/dataplane/hostmem.c | |
parent | 9a8a5ae69d3a436e51a7eb2edafe254572f60823 (diff) | |
parent | d6b1ef89a1ede41334e4d0fa27e600e0b4d4f209 (diff) |
Merge remote-tracking branch 'stefanha/block' into staging
* stefanha/block:
sheepdog: pass oid directly to send_pending_req()
sheepdog: don't update inode when create_and_write fails
block/raw-win32: Fix compiler warnings (wrong format specifiers)
qemu-img: report size overflow error message
cutils: change strtosz_suffix_unit function
virtio-blk: Return UNSUPP for unknown request types
virtio-blk: add x-data-plane=on|off performance feature
dataplane: add virtio-blk data plane code
virtio-blk: restore VirtIOBlkConf->config_wce flag
iov: add qemu_iovec_concat_iov()
test-iov: add iov_discard_front/back() testcases
iov: add iov_discard_front/back() to remove data
dataplane: add Linux AIO request queue
dataplane: add event loop
dataplane: add virtqueue vring code
dataplane: add host memory mapping code
configure: add CONFIG_VIRTIO_BLK_DATA_PLANE
raw-posix: add raw_get_aio_fd() for virtio-blk-data-plane
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Diffstat (limited to 'hw/dataplane/hostmem.c')
-rw-r--r-- | hw/dataplane/hostmem.c | 176 |
1 files changed, 176 insertions, 0 deletions
diff --git a/hw/dataplane/hostmem.c b/hw/dataplane/hostmem.c new file mode 100644 index 0000000000..380537e06d --- /dev/null +++ b/hw/dataplane/hostmem.c @@ -0,0 +1,176 @@ +/* + * 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); +} |