/* | |
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. | |
All rights reserved | |
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. | |
This file is part of the FreeRTOS distribution. | |
FreeRTOS is free software; you can redistribute it and/or modify it under | |
the terms of the GNU General Public License (version 2) as published by the | |
Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. | |
*************************************************************************** | |
>>! NOTE: The modification to the GPL is included to allow you to !<< | |
>>! distribute a combined work that includes FreeRTOS without being !<< | |
>>! obliged to provide the source code for proprietary components !<< | |
>>! outside of the FreeRTOS kernel. !<< | |
*************************************************************************** | |
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY | |
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | |
FOR A PARTICULAR PURPOSE. Full license text is available on the following | |
link: http://www.freertos.org/a00114.html | |
*************************************************************************** | |
* * | |
* FreeRTOS provides completely free yet professionally developed, * | |
* robust, strictly quality controlled, supported, and cross * | |
* platform software that is more than just the market leader, it * | |
* is the industry's de facto standard. * | |
* * | |
* Help yourself get started quickly while simultaneously helping * | |
* to support the FreeRTOS project by purchasing a FreeRTOS * | |
* tutorial book, reference manual, or both: * | |
* http://www.FreeRTOS.org/Documentation * | |
* * | |
*************************************************************************** | |
http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading | |
the FAQ page "My application does not run, what could be wrong?". Have you | |
defined configASSERT()? | |
http://www.FreeRTOS.org/support - In return for receiving this top quality | |
embedded software for free we request you assist our global community by | |
participating in the support forum. | |
http://www.FreeRTOS.org/training - Investing in training allows your team to | |
be as productive as possible as early as possible. Now you can receive | |
FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers | |
Ltd, and the world's leading authority on the world's leading RTOS. | |
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, | |
including FreeRTOS+Trace - an indispensable productivity tool, a DOS | |
compatible FAT file system, and our tiny thread aware UDP/IP stack. | |
http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. | |
Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. | |
http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High | |
Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS | |
licenses offer ticketed support, indemnification and commercial middleware. | |
http://www.SafeRTOS.com - High Integrity Systems also provide a safety | |
engineered and independently SIL3 certified version for use in safety and | |
mission critical applications that require provable dependability. | |
1 tab == 4 spaces! | |
*/ | |
.text | |
/* Variables and functions. */ | |
.extern ullMaxAPIPriorityMask | |
.extern pxCurrentTCB | |
.extern vTaskSwitchContext | |
.extern vApplicationIRQHandler | |
.extern ullPortInterruptNesting | |
.extern ullPortTaskHasFPUContext | |
.extern ullCriticalNesting | |
.extern ullPortYieldRequired | |
.extern ullICCEOIR | |
.extern ullICCIAR | |
.extern _freertos_vector_table | |
.global FreeRTOS_IRQ_Handler | |
.global FreeRTOS_SWI_Handler | |
.global vPortRestoreTaskContext | |
.macro portSAVE_CONTEXT | |
/* Switch to use the EL0 stack pointer. */ | |
MSR SPSEL, #0 | |
/* Save the entire context. */ | |
STP X0, X1, [SP, #-0x10]! | |
STP X2, X3, [SP, #-0x10]! | |
STP X4, X5, [SP, #-0x10]! | |
STP X6, X7, [SP, #-0x10]! | |
STP X8, X9, [SP, #-0x10]! | |
STP X10, X11, [SP, #-0x10]! | |
STP X12, X13, [SP, #-0x10]! | |
STP X14, X15, [SP, #-0x10]! | |
STP X16, X17, [SP, #-0x10]! | |
STP X18, X19, [SP, #-0x10]! | |
STP X20, X21, [SP, #-0x10]! | |
STP X22, X23, [SP, #-0x10]! | |
STP X24, X25, [SP, #-0x10]! | |
STP X26, X27, [SP, #-0x10]! | |
STP X28, X29, [SP, #-0x10]! | |
STP X30, XZR, [SP, #-0x10]! | |
/* Save the SPSR. */ | |
MRS X3, SPSR_EL3 | |
/* Save the ELR. */ | |
MRS X2, ELR_EL3 | |
STP X2, X3, [SP, #-0x10]! | |
/* Save the critical section nesting depth. */ | |
LDR X0, ullCriticalNestingConst | |
LDR X3, [X0] | |
/* Save the FPU context indicator. */ | |
LDR X0, ullPortTaskHasFPUContextConst | |
LDR X2, [X0] | |
/* Save the FPU context, if any (32 128-bit registers). */ | |
CMP X2, #0 | |
B.EQ 1f | |
STP Q0, Q1, [SP,#-0x20]! | |
STP Q2, Q3, [SP,#-0x20]! | |
STP Q4, Q5, [SP,#-0x20]! | |
STP Q6, Q7, [SP,#-0x20]! | |
STP Q8, Q9, [SP,#-0x20]! | |
STP Q10, Q11, [SP,#-0x20]! | |
STP Q12, Q13, [SP,#-0x20]! | |
STP Q14, Q15, [SP,#-0x20]! | |
STP Q16, Q17, [SP,#-0x20]! | |
STP Q18, Q19, [SP,#-0x20]! | |
STP Q20, Q21, [SP,#-0x20]! | |
STP Q22, Q23, [SP,#-0x20]! | |
STP Q24, Q25, [SP,#-0x20]! | |
STP Q26, Q27, [SP,#-0x20]! | |
STP Q28, Q29, [SP,#-0x20]! | |
STP Q30, Q31, [SP,#-0x20]! | |
1: | |
/* Store the critical nesting count and FPU context indicator. */ | |
STP X2, X3, [SP, #-0x10]! | |
LDR X0, pxCurrentTCBConst | |
LDR X1, [X0] | |
MOV X0, SP /* Move SP into X0 for saving. */ | |
STR X0, [X1] | |
/* Switch to use the ELx stack pointer. */ | |
MSR SPSEL, #1 | |
.endm | |
; /**********************************************************************/ | |
.macro portRESTORE_CONTEXT | |
/* Switch to use the EL0 stack pointer. */ | |
MSR SPSEL, #0 | |
/* Set the SP to point to the stack of the task being restored. */ | |
LDR X0, pxCurrentTCBConst | |
LDR X1, [X0] | |
LDR X0, [X1] | |
MOV SP, X0 | |
LDP X2, X3, [SP], #0x10 /* Critical nesting and FPU context. */ | |
/* Set the PMR register to be correct for the current critical nesting | |
depth. */ | |
LDR X0, ullCriticalNestingConst /* X0 holds the address of ullCriticalNesting. */ | |
MOV X1, #255 /* X1 holds the unmask value. */ | |
LDR X4, ullICCPMRConst /* X4 holds the address of the ICCPMR constant. */ | |
CMP X3, #0 | |
LDR X5, [X4] /* X5 holds the address of the ICCPMR register. */ | |
B.EQ 1f | |
LDR X6, ullMaxAPIPriorityMaskConst | |
LDR X1, [X6] /* X1 holds the mask value. */ | |
1: | |
STR W1, [X5] /* Write the mask value to ICCPMR. */ | |
DSB SY /* _RB_Barriers probably not required here. */ | |
ISB SY | |
STR X3, [X0] /* Restore the task's critical nesting count. */ | |
/* Restore the FPU context indicator. */ | |
LDR X0, ullPortTaskHasFPUContextConst | |
STR X2, [X0] | |
/* Restore the FPU context, if any. */ | |
CMP X2, #0 | |
B.EQ 1f | |
LDP Q30, Q31, [SP], #0x20 | |
LDP Q28, Q29, [SP], #0x20 | |
LDP Q26, Q27, [SP], #0x20 | |
LDP Q24, Q25, [SP], #0x20 | |
LDP Q22, Q23, [SP], #0x20 | |
LDP Q20, Q21, [SP], #0x20 | |
LDP Q18, Q19, [SP], #0x20 | |
LDP Q16, Q17, [SP], #0x20 | |
LDP Q14, Q15, [SP], #0x20 | |
LDP Q12, Q13, [SP], #0x20 | |
LDP Q10, Q11, [SP], #0x20 | |
LDP Q8, Q9, [SP], #0x20 | |
LDP Q6, Q7, [SP], #0x20 | |
LDP Q4, Q5, [SP], #0x20 | |
LDP Q2, Q3, [SP], #0x20 | |
LDP Q0, Q1, [SP], #0x20 | |
1: | |
LDP X2, X3, [SP], #0x10 /* SPSR and ELR. */ | |
/* Restore the SPSR. */ | |
MSR SPSR_EL3, X3 /*_RB_ Assumes started in EL3. */ | |
/* Restore the ELR. */ | |
MSR ELR_EL3, X2 | |
LDP X30, XZR, [SP], #0x10 | |
LDP X28, X29, [SP], #0x10 | |
LDP X26, X27, [SP], #0x10 | |
LDP X24, X25, [SP], #0x10 | |
LDP X22, X23, [SP], #0x10 | |
LDP X20, X21, [SP], #0x10 | |
LDP X18, X19, [SP], #0x10 | |
LDP X16, X17, [SP], #0x10 | |
LDP X14, X15, [SP], #0x10 | |
LDP X12, X13, [SP], #0x10 | |
LDP X10, X11, [SP], #0x10 | |
LDP X8, X9, [SP], #0x10 | |
LDP X6, X7, [SP], #0x10 | |
LDP X4, X5, [SP], #0x10 | |
LDP X2, X3, [SP], #0x10 | |
LDP X0, X1, [SP], #0x10 | |
/* Switch to use the ELx stack pointer. _RB_ Might not be required. */ | |
MSR SPSEL, #1 | |
ERET | |
.endm | |
/****************************************************************************** | |
* FreeRTOS_SWI_Handler handler is used to perform a context switch. | |
*****************************************************************************/ | |
.align 8 | |
.type FreeRTOS_SWI_Handler, %function | |
FreeRTOS_SWI_Handler: | |
/* Save the context of the current task and select a new task to run. */ | |
portSAVE_CONTEXT | |
MRS X0, ESR_EL3 | |
LSR X1, X0, #26 | |
CMP X1, #0x17 /* 0x17 = SMC instruction. */ | |
B.NE FreeRTOS_Abort | |
BL vTaskSwitchContext | |
portRESTORE_CONTEXT | |
FreeRTOS_Abort: | |
/* Full ESR is in X0, exception class code is in X1. */ | |
B . | |
/****************************************************************************** | |
* vPortRestoreTaskContext is used to start the scheduler. | |
*****************************************************************************/ | |
.align 8 | |
.type vPortRestoreTaskContext, %function | |
vPortRestoreTaskContext: | |
.set freertos_vector_base, _freertos_vector_table | |
/* Install the FreeRTOS interrupt handlers. */ | |
LDR X1, =freertos_vector_base | |
MSR VBAR_EL3, X1 | |
DSB SY | |
ISB SY | |
/* Start the first task. */ | |
portRESTORE_CONTEXT | |
/****************************************************************************** | |
* FreeRTOS_IRQ_Handler handles IRQ entry and exit. | |
*****************************************************************************/ | |
.align 8 | |
.type FreeRTOS_IRQ_Handler, %function | |
FreeRTOS_IRQ_Handler: | |
/* Save volatile registers. */ | |
STP X0, X1, [SP, #-0x10]! | |
STP X2, X3, [SP, #-0x10]! | |
STP X4, X5, [SP, #-0x10]! | |
STP X6, X7, [SP, #-0x10]! | |
STP X8, X9, [SP, #-0x10]! | |
STP X10, X11, [SP, #-0x10]! | |
STP X12, X13, [SP, #-0x10]! | |
STP X14, X15, [SP, #-0x10]! | |
STP X16, X17, [SP, #-0x10]! | |
STP X18, X19, [SP, #-0x10]! | |
STP X29, X30, [SP, #-0x10]! | |
/* Save the SPSR and ELR. */ | |
MRS X3, SPSR_EL3 | |
MRS X2, ELR_EL3 | |
STP X2, X3, [SP, #-0x10]! | |
/* Increment the interrupt nesting counter. */ | |
LDR X5, ullPortInterruptNestingConst | |
LDR X1, [X5] /* Old nesting count in X1. */ | |
ADD X6, X1, #1 | |
STR X6, [X5] /* Address of nesting count variable in X5. */ | |
/* Maintain the interrupt nesting information across the function call. */ | |
STP X1, X5, [SP, #-0x10]! | |
/* Read value from the interrupt acknowledge register, which is stored in W0 | |
for future parameter and interrupt clearing use. */ | |
LDR X2, ullICCIARConst | |
LDR X3, [X2] | |
LDR W0, [X3] /* ICCIAR in W0 as parameter. */ | |
/* Maintain the ICCIAR value across the function call. */ | |
STP X0, X1, [SP, #-0x10]! | |
/* Call the C handler. */ | |
BL vApplicationIRQHandler | |
/* Disable interrupts. */ | |
MSR DAIFSET, #2 | |
DSB SY | |
ISB SY | |
/* Restore the ICCIAR value. */ | |
LDP X0, X1, [SP], #0x10 | |
/* End IRQ processing by writing ICCIAR to the EOI register. */ | |
LDR X4, ullICCEOIRConst | |
LDR X4, [X4] | |
STR W0, [X4] | |
/* Restore the critical nesting count. */ | |
LDP X1, X5, [SP], #0x10 | |
STR X1, [X5] | |
/* Has interrupt nesting unwound? */ | |
CMP X1, #0 | |
B.NE Exit_IRQ_No_Context_Switch | |
/* Is a context switch required? */ | |
LDR X0, ullPortYieldRequiredConst | |
LDR X1, [X0] | |
CMP X1, #0 | |
B.EQ Exit_IRQ_No_Context_Switch | |
/* Reset ullPortYieldRequired to 0. */ | |
MOV X2, #0 | |
STR X2, [X0] | |
/* Restore volatile registers. */ | |
LDP X4, X5, [SP], #0x10 /* SPSR and ELR. */ | |
MSR SPSR_EL3, X5 /*_RB_ Assumes started in EL3. */ | |
MSR ELR_EL3, X4 | |
DSB SY | |
ISB SY | |
LDP X29, X30, [SP], #0x10 | |
LDP X18, X19, [SP], #0x10 | |
LDP X16, X17, [SP], #0x10 | |
LDP X14, X15, [SP], #0x10 | |
LDP X12, X13, [SP], #0x10 | |
LDP X10, X11, [SP], #0x10 | |
LDP X8, X9, [SP], #0x10 | |
LDP X6, X7, [SP], #0x10 | |
LDP X4, X5, [SP], #0x10 | |
LDP X2, X3, [SP], #0x10 | |
LDP X0, X1, [SP], #0x10 | |
/* Save the context of the current task and select a new task to run. */ | |
portSAVE_CONTEXT | |
BL vTaskSwitchContext | |
portRESTORE_CONTEXT | |
Exit_IRQ_No_Context_Switch: | |
/* Restore volatile registers. */ | |
LDP X4, X5, [SP], #0x10 /* SPSR and ELR. */ | |
MSR SPSR_EL3, X5 /*_RB_ Assumes started in EL3. */ | |
MSR ELR_EL3, X4 | |
DSB SY | |
ISB SY | |
LDP X29, X30, [SP], #0x10 | |
LDP X18, X19, [SP], #0x10 | |
LDP X16, X17, [SP], #0x10 | |
LDP X14, X15, [SP], #0x10 | |
LDP X12, X13, [SP], #0x10 | |
LDP X10, X11, [SP], #0x10 | |
LDP X8, X9, [SP], #0x10 | |
LDP X6, X7, [SP], #0x10 | |
LDP X4, X5, [SP], #0x10 | |
LDP X2, X3, [SP], #0x10 | |
LDP X0, X1, [SP], #0x10 | |
ERET | |
.align 8 | |
pxCurrentTCBConst: .dword pxCurrentTCB | |
ullCriticalNestingConst: .dword ullCriticalNesting | |
ullPortTaskHasFPUContextConst: .dword ullPortTaskHasFPUContext | |
ullICCPMRConst: .dword ullICCPMR | |
ullMaxAPIPriorityMaskConst: .dword ullMaxAPIPriorityMask | |
vApplicationIRQHandlerConst: .word vApplicationIRQHandler | |
ullPortInterruptNestingConst: .dword ullPortInterruptNesting | |
ullPortYieldRequiredConst: .dword ullPortYieldRequired | |
ullICCIARConst: .dword ullICCIAR | |
ullICCEOIRConst: .dword ullICCEOIR | |
.end | |