2 * FreeRTOS Kernel V10.6.2
3 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
5 * SPDX-License-Identifier: MIT
7 * Permission is hereby granted, free of charge, to any person obtaining a copy of
8 * this software and associated documentation files (the "Software"), to deal in
9 * the Software without restriction, including without limitation the rights to
10 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11 * the Software, and to permit persons to whom the Software is furnished to do so,
12 * subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included in all
15 * copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 * https://www.FreeRTOS.org
25 * https://github.com/FreeRTOS
31 #include "FreeRTOSConfig.h"
32 #include "ISR_Support.h"
35 .extern vTaskSwitchContext
36 .extern vPortIncrementTick
38 .extern ulTaskHasFPUContext
40 .global vPortStartFirstTask
42 .global vPortTickInterruptHandler
43 .global vPortInitialiseFPSCR
46 /******************************************************************/
53 /***************************************************************
54 * The following is needed to locate the
55 * vPortTickInterruptHandler function into the correct vector
56 ***************************************************************/
57 #ifdef configTICK_INTERRUPT_VECTOR
58 #if (configTICK_INTERRUPT_VECTOR == _CORE_TIMER_VECTOR)
59 .equ __vector_dispatch_0, vPortTickInterruptHandler
60 .global __vector_dispatch_0
61 .section .vector_0, code, keep
62 #elif (configTICK_INTERRUPT_VECTOR == _TIMER_1_VECTOR)
63 .equ __vector_dispatch_4, vPortTickInterruptHandler
64 .global __vector_dispatch_4
65 .section .vector_4, code, keep
66 #elif (configTICK_INTERRUPT_VECTOR == _TIMER_2_VECTOR)
67 .equ __vector_dispatch_9, vPortTickInterruptHandler
68 .global __vector_dispatch_9
69 .section .vector_9, code, keep
70 #elif (configTICK_INTERRUPT_VECTOR == _TIMER_3_VECTOR)
71 .equ __vector_dispatch_14, vPortTickInterruptHandler
72 .global __vector_dispatch_14
73 .section .vector_14, code, keep
74 #elif (configTICK_INTERRUPT_VECTOR == _TIMER_4_VECTOR)
75 .equ __vector_dispatch_19, vPortTickInterruptHandler
76 .global __vector_dispatch_19
77 .section .vector_19, code, keep
78 #elif (configTICK_INTERRUPT_VECTOR == _TIMER_5_VECTOR)
79 .equ __vector_dispatch_24, vPortTickInterruptHandler
80 .global __vector_dispatch_24
81 .section .vector_24, code, keep
82 #elif (configTICK_INTERRUPT_VECTOR == _TIMER_6_VECTOR)
83 .equ __vector_dispatch_28, vPortTickInterruptHandler
84 .global __vector_dispatch_28
85 .section .vector_28, code, keep
86 #elif (configTICK_INTERRUPT_VECTOR == _TIMER_7_VECTOR)
87 .equ __vector_dispatch_32, vPortTickInterruptHandler
88 .global __vector_dispatch_32
89 .section .vector_32, code, keep
90 #elif (configTICK_INTERRUPT_VECTOR == _TIMER_8_VECTOR)
91 .equ __vector_dispatch_36, vPortTickInterruptHandler
92 .global __vector_dispatch_36
93 .section .vector_36, code, keep
94 #elif (configTICK_INTERRUPT_VECTOR == _TIMER_9_VECTOR)
95 .equ __vector_dispatch_40, vPortTickInterruptHandler
96 .global __vector_dispatch_40
97 .section .vector_40, code, keep
100 .equ __vector_dispatch_4, vPortTickInterruptHandler
101 .global __vector_dispatch_4
102 .section .vector_4, code, keep
105 .ent vPortTickInterruptHandler
107 vPortTickInterruptHandler:
111 jal vPortIncrementTick
116 .end vPortTickInterruptHandler
118 /******************************************************************/
123 .ent vPortStartFirstTask
127 /* Simply restore the context of the highest priority task that has been
131 .end vPortStartFirstTask
135 /*******************************************************************/
141 /***************************************************************
142 * The following is needed to locate the vPortYieldISR function
143 * into the correct vector
144 ***************************************************************/
145 .equ __vector_dispatch_1, vPortYieldISR
146 .global __vector_dispatch_1
147 .section .vector_1, code
152 #if ( __mips_hard_float == 1 ) && ( configUSE_TASK_FPU_SUPPORT == 1 )
153 /* Code sequence for FPU support, the context save requires advance
154 knowledge of the stack frame size and if the current task actually uses the
157 /* Make room for the context. First save the current status so it can be
158 manipulated, and the cause and EPC registers so their original values are
160 la k0, ulTaskHasFPUContext
163 addiu sp, sp, -portCONTEXT_SIZE /* always reserve space for the context. */
164 addiu sp, sp, -portFPU_CONTEXT_SIZE /* reserve additional space for the FPU context. */
168 /* Also save s6 and s5 so they can be used. Any nesting interrupts should
169 maintain the values of these registers across the ISR. */
172 sw k1, portSTATUS_STACK_LOCATION(sp)
173 sw k0, portTASK_HAS_FPU_STACK_LOCATION(sp)
175 /* Prepare to re-enabled interrupts above the kernel priority. */
176 ins k1, zero, 10, 7 /* Clear IPL bits 0:6. */
177 ins k1, zero, 18, 1 /* Clear IPL bit 7. It would be an error here if this bit were set anyway. */
178 ori k1, k1, ( configMAX_SYSCALL_INTERRUPT_PRIORITY << 10 )
179 ins k1, zero, 1, 4 /* Clear EXL, ERL and UM. */
181 /* s5 is used as the frame pointer. */
184 /* Swap to the system stack. This is not conditional on the nesting
185 count as this interrupt is always the lowest priority and therefore
186 the nesting is always 0. */
190 /* Set the nesting count. */
191 la k0, uxInterruptNesting
195 /* s6 holds the EPC value, this is saved with the rest of the context
196 after interrupts are enabled. */
199 /* Re-enable interrupts above configMAX_SYSCALL_INTERRUPT_PRIORITY. */
202 /* Save the context into the space just created. s6 is saved again
203 here as it now contains the EPC value. */
223 sw s6, portEPC_STACK_LOCATION(s5)
224 /* s5 and s6 has already been saved. */
232 /* s7 is used as a scratch register as this should always be saved across
233 nesting interrupts. */
235 /* Save the AC0, AC1, AC2 and AC3. */
259 /* Test if FPU context save is required. */
260 lw s7, portTASK_HAS_FPU_STACK_LOCATION(s5)
264 /* Save the FPU registers above the normal context. */
265 portSAVE_FPU_REGS (portCONTEXT_SIZE + 8), s5
267 /* Save the FPU status register */
269 sw s7, ( portCONTEXT_SIZE + portFPCSR_STACK_LOCATION )(s5)
272 /* Save the stack pointer to the task. */
277 /* Set the interrupt mask to the max priority that can use the API. The
278 yield handler will only be called at configKERNEL_INTERRUPT_PRIORITY which
279 is below configMAX_SYSCALL_INTERRUPT_PRIORITY - so this can only ever
280 raise the IPL value and never lower it. */
286 ori s6, s7, ( configMAX_SYSCALL_INTERRUPT_PRIORITY << 10 ) | 1
288 /* This mtc0 re-enables interrupts, but only above
289 configMAX_SYSCALL_INTERRUPT_PRIORITY. */
293 /* Clear the software interrupt in the core. */
299 /* Clear the interrupt in the interrupt controller. */
304 jal vTaskSwitchContext
307 /* Clear the interrupt mask again. The saved status value is still in s7. */
311 /* Restore the stack pointer from the TCB. */
316 /* Test if the FPU context needs restoring. */
317 lw s0, portTASK_HAS_FPU_STACK_LOCATION(s5)
321 /* Restore the FPU status register. */
322 lw s0, ( portCONTEXT_SIZE + portFPCSR_STACK_LOCATION )(s5)
325 /* Restore the FPU registers. */
326 portLOAD_FPU_REGS ( portCONTEXT_SIZE + 8 ), s5
329 /* Restore the rest of the context. */
360 /* s5 is loaded later. */
382 /* Protect access to the k registers, and others. */
386 /* Set nesting back to zero. As the lowest priority interrupt this
387 interrupt cannot have nested. */
388 la k0, uxInterruptNesting
391 /* Switch back to use the real stack pointer. */
394 /* Restore the real s5 value. */
397 /* Pop the FPU context value from the stack */
398 lw k0, portTASK_HAS_FPU_STACK_LOCATION(sp)
399 la k1, ulTaskHasFPUContext
404 /* task has FPU context so adjust the stack frame after popping the
405 status and epc values. */
406 lw k1, portSTATUS_STACK_LOCATION(sp)
407 lw k0, portEPC_STACK_LOCATION(sp)
408 addiu sp, sp, portFPU_CONTEXT_SIZE
413 /* Pop the status and epc values. */
414 lw k1, portSTATUS_STACK_LOCATION(sp)
415 lw k0, portEPC_STACK_LOCATION(sp)
418 /* Remove stack frame. */
419 addiu sp, sp, portCONTEXT_SIZE
422 /* Code sequence for no FPU support, the context save requires advance
423 knowledge of the stack frame size when no FPU is being used */
425 /* Make room for the context. First save the current status so it can be
426 manipulated, and the cause and EPC registers so thier original values are
428 addiu sp, sp, -portCONTEXT_SIZE
431 /* Also save s6 and s5 so they can be used. Any nesting interrupts should
432 maintain the values of these registers across the ISR. */
435 sw k1, portSTATUS_STACK_LOCATION(sp)
437 /* Prepare to re-enabled interrupts above the kernel priority. */
438 ins k1, zero, 10, 7 /* Clear IPL bits 0:6. */
439 ins k1, zero, 18, 1 /* Clear IPL bit 7. It would be an error here if this bit were set anyway. */
440 ori k1, k1, ( configMAX_SYSCALL_INTERRUPT_PRIORITY << 10 )
441 ins k1, zero, 1, 4 /* Clear EXL, ERL and UM. */
443 /* s5 is used as the frame pointer. */
446 /* Swap to the system stack. This is not conditional on the nesting
447 count as this interrupt is always the lowest priority and therefore
448 the nesting is always 0. */
452 /* Set the nesting count. */
453 la k0, uxInterruptNesting
457 /* s6 holds the EPC value, this is saved with the rest of the context
458 after interrupts are enabled. */
461 /* Re-enable interrupts above configMAX_SYSCALL_INTERRUPT_PRIORITY. */
464 /* Save the context into the space just created. s6 is saved again
465 here as it now contains the EPC value. */
485 sw s6, portEPC_STACK_LOCATION(s5)
486 /* s5 and s6 has already been saved. */
494 /* s7 is used as a scratch register as this should always be saved across
495 nesting interrupts. */
497 /* Save the AC0, AC1, AC2 and AC3. */
521 /* Save the stack pointer to the task. */
526 /* Set the interrupt mask to the max priority that can use the API. The
527 yield handler will only be called at configKERNEL_INTERRUPT_PRIORITY which
528 is below configMAX_SYSCALL_INTERRUPT_PRIORITY - so this can only ever
529 raise the IPL value and never lower it. */
535 ori s6, s7, ( configMAX_SYSCALL_INTERRUPT_PRIORITY << 10 ) | 1
537 /* This mtc0 re-enables interrupts, but only above
538 configMAX_SYSCALL_INTERRUPT_PRIORITY. */
542 /* Clear the software interrupt in the core. */
548 /* Clear the interrupt in the interrupt controller. */
553 jal vTaskSwitchContext
556 /* Clear the interrupt mask again. The saved status value is still in s7. */
560 /* Restore the stack pointer from the TCB. */
565 /* Restore the rest of the context. */
596 /* s5 is loaded later. */
618 /* Protect access to the k registers, and others. */
622 /* Set nesting back to zero. As the lowest priority interrupt this
623 interrupt cannot have nested. */
624 la k0, uxInterruptNesting
627 /* Switch back to use the real stack pointer. */
630 /* Restore the real s5 value. */
633 /* Pop the status and epc values. */
634 lw k1, portSTATUS_STACK_LOCATION(sp)
635 lw k0, portEPC_STACK_LOCATION(sp)
637 /* Remove stack frame. */
638 addiu sp, sp, portCONTEXT_SIZE
640 #endif /* ( __mips_hard_float == 1 ) && ( configUSE_TASK_FPU_SUPPORT == 1 ) */
642 /* Restore the status and EPC registers and return */
651 /******************************************************************/
653 #if ( __mips_hard_float == 1 ) && ( configUSE_TASK_FPU_SUPPORT == 1 )
655 .macro portFPUSetAndInc reg, dest
664 .ent vPortInitialiseFPSCR
666 vPortInitialiseFPSCR:
668 /* Initialize the floating point status register in CP1. The initial
669 value is passed in a0. */
672 /* Clear the FPU registers */
673 addiu a0, zero, 0x0000
674 portFPUSetAndInc a0, $f0
675 portFPUSetAndInc a0, $f1
676 portFPUSetAndInc a0, $f2
677 portFPUSetAndInc a0, $f3
678 portFPUSetAndInc a0, $f4
679 portFPUSetAndInc a0, $f5
680 portFPUSetAndInc a0, $f6
681 portFPUSetAndInc a0, $f7
682 portFPUSetAndInc a0, $f8
683 portFPUSetAndInc a0, $f9
684 portFPUSetAndInc a0, $f10
685 portFPUSetAndInc a0, $f11
686 portFPUSetAndInc a0, $f12
687 portFPUSetAndInc a0, $f13
688 portFPUSetAndInc a0, $f14
689 portFPUSetAndInc a0, $f15
690 portFPUSetAndInc a0, $f16
691 portFPUSetAndInc a0, $f17
692 portFPUSetAndInc a0, $f18
693 portFPUSetAndInc a0, $f19
694 portFPUSetAndInc a0, $f20
695 portFPUSetAndInc a0, $f21
696 portFPUSetAndInc a0, $f22
697 portFPUSetAndInc a0, $f23
698 portFPUSetAndInc a0, $f24
699 portFPUSetAndInc a0, $f25
700 portFPUSetAndInc a0, $f26
701 portFPUSetAndInc a0, $f27
702 portFPUSetAndInc a0, $f28
703 portFPUSetAndInc a0, $f29
704 portFPUSetAndInc a0, $f30
705 portFPUSetAndInc a0, $f31
710 .end vPortInitialiseFPSCR
712 #endif /* ( __mips_hard_float == 1 ) && ( configUSE_TASK_FPU_SUPPORT == 1 ) */
714 #if ( __mips_hard_float == 1 ) && ( configUSE_TASK_FPU_SUPPORT == 1 )
716 /**********************************************************************/
718 /* a0 = address to store registers */
723 .ent vPortFPUReadback
724 .global vPortFPUReadback
763 .end vPortFPUReadback
765 #endif /* ( __mips_hard_float == 1 ) && ( configUSE_TASK_FPU_SUPPORT == 1 ) */