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"
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
);
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;
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
)) {
109 /* Ignore regions with dirty logging, we cannot mark them dirty */
110 if (memory_region_is_logging(section
->mr
)) {
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
,
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
,
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
);