This commit is contained in:
Loustiic 2026-08-27 02:37:43 -07:00 • committed by GitHub
commit f2d0c026a7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 57 additions and 14 deletions

View file

@ -168,7 +168,8 @@ static void prvTaskExitError( void );
/* /*
* If the application provides an implementation of vApplicationIRQHandler(), * If the application provides an implementation of vApplicationIRQHandler(),
* then it will get called directly without saving the FPU registers on * then it will get called directly without saving the FPU registers
* when there is no FPU context to preserve on
* interrupt entry, and this weak implementation of * interrupt entry, and this weak implementation of
* vApplicationFPUSafeIRQHandler() is just provided to remove linkage errors - * vApplicationFPUSafeIRQHandler() is just provided to remove linkage errors -
* it should never actually get called so its implementation contains a * it should never actually get called so its implementation contains a
@ -179,11 +180,16 @@ static void prvTaskExitError( void );
* vApplicationIRQHandler() provided in portASM.S will save the FPU registers * vApplicationIRQHandler() provided in portASM.S will save the FPU registers
* before calling it. * before calling it.
* *
* Therefore, if the application writer wants FPU registers to be saved on * Therefore, if the application writer wants FPU registers to always be saved on
* interrupt entry their IRQ handler must be called * interrupt entry their IRQ handler must be called
* vApplicationFPUSafeIRQHandler(), and if the application writer does not want * vApplicationFPUSafeIRQHandler(), and if the application writer does not want
* FPU registers to be saved on interrupt entry their IRQ handler must be * FPU registers to be saved on interrupt entry their IRQ handler must be
* called vApplicationIRQHandler(). * called vApplicationIRQHandler().
*
* Note that for ARM Cortex A9, the FPU might be used for memory operations,
* depending on the C library used for memcpy, memcmp or memset. For instance,
* glibc uses the FPU, hence always saving it might be preferable when using it.
* See https://freertos.org/Using-FreeRTOS-on-Cortex-A-Embedded-Processors#important-note-for-gcc-and-possibly-other-compiler-users
*/ */
void vApplicationFPUSafeIRQHandler( uint32_t ulICCIAR ) __attribute__( ( weak ) ); void vApplicationFPUSafeIRQHandler( uint32_t ulICCIAR ) __attribute__( ( weak ) );

View file

@ -197,6 +197,18 @@ FreeRTOS_IRQ_Handler:
LDR r2, [r2] LDR r2, [r2]
LDR r0, [r2] LDR r0, [r2]
/* Does the task have a floating point context that needs saving? If
ulPortTaskHasFPUContext is 0 then no. */
LDR r12, ulPortTaskHasFPUContextConst
LDR r4, [r12]
CMP r4, #0 /* r4 contains ulPortTaskHasFPUContext */
/* Save the floating point context, if any. */
FMRXNE r12, FPSCR
VPUSHNE {d0-d15}
VPUSHNE {d16-d31}
PUSHNE {r12} /* r12 contains FPSCR */
/* Ensure bit 2 of the stack pointer is clear. r2 holds the bit 2 value for /* Ensure bit 2 of the stack pointer is clear. r2 holds the bit 2 value for
future use. _RB_ Does this ever actually need to be done provided the start future use. _RB_ Does this ever actually need to be done provided the start
of the stack is 8-byte aligned? */ of the stack is 8-byte aligned? */
@ -204,7 +216,7 @@ FreeRTOS_IRQ_Handler:
AND r2, r2, #4 AND r2, r2, #4
SUB sp, sp, r2 SUB sp, sp, r2
/* Call the interrupt handler. r4 pushed to maintain alignment. */ /* Call the interrupt handler. */
PUSH {r0-r4, lr} PUSH {r0-r4, lr}
LDR r1, vApplicationIRQHandlerConst LDR r1, vApplicationIRQHandlerConst
BLX r1 BLX r1
@ -215,6 +227,13 @@ FreeRTOS_IRQ_Handler:
DSB DSB
ISB ISB
/* Restore the floating point context, if any. */
CMP r4, #0 /* r4 contains ulPortTaskHasFPUContext */
POPNE {r12} /* r12 contains FPSCR */
VPOPNE {d16-d31}
VPOPNE {d0-d15}
VMSRNE FPSCR, r12
/* Write the value read from ICCIAR to ICCEOIR. */ /* Write the value read from ICCIAR to ICCEOIR. */
LDR r4, ulICCEOIRConst LDR r4, ulICCEOIRConst
LDR r4, [r4] LDR r4, [r4]
@ -281,13 +300,13 @@ switch_before_exit:
/****************************************************************************** /******************************************************************************
* If the application provides an implementation of vApplicationIRQHandler(), * If the application provides an implementation of vApplicationIRQHandler(),
* then it will get called directly without saving the FPU registers on * then it will get called directly without saving the FPU registers on
* interrupt entry, and this weak implementation of * interrupt entry when the FPU is not used, and this weak implementation of
* vApplicationIRQHandler() will not get called. * vApplicationIRQHandler() will not get called.
* *
* If the application provides its own implementation of * If the application provides its own implementation of
* vApplicationFPUSafeIRQHandler() then this implementation of * vApplicationFPUSafeIRQHandler() then this implementation of
* vApplicationIRQHandler() will be called, save the FPU registers, and then * vApplicationIRQHandler() will be called, save the FPU registers if not done
* call vApplicationFPUSafeIRQHandler(). * already, and then call vApplicationFPUSafeIRQHandler().
* *
* Therefore, if the application writer wants FPU registers to be saved on * Therefore, if the application writer wants FPU registers to be saved on
* interrupt entry their IRQ handler must be called * interrupt entry their IRQ handler must be called
@ -301,18 +320,36 @@ switch_before_exit:
.type vApplicationIRQHandler, %function .type vApplicationIRQHandler, %function
vApplicationIRQHandler: vApplicationIRQHandler:
PUSH {LR} PUSH {LR}
FMRX R1, FPSCR
VPUSH {D0-D7} /* Does the task have a floating point context that has been saved already? If
VPUSH {D16-D31} ulPortTaskHasFPUContext is 1 then yes. */
PUSH {R1} LDR r12, ulPortTaskHasFPUContextConst
LDR r4, [r12]
/* If there is an FPU context, it was already saved. */
CMP r4, #1 /* If equal, the FPU context was saved by the caller. */
FMRXNE r1, FPSCR
VPUSHNE {d0-d7}
VPUSHNE {d16-d31}
PUSHNE {r1}
PUSHNE {r1} /* Push FPSCR twice to keep memory alignment */
/* Store ulPortTaskHasFPUContext */
PUSH {r4}
LDR r1, vApplicationFPUSafeIRQHandlerConst LDR r1, vApplicationFPUSafeIRQHandlerConst
BLX r1 BLX r1
POP {R0} /* Restore ulPortTaskHasFPUContext */
VPOP {D16-D31} POP {r4}
VPOP {D0-D7}
VMSR FPSCR, R0 /* Skip the FPU register reset if there is an FPU context, the IRQ handler will do it. */
CMP r4, #1 /* If true, the FPU registers will be restored by the caller. */
POPNE {r0}
POPNE {r0} /* FPSCR was pushed twice for alignment purposes */
VPOPNE {d16-d31}
VPOPNE {d0-d7}
VMSRNE FPSCR, r0
POP {PC} POP {PC}