Skip to content

Commit e11a310

Browse files
committed
arch: riscv: Handle multiple pmpcfg registers in PMP init
The PMP initialization and thread seeding logic in arch/riscv/core/pmp.c did not correctly handle scenarios where the global PMP entries span across multiple `pmpcfg` hardware registers. The `global_pmp_cfg` array, intended to store the hardware register values, was hardcoded to size 1. This is only sufficient if all global PMP entries fall within the range covered by the first `pmpcfg` register (e.g., pmpcfg0). When more global entries are used, their configurations reside in subsequent `pmpcfg` registers (pmpcfg1, pmpcfg2, etc.). The code was only saving/restoring and checking `global_pmp_cfg[0]`, leading to loss of configuration for entries mapped to higher `pmpcfg` registers. This patch fixes this by: 1. Resizing the `global_pmp_cfg` array to `CONFIG_PMP_SLOTS / PMPCFG_STRIDE` to correctly accommodate values from all potentially used `pmpcfg` CSRs. 2. In `z_riscv_pmp_init`, using `memcpy` to save the entire contents of the local `pmp_cfg` array (derived from initial setup) into the `global_pmp_cfg` array. 3. In `z_riscv_pmp_thread_init`, using `memcpy` to restore the entire saved global configuration from `global_pmp_cfg` into a thread's `pmp_cfg` array. 4. Updating the SMP consistency assertion in `z_riscv_pmp_init` to use `memcmp` to compare the full contents of the `pmp_cfg` arrays between CPUs. These changes ensure that the configurations from all relevant `pmpcfg` registers are preserved and correctly propagated to thread contexts. Signed-off-by: Firas Sammoura <[email protected]>
1 parent 6024aee commit e11a310

File tree

1 file changed

+9
-7
lines changed

1 file changed

+9
-7
lines changed

arch/riscv/core/pmp.c

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -335,11 +335,13 @@ static void write_pmp_entries(unsigned int start, unsigned int end,
335335
ARRAY_SIZE(thread->arch.u_mode_pmpaddr_regs)
336336

337337
/*
338-
* This is used to seed thread PMP copies with global m-mode cfg entries
339-
* sharing the same cfg register. Locked entries aren't modifiable but
338+
* Stores the initial values of the pmpcfg CSRs, covering all global
339+
* m-mode PMP entries. This array is sized to hold all pmpcfg registers
340+
* necessary for CONFIG_PMP_SLOTS. It is used to seed the per-thread
341+
* PMP configuration copies. Locked entries aren't modifiable but
340342
* we could have non-locked entries here too.
341343
*/
342-
static unsigned long global_pmp_cfg[1];
344+
static unsigned long global_pmp_cfg[CONFIG_PMP_SLOTS / PMPCFG_STRIDE];
343345
static unsigned long global_pmp_last_addr;
344346

345347
/* End of global PMP entry range */
@@ -432,12 +434,12 @@ void z_riscv_pmp_init(void)
432434
/* Make sure secondary CPUs produced the same values */
433435
if (global_pmp_end_index != 0) {
434436
__ASSERT(global_pmp_end_index == index, "");
435-
__ASSERT(global_pmp_cfg[0] == pmp_cfg[0], "");
437+
__ASSERT(memcmp(pmp_cfg, global_pmp_cfg, sizeof(global_pmp_cfg)) == 0, "");
436438
__ASSERT(global_pmp_last_addr == pmp_addr[index - 1], "");
437439
}
438440
#endif
439441

440-
global_pmp_cfg[0] = pmp_cfg[0];
442+
memcpy(global_pmp_cfg, pmp_cfg, sizeof(pmp_cfg));
441443
global_pmp_last_addr = pmp_addr[index - 1];
442444
global_pmp_end_index = index;
443445

@@ -457,9 +459,9 @@ static inline unsigned int z_riscv_pmp_thread_init(unsigned long *pmp_addr,
457459
ARG_UNUSED(index_limit);
458460

459461
/*
460-
* Retrieve pmpcfg0 partial content from global entries.
462+
* Retrieve the pmpcfg register with partial content from global entries.
461463
*/
462-
pmp_cfg[0] = global_pmp_cfg[0];
464+
memcpy(pmp_cfg, global_pmp_cfg, sizeof(global_pmp_cfg));
463465

464466
/*
465467
* Retrieve the pmpaddr value matching the last global PMP slot.

0 commit comments

Comments
 (0)