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 { 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 = ((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); 242 } 243 } 244 #endif 245 246 void x86_cpu_get_memory_mapping(CPUState *cs, MemoryMappingList *list, 247 Error **errp) 248 { 249 X86CPU *cpu = X86_CPU(cs); 250 CPUX86State *env = &cpu->env; 251 252 if (!cpu_paging_enabled(cs)) { 253 /* paging is disabled */ 254 return; 255 } 256 257 if (env->cr[4] & CR4_PAE_MASK) { 258 #ifdef TARGET_X86_64 259 if (env->hflags & HF_LMA_MASK) { 260 hwaddr pml4e_addr; 261 262 pml4e_addr = (env->cr[3] & PLM4_ADDR_MASK) & env->a20_mask; 263 walk_pml4e(list, cs->as, pml4e_addr, env->a20_mask); 264 } else 265 #endif 266 { 267 hwaddr pdpe_addr; 268 269 pdpe_addr = (env->cr[3] & ~0x1f) & env->a20_mask; 270 walk_pdpe2(list, cs->as, pdpe_addr, env->a20_mask); 271 } 272 } else { 273 hwaddr pde_addr; 274 bool pse; 275 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); 279 } 280 } 281 282