1 /* 2 * i386 memory mapping 3 * 4 * Copyright Fujitsu, Corp. 2011, 2012 5 * 6 * Authors: 7 * Wen Congyang <wency@cn.fujitsu.com> 8 * 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. 11 * 12 */ 13 14 #include "qemu/osdep.h" 15 #include "cpu.h" 16 #include "exec/cpu-all.h" 17 #include "sysemu/memory_mapping.h" 18 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) 23 { 24 hwaddr pte_addr, start_paddr; 25 uint64_t pte; 26 target_ulong start_vaddr; 27 int i; 28 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)) { 33 /* not present */ 34 continue; 35 } 36 37 start_paddr = (pte & ~0xfff) & ~(0x1ULL << 63); 38 if (cpu_physical_memory_is_io(start_paddr)) { 39 /* I/O region */ 40 continue; 41 } 42 43 start_vaddr = start_line_addr | ((i & 0x1ff) << 12); 44 memory_mapping_list_add_merge_sorted(list, start_paddr, 45 start_vaddr, 1 << 12); 46 } 47 } 48 49 /* 32-bit Paging */ 50 static void walk_pte2(MemoryMappingList *list, AddressSpace *as, 51 hwaddr pte_start_addr, int32_t a20_mask, 52 target_ulong start_line_addr) 53 { 54 hwaddr pte_addr, start_paddr; 55 uint32_t pte; 56 target_ulong start_vaddr; 57 int i; 58 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)) { 63 /* not present */ 64 continue; 65 } 66 67 start_paddr = pte & ~0xfff; 68 if (cpu_physical_memory_is_io(start_paddr)) { 69 /* I/O region */ 70 continue; 71 } 72 73 start_vaddr = start_line_addr | ((i & 0x3ff) << 12); 74 memory_mapping_list_add_merge_sorted(list, start_paddr, 75 start_vaddr, 1 << 12); 76 } 77 } 78 79 /* PAE Paging or IA-32e Paging */ 80 #define PLM4_ADDR_MASK 0xffffffffff000ULL /* selects bits 51:12 */ 81 82 static void walk_pde(MemoryMappingList *list, AddressSpace *as, 83 hwaddr pde_start_addr, 84 int32_t a20_mask, target_ulong start_line_addr) 85 { 86 hwaddr pde_addr, pte_start_addr, start_paddr; 87 uint64_t pde; 88 target_ulong line_addr, start_vaddr; 89 int i; 90 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)) { 95 /* not present */ 96 continue; 97 } 98 99 line_addr = start_line_addr | ((i & 0x1ff) << 21); 100 if (pde & PG_PSE_MASK) { 101 /* 2 MB page */ 102 start_paddr = (pde & ~0x1fffff) & ~(0x1ULL << 63); 103 if (cpu_physical_memory_is_io(start_paddr)) { 104 /* I/O region */ 105 continue; 106 } 107 start_vaddr = line_addr; 108 memory_mapping_list_add_merge_sorted(list, start_paddr, 109 start_vaddr, 1 << 21); 110 continue; 111 } 112 113 pte_start_addr = (pde & PLM4_ADDR_MASK) & a20_mask; 114 walk_pte(list, as, pte_start_addr, a20_mask, line_addr); 115 } 116 } 117 118 /* 32-bit Paging */ 119 static void walk_pde2(MemoryMappingList *list, AddressSpace *as, 120 hwaddr pde_start_addr, int32_t a20_mask, 121 bool pse) 122 { 123 hwaddr pde_addr, pte_start_addr, start_paddr, high_paddr; 124 uint32_t pde; 125 target_ulong line_addr, start_vaddr; 126 int i; 127 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)) { 132 /* not present */ 133 continue; 134 } 135 136 line_addr = (((unsigned int)i & 0x3ff) << 22); 137 if ((pde & PG_PSE_MASK) && pse) { 138 /* 139 * 4 MB page: 140 * bits 39:32 are bits 20:13 of the PDE 141 * bit3 31:22 are bits 31:22 of the PDE 142 */ 143 high_paddr = ((hwaddr)(pde & 0x1fe000) << 19); 144 start_paddr = (pde & ~0x3fffff) | high_paddr; 145 if (cpu_physical_memory_is_io(start_paddr)) { 146 /* I/O region */ 147 continue; 148 } 149 start_vaddr = line_addr; 150 memory_mapping_list_add_merge_sorted(list, start_paddr, 151 start_vaddr, 1 << 22); 152 continue; 153 } 154 155 pte_start_addr = (pde & ~0xfff) & a20_mask; 156 walk_pte2(list, as, pte_start_addr, a20_mask, line_addr); 157 } 158 } 159 160 /* PAE Paging */ 161 static void walk_pdpe2(MemoryMappingList *list, AddressSpace *as, 162 hwaddr pdpe_start_addr, int32_t a20_mask) 163 { 164 hwaddr pdpe_addr, pde_start_addr; 165 uint64_t pdpe; 166 target_ulong line_addr; 167 int i; 168 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)) { 173 /* not present */ 174 continue; 175 } 176 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); 180 } 181 } 182 183 #ifdef TARGET_X86_64 184 /* IA-32e Paging */ 185 static void walk_pdpe(MemoryMappingList *list, AddressSpace *as, 186 hwaddr pdpe_start_addr, int32_t a20_mask, 187 target_ulong start_line_addr) 188 { 189 hwaddr pdpe_addr, pde_start_addr, start_paddr; 190 uint64_t pdpe; 191 target_ulong line_addr, start_vaddr; 192 int i; 193 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)) { 198 /* not present */ 199 continue; 200 } 201 202 line_addr = start_line_addr | ((i & 0x1ffULL) << 30); 203 if (pdpe & PG_PSE_MASK) { 204 /* 1 GB page */ 205 start_paddr = (pdpe & ~0x3fffffff) & ~(0x1ULL << 63); 206 if (cpu_physical_memory_is_io(start_paddr)) { 207 /* I/O region */ 208 continue; 209 } 210 start_vaddr = line_addr; 211 memory_mapping_list_add_merge_sorted(list, start_paddr, 212 start_vaddr, 1 << 30); 213 continue; 214 } 215 216 pde_start_addr = (pdpe & PLM4_ADDR_MASK) & a20_mask; 217 walk_pde(list, as, pde_start_addr, a20_mask, line_addr); 218 } 219 } 220 221 /* IA-32e Paging */ 222 static void walk_pml4e(MemoryMappingList *list, AddressSpace *as, 223 hwaddr pml4e_start_addr, int32_t a20_mask, 224 target_ulong start_line_addr) 225 { 226 hwaddr pml4e_addr, pdpe_start_addr; 227 uint64_t pml4e; 228 target_ulong line_addr; 229 int i; 230 231 for (i = 0; i < 512; i++) { 232 pml4e_addr = (pml4e_start_addr + i * 8) & a20_mask; 233 pml4e = address_space_ldq(as, pml4e_addr, MEMTXATTRS_UNSPECIFIED, 234 NULL); 235 if (!(pml4e & PG_PRESENT_MASK)) { 236 /* not present */ 237 continue; 238 } 239 240 line_addr = start_line_addr | ((i & 0x1ffULL) << 39); 241 pdpe_start_addr = (pml4e & PLM4_ADDR_MASK) & a20_mask; 242 walk_pdpe(list, as, pdpe_start_addr, a20_mask, line_addr); 243 } 244 } 245 246 static void walk_pml5e(MemoryMappingList *list, AddressSpace *as, 247 hwaddr pml5e_start_addr, int32_t a20_mask) 248 { 249 hwaddr pml5e_addr, pml4e_start_addr; 250 uint64_t pml5e; 251 target_ulong line_addr; 252 int i; 253 254 for (i = 0; i < 512; i++) { 255 pml5e_addr = (pml5e_start_addr + i * 8) & a20_mask; 256 pml5e = address_space_ldq(as, pml5e_addr, MEMTXATTRS_UNSPECIFIED, 257 NULL); 258 if (!(pml5e & PG_PRESENT_MASK)) { 259 /* not present */ 260 continue; 261 } 262 263 line_addr = (0x7fULL << 57) | ((i & 0x1ffULL) << 48); 264 pml4e_start_addr = (pml5e & PLM4_ADDR_MASK) & a20_mask; 265 walk_pml4e(list, as, pml4e_start_addr, a20_mask, line_addr); 266 } 267 } 268 #endif 269 270 void x86_cpu_get_memory_mapping(CPUState *cs, MemoryMappingList *list, 271 Error **errp) 272 { 273 X86CPU *cpu = X86_CPU(cs); 274 CPUX86State *env = &cpu->env; 275 int32_t a20_mask; 276 277 if (!cpu_paging_enabled(cs)) { 278 /* paging is disabled */ 279 return; 280 } 281 282 a20_mask = x86_get_a20_mask(env); 283 if (env->cr[4] & CR4_PAE_MASK) { 284 #ifdef TARGET_X86_64 285 if (env->hflags & HF_LMA_MASK) { 286 if (env->cr[4] & CR4_LA57_MASK) { 287 hwaddr pml5e_addr; 288 289 pml5e_addr = (env->cr[3] & PLM4_ADDR_MASK) & a20_mask; 290 walk_pml5e(list, cs->as, pml5e_addr, a20_mask); 291 } else { 292 hwaddr pml4e_addr; 293 294 pml4e_addr = (env->cr[3] & PLM4_ADDR_MASK) & a20_mask; 295 walk_pml4e(list, cs->as, pml4e_addr, a20_mask, 296 0xffffULL << 48); 297 } 298 } else 299 #endif 300 { 301 hwaddr pdpe_addr; 302 303 pdpe_addr = (env->cr[3] & ~0x1f) & a20_mask; 304 walk_pdpe2(list, cs->as, pdpe_addr, a20_mask); 305 } 306 } else { 307 hwaddr pde_addr; 308 bool pse; 309 310 pde_addr = (env->cr[3] & ~0xfff) & a20_mask; 311 pse = !!(env->cr[4] & CR4_PSE_MASK); 312 walk_pde2(list, cs->as, pde_addr, a20_mask, pse); 313 } 314 } 315 316