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 | } |