@@ -42,7 +42,8 @@ struct riscv_trap_frame {
4242 uint32_t regs [TF_SIZE / 4u ];
4343};
4444
45- uintptr_t g_trap_sp ;
45+ /* Indexed by mhartid — trap.S stores the frame pointer per hart. */
46+ uintptr_t g_trap_sp [ULMK_ARCH_NUM_CPU ];
4647
4748static inline uint32_t read_mstatus (void )
4849{
@@ -478,10 +479,23 @@ void ulmk_arch_mpu_configure(uint8_t prs, const ulmk_arch_region_t *regions,
478479 (void )count ;
479480}
480481
481- static const ulmk_arch_region_t * g_pmp_regions ;
482- static uint8_t g_pmp_count ;
483- static uint8_t g_pmp_prs = 0xFFu ;
484- static uint8_t g_pmp_dyn ; /* non-STACK dynamic slots last programmed */
482+ /*
483+ * PMP CSRs are per-hart. The "last programmed" cache must not be global or
484+ * one CPU's switch causes another's mpu_switch to skip a real rewrite.
485+ */
486+ struct pmp_cpu_cache {
487+ const ulmk_arch_region_t * regions ;
488+ uint8_t count ;
489+ uint8_t prs ;
490+ uint8_t dyn ;
491+ };
492+
493+ static struct pmp_cpu_cache g_pmp_cache [ULMK_ARCH_NUM_CPU ] = {
494+ [0 ] = { .prs = 0xFFu },
495+ #if ULMK_ARCH_NUM_CPU > 1
496+ [1 ] = { .prs = 0xFFu },
497+ #endif
498+ };
485499
486500static uint8_t pmp_dyn_count (const ulmk_arch_region_t * regions , uint8_t count )
487501{
@@ -500,30 +514,44 @@ static uint8_t pmp_dyn_count(const ulmk_arch_region_t *regions, uint8_t count)
500514void ulmk_arch_mpu_switch (const ulmk_arch_region_t * regions , uint8_t count ,
501515 uint8_t prs )
502516{
503- uint8_t eff ;
517+ struct pmp_cpu_cache * c ;
518+ uint32_t cpu ;
519+ uint8_t eff ;
504520
505- if (prs == g_pmp_prs && regions == g_pmp_regions && count == g_pmp_count )
521+ cpu = ulmk_arch_cpu_id ();
522+ if (cpu >= (uint32_t )ULMK_ARCH_NUM_CPU )
523+ cpu = 0u ;
524+ c = & g_pmp_cache [cpu ];
525+
526+ /*
527+ * On SMP only skip when this hart already has the exact same layout.
528+ * The stack-only fast path was UP-friendly but races badly when another
529+ * hart's view of "already programmed" is assumed.
530+ */
531+ if (prs == c -> prs && regions == c -> regions && count == c -> count )
506532 return ;
507533
508534 eff = (prs == ULMK_ARCH_PRS_KERNEL ) ? 0u : pmp_dyn_count (regions , count );
509535
536+ #if !ULMK_CONFIG_ENABLE_SMP
510537 /* Stack-only AS: static URAM covers stacks — skip full PMP rewrite. */
511- if (prs == g_pmp_prs && eff == 0u && g_pmp_dyn == 0u &&
538+ if (prs == c -> prs && eff == 0u && c -> dyn == 0u &&
512539 prs != ULMK_ARCH_PRS_KERNEL ) {
513- g_pmp_regions = regions ;
514- g_pmp_count = count ;
540+ c -> regions = regions ;
541+ c -> count = count ;
515542 return ;
516543 }
544+ #endif
517545
518546 if (prs == ULMK_ARCH_PRS_KERNEL )
519547 pmp_kernel_layout ();
520548 else
521549 pmp_user_layout (regions , count );
522550
523- g_pmp_prs = prs ;
524- g_pmp_regions = regions ;
525- g_pmp_count = count ;
526- g_pmp_dyn = eff ;
551+ c -> prs = prs ;
552+ c -> regions = regions ;
553+ c -> count = count ;
554+ c -> dyn = eff ;
527555}
528556
529557bool ulmk_arch_mpu_addr_permitted (uintptr_t addr , size_t size , uint32_t perms )
@@ -717,5 +745,9 @@ void ulmk_arch_init(ulmk_boot_info_t *info)
717745
718746 ulmk_arch_irq_vectors_init ((uintptr_t )_trap_handler , 0u , 0u );
719747 ulmk_arch_mpu_init ();
748+ #if ULMK_CONFIG_ENABLE_SMP
749+ /* Accept CLINT MSIP reschedule IPIs on every hart. */
750+ __asm__ volatile ("csrs mie, %0" :: "r" (1u << 3 ));
751+ #endif
720752 (void )user_mstatus_init ;
721753}
0 commit comments