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 <xc.h> 30#include <sys/asm.h> 31#include "ISR_Support.h" 32 33 34 .set nomips16 35 .set noreorder 36 37 .extern pxCurrentTCB 38 .extern vTaskSwitchContext 39 .extern vPortIncrementTick 40 .extern xISRStackTop 41 42 .global vPortStartFirstTask 43 .global vPortYieldISR 44 .global vPortTickInterruptHandler 45 46 47/******************************************************************/ 48 49 .set noreorder 50 .set noat 51 .ent vPortTickInterruptHandler 52 53vPortTickInterruptHandler: 54 55 portSAVE_CONTEXT 56 57 jal vPortIncrementTick 58 nop 59 60 portRESTORE_CONTEXT 61 62 .end vPortTickInterruptHandler 63 64/******************************************************************/ 65 66 .set noreorder 67 .set noat 68 .ent vPortStartFirstTask 69 70vPortStartFirstTask: 71 72 /* Simply restore the context of the highest priority task that has been 73 created so far. */ 74 portRESTORE_CONTEXT 75 76 .end vPortStartFirstTask 77 78 79 80/*******************************************************************/ 81 82 .set noreorder 83 .set noat 84 .ent vPortYieldISR 85 86vPortYieldISR: 87 88 /* Make room for the context. First save the current status so it can be 89 manipulated. */ 90 addiu sp, sp, -portCONTEXT_SIZE 91 mfc0 k1, _CP0_STATUS 92 93 /* Also save s6 and s5 so they can be used. Any nesting interrupts should 94 maintain the values of these registers across the ISR. */ 95 sw s6, 44(sp) 96 sw s5, 40(sp) 97 sw k1, portSTATUS_STACK_LOCATION(sp) 98 99 /* Prepare to re-enabled interrupt above the kernel priority. */ 100 ins k1, zero, 10, 6 101 ori k1, k1, ( configMAX_SYSCALL_INTERRUPT_PRIORITY << 10 ) 102 ins k1, zero, 1, 4 103 104 /* s5 is used as the frame pointer. */ 105 add s5, zero, sp 106 107 /* Swap to the system stack. This is not conditional on the nesting 108 count as this interrupt is always the lowest priority and therefore 109 the nesting is always 0. */ 110 la sp, xISRStackTop 111 lw sp, (sp) 112 113 /* Set the nesting count. */ 114 la k0, uxInterruptNesting 115 addiu s6, zero, 1 116 sw s6, 0(k0) 117 118 /* s6 holds the EPC value, this is saved with the rest of the context 119 after interrupts are enabled. */ 120 mfc0 s6, _CP0_EPC 121 122 /* Re-enable interrupts above configMAX_SYSCALL_INTERRUPT_PRIORITY. */ 123 mtc0 k1, _CP0_STATUS 124 125 /* Save the context into the space just created. s6 is saved again 126 here as it now contains the EPC value. */ 127 sw ra, 120(s5) 128 sw s8, 116(s5) 129 sw t9, 112(s5) 130 sw t8, 108(s5) 131 sw t7, 104(s5) 132 sw t6, 100(s5) 133 sw t5, 96(s5) 134 sw t4, 92(s5) 135 sw t3, 88(s5) 136 sw t2, 84(s5) 137 sw t1, 80(s5) 138 sw t0, 76(s5) 139 sw a3, 72(s5) 140 sw a2, 68(s5) 141 sw a1, 64(s5) 142 sw a0, 60(s5) 143 sw v1, 56(s5) 144 sw v0, 52(s5) 145 sw s7, 48(s5) 146 sw s6, portEPC_STACK_LOCATION(s5) 147 /* s5 and s6 has already been saved. */ 148 sw s4, 36(s5) 149 sw s3, 32(s5) 150 sw s2, 28(s5) 151 sw s1, 24(s5) 152 sw s0, 20(s5) 153 sw $1, 16(s5) 154 155 /* s7 is used as a scratch register as this should always be saved across 156 nesting interrupts. */ 157 mfhi s7 158 sw s7, 12(s5) 159 mflo s7 160 sw s7, 8(s5) 161 162 /* Save the stack pointer to the task. */ 163 la s7, pxCurrentTCB 164 lw s7, (s7) 165 sw s5, (s7) 166 167 /* Set the interrupt mask to the max priority that can use the API. The 168 yield handler will only be called at configKERNEL_INTERRUPT_PRIORITY which 169 is below configMAX_SYSCALL_INTERRUPT_PRIORITY - so this can only ever 170 raise the IPL value and never lower it. */ 171 di 172 ehb 173 mfc0 s7, _CP0_STATUS 174 ins s7, zero, 10, 6 175 ori s6, s7, ( configMAX_SYSCALL_INTERRUPT_PRIORITY << 10 ) | 1 176 177 /* This mtc0 re-enables interrupts, but only above 178 configMAX_SYSCALL_INTERRUPT_PRIORITY. */ 179 mtc0 s6, _CP0_STATUS 180 ehb 181 182 /* Clear the software interrupt in the core. */ 183 mfc0 s6, _CP0_CAUSE 184 ins s6, zero, 8, 1 185 mtc0 s6, _CP0_CAUSE 186 ehb 187 188 /* Clear the interrupt in the interrupt controller. */ 189 la s6, IFS0CLR 190 addiu s4, zero, 2 191 sw s4, (s6) 192 193 jal vTaskSwitchContext 194 nop 195 196 /* Clear the interrupt mask again. The saved status value is still in s7. */ 197 mtc0 s7, _CP0_STATUS 198 ehb 199 200 /* Restore the stack pointer from the TCB. */ 201 la s0, pxCurrentTCB 202 lw s0, (s0) 203 lw s5, (s0) 204 205 /* Restore the rest of the context. */ 206 lw s0, 8(s5) 207 mtlo s0 208 lw s0, 12(s5) 209 mthi s0 210 lw $1, 16(s5) 211 lw s0, 20(s5) 212 lw s1, 24(s5) 213 lw s2, 28(s5) 214 lw s3, 32(s5) 215 lw s4, 36(s5) 216 /* s5 is loaded later. */ 217 lw s6, 44(s5) 218 lw s7, 48(s5) 219 lw v0, 52(s5) 220 lw v1, 56(s5) 221 lw a0, 60(s5) 222 lw a1, 64(s5) 223 lw a2, 68(s5) 224 lw a3, 72(s5) 225 lw t0, 76(s5) 226 lw t1, 80(s5) 227 lw t2, 84(s5) 228 lw t3, 88(s5) 229 lw t4, 92(s5) 230 lw t5, 96(s5) 231 lw t6, 100(s5) 232 lw t7, 104(s5) 233 lw t8, 108(s5) 234 lw t9, 112(s5) 235 lw s8, 116(s5) 236 lw ra, 120(s5) 237 238 /* Protect access to the k registers, and others. */ 239 di 240 ehb 241 242 /* Set nesting back to zero. As the lowest priority interrupt this 243 interrupt cannot have nested. */ 244 la k0, uxInterruptNesting 245 sw zero, 0(k0) 246 247 /* Switch back to use the real stack pointer. */ 248 add sp, zero, s5 249 250 /* Restore the real s5 value. */ 251 lw s5, 40(sp) 252 253 /* Pop the status and epc values. */ 254 lw k1, portSTATUS_STACK_LOCATION(sp) 255 lw k0, portEPC_STACK_LOCATION(sp) 256 257 /* Remove stack frame. */ 258 addiu sp, sp, portCONTEXT_SIZE 259 260 mtc0 k1, _CP0_STATUS 261 mtc0 k0, _CP0_EPC 262 ehb 263 eret 264 nop 265 266 .end vPortYieldISR 267