Statistics
| Branch: | Revision:

root / memory_mapping.c @ bf0842b7

History | View | Annotate | Download (7 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 80167a8a Wen Congyang
#include "cpu.h"
15 022c62cb Paolo Bonzini
#include "exec/cpu-all.h"
16 9c17d615 Paolo Bonzini
#include "sysemu/memory_mapping.h"
17 80167a8a Wen Congyang
18 80167a8a Wen Congyang
static void memory_mapping_list_add_mapping_sorted(MemoryMappingList *list,
19 80167a8a Wen Congyang
                                                   MemoryMapping *mapping)
20 80167a8a Wen Congyang
{
21 80167a8a Wen Congyang
    MemoryMapping *p;
22 80167a8a Wen Congyang
23 80167a8a Wen Congyang
    QTAILQ_FOREACH(p, &list->head, next) {
24 80167a8a Wen Congyang
        if (p->phys_addr >= mapping->phys_addr) {
25 80167a8a Wen Congyang
            QTAILQ_INSERT_BEFORE(p, mapping, next);
26 80167a8a Wen Congyang
            return;
27 80167a8a Wen Congyang
        }
28 80167a8a Wen Congyang
    }
29 80167a8a Wen Congyang
    QTAILQ_INSERT_TAIL(&list->head, mapping, next);
30 80167a8a Wen Congyang
}
31 80167a8a Wen Congyang
32 80167a8a Wen Congyang
static void create_new_memory_mapping(MemoryMappingList *list,
33 a8170e5e Avi Kivity
                                      hwaddr phys_addr,
34 a8170e5e Avi Kivity
                                      hwaddr virt_addr,
35 80167a8a Wen Congyang
                                      ram_addr_t length)
36 80167a8a Wen Congyang
{
37 80167a8a Wen Congyang
    MemoryMapping *memory_mapping;
38 80167a8a Wen Congyang
39 80167a8a Wen Congyang
    memory_mapping = g_malloc(sizeof(MemoryMapping));
40 80167a8a Wen Congyang
    memory_mapping->phys_addr = phys_addr;
41 80167a8a Wen Congyang
    memory_mapping->virt_addr = virt_addr;
42 80167a8a Wen Congyang
    memory_mapping->length = length;
43 80167a8a Wen Congyang
    list->last_mapping = memory_mapping;
44 80167a8a Wen Congyang
    list->num++;
45 80167a8a Wen Congyang
    memory_mapping_list_add_mapping_sorted(list, memory_mapping);
46 80167a8a Wen Congyang
}
47 80167a8a Wen Congyang
48 80167a8a Wen Congyang
static inline bool mapping_contiguous(MemoryMapping *map,
49 a8170e5e Avi Kivity
                                      hwaddr phys_addr,
50 a8170e5e Avi Kivity
                                      hwaddr virt_addr)
51 80167a8a Wen Congyang
{
52 80167a8a Wen Congyang
    return phys_addr == map->phys_addr + map->length &&
53 80167a8a Wen Congyang
           virt_addr == map->virt_addr + map->length;
54 80167a8a Wen Congyang
}
55 80167a8a Wen Congyang
56 80167a8a Wen Congyang
/*
57 80167a8a Wen Congyang
 * [map->phys_addr, map->phys_addr + map->length) and
58 80167a8a Wen Congyang
 * [phys_addr, phys_addr + length) have intersection?
59 80167a8a Wen Congyang
 */
60 80167a8a Wen Congyang
static inline bool mapping_have_same_region(MemoryMapping *map,
61 a8170e5e Avi Kivity
                                            hwaddr phys_addr,
62 80167a8a Wen Congyang
                                            ram_addr_t length)
63 80167a8a Wen Congyang
{
64 80167a8a Wen Congyang
    return !(phys_addr + length < map->phys_addr ||
65 80167a8a Wen Congyang
             phys_addr >= map->phys_addr + map->length);
66 80167a8a Wen Congyang
}
67 80167a8a Wen Congyang
68 80167a8a Wen Congyang
/*
69 80167a8a Wen Congyang
 * [map->phys_addr, map->phys_addr + map->length) and
70 80167a8a Wen Congyang
 * [phys_addr, phys_addr + length) have intersection. The virtual address in the
71 80167a8a Wen Congyang
 * intersection are the same?
72 80167a8a Wen Congyang
 */
73 80167a8a Wen Congyang
static inline bool mapping_conflict(MemoryMapping *map,
74 a8170e5e Avi Kivity
                                    hwaddr phys_addr,
75 a8170e5e Avi Kivity
                                    hwaddr virt_addr)
76 80167a8a Wen Congyang
{
77 80167a8a Wen Congyang
    return virt_addr - map->virt_addr != phys_addr - map->phys_addr;
78 80167a8a Wen Congyang
}
79 80167a8a Wen Congyang
80 80167a8a Wen Congyang
/*
81 80167a8a Wen Congyang
 * [map->virt_addr, map->virt_addr + map->length) and
82 80167a8a Wen Congyang
 * [virt_addr, virt_addr + length) have intersection. And the physical address
83 80167a8a Wen Congyang
 * in the intersection are the same.
84 80167a8a Wen Congyang
 */
85 80167a8a Wen Congyang
static inline void mapping_merge(MemoryMapping *map,
86 a8170e5e Avi Kivity
                                 hwaddr virt_addr,
87 80167a8a Wen Congyang
                                 ram_addr_t length)
88 80167a8a Wen Congyang
{
89 80167a8a Wen Congyang
    if (virt_addr < map->virt_addr) {
90 80167a8a Wen Congyang
        map->length += map->virt_addr - virt_addr;
91 80167a8a Wen Congyang
        map->virt_addr = virt_addr;
92 80167a8a Wen Congyang
    }
93 80167a8a Wen Congyang
94 80167a8a Wen Congyang
    if ((virt_addr + length) >
95 80167a8a Wen Congyang
        (map->virt_addr + map->length)) {
96 80167a8a Wen Congyang
        map->length = virt_addr + length - map->virt_addr;
97 80167a8a Wen Congyang
    }
98 80167a8a Wen Congyang
}
99 80167a8a Wen Congyang
100 80167a8a Wen Congyang
void memory_mapping_list_add_merge_sorted(MemoryMappingList *list,
101 a8170e5e Avi Kivity
                                          hwaddr phys_addr,
102 a8170e5e Avi Kivity
                                          hwaddr virt_addr,
103 80167a8a Wen Congyang
                                          ram_addr_t length)
104 80167a8a Wen Congyang
{
105 80167a8a Wen Congyang
    MemoryMapping *memory_mapping, *last_mapping;
106 80167a8a Wen Congyang
107 80167a8a Wen Congyang
    if (QTAILQ_EMPTY(&list->head)) {
108 80167a8a Wen Congyang
        create_new_memory_mapping(list, phys_addr, virt_addr, length);
109 80167a8a Wen Congyang
        return;
110 80167a8a Wen Congyang
    }
111 80167a8a Wen Congyang
112 80167a8a Wen Congyang
    last_mapping = list->last_mapping;
113 80167a8a Wen Congyang
    if (last_mapping) {
114 80167a8a Wen Congyang
        if (mapping_contiguous(last_mapping, phys_addr, virt_addr)) {
115 80167a8a Wen Congyang
            last_mapping->length += length;
116 80167a8a Wen Congyang
            return;
117 80167a8a Wen Congyang
        }
118 80167a8a Wen Congyang
    }
119 80167a8a Wen Congyang
120 80167a8a Wen Congyang
    QTAILQ_FOREACH(memory_mapping, &list->head, next) {
121 80167a8a Wen Congyang
        if (mapping_contiguous(memory_mapping, phys_addr, virt_addr)) {
122 80167a8a Wen Congyang
            memory_mapping->length += length;
123 80167a8a Wen Congyang
            list->last_mapping = memory_mapping;
124 80167a8a Wen Congyang
            return;
125 80167a8a Wen Congyang
        }
126 80167a8a Wen Congyang
127 80167a8a Wen Congyang
        if (phys_addr + length < memory_mapping->phys_addr) {
128 80167a8a Wen Congyang
            /* create a new region before memory_mapping */
129 80167a8a Wen Congyang
            break;
130 80167a8a Wen Congyang
        }
131 80167a8a Wen Congyang
132 80167a8a Wen Congyang
        if (mapping_have_same_region(memory_mapping, phys_addr, length)) {
133 80167a8a Wen Congyang
            if (mapping_conflict(memory_mapping, phys_addr, virt_addr)) {
134 80167a8a Wen Congyang
                continue;
135 80167a8a Wen Congyang
            }
136 80167a8a Wen Congyang
137 80167a8a Wen Congyang
            /* merge this region into memory_mapping */
138 80167a8a Wen Congyang
            mapping_merge(memory_mapping, virt_addr, length);
139 80167a8a Wen Congyang
            list->last_mapping = memory_mapping;
140 80167a8a Wen Congyang
            return;
141 80167a8a Wen Congyang
        }
142 80167a8a Wen Congyang
    }
143 80167a8a Wen Congyang
144 80167a8a Wen Congyang
    /* this region can not be merged into any existed memory mapping. */
145 80167a8a Wen Congyang
    create_new_memory_mapping(list, phys_addr, virt_addr, length);
146 80167a8a Wen Congyang
}
147 80167a8a Wen Congyang
148 80167a8a Wen Congyang
void memory_mapping_list_free(MemoryMappingList *list)
149 80167a8a Wen Congyang
{
150 80167a8a Wen Congyang
    MemoryMapping *p, *q;
151 80167a8a Wen Congyang
152 80167a8a Wen Congyang
    QTAILQ_FOREACH_SAFE(p, &list->head, next, q) {
153 80167a8a Wen Congyang
        QTAILQ_REMOVE(&list->head, p, next);
154 80167a8a Wen Congyang
        g_free(p);
155 80167a8a Wen Congyang
    }
156 80167a8a Wen Congyang
157 80167a8a Wen Congyang
    list->num = 0;
158 80167a8a Wen Congyang
    list->last_mapping = NULL;
159 80167a8a Wen Congyang
}
160 80167a8a Wen Congyang
161 80167a8a Wen Congyang
void memory_mapping_list_init(MemoryMappingList *list)
162 80167a8a Wen Congyang
{
163 80167a8a Wen Congyang
    list->num = 0;
164 80167a8a Wen Congyang
    list->last_mapping = NULL;
165 80167a8a Wen Congyang
    QTAILQ_INIT(&list->head);
166 80167a8a Wen Congyang
}
167 c517076d Wen Congyang
168 c517076d Wen Congyang
static CPUArchState *find_paging_enabled_cpu(CPUArchState *start_cpu)
169 c517076d Wen Congyang
{
170 c517076d Wen Congyang
    CPUArchState *env;
171 c517076d Wen Congyang
172 c517076d Wen Congyang
    for (env = start_cpu; env != NULL; env = env->next_cpu) {
173 c517076d Wen Congyang
        if (cpu_paging_enabled(env)) {
174 c517076d Wen Congyang
            return env;
175 c517076d Wen Congyang
        }
176 c517076d Wen Congyang
    }
177 c517076d Wen Congyang
178 c517076d Wen Congyang
    return NULL;
179 c517076d Wen Congyang
}
180 c517076d Wen Congyang
181 c517076d Wen Congyang
int qemu_get_guest_memory_mapping(MemoryMappingList *list)
182 c517076d Wen Congyang
{
183 c517076d Wen Congyang
    CPUArchState *env, *first_paging_enabled_cpu;
184 c517076d Wen Congyang
    RAMBlock *block;
185 c517076d Wen Congyang
    ram_addr_t offset, length;
186 c517076d Wen Congyang
    int ret;
187 c517076d Wen Congyang
188 c517076d Wen Congyang
    first_paging_enabled_cpu = find_paging_enabled_cpu(first_cpu);
189 c517076d Wen Congyang
    if (first_paging_enabled_cpu) {
190 c517076d Wen Congyang
        for (env = first_paging_enabled_cpu; env != NULL; env = env->next_cpu) {
191 c517076d Wen Congyang
            ret = cpu_get_memory_mapping(list, env);
192 c517076d Wen Congyang
            if (ret < 0) {
193 c517076d Wen Congyang
                return -1;
194 c517076d Wen Congyang
            }
195 c517076d Wen Congyang
        }
196 c517076d Wen Congyang
        return 0;
197 c517076d Wen Congyang
    }
198 c517076d Wen Congyang
199 c517076d Wen Congyang
    /*
200 c517076d Wen Congyang
     * If the guest doesn't use paging, the virtual address is equal to physical
201 c517076d Wen Congyang
     * address.
202 c517076d Wen Congyang
     */
203 a3161038 Paolo Bonzini
    QTAILQ_FOREACH(block, &ram_list.blocks, next) {
204 c517076d Wen Congyang
        offset = block->offset;
205 c517076d Wen Congyang
        length = block->length;
206 c517076d Wen Congyang
        create_new_memory_mapping(list, offset, offset, length);
207 c517076d Wen Congyang
    }
208 c517076d Wen Congyang
209 c517076d Wen Congyang
    return 0;
210 c517076d Wen Congyang
}
211 2b05ab52 Wen Congyang
212 2b05ab52 Wen Congyang
void qemu_get_guest_simple_memory_mapping(MemoryMappingList *list)
213 2b05ab52 Wen Congyang
{
214 2b05ab52 Wen Congyang
    RAMBlock *block;
215 2b05ab52 Wen Congyang
216 a3161038 Paolo Bonzini
    QTAILQ_FOREACH(block, &ram_list.blocks, next) {
217 2b05ab52 Wen Congyang
        create_new_memory_mapping(list, block->offset, 0, block->length);
218 2b05ab52 Wen Congyang
    }
219 2b05ab52 Wen Congyang
}
220 783e9b48 Wen Congyang
221 783e9b48 Wen Congyang
void memory_mapping_filter(MemoryMappingList *list, int64_t begin,
222 783e9b48 Wen Congyang
                           int64_t length)
223 783e9b48 Wen Congyang
{
224 783e9b48 Wen Congyang
    MemoryMapping *cur, *next;
225 783e9b48 Wen Congyang
226 783e9b48 Wen Congyang
    QTAILQ_FOREACH_SAFE(cur, &list->head, next, next) {
227 783e9b48 Wen Congyang
        if (cur->phys_addr >= begin + length ||
228 783e9b48 Wen Congyang
            cur->phys_addr + cur->length <= begin) {
229 783e9b48 Wen Congyang
            QTAILQ_REMOVE(&list->head, cur, next);
230 783e9b48 Wen Congyang
            list->num--;
231 783e9b48 Wen Congyang
            continue;
232 783e9b48 Wen Congyang
        }
233 783e9b48 Wen Congyang
234 783e9b48 Wen Congyang
        if (cur->phys_addr < begin) {
235 783e9b48 Wen Congyang
            cur->length -= begin - cur->phys_addr;
236 783e9b48 Wen Congyang
            if (cur->virt_addr) {
237 783e9b48 Wen Congyang
                cur->virt_addr += begin - cur->phys_addr;
238 783e9b48 Wen Congyang
            }
239 783e9b48 Wen Congyang
            cur->phys_addr = begin;
240 783e9b48 Wen Congyang
        }
241 783e9b48 Wen Congyang
242 783e9b48 Wen Congyang
        if (cur->phys_addr + cur->length > begin + length) {
243 783e9b48 Wen Congyang
            cur->length -= cur->phys_addr + cur->length - begin - length;
244 783e9b48 Wen Congyang
        }
245 783e9b48 Wen Congyang
    }
246 783e9b48 Wen Congyang
}