4 * Copyright Fujitsu, Corp. 2011, 2012
7 * Wen Congyang <wency@cn.fujitsu.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 "qemu/osdep.h"
16 #include "exec/cpu-all.h"
17 #include "sysemu/memory_mapping.h"
19 /* PAE Paging or IA-32e Paging */
20 static void walk_pte(MemoryMappingList
*list
, AddressSpace
*as
,
21 hwaddr pte_start_addr
,
22 int32_t a20_mask
, target_ulong start_line_addr
)
24 hwaddr pte_addr
, start_paddr
;
26 target_ulong start_vaddr
;
29 for (i
= 0; i
< 512; i
++) {
30 pte_addr
= (pte_start_addr
+ i
* 8) & a20_mask
;
31 pte
= address_space_ldq(as
, pte_addr
, MEMTXATTRS_UNSPECIFIED
, NULL
);
32 if (!(pte
& PG_PRESENT_MASK
)) {
37 start_paddr
= (pte
& ~0xfff) & ~(0x1ULL
<< 63);
38 if (cpu_physical_memory_is_io(start_paddr
)) {
43 start_vaddr
= start_line_addr
| ((i
& 0x1ff) << 12);
44 memory_mapping_list_add_merge_sorted(list
, start_paddr
,
45 start_vaddr
, 1 << 12);
50 static void walk_pte2(MemoryMappingList
*list
, AddressSpace
*as
,
51 hwaddr pte_start_addr
, int32_t a20_mask
,
52 target_ulong start_line_addr
)
54 hwaddr pte_addr
, start_paddr
;
56 target_ulong start_vaddr
;
59 for (i
= 0; i
< 1024; i
++) {
60 pte_addr
= (pte_start_addr
+ i
* 4) & a20_mask
;
61 pte
= address_space_ldl(as
, pte_addr
, MEMTXATTRS_UNSPECIFIED
, NULL
);
62 if (!(pte
& PG_PRESENT_MASK
)) {
67 start_paddr
= pte
& ~0xfff;
68 if (cpu_physical_memory_is_io(start_paddr
)) {
73 start_vaddr
= start_line_addr
| ((i
& 0x3ff) << 12);
74 memory_mapping_list_add_merge_sorted(list
, start_paddr
,
75 start_vaddr
, 1 << 12);
79 /* PAE Paging or IA-32e Paging */
80 #define PLM4_ADDR_MASK 0xffffffffff000ULL /* selects bits 51:12 */
82 static void walk_pde(MemoryMappingList
*list
, AddressSpace
*as
,
83 hwaddr pde_start_addr
,
84 int32_t a20_mask
, target_ulong start_line_addr
)
86 hwaddr pde_addr
, pte_start_addr
, start_paddr
;
88 target_ulong line_addr
, start_vaddr
;
91 for (i
= 0; i
< 512; i
++) {
92 pde_addr
= (pde_start_addr
+ i
* 8) & a20_mask
;
93 pde
= address_space_ldq(as
, pde_addr
, MEMTXATTRS_UNSPECIFIED
, NULL
);
94 if (!(pde
& PG_PRESENT_MASK
)) {
99 line_addr
= start_line_addr
| ((i
& 0x1ff) << 21);
100 if (pde
& PG_PSE_MASK
) {
102 start_paddr
= (pde
& ~0x1fffff) & ~(0x1ULL
<< 63);
103 if (cpu_physical_memory_is_io(start_paddr
)) {
107 start_vaddr
= line_addr
;
108 memory_mapping_list_add_merge_sorted(list
, start_paddr
,
109 start_vaddr
, 1 << 21);
113 pte_start_addr
= (pde
& PLM4_ADDR_MASK
) & a20_mask
;
114 walk_pte(list
, as
, pte_start_addr
, a20_mask
, line_addr
);
119 static void walk_pde2(MemoryMappingList
*list
, AddressSpace
*as
,
120 hwaddr pde_start_addr
, int32_t a20_mask
,
123 hwaddr pde_addr
, pte_start_addr
, start_paddr
, high_paddr
;
125 target_ulong line_addr
, start_vaddr
;
128 for (i
= 0; i
< 1024; i
++) {
129 pde_addr
= (pde_start_addr
+ i
* 4) & a20_mask
;
130 pde
= address_space_ldl(as
, pde_addr
, MEMTXATTRS_UNSPECIFIED
, NULL
);
131 if (!(pde
& PG_PRESENT_MASK
)) {
136 line_addr
= (((unsigned int)i
& 0x3ff) << 22);
137 if ((pde
& PG_PSE_MASK
) && pse
) {
140 * bits 39:32 are bits 20:13 of the PDE
141 * bit3 31:22 are bits 31:22 of the PDE
143 high_paddr
= ((hwaddr
)(pde
& 0x1fe000) << 19);
144 start_paddr
= (pde
& ~0x3fffff) | high_paddr
;
145 if (cpu_physical_memory_is_io(start_paddr
)) {
149 start_vaddr
= line_addr
;
150 memory_mapping_list_add_merge_sorted(list
, start_paddr
,
151 start_vaddr
, 1 << 22);
155 pte_start_addr
= (pde
& ~0xfff) & a20_mask
;
156 walk_pte2(list
, as
, pte_start_addr
, a20_mask
, line_addr
);
161 static void walk_pdpe2(MemoryMappingList
*list
, AddressSpace
*as
,
162 hwaddr pdpe_start_addr
, int32_t a20_mask
)
164 hwaddr pdpe_addr
, pde_start_addr
;
166 target_ulong line_addr
;
169 for (i
= 0; i
< 4; i
++) {
170 pdpe_addr
= (pdpe_start_addr
+ i
* 8) & a20_mask
;
171 pdpe
= address_space_ldq(as
, pdpe_addr
, MEMTXATTRS_UNSPECIFIED
, NULL
);
172 if (!(pdpe
& PG_PRESENT_MASK
)) {
177 line_addr
= (((unsigned int)i
& 0x3) << 30);
178 pde_start_addr
= (pdpe
& ~0xfff) & a20_mask
;
179 walk_pde(list
, as
, pde_start_addr
, a20_mask
, line_addr
);
185 static void walk_pdpe(MemoryMappingList
*list
, AddressSpace
*as
,
186 hwaddr pdpe_start_addr
, int32_t a20_mask
,
187 target_ulong start_line_addr
)
189 hwaddr pdpe_addr
, pde_start_addr
, start_paddr
;
191 target_ulong line_addr
, start_vaddr
;
194 for (i
= 0; i
< 512; i
++) {
195 pdpe_addr
= (pdpe_start_addr
+ i
* 8) & a20_mask
;
196 pdpe
= address_space_ldq(as
, pdpe_addr
, MEMTXATTRS_UNSPECIFIED
, NULL
);
197 if (!(pdpe
& PG_PRESENT_MASK
)) {
202 line_addr
= start_line_addr
| ((i
& 0x1ffULL
) << 30);
203 if (pdpe
& PG_PSE_MASK
) {
205 start_paddr
= (pdpe
& ~0x3fffffff) & ~(0x1ULL
<< 63);
206 if (cpu_physical_memory_is_io(start_paddr
)) {
210 start_vaddr
= line_addr
;
211 memory_mapping_list_add_merge_sorted(list
, start_paddr
,
212 start_vaddr
, 1 << 30);
216 pde_start_addr
= (pdpe
& PLM4_ADDR_MASK
) & a20_mask
;
217 walk_pde(list
, as
, pde_start_addr
, a20_mask
, line_addr
);
222 static void walk_pml4e(MemoryMappingList
*list
, AddressSpace
*as
,
223 hwaddr pml4e_start_addr
, int32_t a20_mask
)
225 hwaddr pml4e_addr
, pdpe_start_addr
;
227 target_ulong line_addr
;
230 for (i
= 0; i
< 512; i
++) {
231 pml4e_addr
= (pml4e_start_addr
+ i
* 8) & a20_mask
;
232 pml4e
= address_space_ldq(as
, pml4e_addr
, MEMTXATTRS_UNSPECIFIED
,
234 if (!(pml4e
& PG_PRESENT_MASK
)) {
239 line_addr
= ((i
& 0x1ffULL
) << 39) | (0xffffULL
<< 48);
240 pdpe_start_addr
= (pml4e
& PLM4_ADDR_MASK
) & a20_mask
;
241 walk_pdpe(list
, as
, pdpe_start_addr
, a20_mask
, line_addr
);
246 void x86_cpu_get_memory_mapping(CPUState
*cs
, MemoryMappingList
*list
,
249 X86CPU
*cpu
= X86_CPU(cs
);
250 CPUX86State
*env
= &cpu
->env
;
252 if (!cpu_paging_enabled(cs
)) {
253 /* paging is disabled */
257 if (env
->cr
[4] & CR4_PAE_MASK
) {
259 if (env
->hflags
& HF_LMA_MASK
) {
262 pml4e_addr
= (env
->cr
[3] & PLM4_ADDR_MASK
) & env
->a20_mask
;
263 walk_pml4e(list
, cs
->as
, pml4e_addr
, env
->a20_mask
);
269 pdpe_addr
= (env
->cr
[3] & ~0x1f) & env
->a20_mask
;
270 walk_pdpe2(list
, cs
->as
, pdpe_addr
, env
->a20_mask
);
276 pde_addr
= (env
->cr
[3] & ~0xfff) & env
->a20_mask
;
277 pse
= !!(env
->cr
[4] & CR4_PSE_MASK
);
278 walk_pde2(list
, cs
->as
, pde_addr
, env
->a20_mask
, pse
);