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,7 +499,7 @@ typedef struct CPUX86State { | ||
| 499 | SegmentCache idt; /* only base and limit are used */ | 499 | SegmentCache idt; /* only base and limit are used */ |
| 500 | 500 | ||
| 501 | target_ulong cr[9]; /* NOTE: cr1, cr5-7 are unused */ | 501 | target_ulong cr[9]; /* NOTE: cr1, cr5-7 are unused */ |
| 502 | - uint32_t a20_mask; | 502 | + uint64_t a20_mask; |
| 503 | 503 | ||
| 504 | /* FPU state */ | 504 | /* FPU state */ |
| 505 | unsigned int fpstt; /* top of stack index */ | 505 | unsigned int fpstt; /* top of stack index */ |
target-i386/helper2.c
| @@ -377,7 +377,7 @@ void cpu_reset(CPUX86State *env) | @@ -377,7 +377,7 @@ void cpu_reset(CPUX86State *env) | ||
| 377 | env->hflags |= HF_GIF_MASK; | 377 | env->hflags |= HF_GIF_MASK; |
| 378 | 378 | ||
| 379 | cpu_x86_update_cr0(env, 0x60000010); | 379 | cpu_x86_update_cr0(env, 0x60000010); |
| 380 | - env->a20_mask = 0xffffffff; | 380 | + env->a20_mask = ~0x0; |
| 381 | env->smbase = 0x30000; | 381 | env->smbase = 0x30000; |
| 382 | 382 | ||
| 383 | env->idt.limit = 0xffff; | 383 | env->idt.limit = 0xffff; |
| @@ -695,7 +695,7 @@ void cpu_x86_set_a20(CPUX86State *env, int a20_state) | @@ -695,7 +695,7 @@ void cpu_x86_set_a20(CPUX86State *env, int a20_state) | ||
| 695 | /* when a20 is changed, all the MMU mappings are invalid, so | 695 | /* when a20 is changed, all the MMU mappings are invalid, so |
| 696 | we must flush everything */ | 696 | we must flush everything */ |
| 697 | tlb_flush(env, 1); | 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,7 +800,7 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) | ||
| 800 | 800 | ||
| 801 | #else | 801 | #else |
| 802 | 802 | ||
| 803 | -#define PHYS_ADDR_MASK 0xfffff000 | 803 | +#define PHYS_ADDR_MASK (~0xfff) |
| 804 | 804 | ||
| 805 | /* return value: | 805 | /* return value: |
| 806 | -1 = cannot handle fault | 806 | -1 = cannot handle fault |
| @@ -812,9 +812,10 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, | @@ -812,9 +812,10 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, | ||
| 812 | int is_write1, int mmu_idx, int is_softmmu) | 812 | int is_write1, int mmu_idx, int is_softmmu) |
| 813 | { | 813 | { |
| 814 | uint64_t ptep, pte; | 814 | uint64_t ptep, pte; |
| 815 | - uint32_t pdpe_addr, pde_addr, pte_addr; | 815 | + target_ulong pde_addr, pte_addr; |
| 816 | int error_code, is_dirty, prot, page_size, ret, is_write, is_user; | 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 | target_ulong vaddr, virt_addr; | 819 | target_ulong vaddr, virt_addr; |
| 819 | 820 | ||
| 820 | is_user = mmu_idx == MMU_USER_IDX; | 821 | is_user = mmu_idx == MMU_USER_IDX; |
| @@ -834,12 +835,11 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, | @@ -834,12 +835,11 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, | ||
| 834 | 835 | ||
| 835 | if (env->cr[4] & CR4_PAE_MASK) { | 836 | if (env->cr[4] & CR4_PAE_MASK) { |
| 836 | uint64_t pde, pdpe; | 837 | uint64_t pde, pdpe; |
| 838 | + target_ulong pdpe_addr; | ||
| 837 | 839 | ||
| 838 | - /* XXX: we only use 32 bit physical addresses */ | ||
| 839 | #ifdef TARGET_X86_64 | 840 | #ifdef TARGET_X86_64 |
| 840 | if (env->hflags & HF_LMA_MASK) { | 841 | if (env->hflags & HF_LMA_MASK) { |
| 841 | - uint32_t pml4e_addr; | ||
| 842 | - uint64_t pml4e; | 842 | + uint64_t pml4e_addr, pml4e; |
| 843 | int32_t sext; | 843 | int32_t sext; |
| 844 | 844 | ||
| 845 | /* test virtual address sign extension */ | 845 | /* test virtual address sign extension */ |
| @@ -1101,17 +1101,19 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, | @@ -1101,17 +1101,19 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, | ||
| 1101 | 1101 | ||
| 1102 | target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) | 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 | if (env->cr[4] & CR4_PAE_MASK) { | 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 | #ifdef TARGET_X86_64 | 1114 | #ifdef TARGET_X86_64 |
| 1113 | if (env->hflags & HF_LMA_MASK) { | 1115 | if (env->hflags & HF_LMA_MASK) { |
| 1114 | - uint32_t pml4e_addr, pml4e; | 1116 | + uint64_t pml4e_addr, pml4e; |
| 1115 | int32_t sext; | 1117 | int32_t sext; |
| 1116 | 1118 | ||
| 1117 | /* test virtual address sign extension */ | 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,13 +1123,13 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) | ||
| 1121 | 1123 | ||
| 1122 | pml4e_addr = ((env->cr[3] & ~0xfff) + (((addr >> 39) & 0x1ff) << 3)) & | 1124 | pml4e_addr = ((env->cr[3] & ~0xfff) + (((addr >> 39) & 0x1ff) << 3)) & |
| 1123 | env->a20_mask; | 1125 | env->a20_mask; |
| 1124 | - pml4e = ldl_phys(pml4e_addr); | 1126 | + pml4e = ldq_phys(pml4e_addr); |
| 1125 | if (!(pml4e & PG_PRESENT_MASK)) | 1127 | if (!(pml4e & PG_PRESENT_MASK)) |
| 1126 | return -1; | 1128 | return -1; |
| 1127 | 1129 | ||
| 1128 | pdpe_addr = ((pml4e & ~0xfff) + (((addr >> 30) & 0x1ff) << 3)) & | 1130 | pdpe_addr = ((pml4e & ~0xfff) + (((addr >> 30) & 0x1ff) << 3)) & |
| 1129 | env->a20_mask; | 1131 | env->a20_mask; |
| 1130 | - pdpe = ldl_phys(pdpe_addr); | 1132 | + pdpe = ldq_phys(pdpe_addr); |
| 1131 | if (!(pdpe & PG_PRESENT_MASK)) | 1133 | if (!(pdpe & PG_PRESENT_MASK)) |
| 1132 | return -1; | 1134 | return -1; |
| 1133 | } else | 1135 | } else |
| @@ -1135,14 +1137,14 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) | @@ -1135,14 +1137,14 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) | ||
| 1135 | { | 1137 | { |
| 1136 | pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 27) & 0x18)) & | 1138 | pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 27) & 0x18)) & |
| 1137 | env->a20_mask; | 1139 | env->a20_mask; |
| 1138 | - pdpe = ldl_phys(pdpe_addr); | 1140 | + pdpe = ldq_phys(pdpe_addr); |
| 1139 | if (!(pdpe & PG_PRESENT_MASK)) | 1141 | if (!(pdpe & PG_PRESENT_MASK)) |
| 1140 | return -1; | 1142 | return -1; |
| 1141 | } | 1143 | } |
| 1142 | 1144 | ||
| 1143 | pde_addr = ((pdpe & ~0xfff) + (((addr >> 21) & 0x1ff) << 3)) & | 1145 | pde_addr = ((pdpe & ~0xfff) + (((addr >> 21) & 0x1ff) << 3)) & |
| 1144 | env->a20_mask; | 1146 | env->a20_mask; |
| 1145 | - pde = ldl_phys(pde_addr); | 1147 | + pde = ldq_phys(pde_addr); |
| 1146 | if (!(pde & PG_PRESENT_MASK)) { | 1148 | if (!(pde & PG_PRESENT_MASK)) { |
| 1147 | return -1; | 1149 | return -1; |
| 1148 | } | 1150 | } |
| @@ -1155,9 +1157,11 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) | @@ -1155,9 +1157,11 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) | ||
| 1155 | pte_addr = ((pde & ~0xfff) + (((addr >> 12) & 0x1ff) << 3)) & | 1157 | pte_addr = ((pde & ~0xfff) + (((addr >> 12) & 0x1ff) << 3)) & |
| 1156 | env->a20_mask; | 1158 | env->a20_mask; |
| 1157 | page_size = 4096; | 1159 | page_size = 4096; |
| 1158 | - pte = ldl_phys(pte_addr); | 1160 | + pte = ldq_phys(pte_addr); |
| 1159 | } | 1161 | } |
| 1160 | } else { | 1162 | } else { |
| 1163 | + uint32_t pde; | ||
| 1164 | + | ||
| 1161 | if (!(env->cr[0] & CR0_PG_MASK)) { | 1165 | if (!(env->cr[0] & CR0_PG_MASK)) { |
| 1162 | pte = addr; | 1166 | pte = addr; |
| 1163 | page_size = 4096; | 1167 | page_size = 4096; |