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 #ifdef __LANGUAGE_ASSEMBLY__ 36 37 /******************************************************************/ 38 .macro portSAVE_CONTEXT 39 40 /* Make room for the context. First save the current status so it can be 41 manipulated, and the cause and EPC registers so their original values are 42 captured. */ 43 mfc0 k0, _CP0_CAUSE 44 addiu sp, sp, -portCONTEXT_SIZE 45 mfc0 k1, _CP0_STATUS 46 47 /* Also save s6 and s5 so they can be used. Any nesting interrupts should 48 maintain the values of these registers across the ISR. */ 49 sw s6, 44(sp) 50 sw s5, 40(sp) 51 sw k1, portSTATUS_STACK_LOCATION(sp) 52 53 /* Prepare to enable interrupts above the current priority. 54 k0 = k0 >> 10. Moves RIPL[17:10] to [7:0] */ 55 srl k0, k0, 0xa 56 57 /* Insert bit field. 7 bits k0[6:0] to k1[16:10] */ 58 ins k1, k0, 10, 7 59 60 /* Sets CP0.Status.IPL = CP0.Cause.RIPL 61 Copy the MSB of the IPL, but it would be an error if it was set anyway. */ 62 srl k0, k0, 0x7 63 64 /* MSB of IPL is bit[18] of CP0.Status */ 65 ins k1, k0, 18, 1 66 67 /* CP0.Status[5:1] = 0 b[5]=Rsvd, b[4]=UM, 68 b[3]=Rsvd, b[2]=ERL, b[1]=EXL 69 Setting EXL=0 allows higher priority interrupts 70 to preempt this handler */ 71 ins k1, zero, 1, 4 72 73 74 /* s5 is used as the frame pointer. */ 75 add s5, zero, sp 76 77 /* Check the nesting count value. */ 78 la k0, uxInterruptNesting 79 lw s6, (k0) 80 81 /* If the nesting count is 0 then swap to the the system stack, otherwise 82 the system stack is already being used. */ 83 bne s6, zero, 1f 84 nop 85 86 /* Swap to the system stack. */ 87 la sp, xISRStackTop 88 lw sp, (sp) 89 90 /* Increment and save the nesting count. */ 91 1: addiu s6, s6, 1 92 sw s6, 0(k0) 93 94 /* s6 holds the EPC value, this is saved after interrupts are re-enabled. */ 95 mfc0 s6, _CP0_EPC 96 97 /* Re-enable interrupts. */ 98 mtc0 k1, _CP0_STATUS 99 100 /* Save the context into the space just created. s6 is saved again 101 here as it now contains the EPC value. No other s registers need be 102 saved. */ 103 sw ra, 120(s5) /* Return address (RA=R31) */ 104 sw s8, 116(s5) /* Frame Pointer (FP=R30) */ 105 sw t9, 112(s5) 106 sw t8, 108(s5) 107 sw t7, 104(s5) 108 sw t6, 100(s5) 109 sw t5, 96(s5) 110 sw t4, 92(s5) 111 sw t3, 88(s5) 112 sw t2, 84(s5) 113 sw t1, 80(s5) 114 sw t0, 76(s5) 115 sw a3, 72(s5) 116 sw a2, 68(s5) 117 sw a1, 64(s5) 118 sw a0, 60(s5) 119 sw v1, 56(s5) 120 sw v0, 52(s5) 121 sw s6, portEPC_STACK_LOCATION(s5) 122 sw $1, 16(s5) 123 124 /* MEC14xx does not have DSP, removed 7 words */ 125 mfhi s6 126 sw s6, 12(s5) 127 mflo s6 128 sw s6, 8(s5) 129 130 /* Update the task stack pointer value if nesting is zero. */ 131 la s6, uxInterruptNesting 132 lw s6, (s6) 133 addiu s6, s6, -1 134 bne s6, zero, 1f 135 nop 136 137 /* Save the stack pointer. */ 138 la s6, uxSavedTaskStackPointer 139 sw s5, (s6) 140 1: 141 .endm 142 143 /******************************************************************/ 144 .macro portRESTORE_CONTEXT 145 146 /* Restore the stack pointer from the TCB. This is only done if the 147 nesting count is 1. */ 148 la s6, uxInterruptNesting 149 lw s6, (s6) 150 addiu s6, s6, -1 151 bne s6, zero, 1f 152 nop 153 la s6, uxSavedTaskStackPointer 154 lw s5, (s6) 155 156 /* Restore the context. 157 MCHP MEC14xx does not include DSP */ 158 1: 159 lw s6, 8(s5) 160 mtlo s6 161 lw s6, 12(s5) 162 mthi s6 163 lw $1, 16(s5) 164 165 /* s6 is loaded as it was used as a scratch register and therefore saved 166 as part of the interrupt context. */ 167 lw s6, 44(s5) 168 lw v0, 52(s5) 169 lw v1, 56(s5) 170 lw a0, 60(s5) 171 lw a1, 64(s5) 172 lw a2, 68(s5) 173 lw a3, 72(s5) 174 lw t0, 76(s5) 175 lw t1, 80(s5) 176 lw t2, 84(s5) 177 lw t3, 88(s5) 178 lw t4, 92(s5) 179 lw t5, 96(s5) 180 lw t6, 100(s5) 181 lw t7, 104(s5) 182 lw t8, 108(s5) 183 lw t9, 112(s5) 184 lw s8, 116(s5) 185 lw ra, 120(s5) 186 187 /* Protect access to the k registers, and others. */ 188 di 189 ehb 190 191 /* Decrement the nesting count. */ 192 la k0, uxInterruptNesting 193 lw k1, (k0) 194 addiu k1, k1, -1 195 sw k1, 0(k0) 196 197 lw k0, portSTATUS_STACK_LOCATION(s5) 198 lw k1, portEPC_STACK_LOCATION(s5) 199 200 /* Leave the stack in its original state. First load sp from s5, then 201 restore s5 from the stack. */ 202 add sp, zero, s5 203 lw s5, 40(sp) 204 addiu sp, sp, portCONTEXT_SIZE 205 206 mtc0 k0, _CP0_STATUS 207 mtc0 k1, _CP0_EPC 208 ehb 209 eret 210 nop 211 212 .endm 213 214 #endif /* #ifdef __LANGUAGE_ASSEMBLY__ */ 215