1/* 2 * FreeRTOS Kernel V10.6.2 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.file "portASM.S" 30#include "FreeRTOSConfig.h" 31#include "ISR_Support.h" 32 33 .extern pxCurrentTCB 34 .extern vTaskSwitchContext 35 .extern vPortCentralInterruptHandler 36 .extern xTaskIncrementTick 37 .extern vPortAPICErrorHandler 38 .extern pucPortTaskFPUContextBuffer 39 .extern ulPortYieldPending 40 41 .global vPortStartFirstTask 42 .global vPortCentralInterruptWrapper 43 .global vPortAPICErrorHandlerWrapper 44 .global vPortTimerHandler 45 .global vPortYieldCall 46 .global vPortAPICSpuriousHandler 47 48 .text 49 50/*-----------------------------------------------------------*/ 51 52.align 4 53.func vPortYieldCall 54vPortYieldCall: 55 /* Save general purpose registers. */ 56 pusha 57 58 .if configSUPPORT_FPU == 1 59 60 /* If the task has a buffer allocated to save the FPU context then save 61 the FPU context now. */ 62 movl pucPortTaskFPUContextBuffer, %eax 63 test %eax, %eax 64 je 1f 65 fnsave ( %eax ) 66 fwait 67 68 1: 69 70 /* Save the address of the FPU context, if any. */ 71 push pucPortTaskFPUContextBuffer 72 73 .endif /* configSUPPORT_FPU */ 74 75 /* Find the TCB. */ 76 movl pxCurrentTCB, %eax 77 78 /* Stack location is first item in the TCB. */ 79 movl %esp, (%eax) 80 81 call vTaskSwitchContext 82 83 /* Find the location of pxCurrentTCB again - a callee saved register could 84 be used in place of eax to prevent this second load, but that then relies 85 on the compiler and other asm code. */ 86 movl pxCurrentTCB, %eax 87 movl (%eax), %esp 88 89 .if configSUPPORT_FPU == 1 90 91 /* Restore address of task's FPU context buffer. */ 92 pop pucPortTaskFPUContextBuffer 93 94 /* If the task has a buffer allocated in which its FPU context is saved, 95 then restore it now. */ 96 movl pucPortTaskFPUContextBuffer, %eax 97 test %eax, %eax 98 je 1f 99 frstor ( %eax ) 100 1: 101 .endif 102 103 popa 104 iret 105 106.endfunc 107/*-----------------------------------------------------------*/ 108 109.align 4 110.func vPortStartFirstTask 111vPortStartFirstTask: 112 113 /* Find the TCB. */ 114 movl pxCurrentTCB, %eax 115 116 /* Stack location is first item in the TCB. */ 117 movl (%eax), %esp 118 119 /* Restore FPU context flag. */ 120 .if configSUPPORT_FPU == 1 121 122 pop pucPortTaskFPUContextBuffer 123 124 .endif /* configSUPPORT_FPU */ 125 126 /* Restore general purpose registers. */ 127 popa 128 iret 129.endfunc 130/*-----------------------------------------------------------*/ 131 132.align 4 133.func vPortAPICErrorHandlerWrapper 134vPortAPICErrorHandlerWrapper: 135 pusha 136 call vPortAPICErrorHandler 137 popa 138 /* EOI. */ 139 movl $0x00, (0xFEE000B0) 140 iret 141.endfunc 142/*-----------------------------------------------------------*/ 143 144.align 4 145.func vPortTimerHandler 146vPortTimerHandler: 147 148 /* Save general purpose registers. */ 149 pusha 150 151 /* Interrupts are not nested, so save the rest of the task context. */ 152 .if configSUPPORT_FPU == 1 153 154 /* If the task has a buffer allocated to save the FPU context then save the 155 FPU context now. */ 156 movl pucPortTaskFPUContextBuffer, %eax 157 test %eax, %eax 158 je 1f 159 fnsave ( %eax ) /* Save FLOP context into ucTempFPUBuffer array. */ 160 fwait 161 162 1: 163 /* Save the address of the FPU context, if any. */ 164 push pucPortTaskFPUContextBuffer 165 166 .endif /* configSUPPORT_FPU */ 167 168 /* Find the TCB. */ 169 movl pxCurrentTCB, %eax 170 171 /* Stack location is first item in the TCB. */ 172 movl %esp, (%eax) 173 174 /* Switch stacks. */ 175 movl ulTopOfSystemStack, %esp 176 movl %esp, %ebp 177 178 /* Increment nesting count. */ 179 add $1, ulInterruptNesting 180 181 call xTaskIncrementTick 182 183 sti 184 185 /* Is a switch to another task required? */ 186 test %eax, %eax 187 je _skip_context_switch 188 cli 189 call vTaskSwitchContext 190 191_skip_context_switch: 192 cli 193 194 /* Decrement the variable used to determine if a switch to a system 195 stack is necessary. */ 196 sub $1, ulInterruptNesting 197 198 /* Stack location is first item in the TCB. */ 199 movl pxCurrentTCB, %eax 200 movl (%eax), %esp 201 202 .if configSUPPORT_FPU == 1 203 204 /* Restore address of task's FPU context buffer. */ 205 pop pucPortTaskFPUContextBuffer 206 207 /* If the task has a buffer allocated in which its FPU context is saved, 208 then restore it now. */ 209 movl pucPortTaskFPUContextBuffer, %eax 210 test %eax, %eax 211 je 1f 212 frstor ( %eax ) 213 1: 214 .endif 215 216 popa 217 218 /* EOI. */ 219 movl $0x00, (0xFEE000B0) 220 iret 221 222.endfunc 223/*-----------------------------------------------------------*/ 224 225.if configUSE_COMMON_INTERRUPT_ENTRY_POINT == 1 226 227 .align 4 228 .func vPortCentralInterruptWrapper 229 vPortCentralInterruptWrapper: 230 231 portFREERTOS_INTERRUPT_ENTRY 232 233 movl $0xFEE00170, %eax /* Highest In Service Register (ISR) long word. */ 234 movl $8, %ecx /* Loop counter. */ 235 236 next_isr_long_word: 237 test %ecx, %ecx /* Loop counter reached 0? */ 238 je wrapper_epilogue /* Looked at all ISR registers without finding a bit set. */ 239 sub $1, %ecx /* Sub 1 from loop counter. */ 240 movl (%eax), %ebx /* Load next ISR long word. */ 241 sub $0x10, %eax /* Point to next ISR long word in case no bits are set in the current long word. */ 242 test %ebx, %ebx /* Are there any bits set? */ 243 je next_isr_long_word /* Look at next ISR long word if no bits were set. */ 244 sti 245 bsr %ebx, %ebx /* A bit was set, which one? */ 246 movl $32, %eax /* Destination operand for following multiplication. */ 247 mul %ecx /* Calculate base vector for current register, 32 vectors per register. */ 248 add %ebx, %eax /* Add bit offset into register to get final vector number. */ 249 push %eax /* Vector number is function parameter. */ 250 call vPortCentralInterruptHandler 251 pop %eax /* Remove parameter. */ 252 253 wrapper_epilogue: 254 portFREERTOS_INTERRUPT_EXIT 255 256 .endfunc 257 258.endif /* configUSE_COMMON_INTERRUPT_ENTRY_POINT */ 259/*-----------------------------------------------------------*/ 260 261.align 4 262.func vPortAPISpuriousHandler 263vPortAPICSpuriousHandler: 264 iret 265 266.endfunc 267 268.end 269