Hi all,
Please see below a rough checklist for porting to SMP freertos. Let me know if i am missing something or something is wrong.
Regards
Srinivas
Porting Checklist for FreeRTOS SMP
- Change: Definition in freertosconfig
configNUM_CORES: The number of cores available to run tasks. May be set to anything greater than 0, provided the hardware and port supports it.
configRUN_MULTIPLE_PRIORITIES: Set to 1 to allow tasks with different priority levels to run simultaneously on different cores. Set to 0 to only allow tasks with the same priority level to run simultaneously.
configUSE_CORE_AFFINITY: Gets the core affinity mask for a task, i.e., the cores on which a task can run.
configTICK_CORE: Core in which tick should run
configUSE_TASK_PREEMPTION_DISABLE: In SMP FreeRTOS application, if configUSE_TASK_PREEMPTION_DISABLE is defined as 1, then individual tasks can be set to either pre-emptive or co-operative mode using the vTaskPreemptionDisable and vTaskPreemptionEnable API functions.
portCRITICAL_NESTING_IN_TCB: Storing critical nesting count per task in TCB.
Example for Cortex A53:
configNUM_CORES – 4
configRUN_MULTIPLE_PRIORITIES – 1
configUSE_CORE_AFFINITY – 1
configTICK_CORE - 0
configUSE_TASK_PREEMPTION_DISABLE – 0
portCRITICAL_NESTING_IN_TCB - 1
-
Change: xPortStartScheduler should start scheduler on the number of cores specified by configNUM_CORES specified in FreeRTOSConfig.h file. Each core must end this function by restoring the context of the task assigned to it.
Example for Cortex A53:
Primary core (core 0) executes xPortStartScheduler, wakes up other 3 cores which are in sleep state, and all cores execute vPortRestoreContext. -
Change: pxCurrentTCB has been renamed to pxCurrentTCBs and made into an array indexed by core. Whenever task state needs to be saved or restored, this array must now be indexed first to get the stack pointer.
Example for Cortex A53:
In portSAVE_CONTEXT and portRESTORE_CONTEXT , get the portGET_CORE_ID of the current core executing. Based on the current core, move to that index of pxCurrentTCBs. -
Change: portDisable_interrupts to return interrupt mask prior to disabling.
Example for Cortex A53:
Use the ICC_PMR_EL1 to save priority mask. -
Change: If portCRITICAL_NESTING_IN_TCB is set to 1.
portENTER_CRITICAL() → vTaskEnterCritical()
portEXIT_CRITICAL() → vTaskExitCritical()
portSET_INTERRUPT_MASK_FROM_ISR → This must call vTaskEnterCritical() in addition to returning the interrupt mask prior to calling it
portCLEAR_INTERRUPT_MASK_FROM_ISR → This must first call vTaskExitCritical() before setting the interrupt mask to the value in x.
Reference : FreeRTOS-Kernel/portmacro.h at 4832377117b4198db43009f2b548497d9cdbf8da · FreeRTOS/FreeRTOS-Kernel · GitHub -
Change: portRESTORE_INTERRUPTS This must set the interrupt mask to the value in x. It is used after calling portDISABLE_INTERRUPTS() to restore the interrupt mask to what it was prior to calling portDISABLE_INTERRUPTS(). The value x should be what was returned by portDISABLE_INTERRUPTS().
Example for Cortex A53:
Use the ICC_PMR_EL1 to restore priority mask saved when portDISABLE_INTERRUPTS. -
Change: Tick interrupt should be enabled only on one core (preferably core 0).
Example for Cortex A53:
In function xPortStartScheduler get the portGET_CORE_ID, if it is primary core call configSETUP_TICK_INTERRUPT. -
Change: Two locks must be implemented (portGET_TASK_LOCK portRELEASE_TASK_LOCK) and (portGET_ISR_LOCK, portRELEASE_ISR_LOCK). This should be recursive spinlock implementation.
Example for Cortex A53:
Use FreeRTOS-Kernel/portmacro.h at 4832377117b4198db43009f2b548497d9cdbf8da · FreeRTOS/FreeRTOS-Kernel · GitHub for reference. -
Change: portGET_CORE_ID(). This must return the core ID (between 0 and configNUM_CORES-1) of the calling core.
Example for Cortex A53:
Use the MPIDR_EL1 register to get the core ID. -
Change: portYIELD_CORE(coreID) , This must interrupt the core with ID x. The core that is interrupted must behave as if it called portYIELD() (i.e. save the current task context, call vTaskSwitchContext(), and then restore the context of the new current task).
Example for Cortex A53:
Send an interrupt from the running core to “coreID” core using SPI/PPI .
In the interrupt handler call portYield_FROM_ISR(pdTrue) ,which will make the core to do context switch -
Change: portCHECK_IF_IN_ISR This must return pdTRUE if it is called from within an ISR, otherwise pdFALSE if it is not.
Example for Cortex A53:
Use ISR_EL1 register to check if it’s in ISR. -
Change: Pass coreid to vTaskSwitchContext as argument.
Use portGET_CORE_ID to get the coreID. -
Change:
Integration of ARM GIC – changing interrupt address
Reference:
RTOS for ARM Cortex-A -
Change: Call xTaskIncrementTick in function FreeRTOS_Tick_Handler within portSET_INTERRUPT_MASK_FROM_ISR and portCLEAR_INTERRUPT_MASK_FROM_ISR.