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