1 /* 2 * FreeRTOS Kernel <DEVELOPMENT BRANCH> 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 #ifndef PORTCONTEXT_H 30 #define PORTCONTEXT_H 31 32 #ifndef configENABLE_FPU 33 #define configENABLE_FPU 0 34 #endif 35 36 #ifndef configENABLE_VPU 37 #define configENABLE_VPU 0 38 #endif 39 40 #if __riscv_xlen == 64 41 #define portWORD_SIZE 8 42 #define store_x sd 43 #define load_x ld 44 #elif __riscv_xlen == 32 45 #define store_x sw 46 #define load_x lw 47 #define portWORD_SIZE 4 48 #else 49 #error Assembler did not define __riscv_xlen 50 #endif 51 52 #include "freertos_risc_v_chip_specific_extensions.h" 53 54 /* Only the standard core registers are stored by default. Any additional 55 * registers must be saved by the portasmSAVE_ADDITIONAL_REGISTERS and 56 * portasmRESTORE_ADDITIONAL_REGISTERS macros - which can be defined in a chip 57 * specific version of freertos_risc_v_chip_specific_extensions.h. See the 58 * notes at the top of portASM.S file. */ 59 #ifdef __riscv_32e 60 #define portCONTEXT_SIZE ( 15 * portWORD_SIZE ) 61 #define portCRITICAL_NESTING_OFFSET 14 62 #else 63 #define portCONTEXT_SIZE ( 31 * portWORD_SIZE ) 64 #define portCRITICAL_NESTING_OFFSET 30 65 #endif 66 67 #if ( configENABLE_FPU == 1 ) 68 /* Bit [14:13] in the mstatus encode the status of FPU state which is one of 69 * the following values: 70 * 1. Value: 0, Meaning: Off. 71 * 2. Value: 1, Meaning: Initial. 72 * 3. Value: 2, Meaning: Clean. 73 * 4. Value: 3, Meaning: Dirty. 74 */ 75 #define MSTATUS_FS_MASK 0x6000 76 #define MSTATUS_FS_INITIAL 0x2000 77 #define MSTATUS_FS_CLEAN 0x4000 78 #define MSTATUS_FS_DIRTY 0x6000 79 #define MSTATUS_FS_OFFSET 13 80 81 #ifdef __riscv_fdiv 82 #if __riscv_flen == 32 83 #define load_f flw 84 #define store_f fsw 85 #elif __riscv_flen == 64 86 #define load_f fld 87 #define store_f fsd 88 #else 89 #error Assembler did not define __riscv_flen 90 #endif 91 92 #define portFPU_REG_SIZE ( __riscv_flen / 8 ) 93 #define portFPU_REG_COUNT 33 /* 32 Floating point registers plus one CSR. */ 94 #define portFPU_REG_OFFSET( regIndex ) ( ( 2 * portWORD_SIZE ) + ( regIndex * portFPU_REG_SIZE ) ) 95 #define portFPU_CONTEXT_SIZE ( portFPU_REG_SIZE * portFPU_REG_COUNT ) 96 #else 97 #error configENABLE_FPU must not be set to 1 if the hardware does not have FPU 98 #endif 99 #endif 100 101 #if ( configENABLE_VPU == 1 ) 102 /* Bit [10:9] in the mstatus encode the status of VPU state which is one of 103 * the following values: 104 * 1. Value: 0, Meaning: Off. 105 * 2. Value: 1, Meaning: Initial. 106 * 3. Value: 2, Meaning: Clean. 107 * 4. Value: 3, Meaning: Dirty. 108 */ 109 #define MSTATUS_VS_MASK 0x600 110 #define MSTATUS_VS_INITIAL 0x200 111 #define MSTATUS_VS_CLEAN 0x400 112 #define MSTATUS_VS_DIRTY 0x600 113 #define MSTATUS_VS_OFFSET 9 114 115 #ifndef __riscv_vector 116 #error configENABLE_VPU must not be set to 1 if the hardware does not have VPU 117 #endif 118 #endif 119 /*-----------------------------------------------------------*/ 120 121 .extern pxCurrentTCB 122 .extern xISRStackTop 123 .extern xCriticalNesting 124 .extern pxCriticalNesting 125 /*-----------------------------------------------------------*/ 126 127 .macro portcontexSAVE_FPU_CONTEXT 128 addi sp, sp, -( portFPU_CONTEXT_SIZE ) 129 /* Store the FPU registers. */ 130 store_f f0, portFPU_REG_OFFSET( 0 )( sp ) 131 store_f f1, portFPU_REG_OFFSET( 1 )( sp ) 132 store_f f2, portFPU_REG_OFFSET( 2 )( sp ) 133 store_f f3, portFPU_REG_OFFSET( 3 )( sp ) 134 store_f f4, portFPU_REG_OFFSET( 4 )( sp ) 135 store_f f5, portFPU_REG_OFFSET( 5 )( sp ) 136 store_f f6, portFPU_REG_OFFSET( 6 )( sp ) 137 store_f f7, portFPU_REG_OFFSET( 7 )( sp ) 138 store_f f8, portFPU_REG_OFFSET( 8 )( sp ) 139 store_f f9, portFPU_REG_OFFSET( 9 )( sp ) 140 store_f f10, portFPU_REG_OFFSET( 10 )( sp ) 141 store_f f11, portFPU_REG_OFFSET( 11 )( sp ) 142 store_f f12, portFPU_REG_OFFSET( 12 )( sp ) 143 store_f f13, portFPU_REG_OFFSET( 13 )( sp ) 144 store_f f14, portFPU_REG_OFFSET( 14 )( sp ) 145 store_f f15, portFPU_REG_OFFSET( 15 )( sp ) 146 store_f f16, portFPU_REG_OFFSET( 16 )( sp ) 147 store_f f17, portFPU_REG_OFFSET( 17 )( sp ) 148 store_f f18, portFPU_REG_OFFSET( 18 )( sp ) 149 store_f f19, portFPU_REG_OFFSET( 19 )( sp ) 150 store_f f20, portFPU_REG_OFFSET( 20 )( sp ) 151 store_f f21, portFPU_REG_OFFSET( 21 )( sp ) 152 store_f f22, portFPU_REG_OFFSET( 22 )( sp ) 153 store_f f23, portFPU_REG_OFFSET( 23 )( sp ) 154 store_f f24, portFPU_REG_OFFSET( 24 )( sp ) 155 store_f f25, portFPU_REG_OFFSET( 25 )( sp ) 156 store_f f26, portFPU_REG_OFFSET( 26 )( sp ) 157 store_f f27, portFPU_REG_OFFSET( 27 )( sp ) 158 store_f f28, portFPU_REG_OFFSET( 28 )( sp ) 159 store_f f29, portFPU_REG_OFFSET( 29 )( sp ) 160 store_f f30, portFPU_REG_OFFSET( 30 )( sp ) 161 store_f f31, portFPU_REG_OFFSET( 31 )( sp ) 162 csrr t0, fcsr 163 store_x t0, portFPU_REG_OFFSET( 32 )( sp ) 164 .endm 165 /*-----------------------------------------------------------*/ 166 167 .macro portcontextRESTORE_FPU_CONTEXT 168 /* Restore the FPU registers. */ 169 load_f f0, portFPU_REG_OFFSET( 0 )( sp ) 170 load_f f1, portFPU_REG_OFFSET( 1 )( sp ) 171 load_f f2, portFPU_REG_OFFSET( 2 )( sp ) 172 load_f f3, portFPU_REG_OFFSET( 3 )( sp ) 173 load_f f4, portFPU_REG_OFFSET( 4 )( sp ) 174 load_f f5, portFPU_REG_OFFSET( 5 )( sp ) 175 load_f f6, portFPU_REG_OFFSET( 6 )( sp ) 176 load_f f7, portFPU_REG_OFFSET( 7 )( sp ) 177 load_f f8, portFPU_REG_OFFSET( 8 )( sp ) 178 load_f f9, portFPU_REG_OFFSET( 9 )( sp ) 179 load_f f10, portFPU_REG_OFFSET( 10 )( sp ) 180 load_f f11, portFPU_REG_OFFSET( 11 )( sp ) 181 load_f f12, portFPU_REG_OFFSET( 12 )( sp ) 182 load_f f13, portFPU_REG_OFFSET( 13 )( sp ) 183 load_f f14, portFPU_REG_OFFSET( 14 )( sp ) 184 load_f f15, portFPU_REG_OFFSET( 15 )( sp ) 185 load_f f16, portFPU_REG_OFFSET( 16 )( sp ) 186 load_f f17, portFPU_REG_OFFSET( 17 )( sp ) 187 load_f f18, portFPU_REG_OFFSET( 18 )( sp ) 188 load_f f19, portFPU_REG_OFFSET( 19 )( sp ) 189 load_f f20, portFPU_REG_OFFSET( 20 )( sp ) 190 load_f f21, portFPU_REG_OFFSET( 21 )( sp ) 191 load_f f22, portFPU_REG_OFFSET( 22 )( sp ) 192 load_f f23, portFPU_REG_OFFSET( 23 )( sp ) 193 load_f f24, portFPU_REG_OFFSET( 24 )( sp ) 194 load_f f25, portFPU_REG_OFFSET( 25 )( sp ) 195 load_f f26, portFPU_REG_OFFSET( 26 )( sp ) 196 load_f f27, portFPU_REG_OFFSET( 27 )( sp ) 197 load_f f28, portFPU_REG_OFFSET( 28 )( sp ) 198 load_f f29, portFPU_REG_OFFSET( 29 )( sp ) 199 load_f f30, portFPU_REG_OFFSET( 30 )( sp ) 200 load_f f31, portFPU_REG_OFFSET( 31 )( sp ) 201 load_x t0, portFPU_REG_OFFSET( 32 )( sp ) 202 csrw fcsr, t0 203 addi sp, sp, ( portFPU_CONTEXT_SIZE ) 204 .endm 205 /*-----------------------------------------------------------*/ 206 207 .macro portcontexSAVE_VPU_CONTEXT 208 /* Un-reserve the space reserved for mstatus and epc. */ 209 add sp, sp, ( 2 * portWORD_SIZE ) 210 211 csrr t0, vlenb /* t0 = vlenb. vlenb is the length of each vector register in bytes. */ 212 slli t0, t0, 3 /* t0 = vlenb * 8. t0 now contains the space required to store 8 vector registers. */ 213 neg t0, t0 214 215 /* Store the vector registers in group of 8. */ 216 add sp, sp, t0 217 vs8r.v v0, (sp) /* Store v0-v7. */ 218 add sp, sp, t0 219 vs8r.v v8, (sp) /* Store v8-v15. */ 220 add sp, sp, t0 221 vs8r.v v16, (sp) /* Store v16-v23. */ 222 add sp, sp, t0 223 vs8r.v v24, (sp) /* Store v24-v31. */ 224 225 /* Store the VPU CSRs. */ 226 addi sp, sp, -( 4 * portWORD_SIZE ) 227 csrr t0, vstart 228 store_x t0, 0 * portWORD_SIZE( sp ) 229 csrr t0, vcsr 230 store_x t0, 1 * portWORD_SIZE( sp ) 231 csrr t0, vl 232 store_x t0, 2 * portWORD_SIZE( sp ) 233 csrr t0, vtype 234 store_x t0, 3 * portWORD_SIZE( sp ) 235 236 /* Re-reserve the space for mstatus and epc. */ 237 add sp, sp, -( 2 * portWORD_SIZE ) 238 .endm 239 /*-----------------------------------------------------------*/ 240 241 .macro portcontextRESTORE_VPU_CONTEXT 242 /* Un-reserve the space reserved for mstatus and epc. */ 243 add sp, sp, ( 2 * portWORD_SIZE ) 244 245 /* Restore the VPU CSRs. */ 246 load_x t0, 0 * portWORD_SIZE( sp ) 247 csrw vstart, t0 248 load_x t0, 1 * portWORD_SIZE( sp ) 249 csrw vcsr, t0 250 load_x t0, 2 * portWORD_SIZE( sp ) 251 load_x t1, 3 * portWORD_SIZE( sp ) 252 vsetvl x0, t0, t1 /* vlen and vtype can only be updated by using vset*vl* instructions. */ 253 addi sp, sp, ( 4 * portWORD_SIZE ) 254 255 csrr t0, vlenb /* t0 = vlenb. vlenb is the length of each vector register in bytes. */ 256 slli t0, t0, 3 /* t0 = vlenb * 8. t0 now contains the space required to store 8 vector registers. */ 257 258 /* Restore the vector registers. */ 259 vl8r.v v24, (sp) 260 add sp, sp, t0 261 vl8r.v v16, (sp) 262 add sp, sp, t0 263 vl8r.v v8, (sp) 264 add sp, sp, t0 265 vl8r.v v0, (sp) 266 add sp, sp, t0 267 268 /* Re-reserve the space for mstatus and epc. */ 269 add sp, sp, -( 2 * portWORD_SIZE ) 270 .endm 271 /*-----------------------------------------------------------*/ 272 273 .macro portcontextSAVE_CONTEXT_INTERNAL 274 addi sp, sp, -portCONTEXT_SIZE 275 store_x x1, 2 * portWORD_SIZE( sp ) 276 store_x x5, 3 * portWORD_SIZE( sp ) 277 store_x x6, 4 * portWORD_SIZE( sp ) 278 store_x x7, 5 * portWORD_SIZE( sp ) 279 store_x x8, 6 * portWORD_SIZE( sp ) 280 store_x x9, 7 * portWORD_SIZE( sp ) 281 store_x x10, 8 * portWORD_SIZE( sp ) 282 store_x x11, 9 * portWORD_SIZE( sp ) 283 store_x x12, 10 * portWORD_SIZE( sp ) 284 store_x x13, 11 * portWORD_SIZE( sp ) 285 store_x x14, 12 * portWORD_SIZE( sp ) 286 store_x x15, 13 * portWORD_SIZE( sp ) 287 #ifndef __riscv_32e 288 store_x x16, 14 * portWORD_SIZE( sp ) 289 store_x x17, 15 * portWORD_SIZE( sp ) 290 store_x x18, 16 * portWORD_SIZE( sp ) 291 store_x x19, 17 * portWORD_SIZE( sp ) 292 store_x x20, 18 * portWORD_SIZE( sp ) 293 store_x x21, 19 * portWORD_SIZE( sp ) 294 store_x x22, 20 * portWORD_SIZE( sp ) 295 store_x x23, 21 * portWORD_SIZE( sp ) 296 store_x x24, 22 * portWORD_SIZE( sp ) 297 store_x x25, 23 * portWORD_SIZE( sp ) 298 store_x x26, 24 * portWORD_SIZE( sp ) 299 store_x x27, 25 * portWORD_SIZE( sp ) 300 store_x x28, 26 * portWORD_SIZE( sp ) 301 store_x x29, 27 * portWORD_SIZE( sp ) 302 store_x x30, 28 * portWORD_SIZE( sp ) 303 store_x x31, 29 * portWORD_SIZE( sp ) 304 #endif /* ifndef __riscv_32e */ 305 306 load_x t0, xCriticalNesting /* Load the value of xCriticalNesting into t0. */ 307 store_x t0, portCRITICAL_NESTING_OFFSET * portWORD_SIZE( sp ) /* Store the critical nesting value to the stack. */ 308 309 #if( configENABLE_FPU == 1 ) 310 csrr t0, mstatus 311 srl t1, t0, MSTATUS_FS_OFFSET 312 andi t1, t1, 3 313 addi t2, x0, 3 314 bne t1, t2, 1f /* If FPU status is not dirty, do not save FPU registers. */ 315 316 portcontexSAVE_FPU_CONTEXT 317 1: 318 #endif 319 320 #if( configENABLE_VPU == 1 ) 321 csrr t0, mstatus 322 srl t1, t0, MSTATUS_VS_OFFSET 323 andi t1, t1, 3 324 addi t2, x0, 3 325 bne t1, t2, 2f /* If VPU status is not dirty, do not save FPU registers. */ 326 327 portcontexSAVE_VPU_CONTEXT 328 2: 329 #endif 330 331 portasmSAVE_ADDITIONAL_REGISTERS /* Defined in freertos_risc_v_chip_specific_extensions.h to save any registers unique to the RISC-V implementation. */ 332 333 csrr t0, mstatus 334 store_x t0, 1 * portWORD_SIZE( sp ) 335 336 #if( configENABLE_FPU == 1 ) 337 /* Mark the FPU as clean, if it was dirty and we saved FPU registers. */ 338 srl t1, t0, MSTATUS_FS_OFFSET 339 andi t1, t1, 3 340 addi t2, x0, 3 341 bne t1, t2, 3f 342 343 li t1, ~MSTATUS_FS_MASK 344 and t0, t0, t1 345 li t1, MSTATUS_FS_CLEAN 346 or t0, t0, t1 347 csrw mstatus, t0 348 3: 349 #endif 350 351 #if( configENABLE_VPU == 1 ) 352 /* Mark the VPU as clean, if it was dirty and we saved VPU registers. */ 353 srl t1, t0, MSTATUS_VS_OFFSET 354 andi t1, t1, 3 355 addi t2, x0, 3 356 bne t1, t2, 4f 357 358 li t1, ~MSTATUS_VS_MASK 359 and t0, t0, t1 360 li t1, MSTATUS_VS_CLEAN 361 or t0, t0, t1 362 csrw mstatus, t0 363 4: 364 #endif 365 366 load_x t0, pxCurrentTCB /* Load pxCurrentTCB. */ 367 store_x sp, 0 ( t0 ) /* Write sp to first TCB member. */ 368 369 .endm 370 /*-----------------------------------------------------------*/ 371 372 .macro portcontextSAVE_EXCEPTION_CONTEXT 373 portcontextSAVE_CONTEXT_INTERNAL 374 csrr a0, mcause 375 csrr a1, mepc 376 addi a1, a1, 4 /* Synchronous so update exception return address to the instruction after the instruction that generated the exception. */ 377 store_x a1, 0 ( sp ) /* Save updated exception return address. */ 378 load_x sp, xISRStackTop /* Switch to ISR stack. */ 379 .endm 380 /*-----------------------------------------------------------*/ 381 382 .macro portcontextSAVE_INTERRUPT_CONTEXT 383 portcontextSAVE_CONTEXT_INTERNAL 384 csrr a0, mcause 385 csrr a1, mepc 386 store_x a1, 0 ( sp ) /* Asynchronous interrupt so save unmodified exception return address. */ 387 load_x sp, xISRStackTop /* Switch to ISR stack. */ 388 .endm 389 /*-----------------------------------------------------------*/ 390 391 .macro portcontextRESTORE_CONTEXT 392 load_x t1, pxCurrentTCB /* Load pxCurrentTCB. */ 393 load_x sp, 0 ( t1 ) /* Read sp from first TCB member. */ 394 395 /* Load mepc with the address of the instruction in the task to run next. */ 396 load_x t0, 0 ( sp ) 397 csrw mepc, t0 398 399 /* Restore mstatus register. */ 400 load_x t0, 1 * portWORD_SIZE( sp ) 401 csrw mstatus, t0 402 403 /* Defined in freertos_risc_v_chip_specific_extensions.h to restore any registers unique to the RISC-V implementation. */ 404 portasmRESTORE_ADDITIONAL_REGISTERS 405 406 #if( configENABLE_VPU == 1 ) 407 csrr t0, mstatus 408 srl t1, t0, MSTATUS_VS_OFFSET 409 andi t1, t1, 3 410 addi t2, x0, 3 411 bne t1, t2, 5f /* If VPU status is not dirty, do not restore VPU registers. */ 412 413 portcontextRESTORE_VPU_CONTEXT 414 5: 415 #endif /* ifdef portasmSTORE_VPU_CONTEXT */ 416 417 #if( configENABLE_FPU == 1 ) 418 csrr t0, mstatus 419 srl t1, t0, MSTATUS_FS_OFFSET 420 andi t1, t1, 3 421 addi t2, x0, 3 422 bne t1, t2, 6f /* If FPU status is not dirty, do not restore FPU registers. */ 423 424 portcontextRESTORE_FPU_CONTEXT 425 6: 426 #endif /* ifdef portasmSTORE_FPU_CONTEXT */ 427 428 load_x t0, portCRITICAL_NESTING_OFFSET * portWORD_SIZE( sp ) /* Obtain xCriticalNesting value for this task from task's stack. */ 429 load_x t1, pxCriticalNesting /* Load the address of xCriticalNesting into t1. */ 430 store_x t0, 0 ( t1 ) /* Restore the critical nesting value for this task. */ 431 432 load_x x1, 2 * portWORD_SIZE( sp ) 433 load_x x5, 3 * portWORD_SIZE( sp ) 434 load_x x6, 4 * portWORD_SIZE( sp ) 435 load_x x7, 5 * portWORD_SIZE( sp ) 436 load_x x8, 6 * portWORD_SIZE( sp ) 437 load_x x9, 7 * portWORD_SIZE( sp ) 438 load_x x10, 8 * portWORD_SIZE( sp ) 439 load_x x11, 9 * portWORD_SIZE( sp ) 440 load_x x12, 10 * portWORD_SIZE( sp ) 441 load_x x13, 11 * portWORD_SIZE( sp ) 442 load_x x14, 12 * portWORD_SIZE( sp ) 443 load_x x15, 13 * portWORD_SIZE( sp ) 444 #ifndef __riscv_32e 445 load_x x16, 14 * portWORD_SIZE( sp ) 446 load_x x17, 15 * portWORD_SIZE( sp ) 447 load_x x18, 16 * portWORD_SIZE( sp ) 448 load_x x19, 17 * portWORD_SIZE( sp ) 449 load_x x20, 18 * portWORD_SIZE( sp ) 450 load_x x21, 19 * portWORD_SIZE( sp ) 451 load_x x22, 20 * portWORD_SIZE( sp ) 452 load_x x23, 21 * portWORD_SIZE( sp ) 453 load_x x24, 22 * portWORD_SIZE( sp ) 454 load_x x25, 23 * portWORD_SIZE( sp ) 455 load_x x26, 24 * portWORD_SIZE( sp ) 456 load_x x27, 25 * portWORD_SIZE( sp ) 457 load_x x28, 26 * portWORD_SIZE( sp ) 458 load_x x29, 27 * portWORD_SIZE( sp ) 459 load_x x30, 28 * portWORD_SIZE( sp ) 460 load_x x31, 29 * portWORD_SIZE( sp ) 461 #endif /* ifndef __riscv_32e */ 462 addi sp, sp, portCONTEXT_SIZE 463 464 mret 465 .endm 466 /*-----------------------------------------------------------*/ 467 468 #endif /* PORTCONTEXT_H */ 469