aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>2005-01-25 22:35:05 +0000
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>2005-01-25 22:35:05 +0000
commitf51589dad53ff431d827f1326b5313b81488e0dc (patch)
treea2662b4ce4a6342b1a13c6def6777e70617a002c
parent82e41634cdf063fae727fdb1563479d2209f79ee (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.c92
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;