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