mirror of https://gitee.com/openkylin/linux.git
powerpc/mm: Move the DSISR_PROTFAULT sanity check
This has a page of comment explaining what's going on right in the middle of do_page_fault() which makes things a bit hard to follow. Move it to a helper instead. Also do the test earlier as there's no point waiting until after we found the VMA. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
This commit is contained in:
parent
04aafdc601
commit
2865d08dd9
|
@ -239,6 +239,45 @@ static inline void cmo_account_page_fault(void)
|
||||||
static inline void cmo_account_page_fault(void) { }
|
static inline void cmo_account_page_fault(void) { }
|
||||||
#endif /* CONFIG_PPC_SMLPAR */
|
#endif /* CONFIG_PPC_SMLPAR */
|
||||||
|
|
||||||
|
#ifdef CONFIG_PPC_STD_MMU
|
||||||
|
static void sanity_check_fault(bool is_write, unsigned long error_code)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* For hash translation mode, we should never get a
|
||||||
|
* PROTFAULT. Any update to pte to reduce access will result in us
|
||||||
|
* removing the hash page table entry, thus resulting in a DSISR_NOHPTE
|
||||||
|
* fault instead of DSISR_PROTFAULT.
|
||||||
|
*
|
||||||
|
* A pte update to relax the access will not result in a hash page table
|
||||||
|
* entry invalidate and hence can result in DSISR_PROTFAULT.
|
||||||
|
* ptep_set_access_flags() doesn't do a hpte flush. This is why we have
|
||||||
|
* the special !is_write in the below conditional.
|
||||||
|
*
|
||||||
|
* For platforms that doesn't supports coherent icache and do support
|
||||||
|
* per page noexec bit, we do setup things such that we do the
|
||||||
|
* sync between D/I cache via fault. But that is handled via low level
|
||||||
|
* hash fault code (hash_page_do_lazy_icache()) and we should not reach
|
||||||
|
* here in such case.
|
||||||
|
*
|
||||||
|
* For wrong access that can result in PROTFAULT, the above vma->vm_flags
|
||||||
|
* check should handle those and hence we should fall to the bad_area
|
||||||
|
* handling correctly.
|
||||||
|
*
|
||||||
|
* For embedded with per page exec support that doesn't support coherent
|
||||||
|
* icache we do get PROTFAULT and we handle that D/I cache sync in
|
||||||
|
* set_pte_at while taking the noexec/prot fault. Hence this is WARN_ON
|
||||||
|
* is conditional for server MMU.
|
||||||
|
*
|
||||||
|
* For radix, we can get prot fault for autonuma case, because radix
|
||||||
|
* page table will have them marked noaccess for user.
|
||||||
|
*/
|
||||||
|
if (!radix_enabled() && !is_write)
|
||||||
|
WARN_ON_ONCE(error_code & DSISR_PROTFAULT);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static void sanity_check_fault(bool is_write, unsigned long error_code) { }
|
||||||
|
#endif /* CONFIG_PPC_STD_MMU */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Define the correct "is_write" bit in error_code based
|
* Define the correct "is_write" bit in error_code based
|
||||||
* on the processor family
|
* on the processor family
|
||||||
|
@ -306,6 +345,9 @@ static int __do_page_fault(struct pt_regs *regs, unsigned long address,
|
||||||
return SIGBUS;
|
return SIGBUS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Additional sanity check(s) */
|
||||||
|
sanity_check_fault(is_write, error_code);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The kernel should never take an execute fault nor should it
|
* The kernel should never take an execute fault nor should it
|
||||||
* take a page fault to a kernel address.
|
* take a page fault to a kernel address.
|
||||||
|
@ -441,39 +483,6 @@ static int __do_page_fault(struct pt_regs *regs, unsigned long address,
|
||||||
if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)))
|
if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)))
|
||||||
return bad_area(regs, address);
|
return bad_area(regs, address);
|
||||||
}
|
}
|
||||||
#ifdef CONFIG_PPC_STD_MMU
|
|
||||||
/*
|
|
||||||
* For hash translation mode, we should never get a
|
|
||||||
* PROTFAULT. Any update to pte to reduce access will result in us
|
|
||||||
* removing the hash page table entry, thus resulting in a DSISR_NOHPTE
|
|
||||||
* fault instead of DSISR_PROTFAULT.
|
|
||||||
*
|
|
||||||
* A pte update to relax the access will not result in a hash page table
|
|
||||||
* entry invalidate and hence can result in DSISR_PROTFAULT.
|
|
||||||
* ptep_set_access_flags() doesn't do a hpte flush. This is why we have
|
|
||||||
* the special !is_write in the below conditional.
|
|
||||||
*
|
|
||||||
* For platforms that doesn't supports coherent icache and do support
|
|
||||||
* per page noexec bit, we do setup things such that we do the
|
|
||||||
* sync between D/I cache via fault. But that is handled via low level
|
|
||||||
* hash fault code (hash_page_do_lazy_icache()) and we should not reach
|
|
||||||
* here in such case.
|
|
||||||
*
|
|
||||||
* For wrong access that can result in PROTFAULT, the above vma->vm_flags
|
|
||||||
* check should handle those and hence we should fall to the bad_area
|
|
||||||
* handling correctly.
|
|
||||||
*
|
|
||||||
* For embedded with per page exec support that doesn't support coherent
|
|
||||||
* icache we do get PROTFAULT and we handle that D/I cache sync in
|
|
||||||
* set_pte_at while taking the noexec/prot fault. Hence this is WARN_ON
|
|
||||||
* is conditional for server MMU.
|
|
||||||
*
|
|
||||||
* For radix, we can get prot fault for autonuma case, because radix
|
|
||||||
* page table will have them marked noaccess for user.
|
|
||||||
*/
|
|
||||||
if (!radix_enabled() && !is_write)
|
|
||||||
WARN_ON_ONCE(error_code & DSISR_PROTFAULT);
|
|
||||||
#endif /* CONFIG_PPC_STD_MMU */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If for any reason at all we couldn't handle the fault,
|
* If for any reason at all we couldn't handle the fault,
|
||||||
|
|
Loading…
Reference in New Issue