target-i386: do not duplicate page protection checks
x86_cpu_handle_mmu_fault is currently checking twice for writability and executability of pages; the first time to decide whether to trigger a page fault, the second time to compute the "prot" argument to tlb_set_page_with_attrs. Reorganize code so that first "prot" is computed, then it is used to check whether to raise a page fault, then finally PROT_WRITE is removed if the D bit will have to be set. Reviewed-by: Richard Henderson <rth@twiddle.net> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
3daa41078a
commit
76c64d3360
|
@ -890,38 +890,30 @@ do_check_protect_pse36:
|
||||||
goto do_fault_rsvd;
|
goto do_fault_rsvd;
|
||||||
}
|
}
|
||||||
ptep ^= PG_NX_MASK;
|
ptep ^= PG_NX_MASK;
|
||||||
if ((ptep & PG_NX_MASK) && is_write1 == 2) {
|
|
||||||
goto do_fault_protect;
|
|
||||||
}
|
|
||||||
switch (mmu_idx) {
|
|
||||||
case MMU_USER_IDX:
|
|
||||||
if (!(ptep & PG_USER_MASK)) {
|
|
||||||
goto do_fault_protect;
|
|
||||||
}
|
|
||||||
if (is_write && !(ptep & PG_RW_MASK)) {
|
|
||||||
goto do_fault_protect;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MMU_KSMAP_IDX:
|
/* can the page can be put in the TLB? prot will tell us */
|
||||||
if (is_write1 != 2 && (ptep & PG_USER_MASK)) {
|
if (is_user && !(ptep & PG_USER_MASK)) {
|
||||||
goto do_fault_protect;
|
goto do_fault_protect;
|
||||||
}
|
}
|
||||||
/* fall through */
|
|
||||||
case MMU_KNOSMAP_IDX:
|
|
||||||
if (is_write1 == 2 && (env->cr[4] & CR4_SMEP_MASK) &&
|
|
||||||
(ptep & PG_USER_MASK)) {
|
|
||||||
goto do_fault_protect;
|
|
||||||
}
|
|
||||||
if ((env->cr[0] & CR0_WP_MASK) &&
|
|
||||||
is_write && !(ptep & PG_RW_MASK)) {
|
|
||||||
goto do_fault_protect;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default: /* cannot happen */
|
prot = 0;
|
||||||
break;
|
if (mmu_idx != MMU_KSMAP_IDX || !(ptep & PG_USER_MASK)) {
|
||||||
|
prot |= PAGE_READ;
|
||||||
|
if ((ptep & PG_RW_MASK) || (!is_user && !(env->cr[0] & CR0_WP_MASK))) {
|
||||||
|
prot |= PAGE_WRITE;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (!(ptep & PG_NX_MASK) &&
|
||||||
|
(mmu_idx == MMU_USER_IDX ||
|
||||||
|
!((env->cr[4] & CR4_SMEP_MASK) && (ptep & PG_USER_MASK)))) {
|
||||||
|
prot |= PAGE_EXEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((prot & (1 << is_write1)) == 0) {
|
||||||
|
goto do_fault_protect;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* yes, it can! */
|
||||||
is_dirty = is_write && !(pte & PG_DIRTY_MASK);
|
is_dirty = is_write && !(pte & PG_DIRTY_MASK);
|
||||||
if (!(pte & PG_ACCESSED_MASK) || is_dirty) {
|
if (!(pte & PG_ACCESSED_MASK) || is_dirty) {
|
||||||
pte |= PG_ACCESSED_MASK;
|
pte |= PG_ACCESSED_MASK;
|
||||||
|
@ -931,25 +923,13 @@ do_check_protect_pse36:
|
||||||
x86_stl_phys_notdirty(cs, pte_addr, pte);
|
x86_stl_phys_notdirty(cs, pte_addr, pte);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* the page can be put in the TLB */
|
if (!(pte & PG_DIRTY_MASK)) {
|
||||||
prot = PAGE_READ;
|
|
||||||
if (!(ptep & PG_NX_MASK) &&
|
|
||||||
(mmu_idx == MMU_USER_IDX ||
|
|
||||||
!((env->cr[4] & CR4_SMEP_MASK) && (ptep & PG_USER_MASK)))) {
|
|
||||||
prot |= PAGE_EXEC;
|
|
||||||
}
|
|
||||||
if (pte & PG_DIRTY_MASK) {
|
|
||||||
/* only set write access if already dirty... otherwise wait
|
/* only set write access if already dirty... otherwise wait
|
||||||
for dirty access */
|
for dirty access */
|
||||||
if (is_user) {
|
assert(!is_write);
|
||||||
if (ptep & PG_RW_MASK)
|
prot &= ~PAGE_WRITE;
|
||||||
prot |= PAGE_WRITE;
|
|
||||||
} else {
|
|
||||||
if (!(env->cr[0] & CR0_WP_MASK) ||
|
|
||||||
(ptep & PG_RW_MASK))
|
|
||||||
prot |= PAGE_WRITE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
do_mapping:
|
do_mapping:
|
||||||
pte = pte & env->a20_mask;
|
pte = pte & env->a20_mask;
|
||||||
|
|
||||||
|
@ -962,6 +942,7 @@ do_check_protect_pse36:
|
||||||
page_offset = vaddr & (page_size - 1);
|
page_offset = vaddr & (page_size - 1);
|
||||||
paddr = pte + page_offset;
|
paddr = pte + page_offset;
|
||||||
|
|
||||||
|
assert(prot & (1 << is_write1));
|
||||||
tlb_set_page_with_attrs(cs, vaddr, paddr, cpu_get_mem_attrs(env),
|
tlb_set_page_with_attrs(cs, vaddr, paddr, cpu_get_mem_attrs(env),
|
||||||
prot, mmu_idx, page_size);
|
prot, mmu_idx, page_size);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Reference in a new issue