summaryrefslogtreecommitdiff
path: root/components/mm
diff options
context:
space:
mode:
authorShell <[email protected]>2024-06-07 21:34:03 +0800
committerGitHub <[email protected]>2024-06-07 21:34:03 +0800
commitf00db6381a383d85f1c145cbebac22967e7d2eb8 (patch)
tree220a6143139c9b1d35d1652fed9fad2721d66788 /components/mm
parent479fab77750594aa74c86beada156810fc651407 (diff)
[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
Diffstat (limited to 'components/mm')
-rw-r--r--components/mm/mm_aspace.c2
-rw-r--r--components/mm/mm_fault.c42
-rw-r--r--components/mm/mm_fault.h13
-rw-r--r--components/mm/mm_private.h2
4 files changed, 55 insertions, 4 deletions
diff --git a/components/mm/mm_aspace.c b/components/mm/mm_aspace.c
index acea6cc080..38abc9002f 100644
--- a/components/mm/mm_aspace.c
+++ b/components/mm/mm_aspace.c
@@ -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);
diff --git a/components/mm/mm_fault.c b/components/mm/mm_fault.c
index 4dcef168a5..40af11d4c4 100644
--- a/components/mm/mm_fault.c
+++ b/components/mm/mm_fault.c
@@ -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);
diff --git a/components/mm/mm_fault.h b/components/mm/mm_fault.h
index 28671aef74..9749e99918 100644
--- a/components/mm/mm_fault.h
+++ b/components/mm/mm_fault.h
@@ -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,
};
diff --git a/components/mm/mm_private.h b/components/mm/mm_private.h
index 2a5666e187..7431cc35a2 100644
--- a/components/mm/mm_private.h
+++ b/components/mm/mm_private.h
@@ -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))