mirror of
https://github.com/RT-Thread/rt-thread.git
synced 2026-09-22 03:09:16 +08:00
[mm] precise & readable mm fault type (#9047)
* [smart] fixup: precise mm fault type Also, fixup arm64 read access fault * arm64: using meaningful macro on trap * fixup: renaming macro
This commit is contained in:
@@ -206,13 +206,16 @@ rt_inline rt_size_t lwp_user_mm_flag_to_kernel(int flags)
|
||||
return k_flags;
|
||||
}
|
||||
|
||||
#ifndef MMU_MAP_U_ROCB
|
||||
#define MMU_MAP_U_ROCB MMU_MAP_U_RWCB
|
||||
#endif /* MMU_MAP_U_ROCB */
|
||||
|
||||
rt_inline rt_size_t lwp_user_mm_attr_to_kernel(int prot)
|
||||
{
|
||||
RT_UNUSED(prot);
|
||||
|
||||
rt_size_t k_attr = 0;
|
||||
|
||||
#ifdef IMPL_MPROTECT
|
||||
if ((prot & PROT_EXEC) || (prot & PROT_WRITE) ||
|
||||
((prot & PROT_READ) && (prot & PROT_WRITE)))
|
||||
k_attr = MMU_MAP_U_RWCB;
|
||||
@@ -220,9 +223,6 @@ rt_inline rt_size_t lwp_user_mm_attr_to_kernel(int prot)
|
||||
k_attr = MMU_MAP_K_RWCB;
|
||||
else
|
||||
k_attr = MMU_MAP_U_ROCB;
|
||||
#else
|
||||
k_attr = MMU_MAP_U_RWCB;
|
||||
#endif /* IMPL_MPROTECT */
|
||||
|
||||
return k_attr;
|
||||
}
|
||||
|
||||
@@ -1743,7 +1743,7 @@ rt_err_t rt_aspace_page_put(rt_aspace_t aspace, void *page_va, void *buffer)
|
||||
RDWR_LOCK(aspace);
|
||||
struct rt_aspace_fault_msg msg;
|
||||
msg.fault_op = MM_FAULT_OP_WRITE;
|
||||
msg.fault_type = MM_FAULT_TYPE_ACCESS_FAULT;
|
||||
msg.fault_type = MM_FAULT_TYPE_GENERIC_MMU;
|
||||
msg.fault_vaddr = page_va;
|
||||
rc = rt_varea_fix_private_locked(varea, rt_hw_mmu_v2p(aspace, page_va),
|
||||
&msg, RT_TRUE);
|
||||
|
||||
@@ -60,7 +60,7 @@ static int _write_fault(rt_varea_t varea, void *pa, struct rt_aspace_fault_msg *
|
||||
if (rt_varea_is_private_locked(varea))
|
||||
{
|
||||
if (VAREA_IS_WRITABLE(varea) && (
|
||||
msg->fault_type == MM_FAULT_TYPE_ACCESS_FAULT ||
|
||||
msg->fault_type == MM_FAULT_TYPE_RWX_PERM ||
|
||||
msg->fault_type == MM_FAULT_TYPE_PAGE_FAULT))
|
||||
{
|
||||
RDWR_LOCK(aspace);
|
||||
@@ -102,6 +102,44 @@ static int _exec_fault(rt_varea_t varea, void *pa, struct rt_aspace_fault_msg *m
|
||||
return err;
|
||||
}
|
||||
|
||||
static void _determine_precise_fault_type(struct rt_aspace_fault_msg *msg, rt_ubase_t pa, rt_varea_t varea)
|
||||
{
|
||||
if (msg->fault_type == MM_FAULT_TYPE_GENERIC_MMU)
|
||||
{
|
||||
rt_base_t requesting_perm;
|
||||
switch (msg->fault_op)
|
||||
{
|
||||
case MM_FAULT_OP_READ:
|
||||
requesting_perm = RT_HW_MMU_PROT_READ | RT_HW_MMU_PROT_USER;
|
||||
break;
|
||||
case MM_FAULT_OP_WRITE:
|
||||
requesting_perm = RT_HW_MMU_PROT_WRITE | RT_HW_MMU_PROT_USER;
|
||||
break;
|
||||
case MM_FAULT_OP_EXECUTE:
|
||||
requesting_perm = RT_HW_MMU_PROT_EXECUTE | RT_HW_MMU_PROT_USER;
|
||||
break;
|
||||
}
|
||||
|
||||
/**
|
||||
* always checking the user privileges since dynamic permission is not
|
||||
* supported in kernel. So those faults are never fixable. Hence, adding
|
||||
* permission check never changes the result of checking. In other
|
||||
* words, { 0 && (expr) } is always false.
|
||||
*/
|
||||
if (rt_hw_mmu_attr_test_perm(varea->attr, requesting_perm))
|
||||
{
|
||||
if (pa == (rt_ubase_t)ARCH_MAP_FAILED)
|
||||
{
|
||||
msg->fault_type = MM_FAULT_TYPE_PAGE_FAULT;
|
||||
}
|
||||
else
|
||||
{
|
||||
msg->fault_type = MM_FAULT_TYPE_RWX_PERM;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int rt_aspace_fault_try_fix(rt_aspace_t aspace, struct rt_aspace_fault_msg *msg)
|
||||
{
|
||||
int err = MM_FAULT_FIXABLE_FALSE;
|
||||
@@ -121,6 +159,8 @@ int rt_aspace_fault_try_fix(rt_aspace_t aspace, struct rt_aspace_fault_msg *msg)
|
||||
if (varea)
|
||||
{
|
||||
void *pa = rt_hw_mmu_v2p(aspace, msg->fault_vaddr);
|
||||
_determine_precise_fault_type(msg, (rt_ubase_t)pa, varea);
|
||||
|
||||
if (pa != ARCH_MAP_FAILED && msg->fault_type == MM_FAULT_TYPE_PAGE_FAULT)
|
||||
{
|
||||
LOG_D("%s(fault=%p) has already fixed", __func__, msg->fault_vaddr);
|
||||
|
||||
@@ -34,9 +34,12 @@ enum rt_mm_fault_type
|
||||
{
|
||||
/**
|
||||
* Occurs when an instruction attempts to access a memory address that it
|
||||
* does not have permission to access
|
||||
* does not have R/W/X permission to access
|
||||
*/
|
||||
MM_FAULT_TYPE_ACCESS_FAULT,
|
||||
MM_FAULT_TYPE_RWX_PERM,
|
||||
|
||||
/* Without privileges to access (e.g. user accessing kernel) */
|
||||
MM_FAULT_TYPE_NO_PRIVILEGES,
|
||||
|
||||
/**
|
||||
* Occurs when a load or store instruction accesses a virtual memory
|
||||
@@ -49,6 +52,12 @@ enum rt_mm_fault_type
|
||||
*/
|
||||
MM_FAULT_TYPE_BUS_ERROR,
|
||||
|
||||
/**
|
||||
* Occurs when page table walk failed, permission failed, writings on
|
||||
* non-dirty page.
|
||||
*/
|
||||
MM_FAULT_TYPE_GENERIC_MMU,
|
||||
|
||||
MM_FAULT_TYPE_GENERIC,
|
||||
__PRIVATE_PAGE_INSERT,
|
||||
};
|
||||
|
||||
@@ -38,6 +38,8 @@
|
||||
((!varea->mem_obj || !varea->mem_obj->get_name) \
|
||||
? "unknow" \
|
||||
: varea->mem_obj->get_name(varea))
|
||||
|
||||
/* only user address use COW technique, so user permission is always checked */
|
||||
#define VAREA_IS_WRITABLE(varea) \
|
||||
(rt_hw_mmu_attr_test_perm(varea->attr, \
|
||||
RT_HW_MMU_PROT_USER | RT_HW_MMU_PROT_WRITE))
|
||||
|
||||
Reference in New Issue
Block a user