From 0ba5f006bb143ea5ef5cac1746f52bbbf529c836 Mon Sep 17 00:00:00 2001 From: aurel32 Date: Tue, 22 Apr 2008 20:37:43 +0000 Subject: [PATCH] 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 --- target-i386/cpu.h | 2 +- target-i386/helper2.c | 42 +++++++++++++++++++++++------------------- 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 152b673ee9..235e209b39 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -499,7 +499,7 @@ typedef struct CPUX86State { SegmentCache idt; /* only base and limit are used */ target_ulong cr[9]; /* NOTE: cr1, cr5-7 are unused */ - uint32_t a20_mask; + uint64_t a20_mask; /* FPU state */ unsigned int fpstt; /* top of stack index */ diff --git a/target-i386/helper2.c b/target-i386/helper2.c index 3b9cd947df..d5dc96ba16 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -377,7 +377,7 @@ void cpu_reset(CPUX86State *env) env->hflags |= HF_GIF_MASK; cpu_x86_update_cr0(env, 0x60000010); - env->a20_mask = 0xffffffff; + env->a20_mask = ~0x0; env->smbase = 0x30000; env->idt.limit = 0xffff; @@ -695,7 +695,7 @@ void cpu_x86_set_a20(CPUX86State *env, int a20_state) /* when a20 is changed, all the MMU mappings are invalid, so we must flush everything */ tlb_flush(env, 1); - env->a20_mask = 0xffefffff | (a20_state << 20); + env->a20_mask = (~0x100000) | (a20_state << 20); } } @@ -800,7 +800,7 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) #else -#define PHYS_ADDR_MASK 0xfffff000 +#define PHYS_ADDR_MASK (~0xfff) /* return value: -1 = cannot handle fault @@ -812,9 +812,10 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, int is_write1, int mmu_idx, int is_softmmu) { uint64_t ptep, pte; - uint32_t pdpe_addr, pde_addr, pte_addr; + target_ulong pde_addr, pte_addr; int error_code, is_dirty, prot, page_size, ret, is_write, is_user; - unsigned long paddr, page_offset; + target_phys_addr_t paddr; + uint32_t page_offset; target_ulong vaddr, virt_addr; is_user = mmu_idx == MMU_USER_IDX; @@ -834,12 +835,11 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, if (env->cr[4] & CR4_PAE_MASK) { uint64_t pde, pdpe; + target_ulong pdpe_addr; - /* XXX: we only use 32 bit physical addresses */ #ifdef TARGET_X86_64 if (env->hflags & HF_LMA_MASK) { - uint32_t pml4e_addr; - uint64_t pml4e; + uint64_t pml4e_addr, pml4e; int32_t sext; /* test virtual address sign extension */ @@ -1101,17 +1101,19 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) { - uint32_t pde_addr, pte_addr; - uint32_t pde, pte, paddr, page_offset, page_size; + target_ulong pde_addr, pte_addr; + uint64_t pte; + target_phys_addr_t paddr; + uint32_t page_offset; + int page_size; if (env->cr[4] & CR4_PAE_MASK) { - uint32_t pdpe_addr, pde_addr, pte_addr; - uint32_t pdpe; + target_ulong pdpe_addr; + uint64_t pde, pdpe; - /* XXX: we only use 32 bit physical addresses */ #ifdef TARGET_X86_64 if (env->hflags & HF_LMA_MASK) { - uint32_t pml4e_addr, pml4e; + uint64_t pml4e_addr, pml4e; int32_t sext; /* test virtual address sign extension */ @@ -1121,13 +1123,13 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) pml4e_addr = ((env->cr[3] & ~0xfff) + (((addr >> 39) & 0x1ff) << 3)) & env->a20_mask; - pml4e = ldl_phys(pml4e_addr); + pml4e = ldq_phys(pml4e_addr); if (!(pml4e & PG_PRESENT_MASK)) return -1; pdpe_addr = ((pml4e & ~0xfff) + (((addr >> 30) & 0x1ff) << 3)) & env->a20_mask; - pdpe = ldl_phys(pdpe_addr); + pdpe = ldq_phys(pdpe_addr); if (!(pdpe & PG_PRESENT_MASK)) return -1; } else @@ -1135,14 +1137,14 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) { pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 27) & 0x18)) & env->a20_mask; - pdpe = ldl_phys(pdpe_addr); + pdpe = ldq_phys(pdpe_addr); if (!(pdpe & PG_PRESENT_MASK)) return -1; } pde_addr = ((pdpe & ~0xfff) + (((addr >> 21) & 0x1ff) << 3)) & env->a20_mask; - pde = ldl_phys(pde_addr); + pde = ldq_phys(pde_addr); if (!(pde & PG_PRESENT_MASK)) { return -1; } @@ -1155,9 +1157,11 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) pte_addr = ((pde & ~0xfff) + (((addr >> 12) & 0x1ff) << 3)) & env->a20_mask; page_size = 4096; - pte = ldl_phys(pte_addr); + pte = ldq_phys(pte_addr); } } else { + uint32_t pde; + if (!(env->cr[0] & CR0_PG_MASK)) { pte = addr; page_size = 4096;