2 * Thread-safe guest to host memory mapping
4 * Copyright 2012 Red Hat, Inc. and/or its affiliates
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
) {
24 } else if (phys
>= region
->guest_addr
+ region
->size
) {
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]),
48 if (is_write
&& region
->readonly
) {
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
;
56 qemu_mutex_unlock(&hostmem
->current_regions_lock
);
62 * Install new regions list
64 static void hostmem_listener_commit(MemoryListener
*listener
)
66 HostMem
*hostmem
= container_of(listener
, HostMem
, listener
);
69 qemu_mutex_lock(&hostmem
->current_regions_lock
);
70 for (i
= 0; i
< hostmem
->num_current_regions
; i
++) {
71 memory_region_unref(hostmem
->current_regions
[i
].mr
);
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
);
78 /* Reset new regions list */
79 hostmem
->new_regions
= NULL
;
80 hostmem
->num_new_regions
= 0;
84 * Add a MemoryRegionSection to the new regions list
86 static void hostmem_append_new_region(HostMem
*hostmem
,
87 MemoryRegionSection
*section
)
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]);
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
,
97 .size
= int128_get64(section
->size
),
98 .readonly
= section
->readonly
,
101 hostmem
->num_new_regions
++;
103 memory_region_ref(section
->mr
);
106 static void hostmem_listener_append_region(MemoryListener
*listener
,
107 MemoryRegionSection
*section
)
109 HostMem
*hostmem
= container_of(listener
, HostMem
, listener
);
111 /* Ignore non-RAM regions, we may not be able to map them */
112 if (!memory_region_is_ram(section
->mr
)) {
116 /* Ignore regions with dirty logging, we cannot mark them dirty */
117 if (memory_region_is_logging(section
->mr
)) {
121 hostmem_append_new_region(hostmem
, section
);
124 /* We don't implement most MemoryListener callbacks, use these nop stubs */
125 static void hostmem_listener_dummy(MemoryListener
*listener
)
129 static void hostmem_listener_section_dummy(MemoryListener
*listener
,
130 MemoryRegionSection
*section
)
134 static void hostmem_listener_eventfd_dummy(MemoryListener
*listener
,
135 MemoryRegionSection
*section
,
136 bool match_data
, uint64_t data
,
141 static void hostmem_listener_coalesced_mmio_dummy(MemoryListener
*listener
,
142 MemoryRegionSection
*section
,
143 hwaddr addr
, hwaddr len
)
147 void hostmem_init(HostMem
*hostmem
)
149 memset(hostmem
, 0, sizeof(*hostmem
));
151 qemu_mutex_init(&hostmem
->current_regions_lock
);
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
,
171 memory_listener_register(&hostmem
->listener
, &address_space_memory
);
172 if (hostmem
->num_new_regions
> 0) {
173 hostmem_listener_commit(&hostmem
->listener
);
177 void hostmem_finalize(HostMem
*hostmem
)
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
);