Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions arch/riscv/core/fatal.c
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,13 @@ void _Fault(struct arch_esf *esf)
unsigned int reason = K_ERR_CPU_EXCEPTION;

if (bad_stack_pointer(esf)) {
#ifdef CONFIG_PMP_STACK_GUARD
/*
* Remove the thread's PMP setting to prevent triggering a stack
* overflow error again due to the previous configuration.
*/
z_riscv_pmp_stackguard_disable();
#endif /* CONFIG_PMP_STACK_GUARD */
reason = K_ERR_STACK_CHK_FAIL;
}

Expand Down
15 changes: 15 additions & 0 deletions arch/riscv/core/isr.S
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,21 @@ no_fp: /* increment _current->arch.exception_depth */
*/
li t1, RISCV_EXC_ECALLU
beq t0, t1, is_user_syscall

#ifdef CONFIG_PMP_STACK_GUARD
/*
* Determine if we come from user space. If so, reconfigure the PMP for
* kernel mode stack guard.
*/
csrr t0, mstatus
li t1, MSTATUS_MPP
and t0, t0, t1
bnez t0, 1f
lr a0, ___cpu_t_current_OFFSET(s0)
call z_riscv_pmp_stackguard_enable
1:
#endif /* CONFIG_PMP_STACK_GUARD */

#endif /* CONFIG_USERSPACE */

/*
Expand Down
31 changes: 31 additions & 0 deletions arch/riscv/core/pmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,37 @@ void z_riscv_pmp_stackguard_enable(struct k_thread *thread)
csr_set(mstatus, MSTATUS_MPRV);
}

/**
* @brief Remove PMP stackguard content to actual PMP registers
*/
void z_riscv_pmp_stackguard_disable(void)
{

unsigned long pmp_addr[PMP_M_MODE_SLOTS];
unsigned long pmp_cfg[PMP_M_MODE_SLOTS / sizeof(unsigned long)];
unsigned int index = global_pmp_end_index;

/* Retrieve the pmpaddr value matching the last global PMP slot. */
pmp_addr[global_pmp_end_index - 1] = global_pmp_last_addr;

/* Disable (non-locked) PMP entries for m-mode while we update them. */
csr_clear(mstatus, MSTATUS_MPRV);

/*
* Set a temporary default "catch all" PMP entry for MPRV to work,
* except for the global locked entries.
*/
set_pmp_mprv_catchall(&index, pmp_addr, pmp_cfg, ARRAY_SIZE(pmp_addr));

/* Write "catch all" entry and clear unlocked entries to PMP regs. */
write_pmp_entries(global_pmp_end_index, index,
true, pmp_addr, pmp_cfg, ARRAY_SIZE(pmp_addr));

if (PMP_DEBUG_DUMP) {
dump_pmp_regs("catch all register dump");
}
}

#endif /* CONFIG_PMP_STACK_GUARD */

#ifdef CONFIG_USERSPACE
Expand Down
1 change: 1 addition & 0 deletions arch/riscv/include/pmp.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
void z_riscv_pmp_init(void);
void z_riscv_pmp_stackguard_prepare(struct k_thread *thread);
void z_riscv_pmp_stackguard_enable(struct k_thread *thread);
void z_riscv_pmp_stackguard_disable(void);
void z_riscv_pmp_usermode_init(struct k_thread *thread);
void z_riscv_pmp_usermode_prepare(struct k_thread *thread);
void z_riscv_pmp_usermode_enable(struct k_thread *thread);
Expand Down