diff options
author | bellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162> | 2005-01-25 22:35:05 +0000 |
---|---|---|
committer | bellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162> | 2005-01-25 22:35:05 +0000 |
commit | f51589dad53ff431d827f1326b5313b81488e0dc (patch) | |
tree | a2662b4ce4a6342b1a13c6def6777e70617a002c | |
parent | 82e41634cdf063fae727fdb1563479d2209f79ee (diff) |
Support resolving addresses in PAE mode in cpu_get_phys_page_debug
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1240 c046a42c-6fe2-441c-8c8c-71466251a162
-rw-r--r-- | target-i386/helper2.c | 92 |
1 files changed, 73 insertions, 19 deletions
diff --git a/target-i386/helper2.c b/target-i386/helper2.c index 2a15ec737d..f78786ee6d 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -742,33 +742,87 @@ target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) #else target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) { - uint8_t *pde_ptr, *pte_ptr; + uint32_t pde_addr, pte_addr; uint32_t pde, pte, paddr, page_offset, page_size; - if (!(env->cr[0] & CR0_PG_MASK)) { - pte = addr; - page_size = 4096; - } else { - /* page directory entry */ - pde_ptr = phys_ram_base + - (((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)) & env->a20_mask); - pde = ldl_raw(pde_ptr); - if (!(pde & PG_PRESENT_MASK)) + if (env->cr[4] & CR4_PAE_MASK) { + uint32_t pdpe_addr, pde_addr, pte_addr; + uint32_t pdpe; + + /* XXX: we only use 32 bit physical addresses */ +#ifdef TARGET_X86_64 + if (env->hflags & HF_LMA_MASK) { + uint32_t pml4e_addr, pml4e; + int32_t sext; + + /* test virtual address sign extension */ + sext = (int64_t)addr >> 47; + if (sext != 0 && sext != -1) + return -1; + + pml4e_addr = ((env->cr[3] & ~0xfff) + (((addr >> 39) & 0x1ff) << 3)) & + env->a20_mask; + pml4e = ldl_phys_aligned(pml4e_addr); + if (!(pml4e & PG_PRESENT_MASK)) + return -1; + + pdpe_addr = ((pml4e & ~0xfff) + (((addr >> 30) & 0x1ff) << 3)) & + env->a20_mask; + pdpe = ldl_phys_aligned(pdpe_addr); + if (!(pdpe & PG_PRESENT_MASK)) + return -1; + } else +#endif + { + pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 30) << 3)) & + env->a20_mask; + pdpe = ldl_phys_aligned(pdpe_addr); + if (!(pdpe & PG_PRESENT_MASK)) + return -1; + } + + pde_addr = ((pdpe & ~0xfff) + (((addr >> 21) & 0x1ff) << 3)) & + env->a20_mask; + pde = ldl_phys_aligned(pde_addr); + if (!(pde & PG_PRESENT_MASK)) { return -1; - if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) { - pte = pde & ~0x003ff000; /* align to 4MB */ - page_size = 4096 * 1024; + } + if (pde & PG_PSE_MASK) { + /* 2 MB page */ + page_size = 2048 * 1024; + pte = pde & ~( (page_size - 1) & ~0xfff); /* align to page_size */ + } else { + /* 4 KB page */ + pte_addr = ((pde & ~0xfff) + (((addr >> 12) & 0x1ff) << 3)) & + env->a20_mask; + page_size = 4096; + pte = ldl_phys_aligned(pte_addr); + } + } else { + if (!(env->cr[0] & CR0_PG_MASK)) { + pte = addr; + page_size = 4096; } else { /* page directory entry */ - pte_ptr = phys_ram_base + - (((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & env->a20_mask); - pte = ldl_raw(pte_ptr); - if (!(pte & PG_PRESENT_MASK)) + pde_addr = ((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)) & env->a20_mask; + pde = ldl_phys_aligned(pde_addr); + if (!(pde & PG_PRESENT_MASK)) return -1; - page_size = 4096; + if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) { + pte = pde & ~0x003ff000; /* align to 4MB */ + page_size = 4096 * 1024; + } else { + /* page directory entry */ + pte_addr = ((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & env->a20_mask; + pte = ldl_phys_aligned(pte_addr); + if (!(pte & PG_PRESENT_MASK)) + return -1; + page_size = 4096; + } } + pte = pte & env->a20_mask; } - pte = pte & env->a20_mask; + page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1); paddr = (pte & TARGET_PAGE_MASK) + page_offset; return paddr; |