1 /* 2 * FreeRTOS Kernel V11.1.0 3 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 * 5 * SPDX-License-Identifier: MIT 6 * 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: 13 * 14 * The above copyright notice and this permission notice shall be included in all 15 * copies or substantial portions of the Software. 16 * 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. 23 * 24 * https://www.FreeRTOS.org 25 * https://github.com/FreeRTOS 26 * 27 */ 28 29 #include "FreeRTOSConfig.h" 30 31 #define portCONTEXT_SIZE 132 32 #define portEPC_STACK_LOCATION 124 33 #define portSTATUS_STACK_LOCATION 128 34 35 /******************************************************************/ 36 .macro portSAVE_CONTEXT 37 38 /* Make room for the context. First save the current status so it can be 39 manipulated, and the cause and EPC registers so their original values are 40 captured. */ 41 mfc0 k0, _CP0_CAUSE 42 addiu sp, sp, -portCONTEXT_SIZE 43 mfc0 k1, _CP0_STATUS 44 45 /* Also save s6 and s5 so they can be used. Any nesting interrupts should 46 maintain the values of these registers across the ISR. */ 47 sw s6, 44(sp) 48 sw s5, 40(sp) 49 sw k1, portSTATUS_STACK_LOCATION(sp) 50 51 /* Prepare to enable interrupts above the current priority. */ 52 srl k0, k0, 0xa 53 ins k1, k0, 10, 6 54 ins k1, zero, 1, 4 55 56 /* s5 is used as the frame pointer. */ 57 add s5, zero, sp 58 59 /* Check the nesting count value. */ 60 la k0, uxInterruptNesting 61 lw s6, (k0) 62 63 /* If the nesting count is 0 then swap to the the system stack, otherwise 64 the system stack is already being used. */ 65 bne s6, zero, 1f 66 nop 67 68 /* Swap to the system stack. */ 69 la sp, xISRStackTop 70 lw sp, (sp) 71 72 /* Increment and save the nesting count. */ 73 1: addiu s6, s6, 1 74 sw s6, 0(k0) 75 76 /* s6 holds the EPC value, this is saved after interrupts are re-enabled. */ 77 mfc0 s6, _CP0_EPC 78 79 /* Re-enable interrupts. */ 80 mtc0 k1, _CP0_STATUS 81 82 /* Save the context into the space just created. s6 is saved again 83 here as it now contains the EPC value. No other s registers need be 84 saved. */ 85 sw ra, 120(s5) 86 sw s8, 116(s5) 87 sw t9, 112(s5) 88 sw t8, 108(s5) 89 sw t7, 104(s5) 90 sw t6, 100(s5) 91 sw t5, 96(s5) 92 sw t4, 92(s5) 93 sw t3, 88(s5) 94 sw t2, 84(s5) 95 sw t1, 80(s5) 96 sw t0, 76(s5) 97 sw a3, 72(s5) 98 sw a2, 68(s5) 99 sw a1, 64(s5) 100 sw a0, 60(s5) 101 sw v1, 56(s5) 102 sw v0, 52(s5) 103 sw s6, portEPC_STACK_LOCATION(s5) 104 sw $1, 16(s5) 105 106 /* s6 is used as a scratch register. */ 107 mfhi s6 108 sw s6, 12(s5) 109 mflo s6 110 sw s6, 8(s5) 111 112 /* Update the task stack pointer value if nesting is zero. */ 113 la s6, uxInterruptNesting 114 lw s6, (s6) 115 addiu s6, s6, -1 116 bne s6, zero, 1f 117 nop 118 119 /* Save the stack pointer. */ 120 la s6, uxSavedTaskStackPointer 121 sw s5, (s6) 122 1: 123 .endm 124 125 /******************************************************************/ 126 .macro portRESTORE_CONTEXT 127 128 /* Restore the stack pointer from the TCB. This is only done if the 129 nesting count is 1. */ 130 la s6, uxInterruptNesting 131 lw s6, (s6) 132 addiu s6, s6, -1 133 bne s6, zero, 1f 134 nop 135 la s6, uxSavedTaskStackPointer 136 lw s5, (s6) 137 138 /* Restore the context. */ 139 1: lw s6, 8(s5) 140 mtlo s6 141 lw s6, 12(s5) 142 mthi s6 143 lw $1, 16(s5) 144 /* s6 is loaded as it was used as a scratch register and therefore saved 145 as part of the interrupt context. */ 146 lw s6, 44(s5) 147 lw v0, 52(s5) 148 lw v1, 56(s5) 149 lw a0, 60(s5) 150 lw a1, 64(s5) 151 lw a2, 68(s5) 152 lw a3, 72(s5) 153 lw t0, 76(s5) 154 lw t1, 80(s5) 155 lw t2, 84(s5) 156 lw t3, 88(s5) 157 lw t4, 92(s5) 158 lw t5, 96(s5) 159 lw t6, 100(s5) 160 lw t7, 104(s5) 161 lw t8, 108(s5) 162 lw t9, 112(s5) 163 lw s8, 116(s5) 164 lw ra, 120(s5) 165 166 /* Protect access to the k registers, and others. */ 167 di 168 ehb 169 170 /* Decrement the nesting count. */ 171 la k0, uxInterruptNesting 172 lw k1, (k0) 173 addiu k1, k1, -1 174 sw k1, 0(k0) 175 176 lw k0, portSTATUS_STACK_LOCATION(s5) 177 lw k1, portEPC_STACK_LOCATION(s5) 178 179 /* Leave the stack in its original state. First load sp from s5, then 180 restore s5 from the stack. */ 181 add sp, zero, s5 182 lw s5, 40(sp) 183 addiu sp, sp, portCONTEXT_SIZE 184 185 mtc0 k0, _CP0_STATUS 186 mtc0 k1, _CP0_EPC 187 ehb 188 eret 189 nop 190 191 .endm 192