diff options
author | bellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162> | 2004-01-24 15:29:03 +0000 |
---|---|---|
committer | bellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162> | 2004-01-24 15:29:03 +0000 |
commit | 10f0e412f81c40a2b853b0f44708bb92a99cd587 (patch) | |
tree | 9b525f30a32a27b1e6cf56184aa012030ea3c058 /target-i386/helper2.c | |
parent | 4b7aba517372180537d98434e1604d5b0c4e8527 (diff) |
combine PDE and PTE protections as in intel specs - added cpu_get_phys_page_debug()
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@584 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'target-i386/helper2.c')
-rw-r--r-- | target-i386/helper2.c | 80 |
1 files changed, 62 insertions, 18 deletions
diff --git a/target-i386/helper2.c b/target-i386/helper2.c index d5c7727cb1..5e91b2d1c9 100644 --- a/target-i386/helper2.c +++ b/target-i386/helper2.c @@ -260,7 +260,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, int is_write, int is_user, int is_softmmu) { uint8_t *pde_ptr, *pte_ptr; - uint32_t pde, pte, virt_addr; + uint32_t pde, pte, virt_addr, ptep; int error_code, is_dirty, prot, page_size, ret; unsigned long paddr, vaddr, page_offset; @@ -291,18 +291,18 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, error_code = 0; goto do_fault; } - if (is_user) { - if (!(pde & PG_USER_MASK)) - goto do_fault_protect; - if (is_write && !(pde & PG_RW_MASK)) - goto do_fault_protect; - } else { - if ((env->cr[0] & CR0_WP_MASK) && (pde & PG_USER_MASK) && - is_write && !(pde & PG_RW_MASK)) - goto do_fault_protect; - } /* if PSE bit is set, then we use a 4MB page */ if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) { + if (is_user) { + if (!(pde & PG_USER_MASK)) + goto do_fault_protect; + if (is_write && !(pde & PG_RW_MASK)) + goto do_fault_protect; + } else { + if ((env->cr[0] & CR0_WP_MASK) && (pde & PG_USER_MASK) && + is_write && !(pde & PG_RW_MASK)) + goto do_fault_protect; + } is_dirty = is_write && !(pde & PG_DIRTY_MASK); if (!(pde & PG_ACCESSED_MASK) || is_dirty) { pde |= PG_ACCESSED_MASK; @@ -312,6 +312,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, } pte = pde & ~0x003ff000; /* align to 4MB */ + ptep = pte; page_size = 4096 * 1024; virt_addr = addr & ~0x003fffff; } else { @@ -328,14 +329,16 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, error_code = 0; goto do_fault; } + /* combine pde and pte user and rw protections */ + ptep = pte & pde; if (is_user) { - if (!(pte & PG_USER_MASK)) + if (!(ptep & PG_USER_MASK)) goto do_fault_protect; - if (is_write && !(pte & PG_RW_MASK)) + if (is_write && !(ptep & PG_RW_MASK)) goto do_fault_protect; } else { - if ((env->cr[0] & CR0_WP_MASK) && (pte & PG_USER_MASK) && - is_write && !(pte & PG_RW_MASK)) + if ((env->cr[0] & CR0_WP_MASK) && (ptep & PG_USER_MASK) && + is_write && !(ptep & PG_RW_MASK)) goto do_fault_protect; } is_dirty = is_write && !(pte & PG_DIRTY_MASK); @@ -355,11 +358,11 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, /* only set write access if already dirty... otherwise wait for dirty access */ if (is_user) { - if (pte & PG_RW_MASK) + if (ptep & PG_RW_MASK) prot |= PROT_WRITE; } else { - if (!(env->cr[0] & CR0_WP_MASK) || !(pte & PG_USER_MASK) || - (pte & PG_RW_MASK)) + if (!(env->cr[0] & CR0_WP_MASK) || !(ptep & PG_USER_MASK) || + (ptep & PG_RW_MASK)) prot |= PROT_WRITE; } } @@ -384,3 +387,44 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, env->error_code |= PG_ERROR_U_MASK; return 1; } + +#if defined(CONFIG_USER_ONLY) +target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) +{ + return addr; +} +#else +target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) +{ + uint8_t *pde_ptr, *pte_ptr; + 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)) & a20_mask); + pde = ldl_raw(pde_ptr); + 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; + } else { + /* page directory entry */ + pte_ptr = phys_ram_base + + (((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & a20_mask); + pte = ldl_raw(pte_ptr); + if (!(pte & PG_PRESENT_MASK)) + return -1; + page_size = 4096; + } + } + pte = pte & a20_mask; + page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1); + paddr = (pte & TARGET_PAGE_MASK) + page_offset; + return paddr; +} +#endif |