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/* Including FreeRTOSConfig.h here will cause build errors if the header file 30contains code not understood by the assembler - for example the 'extern' keyword. 31To avoid errors place any such code inside a #ifdef __ICCARM__/#endif block so 32the code is included in C files but excluded by the preprocessor in assembly 33files (__ICCARM__ is defined by the IAR C compiler but not by the IAR assembler. */ 34#include <FreeRTOSConfig.h> 35#include <mpu_syscall_numbers.h> 36 37 RSEG CODE:CODE(2) 38 thumb 39 40 EXTERN pxCurrentTCB 41 EXTERN vTaskSwitchContext 42 EXTERN vPortSVCHandler_C 43 EXTERN vSystemCallEnter 44 EXTERN vSystemCallExit 45 46 PUBLIC xPortPendSVHandler 47 PUBLIC vPortSVCHandler 48 PUBLIC vPortStartFirstTask 49 PUBLIC vPortEnableVFP 50 PUBLIC vPortRestoreContextOfFirstTask 51 PUBLIC xIsPrivileged 52 PUBLIC vResetPrivilege 53 54/*-----------------------------------------------------------*/ 55 56#ifndef configUSE_MPU_WRAPPERS_V1 57 #define configUSE_MPU_WRAPPERS_V1 0 58#endif 59 60/* These must be in sync with portmacro.h. */ 61#define portSVC_START_SCHEDULER 100 62#define portSVC_SYSTEM_CALL_EXIT 103 63/*-----------------------------------------------------------*/ 64 65xPortPendSVHandler: 66 67 ldr r3, =pxCurrentTCB 68 ldr r2, [r3] /* r2 = pxCurrentTCB. */ 69 ldr r1, [r2] /* r1 = Location where the context should be saved. */ 70 71 /*------------ Save Context. ----------- */ 72 mrs r3, control 73 mrs r0, psp 74 isb 75 76 add r0, r0, #0x20 /* Move r0 to location where s0 is saved. */ 77 tst lr, #0x10 78 ittt eq 79 vstmiaeq r1!, {s16-s31} /* Store s16-s31. */ 80 vldmiaeq r0, {s0-s16} /* Copy hardware saved FP context into s0-s16. */ 81 vstmiaeq r1!, {s0-s16} /* Store hardware saved FP context. */ 82 sub r0, r0, #0x20 /* Set r0 back to the location of hardware saved context. */ 83 84 stmia r1!, {r3-r11, lr} /* Store CONTROL register, r4-r11 and LR. */ 85 ldmia r0, {r4-r11} /* Copy hardware saved context into r4-r11. */ 86 stmia r1!, {r0, r4-r11} /* Store original PSP (after hardware has saved context) and the hardware saved context. */ 87 str r1, [r2] /* Save the location from where the context should be restored as the first member of TCB. */ 88 89 /*---------- Select next task. --------- */ 90 mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY 91#if ( configENABLE_ERRATA_837070_WORKAROUND == 1 ) 92 cpsid i /* ARM Cortex-M7 r0p1 Errata 837070 workaround. */ 93#endif 94 msr basepri, r0 95 dsb 96 isb 97#if ( configENABLE_ERRATA_837070_WORKAROUND == 1 ) 98 cpsie i /* ARM Cortex-M7 r0p1 Errata 837070 workaround. */ 99#endif 100 bl vTaskSwitchContext 101 mov r0, #0 102 msr basepri, r0 103 104 /*------------ Program MPU. ------------ */ 105 ldr r3, =pxCurrentTCB 106 ldr r2, [r3] /* r2 = pxCurrentTCB. */ 107 add r2, r2, #4 /* r2 = Second item in the TCB which is xMPUSettings. */ 108 109 dmb /* Complete outstanding transfers before disabling MPU. */ 110 ldr r0, =0xe000ed94 /* MPU_CTRL register. */ 111 ldr r3, [r0] /* Read the value of MPU_CTRL. */ 112 bic r3, #1 /* r3 = r3 & ~1 i.e. Clear the bit 0 in r3. */ 113 str r3, [r0] /* Disable MPU. */ 114 115 ldr r0, =0xe000ed9c /* Region Base Address register. */ 116 ldmia r2!, {r4-r11} /* Read 4 sets of MPU registers [MPU Region # 4 - 7]. */ 117 stmia r0, {r4-r11} /* Write 4 sets of MPU registers [MPU Region # 4 - 7]. */ 118 119#ifdef configTOTAL_MPU_REGIONS 120 #if ( configTOTAL_MPU_REGIONS == 16 ) 121 ldmia r2!, {r4-r11} /* Read 4 sets of MPU registers [MPU Region # 8 - 11]. */ 122 stmia r0, {r4-r11} /* Write 4 sets of MPU registers. [MPU Region # 8 - 11]. */ 123 ldmia r2!, {r4-r11} /* Read 4 sets of MPU registers [MPU Region # 12 - 15]. */ 124 stmia r0, {r4-r11} /* Write 4 sets of MPU registers. [MPU Region # 12 - 15]. */ 125 #endif /* configTOTAL_MPU_REGIONS == 16. */ 126#endif 127 128 ldr r0, =0xe000ed94 /* MPU_CTRL register. */ 129 ldr r3, [r0] /* Read the value of MPU_CTRL. */ 130 orr r3, #1 /* r3 = r3 | 1 i.e. Set the bit 0 in r3. */ 131 str r3, [r0] /* Enable MPU. */ 132 dsb /* Force memory writes before continuing. */ 133 134 /*---------- Restore Context. ---------- */ 135 ldr r3, =pxCurrentTCB 136 ldr r2, [r3] /* r2 = pxCurrentTCB. */ 137 ldr r1, [r2] /* r1 = Location of saved context in TCB. */ 138 139 ldmdb r1!, {r0, r4-r11} /* r0 contains PSP after the hardware had saved context. r4-r11 contain hardware saved context. */ 140 msr psp, r0 141 stmia r0!, {r4-r11} /* Copy the hardware saved context on the task stack. */ 142 ldmdb r1!, {r3-r11, lr} /* r3 contains CONTROL register. r4-r11 and LR restored. */ 143 msr control, r3 144 145 tst lr, #0x10 146 ittt eq 147 vldmdbeq r1!, {s0-s16} /* s0-s16 contain hardware saved FP context. */ 148 vstmiaeq r0!, {s0-s16} /* Copy hardware saved FP context on the task stack. */ 149 vldmdbeq r1!, {s16-s31} /* Restore s16-s31. */ 150 151 str r1, [r2] /* Save the location where the context should be saved next as the first member of TCB. */ 152 bx lr 153 154/*-----------------------------------------------------------*/ 155 156#if ( configUSE_MPU_WRAPPERS_V1 == 0 ) 157 158vPortSVCHandler: 159 tst lr, #4 160 ite eq 161 mrseq r0, msp 162 mrsne r0, psp 163 164 ldr r1, [r0, #24] 165 ldrb r2, [r1, #-2] 166 cmp r2, #NUM_SYSTEM_CALLS 167 blt syscall_enter 168 cmp r2, #portSVC_SYSTEM_CALL_EXIT 169 beq syscall_exit 170 b vPortSVCHandler_C 171 172 syscall_enter: 173 mov r1, lr 174 b vSystemCallEnter 175 176 syscall_exit: 177 mov r1, lr 178 b vSystemCallExit 179 180#else /* #if ( configUSE_MPU_WRAPPERS_V1 == 0 ) */ 181 182vPortSVCHandler: 183 #ifndef USE_PROCESS_STACK 184 tst lr, #4 185 ite eq 186 mrseq r0, msp 187 mrsne r0, psp 188 #else 189 mrs r0, psp 190 #endif 191 b vPortSVCHandler_C 192 193#endif /* #if ( configUSE_MPU_WRAPPERS_V1 == 0 ) */ 194/*-----------------------------------------------------------*/ 195 196vPortStartFirstTask: 197 /* Use the NVIC offset register to locate the stack. */ 198 ldr r0, =0xE000ED08 199 ldr r0, [r0] 200 ldr r0, [r0] 201 /* Set the msp back to the start of the stack. */ 202 msr msp, r0 203 /* Clear the bit that indicates the FPU is in use in case the FPU was used 204 before the scheduler was started - which would otherwise result in the 205 unnecessary leaving of space in the SVC stack for lazy saving of FPU 206 registers. */ 207 mov r0, #0 208 msr control, r0 209 /* Call SVC to start the first task. */ 210 cpsie i 211 cpsie f 212 dsb 213 isb 214 svc #portSVC_START_SCHEDULER 215 216/*-----------------------------------------------------------*/ 217 218vPortRestoreContextOfFirstTask: 219 ldr r0, =0xE000ED08 /* Use the NVIC offset register to locate the stack. */ 220 ldr r0, [r0] 221 ldr r0, [r0] 222 msr msp, r0 /* Set the msp back to the start of the stack. */ 223 224 /*------------ Program MPU. ------------ */ 225 ldr r3, =pxCurrentTCB 226 ldr r2, [r3] /* r2 = pxCurrentTCB. */ 227 add r2, r2, #4 /* r2 = Second item in the TCB which is xMPUSettings. */ 228 229 dmb /* Complete outstanding transfers before disabling MPU. */ 230 ldr r0, =0xe000ed94 /* MPU_CTRL register. */ 231 ldr r3, [r0] /* Read the value of MPU_CTRL. */ 232 bic r3, #1 /* r3 = r3 & ~1 i.e. Clear the bit 0 in r3. */ 233 str r3, [r0] /* Disable MPU. */ 234 235 ldr r0, =0xe000ed9c /* Region Base Address register. */ 236 ldmia r2!, {r4-r11} /* Read 4 sets of MPU registers [MPU Region # 4 - 7]. */ 237 stmia r0, {r4-r11} /* Write 4 sets of MPU registers [MPU Region # 4 - 7]. */ 238 239#ifdef configTOTAL_MPU_REGIONS 240 #if ( configTOTAL_MPU_REGIONS == 16 ) 241 ldmia r2!, {r4-r11} /* Read 4 sets of MPU registers [MPU Region # 8 - 11]. */ 242 stmia r0, {r4-r11} /* Write 4 sets of MPU registers. [MPU Region # 8 - 11]. */ 243 ldmia r2!, {r4-r11} /* Read 4 sets of MPU registers [MPU Region # 12 - 15]. */ 244 stmia r0, {r4-r11} /* Write 4 sets of MPU registers. [MPU Region # 12 - 15]. */ 245 #endif /* configTOTAL_MPU_REGIONS == 16. */ 246#endif 247 248 ldr r0, =0xe000ed94 /* MPU_CTRL register. */ 249 ldr r3, [r0] /* Read the value of MPU_CTRL. */ 250 orr r3, #1 /* r3 = r3 | 1 i.e. Set the bit 0 in r3. */ 251 str r3, [r0] /* Enable MPU. */ 252 dsb /* Force memory writes before continuing. */ 253 254 /*---------- Restore Context. ---------- */ 255 ldr r3, =pxCurrentTCB 256 ldr r2, [r3] /* r2 = pxCurrentTCB. */ 257 ldr r1, [r2] /* r1 = Location of saved context in TCB. */ 258 259 ldmdb r1!, {r0, r4-r11} /* r0 contains PSP after the hardware had saved context. r4-r11 contain hardware saved context. */ 260 msr psp, r0 261 stmia r0, {r4-r11} /* Copy the hardware saved context on the task stack. */ 262 ldmdb r1!, {r3-r11, lr} /* r3 contains CONTROL register. r4-r11 and LR restored. */ 263 msr control, r3 264 str r1, [r2] /* Save the location where the context should be saved next as the first member of TCB. */ 265 266 mov r0, #0 267 msr basepri, r0 268 bx lr 269 270/*-----------------------------------------------------------*/ 271 272vPortEnableVFP: 273 /* The FPU enable bits are in the CPACR. */ 274 ldr.w r0, =0xE000ED88 275 ldr r1, [r0] 276 277 /* Enable CP10 and CP11 coprocessors, then save back. */ 278 orr r1, r1, #( 0xf << 20 ) 279 str r1, [r0] 280 bx r14 281 282/*-----------------------------------------------------------*/ 283 284xIsPrivileged: 285 mrs r0, control /* r0 = CONTROL. */ 286 tst r0, #1 /* Perform r0 & 1 (bitwise AND) and update the conditions flag. */ 287 ite ne 288 movne r0, #0 /* CONTROL[0]!=0. Return false to indicate that the processor is not privileged. */ 289 moveq r0, #1 /* CONTROL[0]==0. Return true to indicate that the processor is privileged. */ 290 bx lr /* Return. */ 291/*-----------------------------------------------------------*/ 292 293vResetPrivilege: 294 mrs r0, control /* r0 = CONTROL. */ 295 orr r0, r0, #1 /* r0 = r0 | 1. */ 296 msr control, r0 /* CONTROL = r0. */ 297 bx lr /* Return to the caller. */ 298/*-----------------------------------------------------------*/ 299 300 END 301