Skip to content

Commit 421f81a

Browse files
jimmyzhenashif
authored andcommitted
arch: riscv: remove PMP stack guard for stack overflow handler
When RISCV_ALWAYS_SWITCH_THROUGH_ECALL is enabled, do_swap() enables PMP checking in is_kernel_syscall. If the PMP stack guard is triggered and do_swap() is called from the fault handler, a PMP error occurs because the stack usage violates the previous PMP setting. Remove the stack guard setting during a stack overflow handler to allow enabling PMP checking safely in fault handler. Signed-off-by: Jimmy Zheng <[email protected]>
1 parent 58bda88 commit 421f81a

File tree

3 files changed

+39
-0
lines changed

3 files changed

+39
-0
lines changed

arch/riscv/core/fatal.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,13 @@ void _Fault(struct arch_esf *esf)
226226
unsigned int reason = K_ERR_CPU_EXCEPTION;
227227

228228
if (bad_stack_pointer(esf)) {
229+
#ifdef CONFIG_PMP_STACK_GUARD
230+
/*
231+
* Remove the thread's PMP setting to prevent triggering a stack
232+
* overflow error again due to the previous configuration.
233+
*/
234+
z_riscv_pmp_stackguard_disable();
235+
#endif /* CONFIG_PMP_STACK_GUARD */
229236
reason = K_ERR_STACK_CHK_FAIL;
230237
}
231238

arch/riscv/core/pmp.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,37 @@ void z_riscv_pmp_stackguard_enable(struct k_thread *thread)
511511
csr_set(mstatus, MSTATUS_MPRV);
512512
}
513513

514+
/**
515+
* @brief Remove PMP stackguard content to actual PMP registers
516+
*/
517+
void z_riscv_pmp_stackguard_disable(void)
518+
{
519+
520+
unsigned long pmp_addr[PMP_M_MODE_SLOTS];
521+
unsigned long pmp_cfg[PMP_M_MODE_SLOTS / sizeof(unsigned long)];
522+
unsigned int index = global_pmp_end_index;
523+
524+
/* Retrieve the pmpaddr value matching the last global PMP slot. */
525+
pmp_addr[global_pmp_end_index - 1] = global_pmp_last_addr;
526+
527+
/* Disable (non-locked) PMP entries for m-mode while we update them. */
528+
csr_clear(mstatus, MSTATUS_MPRV);
529+
530+
/*
531+
* Set a temporary default "catch all" PMP entry for MPRV to work,
532+
* except for the global locked entries.
533+
*/
534+
set_pmp_mprv_catchall(&index, pmp_addr, pmp_cfg, ARRAY_SIZE(pmp_addr));
535+
536+
/* Write "catch all" entry and clear unlocked entries to PMP regs. */
537+
write_pmp_entries(global_pmp_end_index, index,
538+
true, pmp_addr, pmp_cfg, ARRAY_SIZE(pmp_addr));
539+
540+
if (PMP_DEBUG_DUMP) {
541+
dump_pmp_regs("catch all register dump");
542+
}
543+
}
544+
514545
#endif /* CONFIG_PMP_STACK_GUARD */
515546

516547
#ifdef CONFIG_USERSPACE

arch/riscv/include/pmp.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
void z_riscv_pmp_init(void);
1111
void z_riscv_pmp_stackguard_prepare(struct k_thread *thread);
1212
void z_riscv_pmp_stackguard_enable(struct k_thread *thread);
13+
void z_riscv_pmp_stackguard_disable(void);
1314
void z_riscv_pmp_usermode_init(struct k_thread *thread);
1415
void z_riscv_pmp_usermode_prepare(struct k_thread *thread);
1516
void z_riscv_pmp_usermode_enable(struct k_thread *thread);

0 commit comments

Comments
 (0)