riscv: pmp: properly initialize per-thread m-mode/u-mode entry array
Retrieve the pmpaddr value matching the last global PMP slot and add it
to the per-thread m-mode and u-mode entry array. Even if that value is
not written out again on thread context switch, that value can still be
used by set_pmp_entry() to attempt a single-slot TOR mapping with it.
Nicely abstract this with the new z_riscv_pmp_thread_init() where the
PMP_M_MODE(thread) and PMP_U_MODE(thread) argument generators can be
used.
Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
diff --git a/arch/riscv/core/pmp.c b/arch/riscv/core/pmp.c
index 8dd9325..e150cf9 100644
--- a/arch/riscv/core/pmp.c
+++ b/arch/riscv/core/pmp.c
@@ -296,6 +296,7 @@
* we could have non-locked entries here too.
*/
static ulong_t global_pmp_cfg[1];
+static ulong_t global_pmp_last_addr;
/* End of global PMP entry range */
static unsigned int global_pmp_end_index;
@@ -333,10 +334,12 @@
if (global_pmp_end_index != 0) {
__ASSERT(global_pmp_end_index == index, "");
__ASSERT(global_pmp_cfg[0] == pmp_cfg[0], "");
+ __ASSERT(global_pmp_last_addr == pmp_addr[index - 1]);
}
#endif
global_pmp_cfg[0] = pmp_cfg[0];
+ global_pmp_last_addr = pmp_addr[index - 1];
global_pmp_end_index = index;
if (PMP_DEBUG_DUMP) {
@@ -344,6 +347,29 @@
}
}
+/**
+ * @Brief Initialize the per-thread PMP register copy with global values.
+ */
+static inline unsigned int z_riscv_pmp_thread_init(ulong_t *pmp_addr,
+ ulong_t *pmp_cfg,
+ unsigned int index_limit)
+{
+ ARG_UNUSED(index_limit);
+
+ /*
+ * Retrieve pmpcfg0 partial content from global entries.
+ */
+ pmp_cfg[0] = global_pmp_cfg[0];
+
+ /*
+ * Retrieve the pmpaddr value matching the last global PMP slot.
+ * This is so that set_pmp_entry() can safely attempt TOR with it.
+ */
+ pmp_addr[global_pmp_end_index - 1] = global_pmp_last_addr;
+
+ return global_pmp_end_index;
+}
+
#ifdef CONFIG_PMP_STACK_GUARD
/**
@@ -353,12 +379,9 @@
*/
void z_riscv_pmp_stackguard_prepare(struct k_thread *thread)
{
- unsigned int index = global_pmp_end_index;
+ unsigned int index = z_riscv_pmp_thread_init(PMP_M_MODE(thread));
uintptr_t stack_bottom;
- /* Retrieve pmpcfg0 partial content from global entries */
- thread->arch.m_mode_pmpcfg_regs[0] = global_pmp_cfg[0];
-
/* make the bottom addresses of our stack inaccessible */
stack_bottom = thread->stack_info.start - K_KERNEL_STACK_RESERVED;
#ifdef CONFIG_USERSPACE
@@ -445,10 +468,7 @@
*/
void z_riscv_pmp_usermode_prepare(struct k_thread *thread)
{
- unsigned int index = global_pmp_end_index;
-
- /* Retrieve pmpcfg0 partial content from global entries */
- thread->arch.u_mode_pmpcfg_regs[0] = global_pmp_cfg[0];
+ unsigned int index = z_riscv_pmp_thread_init(PMP_U_MODE(thread));
/* Map the usermode stack */
set_pmp_entry(&index, PMP_R | PMP_W,