@@ -702,10 +702,27 @@ static void mpu_write_user_slot(uint8_t idx, const ulmk_arch_region_t *r,
702702}
703703
704704/*
705- * Configure dynamic DPR slots for the given PRS from @regions.
706- * Preserves the static minimum-isolation enables programmed at boot.
705+ * Dynamic DPR slots for the given PRS from @regions.
706+ * STACK is covered by the static URAM window — skip it so typical IPC
707+ * (stack-only AS) programs zero dynamic slots and can early-exit.
707708 * Regions that do not fit (QEMU: USER_DPR_BASE == NUM_DPR) are ignored.
708709 */
710+ static uint8_t mpu_dyn_count (const ulmk_arch_region_t * regions , uint8_t count ,
711+ uint8_t max_dyn )
712+ {
713+ uint8_t n = 0u ;
714+ uint8_t i ;
715+
716+ if (!regions || max_dyn == 0u )
717+ return 0u ;
718+
719+ for (i = 0u ; i < count && n < max_dyn ; i ++ ) {
720+ if (regions [i ].type != ULMK_REGION_STACK )
721+ n ++ ;
722+ }
723+ return n ;
724+ }
725+
709726static void mpu_program_regions (uint8_t prs , const ulmk_arch_region_t * regions ,
710727 uint8_t count )
711728{
@@ -716,6 +733,7 @@ static void mpu_program_regions(uint8_t prs, const ulmk_arch_region_t *regions,
716733 uint8_t i ;
717734 uint8_t prog ;
718735 uint8_t max_dyn ;
736+ uint8_t eff ;
719737 uintptr_t utext_lo ;
720738 uintptr_t utext_hi ;
721739
@@ -744,29 +762,40 @@ static void mpu_program_regions(uint8_t prs, const ulmk_arch_region_t *regions,
744762 }
745763
746764 max_dyn = (uint8_t )(ULMK_ARCH_MPU_NUM_DPR - ULMK_ARCH_MPU_USER_DPR_BASE );
747- if (count > max_dyn )
748- count = max_dyn ;
749765 if (!regions )
750766 count = 0u ;
767+ eff = mpu_dyn_count (regions , count , max_dyn );
751768
752769 /*
753770 * Unchanged domain (typical self-yield / same thread): no CSFR writes.
754771 */
755772 if (prs == g_mpu_prs && regions == g_mpu_regions && count == g_mpu_count )
756773 return ;
757774
775+ /*
776+ * IPC hot path: both sides stack-only → static URAM already covers
777+ * stacks; no dynamic slots live and none requested.
778+ */
779+ if (prs == g_mpu_prs && eff == 0u && g_mpu_live == 0u ) {
780+ g_mpu_regions = regions ;
781+ g_mpu_count = count ;
782+ return ;
783+ }
784+
758785 mpu_prs1_static_enables (& dpre , & dpwe , & cpre , & cpxe );
759786
760787 /*
761- * Fast append: mem_map / heap_extend grew the region table by one.
762- * Only program the new slot and refresh enables .
788+ * Fast append: mem_map grew the table by one non-STACK region and the
789+ * prior layout had no STACK holes (dense slot == region index) .
763790 */
764791 if (prs == g_mpu_prs && regions == g_mpu_regions &&
765- count == (uint8_t )(g_mpu_count + 1u ) && count > 0u ) {
792+ count == (uint8_t )(g_mpu_count + 1u ) && count > 0u &&
793+ regions [count - 1u ].type != ULMK_REGION_STACK &&
794+ mpu_dyn_count (regions , (uint8_t )(count - 1u ), max_dyn ) ==
795+ (uint8_t )(count - 1u )) {
766796 mpu_write_user_slot ((uint8_t )(count - 1u ), & regions [count - 1u ],
767797 & dpre , & dpwe );
768- /* Re-apply bits for already-live slots. */
769- for (i = 0u ; i < g_mpu_count ; i ++ ) {
798+ for (i = 0u ; i < (uint8_t )(count - 1u ); i ++ ) {
770799 uint8_t d_slot =
771800 (uint8_t )(ULMK_ARCH_MPU_USER_DPR_BASE + i );
772801
@@ -781,7 +810,13 @@ static void mpu_program_regions(uint8_t prs, const ulmk_arch_region_t *regions,
781810 return ;
782811 }
783812
784- prog = count ;
813+ prog = 0u ;
814+ for (i = 0u ; i < count && prog < max_dyn ; i ++ ) {
815+ if (regions [i ].type == ULMK_REGION_STACK )
816+ continue ;
817+ mpu_write_user_slot (prog , & regions [i ], & dpre , & dpwe );
818+ prog ++ ;
819+ }
785820
786821 /* Clear only previously live dynamic slots that are no longer used. */
787822 for (i = prog ; i < g_mpu_live ; i ++ ) {
@@ -791,9 +826,6 @@ static void mpu_program_regions(uint8_t prs, const ulmk_arch_region_t *regions,
791826 mpu_write_dpr (d_slot , 0u , 0u );
792827 }
793828
794- for (i = 0u ; i < prog ; i ++ )
795- mpu_write_user_slot (i , & regions [i ], & dpre , & dpwe );
796-
797829 mpu_write_enables (prs , dpre , dpwe , cpre , cpxe );
798830
799831 g_mpu_prs = prs ;
0 commit comments