diff options
| author | Shell <[email protected]> | 2024-06-07 21:34:03 +0800 |
|---|---|---|
| committer | GitHub <[email protected]> | 2024-06-07 21:34:03 +0800 |
| commit | f00db6381a383d85f1c145cbebac22967e7d2eb8 (patch) | |
| tree | 220a6143139c9b1d35d1652fed9fad2721d66788 /components/mm | |
| parent | 479fab77750594aa74c86beada156810fc651407 (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.c | 2 | ||||
| -rw-r--r-- | components/mm/mm_fault.c | 42 | ||||
| -rw-r--r-- | components/mm/mm_fault.h | 13 | ||||
| -rw-r--r-- | components/mm/mm_private.h | 2 |
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)) |
