Updated RP2040 Multicore Startup

This forum is dedicated to feedback, discussions about ongoing or future developments, ideas and suggestions regarding the ChibiOS projects are welcome. This forum is NOT for support.
Post Reply
emulator
Posts: 25
Joined: Tue Dec 09, 2025 12:14 pm
Has thanked: 6 times
Been thanked: 7 times

Updated RP2040 Multicore Startup

Post by emulator »

A couple of patches I'm using to get the new SMP code in trunk working on RP2040.

Defect: Fix path

Code: Select all

--- os/common/ports/ARMv6-M/compilers/GCC/mk/port_rp2.mk   (revision 17689)
+++ os/common/ports/ARMv6-M/compilers/GCC/mk/port_rp2.mk   (working copy)
@@ -10,7 +10,7 @@
 PORTASM = $(CHIBIOS)/os/common/ports/ARMv6-M/compilers/GCC/chcoreasm.S
 
 PORTINC = $(CHIBIOS)/os/common/ports/ARMv6-M \
-          $(CHIBIOS)/os/common/ports/ARMv6-M\smp\rp2
+          $(CHIBIOS)/os/common/ports/ARMv6-M/smp/rp2
 
 # Shared variables
 ALLXASMSRC += $(PORTASM)


Defect: Conditionally include SMP timer

Code: Select all

--- os/common/ports/ARMv6-M/chcore.h   (revision 17689)
+++ os/common/ports/ARMv6-M/chcore.h   (working copy)
@@ -603,7 +603,11 @@
 #if !defined(_FROM_ASM_)
 
 #if CH_CFG_ST_TIMEDELTA > 0
+#if (CH_CFG_SMP_MODE == TRUE) && defined(PORT_CORES_NUMBER) && (PORT_CORES_NUMBER > 1)
+#include "chcoresmp_timer.h"
+#else
 #include "chcore_timer.h"
+#endif
 #endif /* CH_CFG_ST_TIMEDELTA > 0 */
 
 #endif /* !defined(_FROM_ASM_) */


Feature: Add weak reference to allow device specific init

Code: Select all

--- os/common/ports/ARMv6-M/chcore.c   (revision 17689)
+++ os/common/ports/ARMv6-M/chcore.c   (working copy)
@@ -103,12 +103,13 @@
 
 /**
  * @brief   Port-related initialization code.
+ * @note    Weak function that can be overridden by SMP-specific implementations
  *
  * @param[in, out] oip  pointer to the @p os_instance_t structure
  *
  * @notapi
  */
-void port_init(os_instance_t *oip) {
+__attribute__((weak)) void port_init(os_instance_t *oip) {
 
   (void)oip;
 


Feature: RP2040 device specific

Code: Select all

--- os/common/ports/ARMv6-M/smp/rp2/chcoresmp.c   (revision 17689)
+++ os/common/ports/ARMv6-M/smp/rp2/chcoresmp.c   (working copy)
@@ -46,15 +46,116 @@
 /* Module local functions.                                                   */
 /*===========================================================================*/
 
+static void port_local_halt(void) {
+  const char *reason = "remote panic";
+
+  port_disable();
+
+  __trace_halt("remote panic");
+
+  currcore->dbg.panic_msg = reason;
+
+  CH_CFG_SYSTEM_HALT_HOOK(reason);
+
+  while (true) {
+  }
+}
+
 /*===========================================================================*/
 /* Module interrupt handlers.                                                */
 /*===========================================================================*/
 
+/**
+ * @brief   FIFO interrupt handler for core 0.
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(Vector7C) {
+
+  CH_IRQ_PROLOGUE();
+
+  SIO->FIFO_ST = SIO_FIFO_ST_ROE | SIO_FIFO_ST_WOF;
+
+  while ((SIO->FIFO_ST & SIO_FIFO_ST_VLD) != 0U) {
+    uint32_t message = SIO->FIFO_RD;
+#if defined(PORT_HANDLE_FIFO_MESSAGE)
+    if (message != PORT_FIFO_RESCHEDULE_MESSAGE) {
+      PORT_HANDLE_FIFO_MESSAGE(1U, message);
+    }
+#else
+    (void)message;
+#endif
+  }
+
+  __SEV();
+
+  CH_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief   FIFO interrupt handler for core 1.
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(Vector80) {
+
+  CH_IRQ_PROLOGUE();
+
+  SIO->FIFO_ST = SIO_FIFO_ST_ROE | SIO_FIFO_ST_WOF;
+
+  while ((SIO->FIFO_ST & SIO_FIFO_ST_VLD) != 0U) {
+    uint32_t message = SIO->FIFO_RD;
+    if (message == PORT_FIFO_PANIC_MESSAGE) {
+      port_local_halt();
+    }
+#if defined(PORT_HANDLE_FIFO_MESSAGE)
+    if (message != PORT_FIFO_RESCHEDULE_MESSAGE) {
+      PORT_HANDLE_FIFO_MESSAGE(0U, message);
+    }
+#endif
+  }
+
+  __SEV();
+
+  CH_IRQ_EPILOGUE();
+}
+
 /*===========================================================================*/
 /* Module exported functions.                                                */
 /*===========================================================================*/
 
 /**
+ * @brief   RP2040 initialization code for SMP.
+ * @details Overrides the weak port_init() in chcore.c.
+ *
+ * @param[in, out] oip  pointer to the @p os_instance_t structure
+ *
+ * @notapi
+ */
+void port_init(os_instance_t *oip) {
+
+#if CH_CFG_ST_TIMEDELTA > 0
+  /* Activating timer for this instance */
+  port_timer_enable(oip);
+#endif
+
+  SIO->FIFO_ST = SIO_FIFO_ST_ROE | SIO_FIFO_ST_WOF;
+  if (oip->core_id == 0U) {
+    NVIC_SetPriority(15, CORTEX_MINIMUM_PRIORITY);
+    NVIC_EnableIRQ(15);
+  }
+  else if (oip->core_id == 1U) {
+    NVIC_SetPriority(16, CORTEX_MINIMUM_PRIORITY);
+    NVIC_EnableIRQ(16);
+  }
+  else {
+    chDbgAssert(false, "unexpected core id");
+  }
+
+  NVIC_SetPriority(PendSV_IRQn, CORTEX_PRIORITY_PENDSV);
+}
+
+/**
  * @brief   Takes the kernel spinlock.
  */
 void __port_spinlock_take(void) {
User avatar
Giovanni
Site Admin
Posts: 14891
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: Updated RP2040 Multicore Startup

Post by Giovanni »

Hi,

Overall ok but careful with shared code, __attribute__ is GCC-only and that module is meant to be cross-compiler. I will add a hook macro in there that can be taken by SMP extensions.

Giovanni
emulator
Posts: 25
Joined: Tue Dec 09, 2025 12:14 pm
Has thanked: 6 times
Been thanked: 7 times

Re: Updated RP2040 Multicore Startup

Post by emulator »

Got it, I also see CC_WEAK now in os/common/portability...
User avatar
Giovanni
Site Admin
Posts: 14891
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: Updated RP2040 Multicore Startup

Post by Giovanni »

Hi,

I committed the change avoiding that weak declaration, please give it a try when possible thanks.

If it is OK then I will remove the old port and proceed to do the same changes to ARMv7-M and ARMv8-M-ML.

Giovanni
emulator
Posts: 25
Joined: Tue Dec 09, 2025 12:14 pm
Has thanked: 6 times
Been thanked: 7 times

Re: Updated RP2040 Multicore Startup

Post by emulator »

Ran through a full test today on RP2040 and everything is working. I did a quick and dirty port to ARMv8-M-ML and the same approach is working on the RP2350, the core gist is in this diff which is basically the same thing but using a few THUMB-2 instructions to simplify.

Code: Select all

Index: os/common/startup/ARMCMx/compilers/GCC/crt0_v8m-ml.S
===================================================================
--- os/common/startup/ARMCMx/compilers/GCC/crt0_v8m-ml.S   (revision 17694)
+++ os/common/startup/ARMCMx/compilers/GCC/crt0_v8m-ml.S   (working copy)
@@ -155,6 +155,13 @@
 #endif
 
 /**
+ * @brief   Number of extra cores.
+ */
+#if !defined(CRT0_EXTRA_CORES_NUMBER) || defined(__DOXYGEN__)
+#define CRT0_EXTRA_CORES_NUMBER             0
+#endif
+
+/**
  * @brief   FPU FPCCR register initialization value.
  * @note    Only used if @p CRT0_INIT_FPU is equal to @p TRUE.
  */
@@ -375,4 +382,112 @@
 
 #endif /* !defined(__DOXYGEN__) */
 
+#if CRT0_EXTRA_CORES_NUMBER > 0
+                .align  2
+                .thumb_func
+                .global _crt0_c1_entry
+_crt0_c1_entry:
+                /* Interrupts are globally masked initially.*/
+                cpsid   i
+
+#if CRT0_FORCE_MSP_INIT == TRUE
+                /* MSP stack pointers initialization.*/
+                ldr     r0, =__c1_main_stack_end__
+                msr     MSP, r0
+#endif
+                ldr     r0, =__c1_main_stack_base__
+                msr     MSPLIM, r0
+
+                /* PSP stack pointers initialization.*/
+                ldr     r0, =__c1_process_stack_end__
+                msr     PSP, r0
+                ldr     r0, =__c1_process_stack_base__
+                msr     PSPLIM, r0
+
+#if CRT0_VTOR_INIT == TRUE
+                ldr     r0, =_vectors
+                ldr     r1, =SCB_VTOR
+                str     r0, [r1]
+#endif
+
+#if CRT0_INIT_FPU == TRUE
+                /* FPU FPCCR initialization.*/
+                movw    r0, #CRT0_FPCCR_INIT & 0xFFFF
+                movt    r0, #CRT0_FPCCR_INIT >> 16
+                movw    r1, #SCB_FPCCR & 0xFFFF
+                movt    r1, #SCB_FPCCR >> 16
+                str     r0, [r1]
+                dsb
+                isb
+
+                /* CPACR initialization.*/
+                movw    r0, #CRT0_CPACR_INIT & 0xFFFF
+                movt    r0, #CRT0_CPACR_INIT >> 16
+                movw    r1, #SCB_CPACR & 0xFFFF
+                movt    r1, #SCB_CPACR >> 16
+                str     r0, [r1]
+                dsb
+                isb
+
+                /* FPU FPSCR initially cleared.*/
+                mov     r0, #0
+                vmsr    FPSCR, r0
+
+                /* FPU FPDSCR initially cleared.*/
+                movw    r1, #SCB_FPDSCR & 0xFFFF
+                movt    r1, #SCB_FPDSCR >> 16
+                str     r0, [r1]
+#endif
+
+                /* CONTROL register initialization as configured.*/
+                movs    r0, #CRT0_CONTROL_INIT
+                msr     CONTROL, r0
+                isb
+
+#if CRT0_INIT_CORE == TRUE
+                /* Core initialization.*/
+                bl      __c1_cpu_init
+#endif
+
+                /* Early initialization.*/
+                bl      __c1_early_init
+
+#if CRT0_INIT_STACKS == TRUE
+                ldr     r0, =CRT0_STACKS_FILL_PATTERN
+                /* Main Stack initialization. Note, it assumes that the
+                   stack size is a multiple of 4 so the linker file must
+                   ensure this.*/
+                ldr     r1, =__c1_main_stack_base__
+                ldr     r2, =__c1_main_stack_end__
+.Lc1msloop:
+                cmp     r1, r2
+                itt     lo
+                strlo   r0, [r1], #4
+                blo     .Lc1msloop
+
+                /* Process Stack initialization. Note, it assumes that the
+                   stack size is a multiple of 4 so the linker file must
+                   ensure this.*/
+                ldr     r1, =__c1_process_stack_base__
+                ldr     r2, =__c1_process_stack_end__
+.Lc1psloop:
+                cmp     r1, r2
+                itt     lo
+                strlo   r0, [r1], #4
+                blo     .Lc1psloop
+#endif
+
+                /* Late initialization.*/
+                bl      __c1_late_init
+
+                /* Main program invocation, r0 contains the returned value.*/
+                bl      c1_main
+
+                /* Branching to the defined exit handler.*/
+                b       __c1_default_exit
+
+#elif CRT0_EXTRA_CORES_NUMBER > 1
+#error "unsupported number of extra cores"
+#endif
+
 /** @} */

User avatar
Giovanni
Site Admin
Posts: 14891
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: Updated RP2040 Multicore Startup

Post by Giovanni »

Hi,

Applied the patch with some changes (made the extra path a macro), extended it also to v7, increased the number of configurable cores up to 4.

Giovanni
emulator
Posts: 25
Joined: Tue Dec 09, 2025 12:14 pm
Has thanked: 6 times
Been thanked: 7 times

Re: Updated RP2040 Multicore Startup

Post by emulator »

Good Morning,
Nice will run through tests after my morning meetings.

- E
emulator
Posts: 25
Joined: Tue Dec 09, 2025 12:14 pm
Has thanked: 6 times
Been thanked: 7 times

Re: Updated RP2040 Multicore Startup

Post by emulator »

Hi,
Tested and everything is working with a few more changes. (Just ARMv6 and ARMv8, ARMv7 will need similar changes)

ARMv6-M add spinlock release when exiting ISR
Please check my thought here but port_lock_from_isr takes a spinlock without releasing it so without this change when interrupts are re-enabled the spinlock is still held.

Code: Select all

Index: os/common/ports/ARMv6-M/compilers/GCC/chcoreasm.S
===================================================================
--- os/common/ports/ARMv6-M/compilers/GCC/chcoreasm.S   (revision 17716)
+++ os/common/ports/ARMv6-M/compilers/GCC/chcoreasm.S   (working copy)
@@ -145,6 +145,9 @@
 #endif
                 str     r3, [r2, #0]
 #if CORTEX_ALTERNATE_SWITCH
+#if CH_CFG_SMP_MODE == TRUE
+                bl      __port_spinlock_release
+#endif
                 cpsie   i
 #endif
 1:              b       1b

ARMv8-M-ML
This is just the remainder of the updated SMP code ported to ARMv8 including the additional spinlock release when exiting ISR

Code: Select all

Index: os/common/ports/ARMv8-M-ML/chcore.c
===================================================================
--- os/common/ports/ARMv8-M-ML/chcore.c (revision 17716)
+++ os/common/ports/ARMv8-M-ML/chcore.c (working copy)
@@ -149,6 +149,10 @@
 //  DWT->LAR = 0xC5ACCE55U;
   DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
 
+#if defined(port_smp_init)
+  port_smp_init(oip);
+#endif
+
   /* Initialization of the system vectors used by the port.*/
 #if CORTEX_SIMPLIFIED_PRIORITY == FALSE
   NVIC_SetPriority(SVCall_IRQn, CORTEX_PRIORITY_SVCALL);

Code: Select all

Index: os/common/ports/ARMv8-M-ML/chcore.h
===================================================================
--- os/common/ports/ARMv8-M-ML/chcore.h (revision 17716)
+++ os/common/ports/ARMv8-M-ML/chcore.h (working copy)
@@ -186,6 +186,23 @@
 /* Derived constants and error checks.                                       */
 /*===========================================================================*/
 
+/* Inclusion of SMP support, if enabled.*/
+#if (CH_CFG_SMP_MODE == TRUE) || defined(__DOXYGEN__)
+#if !defined(_FROM_ASM_)
+#if !defined(__CHIBIOS_RT__)
+#error "SMP is supported in RT only"
+#endif
+
+#include "chcoresmp.h"
+
+#if !defined(PORT_CORES_NUMBER)
+#error "PORT_CORES_NUMBER not defined in chcoresmp.h"
+#endif
+
+#endif
+#else /* CH_CFG_SMP_MODE != TRUE */
+#endif /* CH_CFG_SMP_MODE != TRUE */
+
 /**
  * @name    Port Capabilities and Constants
  * @{
@@ -624,6 +641,9 @@
  #else /* CORTEX_SIMPLIFIED_PRIORITY */
    __disable_irq();
  #endif /* CORTEX_SIMPLIFIED_PRIORITY */
+ #if CH_CFG_SMP_MODE == TRUE
+   port_spinlock_take();
+ #endif
  }

  /**
@@ -633,6 +653,9 @@
   */
  __STATIC_FORCEINLINE void port_unlock(void) {
 
+ #if CH_CFG_SMP_MODE == TRUE
+   port_spinlock_release();
+ #endif
  #if CORTEX_SIMPLIFIED_PRIORITY == FALSE
    __set_BASEPRI(CORTEX_BASEPRI_DISABLED);
  #else /* CORTEX_SIMPLIFIED_PRIORITY */
@@ -714,6 +737,7 @@
  #endif
  }
 
+#if !defined(port_rt_get_counter_value)
  /**
   * @brief   Returns the current value of the realtime counter.
   *
@@ -723,6 +747,7 @@
 
    return DWT->CYCCNT;
  }
+#endif
 
  /*lint -restore*/
 
@@ -735,7 +760,11 @@
 #if !defined(_FROM_ASM_)
 
 #if CH_CFG_ST_TIMEDELTA > 0
+#if (CH_CFG_SMP_MODE == TRUE) && (PORT_CORES_NUMBER > 1)
+#include "chcoresmp_timer.h"
+#else
 #include "chcore_timer.h"
+#endif
 #endif /* CH_CFG_ST_TIMEDELTA > 0 */
 
 #endif /* !defined(_FROM_ASM_) */

Code: Select all

Index: os/common/ports/ARMv8-M-ML/compilers/GCC/chcoreasm.S
===================================================================
--- os/common/ports/ARMv8-M-ML/compilers/GCC/chcoreasm.S        (revision 17716)
+++ os/common/ports/ARMv8-M-ML/compilers/GCC/chcoreasm.S        (working copy)
@@ -122,6 +122,9 @@
 #if CH_DBG_STATISTICS
                 bl      __stats_stop_measure_crit_thd
 #endif
+#if CH_CFG_SMP_MODE == TRUE
+                bl      __port_spinlock_release
+#endif
 #if CORTEX_SIMPLIFIED_PRIORITY
                 cpsie   i
 #else
@@ -162,6 +165,9 @@
                 movt    r3, #:upper16:SCB_ICSR
                 mov     r2, ICSR_PENDSVSET
                 str     r2, [r3, #0]
+#if CH_CFG_SMP_MODE == TRUE
+                bl      __port_spinlock_release
+#endif
                 cpsie   i
 #else /* !CORTEX_SIMPLIFIED_PRIORITY */
                 svc     #0
User avatar
Giovanni
Site Admin
Posts: 14891
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: Updated RP2040 Multicore Startup

Post by Giovanni »

Hi,

I approve those changes, commit directly.

Giovanni
Post Reply