hw: move headers to include/
[qemu/ar7.git] / hw / dataplane / hostmem.c
blob37292ffd00ec83b24640a3a7c17536370844b5f2
1 /*
2 * Thread-safe guest to host memory mapping
4 * Copyright 2012 Red Hat, Inc. and/or its affiliates
6 * Authors:
7 * Stefan Hajnoczi <stefanha@redhat.com>
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.
14 #include "exec/address-spaces.h"
15 #include "hw/virtio/dataplane/hostmem.h"
17 static int hostmem_lookup_cmp(const void *phys_, const void *region_)
19 hwaddr phys = *(const hwaddr *)phys_;
20 const HostMemRegion *region = region_;
22 if (phys < region->guest_addr) {
23 return -1;
24 } else if (phys >= region->guest_addr + region->size) {
25 return 1;
26 } else {
27 return 0;
31 /**
32 * Map guest physical address to host pointer
34 void *hostmem_lookup(HostMem *hostmem, hwaddr phys, hwaddr len, bool is_write)
36 HostMemRegion *region;
37 void *host_addr = NULL;
38 hwaddr offset_within_region;
40 qemu_mutex_lock(&hostmem->current_regions_lock);
41 region = bsearch(&phys, hostmem->current_regions,
42 hostmem->num_current_regions,
43 sizeof(hostmem->current_regions[0]),
44 hostmem_lookup_cmp);
45 if (!region) {
46 goto out;
48 if (is_write && region->readonly) {
49 goto out;
51 offset_within_region = phys - region->guest_addr;
52 if (len <= region->size - offset_within_region) {
53 host_addr = region->host_addr + offset_within_region;
55 out:
56 qemu_mutex_unlock(&hostmem->current_regions_lock);
58 return host_addr;
61 /**
62 * Install new regions list
64 static void hostmem_listener_commit(MemoryListener *listener)
66 HostMem *hostmem = container_of(listener, HostMem, listener);
68 qemu_mutex_lock(&hostmem->current_regions_lock);
69 g_free(hostmem->current_regions);
70 hostmem->current_regions = hostmem->new_regions;
71 hostmem->num_current_regions = hostmem->num_new_regions;
72 qemu_mutex_unlock(&hostmem->current_regions_lock);
74 /* Reset new regions list */
75 hostmem->new_regions = NULL;
76 hostmem->num_new_regions = 0;
79 /**
80 * Add a MemoryRegionSection to the new regions list
82 static void hostmem_append_new_region(HostMem *hostmem,
83 MemoryRegionSection *section)
85 void *ram_ptr = memory_region_get_ram_ptr(section->mr);
86 size_t num = hostmem->num_new_regions;
87 size_t new_size = (num + 1) * sizeof(hostmem->new_regions[0]);
89 hostmem->new_regions = g_realloc(hostmem->new_regions, new_size);
90 hostmem->new_regions[num] = (HostMemRegion){
91 .host_addr = ram_ptr + section->offset_within_region,
92 .guest_addr = section->offset_within_address_space,
93 .size = section->size,
94 .readonly = section->readonly,
96 hostmem->num_new_regions++;
99 static void hostmem_listener_append_region(MemoryListener *listener,
100 MemoryRegionSection *section)
102 HostMem *hostmem = container_of(listener, HostMem, listener);
104 /* Ignore non-RAM regions, we may not be able to map them */
105 if (!memory_region_is_ram(section->mr)) {
106 return;
109 /* Ignore regions with dirty logging, we cannot mark them dirty */
110 if (memory_region_is_logging(section->mr)) {
111 return;
114 hostmem_append_new_region(hostmem, section);
117 /* We don't implement most MemoryListener callbacks, use these nop stubs */
118 static void hostmem_listener_dummy(MemoryListener *listener)
122 static void hostmem_listener_section_dummy(MemoryListener *listener,
123 MemoryRegionSection *section)
127 static void hostmem_listener_eventfd_dummy(MemoryListener *listener,
128 MemoryRegionSection *section,
129 bool match_data, uint64_t data,
130 EventNotifier *e)
134 static void hostmem_listener_coalesced_mmio_dummy(MemoryListener *listener,
135 MemoryRegionSection *section,
136 hwaddr addr, hwaddr len)
140 void hostmem_init(HostMem *hostmem)
142 memset(hostmem, 0, sizeof(*hostmem));
144 qemu_mutex_init(&hostmem->current_regions_lock);
146 hostmem->listener = (MemoryListener){
147 .begin = hostmem_listener_dummy,
148 .commit = hostmem_listener_commit,
149 .region_add = hostmem_listener_append_region,
150 .region_del = hostmem_listener_section_dummy,
151 .region_nop = hostmem_listener_append_region,
152 .log_start = hostmem_listener_section_dummy,
153 .log_stop = hostmem_listener_section_dummy,
154 .log_sync = hostmem_listener_section_dummy,
155 .log_global_start = hostmem_listener_dummy,
156 .log_global_stop = hostmem_listener_dummy,
157 .eventfd_add = hostmem_listener_eventfd_dummy,
158 .eventfd_del = hostmem_listener_eventfd_dummy,
159 .coalesced_mmio_add = hostmem_listener_coalesced_mmio_dummy,
160 .coalesced_mmio_del = hostmem_listener_coalesced_mmio_dummy,
161 .priority = 10,
164 memory_listener_register(&hostmem->listener, &address_space_memory);
165 if (hostmem->num_new_regions > 0) {
166 hostmem_listener_commit(&hostmem->listener);
170 void hostmem_finalize(HostMem *hostmem)
172 memory_listener_unregister(&hostmem->listener);
173 g_free(hostmem->new_regions);
174 g_free(hostmem->current_regions);
175 qemu_mutex_destroy(&hostmem->current_regions_lock);