mirror of
https://github.com/FreeRTOS/FreeRTOS-Kernel.git
synced 2025-09-01 20:03:50 -04:00
Update ARM_CRx_No_GIC port (#1101)
This PR makes the following improvements to the ARM_CRx_No_GIC port- 1. Remove inline assembly and move all the assembly code to the portASM.S file. 2. Add support for configUSE_TASK_FPU_SUPPORT - - When configUSE_TASK_FPU_SUPPORT is defined to 1, tasks are created without floating point context. Tasks that want to use floating point, need to call portTASK_USES_FLOATING_POINT(). This is the current behavior. - When configUSE_TASK_FPU_SUPPORT is defined to 2, each task is created with a floating point context. If left undefined, configUSE_TASK_FPU_SUPPORT defaults to 1 for backward compatibility. 3. The application writer can now implement vApplicationSVCHandler to handle the SVC calls raised within the application. SVC 0 is used for the yield kernel operation and the application can use all the SVC calls other than 0. Signed-off-by: kar-rahul-aws <karahulx@amazon.com>
This commit is contained in:
parent
0452603a94
commit
5588ae68c8
3 changed files with 308 additions and 148 deletions
|
@ -28,14 +28,14 @@
|
|||
|
||||
.text
|
||||
.arm
|
||||
.syntax unified
|
||||
|
||||
.set SYS_MODE, 0x1f
|
||||
.set SVC_MODE, 0x13
|
||||
.set IRQ_MODE, 0x12
|
||||
.set SYS_MODE, 0x1f
|
||||
.set SVC_MODE, 0x13
|
||||
.set IRQ_MODE, 0x12
|
||||
.set CPSR_I_BIT, 0x80
|
||||
|
||||
/* Variables and functions. */
|
||||
.extern ulMaxAPIPriorityMask
|
||||
.extern _freertos_vector_table
|
||||
.extern pxCurrentTCB
|
||||
.extern vTaskSwitchContext
|
||||
.extern vApplicationIRQHandler
|
||||
|
@ -47,29 +47,38 @@
|
|||
.global FreeRTOS_IRQ_Handler
|
||||
.global FreeRTOS_SVC_Handler
|
||||
.global vPortRestoreTaskContext
|
||||
.global vPortInitialiseFPSCR
|
||||
.global ulReadAPSR
|
||||
.global vPortYield
|
||||
.global vPortEnableInterrupts
|
||||
.global vPortDisableInterrupts
|
||||
.global ulPortSetInterruptMaskFromISR
|
||||
.global ulPortCountLeadingZeros
|
||||
|
||||
.weak vApplicationSVCHandler
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
.macro portSAVE_CONTEXT
|
||||
|
||||
/* Save the LR and SPSR onto the system mode stack before switching to
|
||||
system mode to save the remaining system mode registers. */
|
||||
SRSDB sp!, #SYS_MODE
|
||||
* system mode to save the remaining system mode registers. */
|
||||
SRSDB SP!, #SYS_MODE
|
||||
CPS #SYS_MODE
|
||||
PUSH {R0-R12, R14}
|
||||
|
||||
/* Push the critical nesting count. */
|
||||
LDR R2, ulCriticalNestingConst
|
||||
LDR R2, =ulCriticalNesting
|
||||
LDR R1, [R2]
|
||||
PUSH {R1}
|
||||
|
||||
/* Does the task have a floating point context that needs saving? If
|
||||
ulPortTaskHasFPUContext is 0 then no. */
|
||||
LDR R2, ulPortTaskHasFPUContextConst
|
||||
* ulPortTaskHasFPUContext is 0 then no. */
|
||||
LDR R2, =ulPortTaskHasFPUContext
|
||||
LDR R3, [R2]
|
||||
CMP R3, #0
|
||||
|
||||
/* Save the floating point context, if any. */
|
||||
FMRXNE R1, FPSCR
|
||||
VMRSNE R1, FPSCR
|
||||
VPUSHNE {D0-D15}
|
||||
#if configFPU_D32 == 1
|
||||
VPUSHNE {D16-D31}
|
||||
|
@ -80,24 +89,24 @@
|
|||
PUSH {R3}
|
||||
|
||||
/* Save the stack pointer in the TCB. */
|
||||
LDR R0, pxCurrentTCBConst
|
||||
LDR R0, =pxCurrentTCB
|
||||
LDR R1, [R0]
|
||||
STR SP, [R1]
|
||||
|
||||
.endm
|
||||
|
||||
; /**********************************************************************/
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
.macro portRESTORE_CONTEXT
|
||||
|
||||
/* Set the SP to point to the stack of the task being restored. */
|
||||
LDR R0, pxCurrentTCBConst
|
||||
LDR R0, =pxCurrentTCB
|
||||
LDR R1, [R0]
|
||||
LDR SP, [R1]
|
||||
|
||||
/* Is there a floating point context to restore? If the restored
|
||||
ulPortTaskHasFPUContext is zero then no. */
|
||||
LDR R0, ulPortTaskHasFPUContextConst
|
||||
* ulPortTaskHasFPUContext is zero then no. */
|
||||
LDR R0, =ulPortTaskHasFPUContext
|
||||
POP {R1}
|
||||
STR R1, [R0]
|
||||
CMP R1, #0
|
||||
|
@ -111,7 +120,7 @@
|
|||
VMSRNE FPSCR, R0
|
||||
|
||||
/* Restore the critical section nesting depth. */
|
||||
LDR R0, ulCriticalNestingConst
|
||||
LDR R0, =ulCriticalNesting
|
||||
POP {R1}
|
||||
STR R1, [R0]
|
||||
|
||||
|
@ -120,29 +129,17 @@
|
|||
POP {R0-R12, R14}
|
||||
|
||||
/* Return to the task code, loading CPSR on the way. */
|
||||
RFEIA sp!
|
||||
RFEIA SP!
|
||||
|
||||
.endm
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* SVC handler is used to yield.
|
||||
*****************************************************************************/
|
||||
.align 4
|
||||
.type FreeRTOS_SVC_Handler, %function
|
||||
FreeRTOS_SVC_Handler:
|
||||
/* Save the context of the current task and select a new task to run. */
|
||||
portSAVE_CONTEXT
|
||||
LDR R0, vTaskSwitchContextConst
|
||||
BLX R0
|
||||
portRESTORE_CONTEXT
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
/*
|
||||
* void vPortRestoreTaskContext( void );
|
||||
*
|
||||
* vPortRestoreTaskContext is used to start the scheduler.
|
||||
*****************************************************************************/
|
||||
*/
|
||||
.align 4
|
||||
.type vPortRestoreTaskContext, %function
|
||||
vPortRestoreTaskContext:
|
||||
|
@ -150,72 +147,212 @@ vPortRestoreTaskContext:
|
|||
CPS #SYS_MODE
|
||||
portRESTORE_CONTEXT
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* void vPortInitialiseFPSCR( void );
|
||||
*
|
||||
* vPortInitialiseFPSCR is used to initialize the FPSCR register.
|
||||
*/
|
||||
.align 4
|
||||
.type vPortInitialiseFPSCR, %function
|
||||
vPortInitialiseFPSCR:
|
||||
MOV R0, #0
|
||||
VMSR FPSCR, R0
|
||||
BX LR
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* uint32_t ulReadAPSR( void );
|
||||
*
|
||||
* ulReadAPSR is used to read the value of APSR context.
|
||||
*/
|
||||
.align 4
|
||||
.type ulReadAPSR, %function
|
||||
ulReadAPSR:
|
||||
MRS R0, APSR
|
||||
BX LR
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* void vPortYield( void );
|
||||
*/
|
||||
.align 4
|
||||
.type vPortYield, %function
|
||||
vPortYield:
|
||||
SVC 0
|
||||
ISB
|
||||
BX LR
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* void vPortEnableInterrupts( void );
|
||||
*/
|
||||
.align 4
|
||||
.type vPortEnableInterrupts, %function
|
||||
vPortEnableInterrupts:
|
||||
CPSIE I
|
||||
BX LR
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* void vPortDisableInterrupts( void );
|
||||
*/
|
||||
.align 4
|
||||
.type vPortDisableInterrupts, %function
|
||||
vPortDisableInterrupts:
|
||||
CPSID I
|
||||
DSB
|
||||
ISB
|
||||
BX LR
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* uint32_t ulPortSetInterruptMaskFromISR( void );
|
||||
*/
|
||||
.align 4
|
||||
.type ulPortSetInterruptMaskFromISR, %function
|
||||
ulPortSetInterruptMaskFromISR:
|
||||
MRS R0, CPSR
|
||||
AND R0, R0, #CPSR_I_BIT
|
||||
CPSID I
|
||||
DSB
|
||||
ISB
|
||||
BX LR
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* void vApplicationSVCHandler( uint32_t ulSvcNumber );
|
||||
*/
|
||||
.align 4
|
||||
.type vApplicationSVCHandler, %function
|
||||
vApplicationSVCHandler:
|
||||
B vApplicationSVCHandler
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* UBaseType_t ulPortCountLeadingZeros( UBaseType_t ulBitmap );
|
||||
*
|
||||
* According to the Procedure Call Standard for the ARM Architecture (AAPCS):
|
||||
* - Parameter ulBitmap is passed in R0.
|
||||
* - Return value must be in R0.
|
||||
*/
|
||||
.align 4
|
||||
.type ulPortCountLeadingZeros, %function
|
||||
ulPortCountLeadingZeros:
|
||||
CLZ R0, R0
|
||||
BX LR
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* SVC handler is used to yield.
|
||||
*/
|
||||
.align 4
|
||||
.type FreeRTOS_SVC_Handler, %function
|
||||
FreeRTOS_SVC_Handler:
|
||||
PUSH { R0-R1 }
|
||||
|
||||
/* ---------------------------- Get Caller SVC Number ---------------------------- */
|
||||
MRS R0, SPSR /* R0 = CPSR at the time of SVC. */
|
||||
TST R0, #0x20 /* Check Thumb bit (5) in CPSR. */
|
||||
LDRHNE R0, [LR, #-0x2] /* If Thumb, load halfword. */
|
||||
BICNE R0, R0, #0xFF00 /* And extract immidiate field (i.e. SVC number). */
|
||||
LDREQ R0, [LR, #-0x4] /* If ARM, load word. */
|
||||
BICEQ R0, R0, #0xFF000000 /* And extract immidiate field (i.e. SVC number). */
|
||||
|
||||
/* --------------------------------- SVC Routing --------------------------------- */
|
||||
CMP R0, #0
|
||||
BEQ svcPortYield
|
||||
BNE svcApplicationCall
|
||||
|
||||
svcPortYield:
|
||||
POP { R0-R1 }
|
||||
portSAVE_CONTEXT
|
||||
BLX vTaskSwitchContext
|
||||
portRESTORE_CONTEXT
|
||||
|
||||
svcApplicationCall:
|
||||
POP { R0-R1 }
|
||||
portSAVE_CONTEXT
|
||||
BLX vApplicationSVCHandler
|
||||
portRESTORE_CONTEXT
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
.align 4
|
||||
.type FreeRTOS_IRQ_Handler, %function
|
||||
FreeRTOS_IRQ_Handler:
|
||||
/* Return to the interrupted instruction. */
|
||||
SUB lr, lr, #4
|
||||
SUB LR, LR, #4
|
||||
|
||||
/* Push the return address and SPSR. */
|
||||
PUSH {lr}
|
||||
MRS lr, SPSR
|
||||
PUSH {lr}
|
||||
PUSH {LR}
|
||||
MRS LR, SPSR
|
||||
PUSH {LR}
|
||||
|
||||
/* Change to supervisor mode to allow reentry. */
|
||||
CPS #0x13
|
||||
CPS #SVC_MODE
|
||||
|
||||
/* Push used registers. */
|
||||
PUSH {r0-r3, r12}
|
||||
PUSH {R0-R3, R12}
|
||||
|
||||
/* Increment nesting count. r3 holds the address of ulPortInterruptNesting
|
||||
for future use. r1 holds the original ulPortInterruptNesting value for
|
||||
future use. */
|
||||
LDR r3, ulPortInterruptNestingConst
|
||||
LDR r1, [r3]
|
||||
ADD r0, r1, #1
|
||||
STR r0, [r3]
|
||||
* for future use. r1 holds the original ulPortInterruptNesting value for
|
||||
* future use. */
|
||||
LDR R3, =ulPortInterruptNesting
|
||||
LDR R1, [R3]
|
||||
ADD R0, R1, #1
|
||||
STR R0, [R3]
|
||||
|
||||
/* Ensure bit 2 of the stack pointer is clear. r2 holds the bit 2 value for
|
||||
future use. */
|
||||
MOV r0, sp
|
||||
AND r2, r0, #4
|
||||
SUB sp, sp, r2
|
||||
* future use. */
|
||||
MOV R0, SP
|
||||
AND R2, R0, #4
|
||||
SUB SP, SP, R2
|
||||
|
||||
/* Call the interrupt handler. */
|
||||
PUSH {r0-r3, lr}
|
||||
LDR r1, vApplicationIRQHandlerConst
|
||||
BLX r1
|
||||
POP {r0-r3, lr}
|
||||
ADD sp, sp, r2
|
||||
PUSH {R0-R3, LR}
|
||||
BLX vApplicationIRQHandler
|
||||
POP {R0-R3, LR}
|
||||
ADD SP, SP, R2
|
||||
|
||||
/* Disable IRQs incase vApplicationIRQHandler enabled them for re-entry. */
|
||||
CPSID i
|
||||
DSB
|
||||
ISB
|
||||
|
||||
/* Write to the EOI register. */
|
||||
LDR r0, ulICCEOIRConst
|
||||
LDR r2, [r0]
|
||||
STR r0, [r2]
|
||||
LDR R0, =ulICCEOIR
|
||||
LDR R2, [R0]
|
||||
STR R0, [R2]
|
||||
|
||||
/* Restore the old nesting count. */
|
||||
STR r1, [r3]
|
||||
STR R1, [R3]
|
||||
|
||||
/* A context switch is never performed if the nesting count is not 0. */
|
||||
CMP r1, #0
|
||||
CMP R1, #0
|
||||
BNE exit_without_switch
|
||||
|
||||
/* Did the interrupt request a context switch? r1 holds the address of
|
||||
ulPortYieldRequired and r0 the value of ulPortYieldRequired for future
|
||||
use. */
|
||||
LDR r1, ulPortYieldRequiredConst
|
||||
LDR r0, [r1]
|
||||
CMP r0, #0
|
||||
* ulPortYieldRequired and r0 the value of ulPortYieldRequired for future
|
||||
* use. */
|
||||
LDR R1, =ulPortYieldRequired
|
||||
LDR R0, [R1]
|
||||
CMP R0, #0
|
||||
BNE switch_before_exit
|
||||
|
||||
exit_without_switch:
|
||||
/* No context switch. Restore used registers, LR_irq and SPSR before
|
||||
returning. */
|
||||
POP {r0-r3, r12}
|
||||
* returning. */
|
||||
POP {R0-R3, R12}
|
||||
CPS #IRQ_MODE
|
||||
POP {LR}
|
||||
MSR SPSR_cxsf, LR
|
||||
|
@ -224,13 +361,13 @@ exit_without_switch:
|
|||
|
||||
switch_before_exit:
|
||||
/* A context switch is to be performed. Clear the context switch pending
|
||||
flag. */
|
||||
MOV r0, #0
|
||||
STR r0, [r1]
|
||||
* flag. */
|
||||
MOV R0, #0
|
||||
STR R0, [R1]
|
||||
|
||||
/* Restore used registers, LR-irq and SPSR before saving the context
|
||||
to the task stack. */
|
||||
POP {r0-r3, r12}
|
||||
* to the task stack. */
|
||||
POP {R0-R3, R12}
|
||||
CPS #IRQ_MODE
|
||||
POP {LR}
|
||||
MSR SPSR_cxsf, LR
|
||||
|
@ -238,23 +375,15 @@ switch_before_exit:
|
|||
portSAVE_CONTEXT
|
||||
|
||||
/* Call the function that selects the new task to execute.
|
||||
vTaskSwitchContext() if vTaskSwitchContext() uses LDRD or STRD
|
||||
instructions, or 8 byte aligned stack allocated data. LR does not need
|
||||
saving as a new LR will be loaded by portRESTORE_CONTEXT anyway. */
|
||||
LDR R0, vTaskSwitchContextConst
|
||||
BLX R0
|
||||
* vTaskSwitchContext() if vTaskSwitchContext() uses LDRD or STRD
|
||||
* instructions, or 8 byte aligned stack allocated data. LR does not need
|
||||
* saving as a new LR will be loaded by portRESTORE_CONTEXT anyway. */
|
||||
BLX vTaskSwitchContext
|
||||
|
||||
/* Restore the context of, and branch to, the task selected to execute
|
||||
next. */
|
||||
* next. */
|
||||
portRESTORE_CONTEXT
|
||||
|
||||
ulICCEOIRConst: .word ulICCEOIR
|
||||
pxCurrentTCBConst: .word pxCurrentTCB
|
||||
ulCriticalNestingConst: .word ulCriticalNesting
|
||||
ulPortTaskHasFPUContextConst: .word ulPortTaskHasFPUContext
|
||||
vTaskSwitchContextConst: .word vTaskSwitchContext
|
||||
vApplicationIRQHandlerConst: .word vApplicationIRQHandler
|
||||
ulPortInterruptNestingConst: .word ulPortInterruptNesting
|
||||
ulPortYieldRequiredConst: .word ulPortYieldRequired
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
.end
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue