Remove the use of ulContext and a controlled SVC stack pointer for the port

This commit is contained in:
Soren Ptak 2024-01-03 17:04:10 -05:00
parent ae127206fa
commit d23078088c
3 changed files with 84 additions and 110 deletions

View file

@ -103,10 +103,6 @@ PRIVILEGED_DATA volatile uint32_t ulICCEOIR = configEOI_ADDRESS;
* expected by the portRESTORE_CONTEXT() macro. */ * expected by the portRESTORE_CONTEXT() macro. */
UBaseType_t ulContextIndex = MAX_CONTEXT_SIZE - 1U; UBaseType_t ulContextIndex = MAX_CONTEXT_SIZE - 1U;
/* These two locations are used for SVC entry, fill them for debugging */
xMPUSettings->ulContext[ ulContextIndex-- ] = 0xFEED2002;
xMPUSettings->ulContext[ ulContextIndex-- ] = 0xFEED1001;
if( xRunPrivileged == pdTRUE ) if( xRunPrivileged == pdTRUE )
{ {
/* Current Program Status and Control Register */ /* Current Program Status and Control Register */
@ -235,7 +231,6 @@ PRIVILEGED_DATA volatile uint32_t ulICCEOIR = configEOI_ADDRESS;
/* Set the System Call LR to go directly to vPortSystemCallExit */ /* Set the System Call LR to go directly to vPortSystemCallExit */
xSysCallInfo->pulSystemCallLinkRegister = &vPortSystemCallExit; xSysCallInfo->pulSystemCallLinkRegister = &vPortSystemCallExit;
UBaseType_t ulStackIndex;
/* Return the address where the context of this task should be restored from */ /* Return the address where the context of this task should be restored from */
return ( &xMPUSettings->ulContext[ ulContextIndex ] ); return ( &xMPUSettings->ulContext[ ulContextIndex ] );

View file

@ -55,69 +55,67 @@
.extern vTaskSwitchContext .extern vTaskSwitchContext
.extern vApplicationIRQHandler .extern vApplicationIRQHandler
/* ------------------------------------------------------------------------- */ /* ----------------------------------------------------------------------------------- */
/* Save the register context of a FreeRTOS Task. */ /* Save the register context of a FreeRTOS Task. */
.macro portSAVE_CONTEXT .macro portSAVE_CONTEXT
DSB DSB
ISB ISB
/* Move the SVC SP backwards before calling the SRS */ /* Push R0 and the Link Register (LR) for scratch register space */
SRSDB SP!, #SVC_MODE PUSH { R0, LR }
/* Change to Supervisor Mode for the Context Save */ /* Load the pointer to the current task's Task Control Block (TCB) */
CPS #SVC_MODE LDR LR, =pxCurrentTCB
/* Get the saved SPSR that was pushed to the SVC SP */ /* Load the actual TCB into LR */
LDR LR, [SP, #0x4] LDR LR, [LR]
/* Move it to our SPSR so we can save the correct SP and LR */ /* Set LR to pxTopOfStack, the address of where to save the task context */
MSR SPSR_cxsf, LR LDR LR, [LR]
/* Save the previous operating modes Registers, Stack Pointer, and Link Register */
STMDB SP, {R0-R14}^
/** Can't do a PUSH when using the ^ character, so need to manually move
* the SP after pushing the registers */
SUB SP, SP, #portREGISTER_CONTEXT_LENGTH
#ifdef portENABLE_FPU
/* Save the floating point context */
/* Push the 16 floating point registers onto the stack */
VPUSH {D0-D15}
/* Load the FPSCR into R0 */
FMRX R0, FPSCR
/* Push the value of FPSCR onto the stack */
PUSH {R0}
#endif /* portENABLE_FPU */
/* Load the address of ulCriticalNesting */ /* Load the address of ulCriticalNesting */
LDR R0, =ulCriticalNesting LDR R0, =ulCriticalNesting
/* Load the value of ulCriticalNesting into R0 */ /* Load the value of ulCriticalNesting into R0 */
LDR R0, [R0] LDR R0, [R0]
/* Push the value of ulCriticalNesting into the context */ /* Push the value of ulCriticalNesting into the context */
PUSH {R0} STM LR!, {R0}
/* Load the address of pxCurrentTCB into R0 */
LDR R0, =pxCurrentTCB #if ( portENABLE_FPU == 1 )
/* Load the TCB into R0 */ /* Save the floating point context */
LDR R0, [R0] /* Load the Floating Point Status and Control Register (FPSRC) into R1 */
/* Set pxTopOfStack in the TCB to be the current Stack Pointer. This is FMRX R0, FPSCR
* where to load the FreeRTOS-Task context from. */ /* Push the value of FPSCR onto the stack */
STR SP, [R0] STM LR!, { R0 }
/* Move the SVC SP forward to the scratch area in ulContext */ /* Push the 32 Floating Point Registers (FPRs) onto the stack */
ADD SP, SP, 0x8 VSTM LR!, { D0-D15 }
#endif /* ( portENABLE_FPU == 1 ) */
/* Restore the saved R0 */
POP { R0 }
/* Save the pre-exception Registers, Stack Pointer (SP), and LR */
STM LR, { R0-R14 }^
/* Increment the LR after the popped registers */
ADD LR, LR, #portGPR_LENGTH
/* Pop the pushed LR, which is the pre-exception Program Counter (PC) */
POP { R0 }
/* Move the pre-exception Current Program Status and Control Register (CPSR)
* which is banked as the Saved Program Status and Control Register (SPSR)
* to R1 to save as part of the context. */
MRS R1, SPSR
/* Store the pre-exception CPSR and PC */
STM LR!, { R0-R1 }
.endm .endm
/* ------------------------------------------------------------------------- */ /* ----------------------------------------------------------------------------------- */
/* Restore the register context of a FreeRTOS Task. */ /* Restore the register context of a FreeRTOS Task. */
.macro portRESTORE_CONTEXT .macro portRESTORE_CONTEXT
/* Load the address of the current task TCB */ /* Load the pointer to the current task's Task Control Block (TCB) */
LDR R0, =pxCurrentTCB LDR LR, =pxCurrentTCB
/* Load the TCB into R0 */ /* Load the actual TCB into LR */
LDR R0, [R0] LDR LR, [LR]
/* Set R1 to the second member of the TCB struct, xMPUSettings */ /* Set R1 to the second member of the TCB struct, xMPUSettings */
ADD R1, R0, #0x4 ADD R1, LR, #0x4
/* Set our SP to pxTopOfStack, the address of the Task context */ /* Set LR to pxTopOfStack, the address to restore the task context from */
LDR SP, [R0] LDR LR, [LR]
/* Load the first per-task MPU region into R5 */ /* Load the first per-task MPU region into R5 */
MOV R5, #portFIRST_CONFIGURABLE_REGION MOV R5, #portFIRST_CONFIGURABLE_REGION
/* Dynamically load the last MPU region */
MRC p15, 0, R6, c0, c0, 0x4
/* Move the number of MPU regions forward */
LSR R6, #0x8
/* Clear other bits, as there can only be 8-16 regions */
AND R6, 0x1F
/* When creating a loop label in a macro it has to be a numeric label. /* When creating a loop label in a macro it has to be a numeric label.
* For (R5 = portFIRST_CONFIGURABLE_REGION ; R5 <= portSTACK_REGION ; R5++ ) */ * For (R5 = portFIRST_CONFIGURABLE_REGION ; R5 <= portSTACK_REGION ; R5++ ) */
123: 123:
@ -148,38 +146,33 @@
/* Load the address of the ulCriticalNesting variable into R1 */ /* Load the address of the ulCriticalNesting variable into R1 */
LDR R1, =ulCriticalNesting LDR R1, =ulCriticalNesting
/* Pop the previously saved value of ulCriticalNesting from ulContext */ /* Pop the previously saved value of ulCriticalNesting from ulContext */
POP {R2} LDM LR!, { R2 }
/* Store the value of ulCriticalNesting into address of ulCriticalNesting */ /* Store the value of ulCriticalNesting into address of ulCriticalNesting */
STR R2, [R1] STR R2, [R1]
#ifdef portENABLE_FPU #if ( portENABLE_FPU == 1 )
/* Restore Floating Point Context: Restore previous FPSCR from ulContext */ /* Restore Floating Point Context: Restore previous FPSCR from ulContext */
POP {R1} LDM LR!, { R1 }
/* Move the saved FPSCR value into the FPSCR */ /* Move the saved FPSCR value into the FPSCR */
VMSR FPSCR, R1 VMSR FPSCR, R1
/* Restore the Floating Point Registers */ /* Restore the Floating Point Registers */
VPOP {D0-D15} VLDM LR!, {D0-D15}
#endif /* portENABLE_FPU*/ #endif /* portENABLE_FPU*/
/* Restore the register context, first need to load the mode bits */ /* Load the value of the CPSR into R1, needed to set the SP and the LR */
/* Set R1 to be past R0-R12 */ LDR R0, [LR, +#portREGISTER_CONTEXT_LENGTH]
ADD R1, SP, #portGPR_LENGTH
/* Get the CPSR from the context, needed to set the SP and the LR */
LDR R2, [R1, +#0x0C]
/* Move the CPSR the into our SPSR */ /* Move the CPSR the into our SPSR */
MSR SPSR_cxsf, R2 MSR SPSR_cxsf, R0
/* Load the stored Stack Pointer and Link Register */ /* Restore the saved Stack Pointer and Link Register */
LDM R1, {R13-R14}^ LDM LR, {R0-R14}^
/* Load R0-R12 from the context */ /* Increment the Link Register after the popped registers */
POP {R0-R12} ADD LR, LR, #portGPR_LENGTH
/* Jump over the already set R13 and R14 */ /* Load the PC to return from the exception */
ADD SP, SP, #0x8 RFE LR
/* Return from the exception, loading the PC and CPSR */
RFE SP!
.endm .endm
/* ------------------------------------------------------------------------- */ /* ----------------------------------------------------------------------------------- */
/* Default FreeRTOS-Kernel System Tick Interrupt for VIM support */ /* Default FreeRTOS-Kernel System Tick Interrupt for VIM support */
.align 4 .align 4
.global FreeRTOS_Tick_Handler .global FreeRTOS_Tick_Handler
@ -187,9 +180,8 @@
FreeRTOS_Tick_Handler: FreeRTOS_Tick_Handler:
/* Return to the interrupted instruction. */ /* Return to the interrupted instruction. */
SUB LR, LR, #4 SUB LR, LR, #4
/* Save the context of the current task. */ /* Save Currently Executing Task Context */
portSAVE_CONTEXT portSAVE_CONTEXT
/* Clear interrupt flag in Real Time Interrupt. */ /* Clear interrupt flag in Real Time Interrupt. */
LDR R0, =configRTI_ADDRESS LDR R0, =configRTI_ADDRESS
MOV R1, #1 MOV R1, #1
@ -200,12 +192,10 @@ FreeRTOS_Tick_Handler:
/* If xTaskIncrementTick returned non-zero then select the next task to execute. */ /* If xTaskIncrementTick returned non-zero then select the next task to execute. */
CMP R0, #0 CMP R0, #0
BLNE vTaskSwitchContext BLNE vTaskSwitchContext
/* Swap to SVC Mode to restore the task context */
CPS #SVC_MODE
/* Restore the context of the task selected to execute. */ /* Restore the context of the task selected to execute. */
portRESTORE_CONTEXT portRESTORE_CONTEXT
/* ------------------------------------------------------------------------- */ /* ----------------------------------------------------------------------------------- */
/* Respond to a pending IRQ raised by the FreeRTOS-Kernel to swap tasks */ /* Respond to a pending IRQ raised by the FreeRTOS-Kernel to swap tasks */
.align 4 .align 4
.global vPortYieldWithinAPI .global vPortYieldWithinAPI
@ -213,21 +203,17 @@ FreeRTOS_Tick_Handler:
vPortYieldWithinAPI: vPortYieldWithinAPI:
/* Return to the interrupted instruction. */ /* Return to the interrupted instruction. */
SUB LR, LR, #4 SUB LR, LR, #4
/* Save the context of the current task */ /* Save Currently Executing Task Context */
portSAVE_CONTEXT portSAVE_CONTEXT
/* Swap back to IRQ Mode for selecting the next task */
CPS #IRQ_MODE
/* Clear the Interrupt Flag for vPortYieldWithinAPI */ /* Clear the Interrupt Flag for vPortYieldWithinAPI */
MOV R0, #configSSI_ADDRESS MOV R0, #configSSI_ADDRESS
LDR R0, [R0] LDR R0, [R0]
/* Select the next task to execute. */ /* Select the next task to execute. */
BL vTaskSwitchContext BL vTaskSwitchContext
/* Swap back to SVC Mode for context restore */
CPS #SVC_MODE
/* Restore the context of the task selected to execute. */ /* Restore the context of the task selected to execute. */
portRESTORE_CONTEXT portRESTORE_CONTEXT
/* ------------------------------------------------------------------------- */ /* ----------------------------------------------------------------------------------- */
/* Load the context of the first task, starting the FreeRTOS-Scheduler */ /* Load the context of the first task, starting the FreeRTOS-Scheduler */
.align 4 .align 4
.global vPortStartFirstTask .global vPortStartFirstTask
@ -244,13 +230,11 @@ vPortStartFirstTask:
/* Load the context of first task, starting the FreeRTOS-Scheduler */ /* Load the context of first task, starting the FreeRTOS-Scheduler */
portRESTORE_CONTEXT portRESTORE_CONTEXT
/* ------------------------------------------------------------------------- */ /* ----------------------------------------------------------------------------------- */
/* Handler for Supervisor Calls (SVCs) when using this FreeRTOS Port */ /* Handler for Supervisor Calls (SVCs) when using this FreeRTOS Port */
/* Upon entering here the LR, or R14, will hold the address of the following /* Upon entering here the LR, or R14, will hold the address of the following
* instruction. This then checks that instruction for the SVC # raised. * instruction. This then checks that instruction for the SVC # raised.
* This handler is ONLY safe when called from the exposed SVC wrapper functions
* located after this handler in this file.
* Checks: * Checks:
* 1. SVC is raised from the system call section (i.e. application is * 1. SVC is raised from the system call section (i.e. application is
* not raising SVC directly). * not raising SVC directly).
@ -267,8 +251,8 @@ vPortStartFirstTask:
.global FreeRTOS_SVC_Handler .global FreeRTOS_SVC_Handler
.type FreeRTOS_SVC_Handler, %function .type FreeRTOS_SVC_Handler, %function
FreeRTOS_SVC_Handler: FreeRTOS_SVC_Handler:
/* Push R11 and R12 to the bottom two, pre-resereved, addresses in ulContext */ /* Push R10-R12 for scratch space */
STM R13, {R11, R12} PUSH { R10-R12 }
/* -------------------- Caller Flash Location Check -------------------- */ /* -------------------- Caller Flash Location Check -------------------- */
@ -316,27 +300,23 @@ FreeRTOS_SVC_Handler:
/* If one of the above jumps wasn't taken, go straight to the exit */ /* If one of the above jumps wasn't taken, go straight to the exit */
SVC_Handler_Exit: SVC_Handler_Exit:
/** Restore the saved R11 and R12, then return to the caller */ /** Restore the saved R11 and R12, then return to the caller */
LDM SP, {R11, R12} POP { R10-R12 }
/* This instruction loads the SPSR into the CPSR, performing the mode swap */ /* This instruction loads the SPSR into the CPSR, performing the mode swap */
MOVS PC, LR MOVS PC, LR
/* ------------------------------------------------------------------------- */ /* ----------------------------------------------------------------------------------- */
/* Perform a task swap */ /* Perform a task swap */
svcPortYield: svcPortYield:
/* Restore the previously saved R11, R12 */ /* Restore the previously saved R11, R12 */
LDM SP, {R11, R12} POP { R10-R12 }
/* Save the context of the current task and select a new task to run. */ /* Save the context of the current task and select a new task to run. */
portSAVE_CONTEXT portSAVE_CONTEXT
/* Run the following function from the IRQ stack */
CPS #IRQ_MODE
/* Select a new task to swap to */ /* Select a new task to swap to */
BL vTaskSwitchContext BL vTaskSwitchContext
/* Swap back to SVC Mode for context restore */
CPS #SVC_MODE
/* Restore the context of the task selected to execute. */ /* Restore the context of the task selected to execute. */
portRESTORE_CONTEXT portRESTORE_CONTEXT
/* ------------------------------------------------------------------------- */ /* ----------------------------------------------------------------------------------- */
/* Reset task stack and link register after a FreeRTOS System Call */ /* Reset task stack and link register after a FreeRTOS System Call */
svcSystemCallExit: svcSystemCallExit:
/* Restore the Task Stack Pointer and Link Register */ /* Restore the Task Stack Pointer and Link Register */
@ -369,7 +349,7 @@ svcSystemCallExit:
/* Jump back */ /* Jump back */
B SVC_Handler_Exit B SVC_Handler_Exit
/* ------------------------------------------------------------------------- */ /* ----------------------------------------------------------------------------------- */
/* Save task's SP and LR, swap to ulSystemCallStack Buffer, raise privilege */ /* Save task's SP and LR, swap to ulSystemCallStack Buffer, raise privilege */
svcSystemCallEnter: svcSystemCallEnter:
/* Load the base address of the uxSystemCallImplementations[] table into R14 */ /* Load the base address of the uxSystemCallImplementations[] table into R14 */
@ -418,7 +398,7 @@ svcSystemCallEnter:
/* Leave through the SVC Exit */ /* Leave through the SVC Exit */
B SVC_Handler_Exit B SVC_Handler_Exit
/* ------------------------------------------------------------------------- */ /* ----------------------------------------------------------------------------------- */
/* Disable IRQs and increment the critical nesting count */ /* Disable IRQs and increment the critical nesting count */
.align 4 .align 4
.global vPortEnterCritical .global vPortEnterCritical
@ -440,7 +420,7 @@ vPortEnterCritical:
POP {R0-R1} POP {R0-R1}
BX LR BX LR
/* ------------------------------------------------------------------------- */ /* ----------------------------------------------------------------------------------- */
/* Disable IRQs */ /* Disable IRQs */
.align 4 .align 4
.global vPortDisableInterrupts .global vPortDisableInterrupts
@ -451,7 +431,7 @@ vPortDisableInterrupts:
/* Return to caller */ /* Return to caller */
BX LR BX LR
/* ------------------------------------------------------------------------- */ /* ----------------------------------------------------------------------------------- */
/* Enable IRQs and decrement the critical nesting count */ /* Enable IRQs and decrement the critical nesting count */
.align 4 .align 4
.global vPortExitCritical .global vPortExitCritical
@ -475,7 +455,7 @@ vPortExitCritical:
POP {R0-R1} POP {R0-R1}
BX LR BX LR
/* ------------------------------------------------------------------------- */ /* ----------------------------------------------------------------------------------- */
/* Enable IRQs */ /* Enable IRQs */
.align 4 .align 4
.global vPortEnableInterrupts .global vPortEnableInterrupts
@ -486,7 +466,7 @@ vPortEnableInterrupts:
/* Return to caller */ /* Return to caller */
BX LR BX LR
/* ------------------------------------------------------------------------- */ /* ----------------------------------------------------------------------------------- */
/** Set MPU Registers using provided values /** Set MPU Registers using provided values
* Function: void prvMpuSetRegion * Function: void prvMpuSetRegion
* Inputs: uint32_t ulRegionNumber * Inputs: uint32_t ulRegionNumber
@ -511,7 +491,7 @@ prvMpuSetRegion:
/* Return to caller */ /* Return to caller */
BX LR BX LR
/* ------------------------------------------------------------------------- */ /* ----------------------------------------------------------------------------------- */
/* Set the Enable bit of the MPU Enable Register to 1. */ /* Set the Enable bit of the MPU Enable Register to 1. */
.align 4 .align 4
.global prvMpuEnable .global prvMpuEnable
@ -530,7 +510,7 @@ prvMpuEnable:
/* Return to caller */ /* Return to caller */
BX LR BX LR
/* ------------------------------------------------------------------------- */ /* ----------------------------------------------------------------------------------- */
/* Set the Enable bit of the MPU Enable Register to 0. */ /* Set the Enable bit of the MPU Enable Register to 0. */
.align 4 .align 4
.global prvMpuDisable .global prvMpuDisable

View file

@ -479,12 +479,12 @@ extern "C" {
/** @brief The length in ulContext for the General Purpose Registers in bytes /** @brief The length in ulContext for the General Purpose Registers in bytes
* @note There are 13 GPRs, R0-R12 each is 32 bits, so 13 registers * 4 Bytes each * @note There are 13 GPRs, R0-R12 each is 32 bits, so 13 registers * 4 Bytes each
*/ */
#define portGPR_LENGTH ( 13U * 4U ) #define portGPR_LENGTH ( 15U * 4U )
/** @brief The length in ulContext for all the registers in a context /** @brief The length in ulContext for all the registers in a context
* @note There are the 13 GPRs, the Stack Pointer, and the Link Register * @note There are the 13 GPRs, the Stack Pointer, and the Link Register
*/ */
#define portREGISTER_CONTEXT_LENGTH ( portGPR_LENGTH + ( 2 * 4U ) ) #define portREGISTER_CONTEXT_LENGTH ( ( 16 * 4U ) )
/** If you KNOW that your system will not utilize the FPU in any capacity /** If you KNOW that your system will not utilize the FPU in any capacity
* you can set portENABLE_FPU to 0, which will reduce the per-task RAM usage * you can set portENABLE_FPU to 0, which will reduce the per-task RAM usage
@ -512,18 +512,17 @@ extern "C" {
* ulContext[ 48 ]: Link Register * ulContext[ 48 ]: Link Register
* ulContext[ 49 ]: Program Counter * ulContext[ 49 ]: Program Counter
* ulContext[ 50 ]: Current Program Status and Control Register * ulContext[ 50 ]: Current Program Status and Control Register
* ulContext[ 51 ]: Supervisor Mode SRS PC Scratch Space
* ulContext[ 52 ]: Supervisor Mode SRS CPSR Scratch Space
*/ */
#define portENABLE_FPU configENABLE_FPU #define portENABLE_FPU configENABLE_FPU
#if( portENABLE_FPU == 1 ) #if( portENABLE_FPU == 1 )
/** @brief Length of a Task's Register Context when using an FPU. */ /** @brief Length of a Task's Register Context when using an FPU. */
#define MAX_CONTEXT_SIZE 52U #define MAX_CONTEXT_SIZE 50U
#else #else
/** @brief Length of a Task's Register Context when not using an FPU. */ /** @brief Length of a Task's Register Context when not using an FPU. */
#define MAX_CONTEXT_SIZE 20U #define MAX_CONTEXT_SIZE 18U
#endif #endif
/** @brief Numerical offset from the start of a TCB to xSystemCallStackInfo /** @brief Numerical offset from the start of a TCB to xSystemCallStackInfo
* @note In the exception handlers it is necessary to load this variable from the TCB. * @note In the exception handlers it is necessary to load this variable from the TCB.
* This provides an easy way for the exception handlers to get this structure. * This provides an easy way for the exception handlers to get this structure.