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