Commit 0ba5f006bb143ea5ef5cac1746f52bbbf529c836
1 parent
967032c3
x86/x86-64 MMU PAE fixes
This patch fixes MMU emulation in PAE mode for > 4GB physical addresses: - a20_mask should have the correct size to not clear the high part of the addresses. - PHYS_ADDR_MASK should not clear the high part of the addresses. - pdpe, pde and pte could be located anywhere in memory on x86-64, but only in the first 4GB on x86, define their pointer to as target_ulong. - pml4e_addr could be located anywhere in memory, define its pointer as uint64_t. - paddr represents a physical address and thus should be of type target_phys_addr_t. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4239 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
2 changed files
with
24 additions
and
20 deletions
target-i386/cpu.h
| ... | ... | @@ -499,7 +499,7 @@ typedef struct CPUX86State { |
| 499 | 499 | SegmentCache idt; /* only base and limit are used */ |
| 500 | 500 | |
| 501 | 501 | target_ulong cr[9]; /* NOTE: cr1, cr5-7 are unused */ |
| 502 | - uint32_t a20_mask; | |
| 502 | + uint64_t a20_mask; | |
| 503 | 503 | |
| 504 | 504 | /* FPU state */ |
| 505 | 505 | unsigned int fpstt; /* top of stack index */ | ... | ... |
target-i386/helper2.c
| ... | ... | @@ -377,7 +377,7 @@ void cpu_reset(CPUX86State *env) |
| 377 | 377 | env->hflags |= HF_GIF_MASK; |
| 378 | 378 | |
| 379 | 379 | cpu_x86_update_cr0(env, 0x60000010); |
| 380 | - env->a20_mask = 0xffffffff; | |
| 380 | + env->a20_mask = ~0x0; | |
| 381 | 381 | env->smbase = 0x30000; |
| 382 | 382 | |
| 383 | 383 | env->idt.limit = 0xffff; |
| ... | ... | @@ -695,7 +695,7 @@ void cpu_x86_set_a20(CPUX86State *env, int a20_state) |
| 695 | 695 | /* when a20 is changed, all the MMU mappings are invalid, so |
| 696 | 696 | we must flush everything */ |
| 697 | 697 | tlb_flush(env, 1); |
| 698 | - env->a20_mask = 0xffefffff | (a20_state << 20); | |
| 698 | + env->a20_mask = (~0x100000) | (a20_state << 20); | |
| 699 | 699 | } |
| 700 | 700 | } |
| 701 | 701 | |
| ... | ... | @@ -800,7 +800,7 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) |
| 800 | 800 | |
| 801 | 801 | #else |
| 802 | 802 | |
| 803 | -#define PHYS_ADDR_MASK 0xfffff000 | |
| 803 | +#define PHYS_ADDR_MASK (~0xfff) | |
| 804 | 804 | |
| 805 | 805 | /* return value: |
| 806 | 806 | -1 = cannot handle fault |
| ... | ... | @@ -812,9 +812,10 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, |
| 812 | 812 | int is_write1, int mmu_idx, int is_softmmu) |
| 813 | 813 | { |
| 814 | 814 | uint64_t ptep, pte; |
| 815 | - uint32_t pdpe_addr, pde_addr, pte_addr; | |
| 815 | + target_ulong pde_addr, pte_addr; | |
| 816 | 816 | int error_code, is_dirty, prot, page_size, ret, is_write, is_user; |
| 817 | - unsigned long paddr, page_offset; | |
| 817 | + target_phys_addr_t paddr; | |
| 818 | + uint32_t page_offset; | |
| 818 | 819 | target_ulong vaddr, virt_addr; |
| 819 | 820 | |
| 820 | 821 | is_user = mmu_idx == MMU_USER_IDX; |
| ... | ... | @@ -834,12 +835,11 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, |
| 834 | 835 | |
| 835 | 836 | if (env->cr[4] & CR4_PAE_MASK) { |
| 836 | 837 | uint64_t pde, pdpe; |
| 838 | + target_ulong pdpe_addr; | |
| 837 | 839 | |
| 838 | - /* XXX: we only use 32 bit physical addresses */ | |
| 839 | 840 | #ifdef TARGET_X86_64 |
| 840 | 841 | if (env->hflags & HF_LMA_MASK) { |
| 841 | - uint32_t pml4e_addr; | |
| 842 | - uint64_t pml4e; | |
| 842 | + uint64_t pml4e_addr, pml4e; | |
| 843 | 843 | int32_t sext; |
| 844 | 844 | |
| 845 | 845 | /* test virtual address sign extension */ |
| ... | ... | @@ -1101,17 +1101,19 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, |
| 1101 | 1101 | |
| 1102 | 1102 | target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) |
| 1103 | 1103 | { |
| 1104 | - uint32_t pde_addr, pte_addr; | |
| 1105 | - uint32_t pde, pte, paddr, page_offset, page_size; | |
| 1104 | + target_ulong pde_addr, pte_addr; | |
| 1105 | + uint64_t pte; | |
| 1106 | + target_phys_addr_t paddr; | |
| 1107 | + uint32_t page_offset; | |
| 1108 | + int page_size; | |
| 1106 | 1109 | |
| 1107 | 1110 | if (env->cr[4] & CR4_PAE_MASK) { |
| 1108 | - uint32_t pdpe_addr, pde_addr, pte_addr; | |
| 1109 | - uint32_t pdpe; | |
| 1111 | + target_ulong pdpe_addr; | |
| 1112 | + uint64_t pde, pdpe; | |
| 1110 | 1113 | |
| 1111 | - /* XXX: we only use 32 bit physical addresses */ | |
| 1112 | 1114 | #ifdef TARGET_X86_64 |
| 1113 | 1115 | if (env->hflags & HF_LMA_MASK) { |
| 1114 | - uint32_t pml4e_addr, pml4e; | |
| 1116 | + uint64_t pml4e_addr, pml4e; | |
| 1115 | 1117 | int32_t sext; |
| 1116 | 1118 | |
| 1117 | 1119 | /* test virtual address sign extension */ |
| ... | ... | @@ -1121,13 +1123,13 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) |
| 1121 | 1123 | |
| 1122 | 1124 | pml4e_addr = ((env->cr[3] & ~0xfff) + (((addr >> 39) & 0x1ff) << 3)) & |
| 1123 | 1125 | env->a20_mask; |
| 1124 | - pml4e = ldl_phys(pml4e_addr); | |
| 1126 | + pml4e = ldq_phys(pml4e_addr); | |
| 1125 | 1127 | if (!(pml4e & PG_PRESENT_MASK)) |
| 1126 | 1128 | return -1; |
| 1127 | 1129 | |
| 1128 | 1130 | pdpe_addr = ((pml4e & ~0xfff) + (((addr >> 30) & 0x1ff) << 3)) & |
| 1129 | 1131 | env->a20_mask; |
| 1130 | - pdpe = ldl_phys(pdpe_addr); | |
| 1132 | + pdpe = ldq_phys(pdpe_addr); | |
| 1131 | 1133 | if (!(pdpe & PG_PRESENT_MASK)) |
| 1132 | 1134 | return -1; |
| 1133 | 1135 | } else |
| ... | ... | @@ -1135,14 +1137,14 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) |
| 1135 | 1137 | { |
| 1136 | 1138 | pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 27) & 0x18)) & |
| 1137 | 1139 | env->a20_mask; |
| 1138 | - pdpe = ldl_phys(pdpe_addr); | |
| 1140 | + pdpe = ldq_phys(pdpe_addr); | |
| 1139 | 1141 | if (!(pdpe & PG_PRESENT_MASK)) |
| 1140 | 1142 | return -1; |
| 1141 | 1143 | } |
| 1142 | 1144 | |
| 1143 | 1145 | pde_addr = ((pdpe & ~0xfff) + (((addr >> 21) & 0x1ff) << 3)) & |
| 1144 | 1146 | env->a20_mask; |
| 1145 | - pde = ldl_phys(pde_addr); | |
| 1147 | + pde = ldq_phys(pde_addr); | |
| 1146 | 1148 | if (!(pde & PG_PRESENT_MASK)) { |
| 1147 | 1149 | return -1; |
| 1148 | 1150 | } |
| ... | ... | @@ -1155,9 +1157,11 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) |
| 1155 | 1157 | pte_addr = ((pde & ~0xfff) + (((addr >> 12) & 0x1ff) << 3)) & |
| 1156 | 1158 | env->a20_mask; |
| 1157 | 1159 | page_size = 4096; |
| 1158 | - pte = ldl_phys(pte_addr); | |
| 1160 | + pte = ldq_phys(pte_addr); | |
| 1159 | 1161 | } |
| 1160 | 1162 | } else { |
| 1163 | + uint32_t pde; | |
| 1164 | + | |
| 1161 | 1165 | if (!(env->cr[0] & CR0_PG_MASK)) { |
| 1162 | 1166 | pte = addr; |
| 1163 | 1167 | page_size = 4096; | ... | ... |