aboutsummaryrefslogtreecommitdiff
path: root/target-i386
diff options
context:
space:
mode:
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>2004-01-24 15:29:03 +0000
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>2004-01-24 15:29:03 +0000
commit10f0e412f81c40a2b853b0f44708bb92a99cd587 (patch)
tree9b525f30a32a27b1e6cf56184aa012030ea3c058 /target-i386
parent4b7aba517372180537d98434e1604d5b0c4e8527 (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')
-rw-r--r--target-i386/helper2.c80
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