]> git.proxmox.com Git - qemu.git/blame - hw/virtio/dataplane/hostmem.c
Merge git://github.com/hw-claudio/qemu-aarch64-queue into tcg-next
[qemu.git] / hw / virtio / dataplane / hostmem.c
CommitLineData
185ecf40
SH
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
14#include "exec/address-spaces.h"
0d09e41a 15#include "hw/virtio/dataplane/hostmem.h"
185ecf40
SH
16
17static int hostmem_lookup_cmp(const void *phys_, const void *region_)
18{
19 hwaddr phys = *(const hwaddr *)phys_;
20 const HostMemRegion *region = region_;
21
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;
28 }
29}
30
31/**
32 * Map guest physical address to host pointer
33 */
34void *hostmem_lookup(HostMem *hostmem, hwaddr phys, hwaddr len, bool is_write)
35{
36 HostMemRegion *region;
37 void *host_addr = NULL;
38 hwaddr offset_within_region;
39
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;
47 }
48 if (is_write && region->readonly) {
49 goto out;
50 }
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;
54 }
55out:
56 qemu_mutex_unlock(&hostmem->current_regions_lock);
57
58 return host_addr;
59}
60
61/**
62 * Install new regions list
63 */
64static void hostmem_listener_commit(MemoryListener *listener)
65{
66 HostMem *hostmem = container_of(listener, HostMem, listener);
dfde4e6e 67 int i;
185ecf40
SH
68
69 qemu_mutex_lock(&hostmem->current_regions_lock);
dfde4e6e
PB
70 for (i = 0; i < hostmem->num_current_regions; i++) {
71 memory_region_unref(hostmem->current_regions[i].mr);
72 }
185ecf40
SH
73 g_free(hostmem->current_regions);
74 hostmem->current_regions = hostmem->new_regions;
75 hostmem->num_current_regions = hostmem->num_new_regions;
76 qemu_mutex_unlock(&hostmem->current_regions_lock);
77
78 /* Reset new regions list */
79 hostmem->new_regions = NULL;
80 hostmem->num_new_regions = 0;
81}
82
83/**
84 * Add a MemoryRegionSection to the new regions list
85 */
86static void hostmem_append_new_region(HostMem *hostmem,
87 MemoryRegionSection *section)
88{
89 void *ram_ptr = memory_region_get_ram_ptr(section->mr);
90 size_t num = hostmem->num_new_regions;
91 size_t new_size = (num + 1) * sizeof(hostmem->new_regions[0]);
92
93 hostmem->new_regions = g_realloc(hostmem->new_regions, new_size);
94 hostmem->new_regions[num] = (HostMemRegion){
95 .host_addr = ram_ptr + section->offset_within_region,
96 .guest_addr = section->offset_within_address_space,
052e87b0 97 .size = int128_get64(section->size),
185ecf40 98 .readonly = section->readonly,
dfde4e6e 99 .mr = section->mr,
185ecf40
SH
100 };
101 hostmem->num_new_regions++;
dfde4e6e
PB
102
103 memory_region_ref(section->mr);
185ecf40
SH
104}
105
106static void hostmem_listener_append_region(MemoryListener *listener,
107 MemoryRegionSection *section)
108{
109 HostMem *hostmem = container_of(listener, HostMem, listener);
110
111 /* Ignore non-RAM regions, we may not be able to map them */
112 if (!memory_region_is_ram(section->mr)) {
113 return;
114 }
115
116 /* Ignore regions with dirty logging, we cannot mark them dirty */
117 if (memory_region_is_logging(section->mr)) {
118 return;
119 }
120
121 hostmem_append_new_region(hostmem, section);
122}
123
124/* We don't implement most MemoryListener callbacks, use these nop stubs */
125static void hostmem_listener_dummy(MemoryListener *listener)
126{
127}
128
129static void hostmem_listener_section_dummy(MemoryListener *listener,
130 MemoryRegionSection *section)
131{
132}
133
134static void hostmem_listener_eventfd_dummy(MemoryListener *listener,
135 MemoryRegionSection *section,
136 bool match_data, uint64_t data,
137 EventNotifier *e)
138{
139}
140
141static void hostmem_listener_coalesced_mmio_dummy(MemoryListener *listener,
142 MemoryRegionSection *section,
143 hwaddr addr, hwaddr len)
144{
145}
146
147void hostmem_init(HostMem *hostmem)
148{
149 memset(hostmem, 0, sizeof(*hostmem));
150
151 qemu_mutex_init(&hostmem->current_regions_lock);
152
153 hostmem->listener = (MemoryListener){
154 .begin = hostmem_listener_dummy,
155 .commit = hostmem_listener_commit,
156 .region_add = hostmem_listener_append_region,
157 .region_del = hostmem_listener_section_dummy,
158 .region_nop = hostmem_listener_append_region,
159 .log_start = hostmem_listener_section_dummy,
160 .log_stop = hostmem_listener_section_dummy,
161 .log_sync = hostmem_listener_section_dummy,
162 .log_global_start = hostmem_listener_dummy,
163 .log_global_stop = hostmem_listener_dummy,
164 .eventfd_add = hostmem_listener_eventfd_dummy,
165 .eventfd_del = hostmem_listener_eventfd_dummy,
166 .coalesced_mmio_add = hostmem_listener_coalesced_mmio_dummy,
167 .coalesced_mmio_del = hostmem_listener_coalesced_mmio_dummy,
168 .priority = 10,
169 };
170
171 memory_listener_register(&hostmem->listener, &address_space_memory);
172 if (hostmem->num_new_regions > 0) {
173 hostmem_listener_commit(&hostmem->listener);
174 }
175}
176
177void hostmem_finalize(HostMem *hostmem)
178{
179 memory_listener_unregister(&hostmem->listener);
180 g_free(hostmem->new_regions);
181 g_free(hostmem->current_regions);
182 qemu_mutex_destroy(&hostmem->current_regions_lock);
183}