Statistics
| Branch: | Revision:

root / memory_mapping.c @ 8cfd0495

History | View | Annotate | Download (10.4 kB)

1 80167a8a Wen Congyang
/*
2 80167a8a Wen Congyang
 * QEMU memory mapping
3 80167a8a Wen Congyang
 *
4 80167a8a Wen Congyang
 * Copyright Fujitsu, Corp. 2011, 2012
5 80167a8a Wen Congyang
 *
6 80167a8a Wen Congyang
 * Authors:
7 80167a8a Wen Congyang
 *     Wen Congyang <wency@cn.fujitsu.com>
8 80167a8a Wen Congyang
 *
9 fc0608ac Stefan Weil
 * This work is licensed under the terms of the GNU GPL, version 2 or later.
10 fc0608ac Stefan Weil
 * See the COPYING file in the top-level directory.
11 80167a8a Wen Congyang
 *
12 80167a8a Wen Congyang
 */
13 80167a8a Wen Congyang
14 c5d7f60f Laszlo Ersek
#include <glib.h>
15 c5d7f60f Laszlo Ersek
16 80167a8a Wen Congyang
#include "cpu.h"
17 022c62cb Paolo Bonzini
#include "exec/cpu-all.h"
18 9c17d615 Paolo Bonzini
#include "sysemu/memory_mapping.h"
19 c5d7f60f Laszlo Ersek
#include "exec/memory.h"
20 c5d7f60f Laszlo Ersek
#include "exec/address-spaces.h"
21 c5d7f60f Laszlo Ersek
22 c5d7f60f Laszlo Ersek
//#define DEBUG_GUEST_PHYS_REGION_ADD
23 80167a8a Wen Congyang
24 80167a8a Wen Congyang
static void memory_mapping_list_add_mapping_sorted(MemoryMappingList *list,
25 80167a8a Wen Congyang
                                                   MemoryMapping *mapping)
26 80167a8a Wen Congyang
{
27 80167a8a Wen Congyang
    MemoryMapping *p;
28 80167a8a Wen Congyang
29 80167a8a Wen Congyang
    QTAILQ_FOREACH(p, &list->head, next) {
30 80167a8a Wen Congyang
        if (p->phys_addr >= mapping->phys_addr) {
31 80167a8a Wen Congyang
            QTAILQ_INSERT_BEFORE(p, mapping, next);
32 80167a8a Wen Congyang
            return;
33 80167a8a Wen Congyang
        }
34 80167a8a Wen Congyang
    }
35 80167a8a Wen Congyang
    QTAILQ_INSERT_TAIL(&list->head, mapping, next);
36 80167a8a Wen Congyang
}
37 80167a8a Wen Congyang
38 80167a8a Wen Congyang
static void create_new_memory_mapping(MemoryMappingList *list,
39 a8170e5e Avi Kivity
                                      hwaddr phys_addr,
40 a8170e5e Avi Kivity
                                      hwaddr virt_addr,
41 80167a8a Wen Congyang
                                      ram_addr_t length)
42 80167a8a Wen Congyang
{
43 80167a8a Wen Congyang
    MemoryMapping *memory_mapping;
44 80167a8a Wen Congyang
45 80167a8a Wen Congyang
    memory_mapping = g_malloc(sizeof(MemoryMapping));
46 80167a8a Wen Congyang
    memory_mapping->phys_addr = phys_addr;
47 80167a8a Wen Congyang
    memory_mapping->virt_addr = virt_addr;
48 80167a8a Wen Congyang
    memory_mapping->length = length;
49 80167a8a Wen Congyang
    list->last_mapping = memory_mapping;
50 80167a8a Wen Congyang
    list->num++;
51 80167a8a Wen Congyang
    memory_mapping_list_add_mapping_sorted(list, memory_mapping);
52 80167a8a Wen Congyang
}
53 80167a8a Wen Congyang
54 80167a8a Wen Congyang
static inline bool mapping_contiguous(MemoryMapping *map,
55 a8170e5e Avi Kivity
                                      hwaddr phys_addr,
56 a8170e5e Avi Kivity
                                      hwaddr virt_addr)
57 80167a8a Wen Congyang
{
58 80167a8a Wen Congyang
    return phys_addr == map->phys_addr + map->length &&
59 80167a8a Wen Congyang
           virt_addr == map->virt_addr + map->length;
60 80167a8a Wen Congyang
}
61 80167a8a Wen Congyang
62 80167a8a Wen Congyang
/*
63 80167a8a Wen Congyang
 * [map->phys_addr, map->phys_addr + map->length) and
64 80167a8a Wen Congyang
 * [phys_addr, phys_addr + length) have intersection?
65 80167a8a Wen Congyang
 */
66 80167a8a Wen Congyang
static inline bool mapping_have_same_region(MemoryMapping *map,
67 a8170e5e Avi Kivity
                                            hwaddr phys_addr,
68 80167a8a Wen Congyang
                                            ram_addr_t length)
69 80167a8a Wen Congyang
{
70 80167a8a Wen Congyang
    return !(phys_addr + length < map->phys_addr ||
71 80167a8a Wen Congyang
             phys_addr >= map->phys_addr + map->length);
72 80167a8a Wen Congyang
}
73 80167a8a Wen Congyang
74 80167a8a Wen Congyang
/*
75 80167a8a Wen Congyang
 * [map->phys_addr, map->phys_addr + map->length) and
76 80167a8a Wen Congyang
 * [phys_addr, phys_addr + length) have intersection. The virtual address in the
77 80167a8a Wen Congyang
 * intersection are the same?
78 80167a8a Wen Congyang
 */
79 80167a8a Wen Congyang
static inline bool mapping_conflict(MemoryMapping *map,
80 a8170e5e Avi Kivity
                                    hwaddr phys_addr,
81 a8170e5e Avi Kivity
                                    hwaddr virt_addr)
82 80167a8a Wen Congyang
{
83 80167a8a Wen Congyang
    return virt_addr - map->virt_addr != phys_addr - map->phys_addr;
84 80167a8a Wen Congyang
}
85 80167a8a Wen Congyang
86 80167a8a Wen Congyang
/*
87 80167a8a Wen Congyang
 * [map->virt_addr, map->virt_addr + map->length) and
88 80167a8a Wen Congyang
 * [virt_addr, virt_addr + length) have intersection. And the physical address
89 80167a8a Wen Congyang
 * in the intersection are the same.
90 80167a8a Wen Congyang
 */
91 80167a8a Wen Congyang
static inline void mapping_merge(MemoryMapping *map,
92 a8170e5e Avi Kivity
                                 hwaddr virt_addr,
93 80167a8a Wen Congyang
                                 ram_addr_t length)
94 80167a8a Wen Congyang
{
95 80167a8a Wen Congyang
    if (virt_addr < map->virt_addr) {
96 80167a8a Wen Congyang
        map->length += map->virt_addr - virt_addr;
97 80167a8a Wen Congyang
        map->virt_addr = virt_addr;
98 80167a8a Wen Congyang
    }
99 80167a8a Wen Congyang
100 80167a8a Wen Congyang
    if ((virt_addr + length) >
101 80167a8a Wen Congyang
        (map->virt_addr + map->length)) {
102 80167a8a Wen Congyang
        map->length = virt_addr + length - map->virt_addr;
103 80167a8a Wen Congyang
    }
104 80167a8a Wen Congyang
}
105 80167a8a Wen Congyang
106 80167a8a Wen Congyang
void memory_mapping_list_add_merge_sorted(MemoryMappingList *list,
107 a8170e5e Avi Kivity
                                          hwaddr phys_addr,
108 a8170e5e Avi Kivity
                                          hwaddr virt_addr,
109 80167a8a Wen Congyang
                                          ram_addr_t length)
110 80167a8a Wen Congyang
{
111 80167a8a Wen Congyang
    MemoryMapping *memory_mapping, *last_mapping;
112 80167a8a Wen Congyang
113 80167a8a Wen Congyang
    if (QTAILQ_EMPTY(&list->head)) {
114 80167a8a Wen Congyang
        create_new_memory_mapping(list, phys_addr, virt_addr, length);
115 80167a8a Wen Congyang
        return;
116 80167a8a Wen Congyang
    }
117 80167a8a Wen Congyang
118 80167a8a Wen Congyang
    last_mapping = list->last_mapping;
119 80167a8a Wen Congyang
    if (last_mapping) {
120 80167a8a Wen Congyang
        if (mapping_contiguous(last_mapping, phys_addr, virt_addr)) {
121 80167a8a Wen Congyang
            last_mapping->length += length;
122 80167a8a Wen Congyang
            return;
123 80167a8a Wen Congyang
        }
124 80167a8a Wen Congyang
    }
125 80167a8a Wen Congyang
126 80167a8a Wen Congyang
    QTAILQ_FOREACH(memory_mapping, &list->head, next) {
127 80167a8a Wen Congyang
        if (mapping_contiguous(memory_mapping, phys_addr, virt_addr)) {
128 80167a8a Wen Congyang
            memory_mapping->length += length;
129 80167a8a Wen Congyang
            list->last_mapping = memory_mapping;
130 80167a8a Wen Congyang
            return;
131 80167a8a Wen Congyang
        }
132 80167a8a Wen Congyang
133 80167a8a Wen Congyang
        if (phys_addr + length < memory_mapping->phys_addr) {
134 80167a8a Wen Congyang
            /* create a new region before memory_mapping */
135 80167a8a Wen Congyang
            break;
136 80167a8a Wen Congyang
        }
137 80167a8a Wen Congyang
138 80167a8a Wen Congyang
        if (mapping_have_same_region(memory_mapping, phys_addr, length)) {
139 80167a8a Wen Congyang
            if (mapping_conflict(memory_mapping, phys_addr, virt_addr)) {
140 80167a8a Wen Congyang
                continue;
141 80167a8a Wen Congyang
            }
142 80167a8a Wen Congyang
143 80167a8a Wen Congyang
            /* merge this region into memory_mapping */
144 80167a8a Wen Congyang
            mapping_merge(memory_mapping, virt_addr, length);
145 80167a8a Wen Congyang
            list->last_mapping = memory_mapping;
146 80167a8a Wen Congyang
            return;
147 80167a8a Wen Congyang
        }
148 80167a8a Wen Congyang
    }
149 80167a8a Wen Congyang
150 80167a8a Wen Congyang
    /* this region can not be merged into any existed memory mapping. */
151 80167a8a Wen Congyang
    create_new_memory_mapping(list, phys_addr, virt_addr, length);
152 80167a8a Wen Congyang
}
153 80167a8a Wen Congyang
154 80167a8a Wen Congyang
void memory_mapping_list_free(MemoryMappingList *list)
155 80167a8a Wen Congyang
{
156 80167a8a Wen Congyang
    MemoryMapping *p, *q;
157 80167a8a Wen Congyang
158 80167a8a Wen Congyang
    QTAILQ_FOREACH_SAFE(p, &list->head, next, q) {
159 80167a8a Wen Congyang
        QTAILQ_REMOVE(&list->head, p, next);
160 80167a8a Wen Congyang
        g_free(p);
161 80167a8a Wen Congyang
    }
162 80167a8a Wen Congyang
163 80167a8a Wen Congyang
    list->num = 0;
164 80167a8a Wen Congyang
    list->last_mapping = NULL;
165 80167a8a Wen Congyang
}
166 80167a8a Wen Congyang
167 80167a8a Wen Congyang
void memory_mapping_list_init(MemoryMappingList *list)
168 80167a8a Wen Congyang
{
169 80167a8a Wen Congyang
    list->num = 0;
170 80167a8a Wen Congyang
    list->last_mapping = NULL;
171 80167a8a Wen Congyang
    QTAILQ_INIT(&list->head);
172 80167a8a Wen Congyang
}
173 c517076d Wen Congyang
174 5ee163e8 Laszlo Ersek
void guest_phys_blocks_free(GuestPhysBlockList *list)
175 5ee163e8 Laszlo Ersek
{
176 5ee163e8 Laszlo Ersek
    GuestPhysBlock *p, *q;
177 5ee163e8 Laszlo Ersek
178 5ee163e8 Laszlo Ersek
    QTAILQ_FOREACH_SAFE(p, &list->head, next, q) {
179 5ee163e8 Laszlo Ersek
        QTAILQ_REMOVE(&list->head, p, next);
180 5ee163e8 Laszlo Ersek
        g_free(p);
181 5ee163e8 Laszlo Ersek
    }
182 5ee163e8 Laszlo Ersek
    list->num = 0;
183 5ee163e8 Laszlo Ersek
}
184 5ee163e8 Laszlo Ersek
185 5ee163e8 Laszlo Ersek
void guest_phys_blocks_init(GuestPhysBlockList *list)
186 5ee163e8 Laszlo Ersek
{
187 5ee163e8 Laszlo Ersek
    list->num = 0;
188 5ee163e8 Laszlo Ersek
    QTAILQ_INIT(&list->head);
189 5ee163e8 Laszlo Ersek
}
190 5ee163e8 Laszlo Ersek
191 c5d7f60f Laszlo Ersek
typedef struct GuestPhysListener {
192 c5d7f60f Laszlo Ersek
    GuestPhysBlockList *list;
193 c5d7f60f Laszlo Ersek
    MemoryListener listener;
194 c5d7f60f Laszlo Ersek
} GuestPhysListener;
195 c5d7f60f Laszlo Ersek
196 c5d7f60f Laszlo Ersek
static void guest_phys_blocks_region_add(MemoryListener *listener,
197 c5d7f60f Laszlo Ersek
                                         MemoryRegionSection *section)
198 c5d7f60f Laszlo Ersek
{
199 c5d7f60f Laszlo Ersek
    GuestPhysListener *g;
200 c5d7f60f Laszlo Ersek
    uint64_t section_size;
201 c5d7f60f Laszlo Ersek
    hwaddr target_start, target_end;
202 c5d7f60f Laszlo Ersek
    uint8_t *host_addr;
203 c5d7f60f Laszlo Ersek
    GuestPhysBlock *predecessor;
204 c5d7f60f Laszlo Ersek
205 c5d7f60f Laszlo Ersek
    /* we only care about RAM */
206 c5d7f60f Laszlo Ersek
    if (!memory_region_is_ram(section->mr)) {
207 c5d7f60f Laszlo Ersek
        return;
208 c5d7f60f Laszlo Ersek
    }
209 c5d7f60f Laszlo Ersek
210 c5d7f60f Laszlo Ersek
    g            = container_of(listener, GuestPhysListener, listener);
211 c5d7f60f Laszlo Ersek
    section_size = int128_get64(section->size);
212 c5d7f60f Laszlo Ersek
    target_start = section->offset_within_address_space;
213 c5d7f60f Laszlo Ersek
    target_end   = target_start + section_size;
214 c5d7f60f Laszlo Ersek
    host_addr    = memory_region_get_ram_ptr(section->mr) +
215 c5d7f60f Laszlo Ersek
                   section->offset_within_region;
216 c5d7f60f Laszlo Ersek
    predecessor  = NULL;
217 c5d7f60f Laszlo Ersek
218 c5d7f60f Laszlo Ersek
    /* find continuity in guest physical address space */
219 c5d7f60f Laszlo Ersek
    if (!QTAILQ_EMPTY(&g->list->head)) {
220 c5d7f60f Laszlo Ersek
        hwaddr predecessor_size;
221 c5d7f60f Laszlo Ersek
222 c5d7f60f Laszlo Ersek
        predecessor = QTAILQ_LAST(&g->list->head, GuestPhysBlockHead);
223 c5d7f60f Laszlo Ersek
        predecessor_size = predecessor->target_end - predecessor->target_start;
224 c5d7f60f Laszlo Ersek
225 c5d7f60f Laszlo Ersek
        /* the memory API guarantees monotonically increasing traversal */
226 c5d7f60f Laszlo Ersek
        g_assert(predecessor->target_end <= target_start);
227 c5d7f60f Laszlo Ersek
228 c5d7f60f Laszlo Ersek
        /* we want continuity in both guest-physical and host-virtual memory */
229 c5d7f60f Laszlo Ersek
        if (predecessor->target_end < target_start ||
230 c5d7f60f Laszlo Ersek
            predecessor->host_addr + predecessor_size != host_addr) {
231 c5d7f60f Laszlo Ersek
            predecessor = NULL;
232 c5d7f60f Laszlo Ersek
        }
233 c5d7f60f Laszlo Ersek
    }
234 c5d7f60f Laszlo Ersek
235 c5d7f60f Laszlo Ersek
    if (predecessor == NULL) {
236 c5d7f60f Laszlo Ersek
        /* isolated mapping, allocate it and add it to the list */
237 c5d7f60f Laszlo Ersek
        GuestPhysBlock *block = g_malloc0(sizeof *block);
238 c5d7f60f Laszlo Ersek
239 c5d7f60f Laszlo Ersek
        block->target_start = target_start;
240 c5d7f60f Laszlo Ersek
        block->target_end   = target_end;
241 c5d7f60f Laszlo Ersek
        block->host_addr    = host_addr;
242 c5d7f60f Laszlo Ersek
243 c5d7f60f Laszlo Ersek
        QTAILQ_INSERT_TAIL(&g->list->head, block, next);
244 c5d7f60f Laszlo Ersek
        ++g->list->num;
245 c5d7f60f Laszlo Ersek
    } else {
246 c5d7f60f Laszlo Ersek
        /* expand predecessor until @target_end; predecessor's start doesn't
247 c5d7f60f Laszlo Ersek
         * change
248 c5d7f60f Laszlo Ersek
         */
249 c5d7f60f Laszlo Ersek
        predecessor->target_end = target_end;
250 c5d7f60f Laszlo Ersek
    }
251 c5d7f60f Laszlo Ersek
252 c5d7f60f Laszlo Ersek
#ifdef DEBUG_GUEST_PHYS_REGION_ADD
253 c5d7f60f Laszlo Ersek
    fprintf(stderr, "%s: target_start=" TARGET_FMT_plx " target_end="
254 c5d7f60f Laszlo Ersek
            TARGET_FMT_plx ": %s (count: %u)\n", __FUNCTION__, target_start,
255 c5d7f60f Laszlo Ersek
            target_end, predecessor ? "joined" : "added", g->list->num);
256 c5d7f60f Laszlo Ersek
#endif
257 c5d7f60f Laszlo Ersek
}
258 c5d7f60f Laszlo Ersek
259 c5d7f60f Laszlo Ersek
void guest_phys_blocks_append(GuestPhysBlockList *list)
260 c5d7f60f Laszlo Ersek
{
261 c5d7f60f Laszlo Ersek
    GuestPhysListener g = { 0 };
262 c5d7f60f Laszlo Ersek
263 c5d7f60f Laszlo Ersek
    g.list = list;
264 c5d7f60f Laszlo Ersek
    g.listener.region_add = &guest_phys_blocks_region_add;
265 c5d7f60f Laszlo Ersek
    memory_listener_register(&g.listener, &address_space_memory);
266 c5d7f60f Laszlo Ersek
    memory_listener_unregister(&g.listener);
267 c5d7f60f Laszlo Ersek
}
268 c5d7f60f Laszlo Ersek
269 182735ef Andreas Färber
static CPUState *find_paging_enabled_cpu(CPUState *start_cpu)
270 c517076d Wen Congyang
{
271 182735ef Andreas Färber
    CPUState *cpu;
272 c517076d Wen Congyang
273 182735ef Andreas Färber
    for (cpu = start_cpu; cpu != NULL; cpu = cpu->next_cpu) {
274 182735ef Andreas Färber
        if (cpu_paging_enabled(cpu)) {
275 182735ef Andreas Färber
            return cpu;
276 c517076d Wen Congyang
        }
277 c517076d Wen Congyang
    }
278 c517076d Wen Congyang
279 c517076d Wen Congyang
    return NULL;
280 c517076d Wen Congyang
}
281 c517076d Wen Congyang
282 56c4bfb3 Laszlo Ersek
void qemu_get_guest_memory_mapping(MemoryMappingList *list,
283 56c4bfb3 Laszlo Ersek
                                   const GuestPhysBlockList *guest_phys_blocks,
284 56c4bfb3 Laszlo Ersek
                                   Error **errp)
285 c517076d Wen Congyang
{
286 182735ef Andreas Färber
    CPUState *cpu, *first_paging_enabled_cpu;
287 56c4bfb3 Laszlo Ersek
    GuestPhysBlock *block;
288 c517076d Wen Congyang
    ram_addr_t offset, length;
289 c517076d Wen Congyang
290 c517076d Wen Congyang
    first_paging_enabled_cpu = find_paging_enabled_cpu(first_cpu);
291 c517076d Wen Congyang
    if (first_paging_enabled_cpu) {
292 182735ef Andreas Färber
        for (cpu = first_paging_enabled_cpu; cpu != NULL; cpu = cpu->next_cpu) {
293 a23bbfda Andreas Färber
            Error *err = NULL;
294 182735ef Andreas Färber
            cpu_get_memory_mapping(cpu, list, &err);
295 a23bbfda Andreas Färber
            if (err) {
296 11ed09cf Andreas Färber
                error_propagate(errp, err);
297 11ed09cf Andreas Färber
                return;
298 c517076d Wen Congyang
            }
299 c517076d Wen Congyang
        }
300 11ed09cf Andreas Färber
        return;
301 c517076d Wen Congyang
    }
302 c517076d Wen Congyang
303 c517076d Wen Congyang
    /*
304 c517076d Wen Congyang
     * If the guest doesn't use paging, the virtual address is equal to physical
305 c517076d Wen Congyang
     * address.
306 c517076d Wen Congyang
     */
307 56c4bfb3 Laszlo Ersek
    QTAILQ_FOREACH(block, &guest_phys_blocks->head, next) {
308 56c4bfb3 Laszlo Ersek
        offset = block->target_start;
309 56c4bfb3 Laszlo Ersek
        length = block->target_end - block->target_start;
310 c517076d Wen Congyang
        create_new_memory_mapping(list, offset, offset, length);
311 c517076d Wen Congyang
    }
312 c517076d Wen Congyang
}
313 2b05ab52 Wen Congyang
314 56c4bfb3 Laszlo Ersek
void qemu_get_guest_simple_memory_mapping(MemoryMappingList *list,
315 56c4bfb3 Laszlo Ersek
                                   const GuestPhysBlockList *guest_phys_blocks)
316 2b05ab52 Wen Congyang
{
317 56c4bfb3 Laszlo Ersek
    GuestPhysBlock *block;
318 2b05ab52 Wen Congyang
319 56c4bfb3 Laszlo Ersek
    QTAILQ_FOREACH(block, &guest_phys_blocks->head, next) {
320 56c4bfb3 Laszlo Ersek
        create_new_memory_mapping(list, block->target_start, 0,
321 56c4bfb3 Laszlo Ersek
                                  block->target_end - block->target_start);
322 2b05ab52 Wen Congyang
    }
323 2b05ab52 Wen Congyang
}
324 783e9b48 Wen Congyang
325 783e9b48 Wen Congyang
void memory_mapping_filter(MemoryMappingList *list, int64_t begin,
326 783e9b48 Wen Congyang
                           int64_t length)
327 783e9b48 Wen Congyang
{
328 783e9b48 Wen Congyang
    MemoryMapping *cur, *next;
329 783e9b48 Wen Congyang
330 783e9b48 Wen Congyang
    QTAILQ_FOREACH_SAFE(cur, &list->head, next, next) {
331 783e9b48 Wen Congyang
        if (cur->phys_addr >= begin + length ||
332 783e9b48 Wen Congyang
            cur->phys_addr + cur->length <= begin) {
333 783e9b48 Wen Congyang
            QTAILQ_REMOVE(&list->head, cur, next);
334 783e9b48 Wen Congyang
            list->num--;
335 783e9b48 Wen Congyang
            continue;
336 783e9b48 Wen Congyang
        }
337 783e9b48 Wen Congyang
338 783e9b48 Wen Congyang
        if (cur->phys_addr < begin) {
339 783e9b48 Wen Congyang
            cur->length -= begin - cur->phys_addr;
340 783e9b48 Wen Congyang
            if (cur->virt_addr) {
341 783e9b48 Wen Congyang
                cur->virt_addr += begin - cur->phys_addr;
342 783e9b48 Wen Congyang
            }
343 783e9b48 Wen Congyang
            cur->phys_addr = begin;
344 783e9b48 Wen Congyang
        }
345 783e9b48 Wen Congyang
346 783e9b48 Wen Congyang
        if (cur->phys_addr + cur->length > begin + length) {
347 783e9b48 Wen Congyang
            cur->length -= cur->phys_addr + cur->length - begin - length;
348 783e9b48 Wen Congyang
        }
349 783e9b48 Wen Congyang
    }
350 783e9b48 Wen Congyang
}