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; |