Skip to content

Commit f00db63

Browse files
authored
[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
1 parent 479fab7 commit f00db63

File tree

11 files changed

+138
-47
lines changed

11 files changed

+138
-47
lines changed

Diff for: components/lwp/lwp_user_mm.h

+4-4
Original file line numberDiff line numberDiff line change
@@ -206,23 +206,23 @@ rt_inline rt_size_t lwp_user_mm_flag_to_kernel(int flags)
206206
return k_flags;
207207
}
208208

209+
#ifndef MMU_MAP_U_ROCB
210+
#define MMU_MAP_U_ROCB MMU_MAP_U_RWCB
211+
#endif /* MMU_MAP_U_ROCB */
212+
209213
rt_inline rt_size_t lwp_user_mm_attr_to_kernel(int prot)
210214
{
211215
RT_UNUSED(prot);
212216

213217
rt_size_t k_attr = 0;
214218

215-
#ifdef IMPL_MPROTECT
216219
if ((prot & PROT_EXEC) || (prot & PROT_WRITE) ||
217220
((prot & PROT_READ) && (prot & PROT_WRITE)))
218221
k_attr = MMU_MAP_U_RWCB;
219222
else if (prot == PROT_NONE)
220223
k_attr = MMU_MAP_K_RWCB;
221224
else
222225
k_attr = MMU_MAP_U_ROCB;
223-
#else
224-
k_attr = MMU_MAP_U_RWCB;
225-
#endif /* IMPL_MPROTECT */
226226

227227
return k_attr;
228228
}

Diff for: components/mm/mm_aspace.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -1743,7 +1743,7 @@ rt_err_t rt_aspace_page_put(rt_aspace_t aspace, void *page_va, void *buffer)
17431743
RDWR_LOCK(aspace);
17441744
struct rt_aspace_fault_msg msg;
17451745
msg.fault_op = MM_FAULT_OP_WRITE;
1746-
msg.fault_type = MM_FAULT_TYPE_ACCESS_FAULT;
1746+
msg.fault_type = MM_FAULT_TYPE_GENERIC_MMU;
17471747
msg.fault_vaddr = page_va;
17481748
rc = rt_varea_fix_private_locked(varea, rt_hw_mmu_v2p(aspace, page_va),
17491749
&msg, RT_TRUE);

Diff for: components/mm/mm_fault.c

+41-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ static int _write_fault(rt_varea_t varea, void *pa, struct rt_aspace_fault_msg *
6060
if (rt_varea_is_private_locked(varea))
6161
{
6262
if (VAREA_IS_WRITABLE(varea) && (
63-
msg->fault_type == MM_FAULT_TYPE_ACCESS_FAULT ||
63+
msg->fault_type == MM_FAULT_TYPE_RWX_PERM ||
6464
msg->fault_type == MM_FAULT_TYPE_PAGE_FAULT))
6565
{
6666
RDWR_LOCK(aspace);
@@ -102,6 +102,44 @@ static int _exec_fault(rt_varea_t varea, void *pa, struct rt_aspace_fault_msg *m
102102
return err;
103103
}
104104

105+
static void _determine_precise_fault_type(struct rt_aspace_fault_msg *msg, rt_ubase_t pa, rt_varea_t varea)
106+
{
107+
if (msg->fault_type == MM_FAULT_TYPE_GENERIC_MMU)
108+
{
109+
rt_base_t requesting_perm;
110+
switch (msg->fault_op)
111+
{
112+
case MM_FAULT_OP_READ:
113+
requesting_perm = RT_HW_MMU_PROT_READ | RT_HW_MMU_PROT_USER;
114+
break;
115+
case MM_FAULT_OP_WRITE:
116+
requesting_perm = RT_HW_MMU_PROT_WRITE | RT_HW_MMU_PROT_USER;
117+
break;
118+
case MM_FAULT_OP_EXECUTE:
119+
requesting_perm = RT_HW_MMU_PROT_EXECUTE | RT_HW_MMU_PROT_USER;
120+
break;
121+
}
122+
123+
/**
124+
* always checking the user privileges since dynamic permission is not
125+
* supported in kernel. So those faults are never fixable. Hence, adding
126+
* permission check never changes the result of checking. In other
127+
* words, { 0 && (expr) } is always false.
128+
*/
129+
if (rt_hw_mmu_attr_test_perm(varea->attr, requesting_perm))
130+
{
131+
if (pa == (rt_ubase_t)ARCH_MAP_FAILED)
132+
{
133+
msg->fault_type = MM_FAULT_TYPE_PAGE_FAULT;
134+
}
135+
else
136+
{
137+
msg->fault_type = MM_FAULT_TYPE_RWX_PERM;
138+
}
139+
}
140+
}
141+
}
142+
105143
int rt_aspace_fault_try_fix(rt_aspace_t aspace, struct rt_aspace_fault_msg *msg)
106144
{
107145
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)
121159
if (varea)
122160
{
123161
void *pa = rt_hw_mmu_v2p(aspace, msg->fault_vaddr);
162+
_determine_precise_fault_type(msg, (rt_ubase_t)pa, varea);
163+
124164
if (pa != ARCH_MAP_FAILED && msg->fault_type == MM_FAULT_TYPE_PAGE_FAULT)
125165
{
126166
LOG_D("%s(fault=%p) has already fixed", __func__, msg->fault_vaddr);

Diff for: components/mm/mm_fault.h

+11-2
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,12 @@ enum rt_mm_fault_type
3434
{
3535
/**
3636
* Occurs when an instruction attempts to access a memory address that it
37-
* does not have permission to access
37+
* does not have R/W/X permission to access
3838
*/
39-
MM_FAULT_TYPE_ACCESS_FAULT,
39+
MM_FAULT_TYPE_RWX_PERM,
40+
41+
/* Without privileges to access (e.g. user accessing kernel) */
42+
MM_FAULT_TYPE_NO_PRIVILEGES,
4043

4144
/**
4245
* Occurs when a load or store instruction accesses a virtual memory
@@ -49,6 +52,12 @@ enum rt_mm_fault_type
4952
*/
5053
MM_FAULT_TYPE_BUS_ERROR,
5154

55+
/**
56+
* Occurs when page table walk failed, permission failed, writings on
57+
* non-dirty page.
58+
*/
59+
MM_FAULT_TYPE_GENERIC_MMU,
60+
5261
MM_FAULT_TYPE_GENERIC,
5362
__PRIVATE_PAGE_INSERT,
5463
};

Diff for: components/mm/mm_private.h

+2
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@
3838
((!varea->mem_obj || !varea->mem_obj->get_name) \
3939
? "unknow" \
4040
: varea->mem_obj->get_name(varea))
41+
42+
/* only user address use COW technique, so user permission is always checked */
4143
#define VAREA_IS_WRITABLE(varea) \
4244
(rt_hw_mmu_attr_test_perm(varea->attr, \
4345
RT_HW_MMU_PROT_USER | RT_HW_MMU_PROT_WRITE))

Diff for: examples/utest/testcases/mm/lwp_mmap_fix_private.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ static void test_mmap_fix_private(void)
5656
char *next_va;
5757
struct rt_aspace_fault_msg msg;
5858
msg.fault_op = MM_FAULT_OP_WRITE;
59-
msg.fault_type = MM_FAULT_TYPE_ACCESS_FAULT;
59+
msg.fault_type = MM_FAULT_TYPE_RWX_PERM;
6060

6161
/* map new pages at ex_vaddr to anonymous */
6262
next_va = ex_vaddr;

Diff for: libcpu/aarch64/common/armv8.h

+25
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,31 @@ rt_ubase_t rt_hw_get_current_el(void);
149149
void rt_hw_set_elx_env(void);
150150
void rt_hw_set_current_vbar(rt_ubase_t addr);
151151

152+
/* ESR:generic */
153+
#define ARM64_ABORT_WNR(esr) ((esr) & 0x40)
154+
#define ARM64_ESR_EXTRACT_EC(esr) ((((esr) >> 26) & 0x3fU))
155+
#define ARM64_ESR_EXTRACT_FSC(esr) ((esr) & 0x3f)
156+
157+
/* ESR:EC */
158+
#define ARM64_EC_INST_ABORT_FROM_LO_EXCEPTION (0b100000)
159+
#define ARM64_EC_INST_ABORT_WITHOUT_A_CHANGE (0b100001)
160+
#define ARM64_EC_DATA_ABORT_FROM_LO_EXCEPTION (0b100100)
161+
#define ARM64_EC_DATA_ABORT_WITHOUT_A_CHANGE (0b100101)
162+
163+
/* ESR:FSC */
164+
#define ARM64_FSC_TRANSLATION_FAULT_LEVEL_0 (0b000100)
165+
#define ARM64_FSC_TRANSLATION_FAULT_LEVEL_1 (0b000101)
166+
#define ARM64_FSC_TRANSLATION_FAULT_LEVEL_2 (0b000110)
167+
#define ARM64_FSC_TRANSLATION_FAULT_LEVEL_3 (0b000111)
168+
#define ARM64_FSC_PERMISSION_FAULT_LEVEL_0 (0b001100)
169+
#define ARM64_FSC_PERMISSION_FAULT_LEVEL_1 (0b001101)
170+
#define ARM64_FSC_PERMISSION_FAULT_LEVEL_2 (0b001110)
171+
#define ARM64_FSC_PERMISSION_FAULT_LEVEL_3 (0b001111)
172+
#define ARM64_FSC_ACCESS_FLAG_FAULT_LEVEL_0 (0b001000)
173+
#define ARM64_FSC_ACCESS_FLAG_FAULT_LEVEL_1 (0b001001)
174+
#define ARM64_FSC_ACCESS_FLAG_FAULT_LEVEL_2 (0b001010)
175+
#define ARM64_FSC_ACCESS_FLAG_FAULT_LEVEL_3 (0b001011)
176+
152177
#endif /* __ASSEMBLY__ */
153178

154179
#endif

Diff for: libcpu/aarch64/common/trap.c

+25-25
Original file line numberDiff line numberDiff line change
@@ -62,26 +62,26 @@ static void _check_fault(struct rt_hw_exp_stack *regs, uint32_t pc_adj, char *in
6262
rt_inline int _get_type(unsigned long esr)
6363
{
6464
int ret;
65-
int fsc = esr & 0x3f;
65+
int fsc = ARM64_ESR_EXTRACT_FSC(esr);
6666
switch (fsc)
6767
{
68-
case 0x4:
69-
case 0x5:
70-
case 0x6:
71-
case 0x7:
68+
case ARM64_FSC_TRANSLATION_FAULT_LEVEL_0:
69+
case ARM64_FSC_TRANSLATION_FAULT_LEVEL_1:
70+
case ARM64_FSC_TRANSLATION_FAULT_LEVEL_2:
71+
case ARM64_FSC_TRANSLATION_FAULT_LEVEL_3:
7272
ret = MM_FAULT_TYPE_PAGE_FAULT;
7373
break;
74-
case 0xc:
75-
case 0xd:
76-
case 0xe:
77-
case 0xf:
78-
ret = MM_FAULT_TYPE_ACCESS_FAULT;
74+
case ARM64_FSC_PERMISSION_FAULT_LEVEL_0:
75+
case ARM64_FSC_PERMISSION_FAULT_LEVEL_1:
76+
case ARM64_FSC_PERMISSION_FAULT_LEVEL_2:
77+
case ARM64_FSC_PERMISSION_FAULT_LEVEL_3:
78+
ret = MM_FAULT_TYPE_RWX_PERM;
7979
break;
80-
case 0x8:
81-
case 0x9:
82-
case 0xa:
83-
case 0xb:
84-
/* access flag fault */
80+
case ARM64_FSC_ACCESS_FLAG_FAULT_LEVEL_0:
81+
case ARM64_FSC_ACCESS_FLAG_FAULT_LEVEL_1:
82+
case ARM64_FSC_ACCESS_FLAG_FAULT_LEVEL_2:
83+
case ARM64_FSC_ACCESS_FLAG_FAULT_LEVEL_3:
84+
/* access flag fault, not handle currently */
8585
default:
8686
ret = MM_FAULT_TYPE_GENERIC;
8787
}
@@ -96,28 +96,28 @@ rt_inline long _irq_is_disable(long cpsr)
9696
static int user_fault_fixable(unsigned long esr, struct rt_hw_exp_stack *regs)
9797
{
9898
rt_ubase_t level;
99-
unsigned char ec;
100-
void *dfar;
101-
int ret = 0;
102-
103-
ec = (unsigned char)((esr >> 26) & 0x3fU);
10499
enum rt_mm_fault_op fault_op;
105100
enum rt_mm_fault_type fault_type;
106101
struct rt_lwp *lwp;
102+
void *dfar;
103+
int ret = 0;
104+
unsigned char ec = ARM64_ESR_EXTRACT_EC(esr);
105+
rt_bool_t is_write = ARM64_ABORT_WNR(esr);
107106

108107
switch (ec)
109108
{
110-
case 0x20:
109+
case ARM64_EC_INST_ABORT_FROM_LO_EXCEPTION:
111110
fault_op = MM_FAULT_OP_EXECUTE;
112111
fault_type = _get_type(esr);
113112
break;
114-
case 0x21:
115-
case 0x24:
116-
case 0x25:
117-
fault_op = MM_FAULT_OP_WRITE;
113+
case ARM64_EC_INST_ABORT_WITHOUT_A_CHANGE:
114+
case ARM64_EC_DATA_ABORT_FROM_LO_EXCEPTION:
115+
case ARM64_EC_DATA_ABORT_WITHOUT_A_CHANGE:
116+
fault_op = is_write ? MM_FAULT_OP_WRITE : MM_FAULT_OP_READ;
118117
fault_type = _get_type(esr);
119118
break;
120119
default:
120+
/* non-fixable */
121121
fault_op = 0;
122122
break;
123123
}

Diff for: libcpu/risc-v/t-head/c906/trap.c

+3-3
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ void handle_user(rt_size_t scause, rt_size_t stval, rt_size_t sepc, struct rt_hw
169169
break;
170170
case EP_LOAD_ACCESS_FAULT:
171171
fault_op = MM_FAULT_OP_READ;
172-
fault_type = MM_FAULT_TYPE_ACCESS_FAULT;
172+
fault_type = MM_FAULT_TYPE_GENERIC;
173173
break;
174174
case EP_LOAD_ADDRESS_MISALIGNED:
175175
fault_op = MM_FAULT_OP_READ;
@@ -181,7 +181,7 @@ void handle_user(rt_size_t scause, rt_size_t stval, rt_size_t sepc, struct rt_hw
181181
break;
182182
case EP_STORE_ACCESS_FAULT:
183183
fault_op = MM_FAULT_OP_WRITE;
184-
fault_type = MM_FAULT_TYPE_ACCESS_FAULT;
184+
fault_type = MM_FAULT_TYPE_GENERIC;
185185
break;
186186
case EP_STORE_ADDRESS_MISALIGNED:
187187
fault_op = MM_FAULT_OP_WRITE;
@@ -193,7 +193,7 @@ void handle_user(rt_size_t scause, rt_size_t stval, rt_size_t sepc, struct rt_hw
193193
break;
194194
case EP_INSTRUCTION_ACCESS_FAULT:
195195
fault_op = MM_FAULT_OP_EXECUTE;
196-
fault_type = MM_FAULT_TYPE_ACCESS_FAULT;
196+
fault_type = MM_FAULT_TYPE_GENERIC;
197197
break;
198198
case EP_INSTRUCTION_ADDRESS_MISALIGNED:
199199
fault_op = MM_FAULT_OP_EXECUTE;

Diff for: libcpu/risc-v/virt64/riscv_mmu.h

+19-4
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,10 @@ rt_inline size_t rt_hw_mmu_attr_rm_perm(size_t attr, rt_base_t prot)
116116
case RT_HW_MMU_PROT_WRITE | RT_HW_MMU_PROT_USER:
117117
attr &= ~PTE_W;
118118
break;
119+
/* remove write permission for kernel */
120+
case RT_HW_MMU_PROT_WRITE | RT_HW_MMU_PROT_KERNEL:
121+
attr &= ~PTE_W;
122+
break;
119123
default:
120124
RT_ASSERT(0);
121125
}
@@ -135,7 +139,7 @@ rt_inline size_t rt_hw_mmu_attr_add_perm(size_t attr, rt_base_t prot)
135139
{
136140
/* add write permission for user */
137141
case RT_HW_MMU_PROT_WRITE | RT_HW_MMU_PROT_USER:
138-
attr |= PTE_W;
142+
attr |= (PTE_R | PTE_W | PTE_U);
139143
break;
140144
default:
141145
RT_ASSERT(0);
@@ -153,15 +157,26 @@ rt_inline size_t rt_hw_mmu_attr_add_perm(size_t attr, rt_base_t prot)
153157
rt_inline rt_bool_t rt_hw_mmu_attr_test_perm(size_t attr, rt_base_t prot)
154158
{
155159
rt_bool_t rc = 0;
156-
switch (prot)
160+
switch (prot & ~RT_HW_MMU_PROT_USER)
157161
{
158162
/* test write permission for user */
159-
case RT_HW_MMU_PROT_WRITE | RT_HW_MMU_PROT_USER:
160-
rc = !!(attr & PTE_W);
163+
case RT_HW_MMU_PROT_WRITE:
164+
rc = ((attr & PTE_W) && (attr & PTE_R));
165+
break;
166+
case RT_HW_MMU_PROT_READ:
167+
rc = !!(attr & PTE_R);
168+
break;
169+
case RT_HW_MMU_PROT_EXECUTE:
170+
rc = !!(attr & PTE_X);
161171
break;
162172
default:
163173
RT_ASSERT(0);
164174
}
175+
176+
if (rc && (prot & RT_HW_MMU_PROT_USER))
177+
{
178+
rc = !!(attr & PTE_U);
179+
}
165180
return rc;
166181
}
167182

Diff for: libcpu/risc-v/virt64/trap.c

+6-6
Original file line numberDiff line numberDiff line change
@@ -162,35 +162,35 @@ void handle_user(rt_size_t scause, rt_size_t stval, rt_size_t sepc, struct rt_hw
162162
{
163163
case EP_LOAD_PAGE_FAULT:
164164
fault_op = MM_FAULT_OP_READ;
165-
fault_type = MM_FAULT_TYPE_PAGE_FAULT;
165+
fault_type = MM_FAULT_TYPE_GENERIC_MMU;
166166
break;
167167
case EP_LOAD_ACCESS_FAULT:
168168
fault_op = MM_FAULT_OP_READ;
169-
fault_type = MM_FAULT_TYPE_ACCESS_FAULT;
169+
fault_type = MM_FAULT_TYPE_BUS_ERROR;
170170
break;
171171
case EP_LOAD_ADDRESS_MISALIGNED:
172172
fault_op = MM_FAULT_OP_READ;
173173
fault_type = MM_FAULT_TYPE_BUS_ERROR;
174174
break;
175175
case EP_STORE_PAGE_FAULT:
176176
fault_op = MM_FAULT_OP_WRITE;
177-
fault_type = MM_FAULT_TYPE_PAGE_FAULT;
177+
fault_type = MM_FAULT_TYPE_GENERIC_MMU;
178178
break;
179179
case EP_STORE_ACCESS_FAULT:
180180
fault_op = MM_FAULT_OP_WRITE;
181-
fault_type = MM_FAULT_TYPE_ACCESS_FAULT;
181+
fault_type = MM_FAULT_TYPE_BUS_ERROR;
182182
break;
183183
case EP_STORE_ADDRESS_MISALIGNED:
184184
fault_op = MM_FAULT_OP_WRITE;
185185
fault_type = MM_FAULT_TYPE_BUS_ERROR;
186186
break;
187187
case EP_INSTRUCTION_PAGE_FAULT:
188188
fault_op = MM_FAULT_OP_EXECUTE;
189-
fault_type = MM_FAULT_TYPE_PAGE_FAULT;
189+
fault_type = MM_FAULT_TYPE_GENERIC_MMU;
190190
break;
191191
case EP_INSTRUCTION_ACCESS_FAULT:
192192
fault_op = MM_FAULT_OP_EXECUTE;
193-
fault_type = MM_FAULT_TYPE_ACCESS_FAULT;
193+
fault_type = MM_FAULT_TYPE_BUS_ERROR;
194194
break;
195195
case EP_INSTRUCTION_ADDRESS_MISALIGNED:
196196
fault_op = MM_FAULT_OP_EXECUTE;

0 commit comments

Comments
 (0)