[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:
Shell
2024-06-07 21:34:03 +08:00
committed by GitHub
parent 479fab7775
commit f00db6381a
11 changed files with 138 additions and 47 deletions
+4 -4
View File
@@ -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;
}
+1 -1
View File
@@ -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);
+41 -1
View File
@@ -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);
+11 -2
View File
@@ -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,
};
+2
View File
@@ -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))