1/* 2 * FreeRTOS Kernel V11.1.0 3 * Copyright (C) 2020 Synopsys, 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/** 30 * \file 31 * \ingroup OS_FREERTOS 32 * \brief freertos support for arc processor 33 * like task dispatcher, interrupt handler 34 */ 35/** @cond OS_FREERTOS_ASM_ARC_SUPPORT */ 36 37/* 38 * core-dependent part in assemble language (for arc) 39 */ 40#define __ASSEMBLY__ 41#include "arc/arc.h" 42#include "arc/arc_asm_common.h" 43 44/* 45 * task dispatcher 46 * 47 */ 48 .text 49 .align 4 50 .global dispatch 51dispatch: 52/* 53 * the pre-conditions of this routine are task context, CPU is 54 * locked, dispatch is enabled. 55 */ 56 SAVE_NONSCRATCH_REGS /* save callee save registers */ 57 mov r1, dispatch_r 58 PUSH r1 /* save return address */ 59 ld r0, [pxCurrentTCB] 60 bl dispatcher 61 62/* return routine when task dispatch happened in task context */ 63dispatch_r: 64 RESTORE_NONSCRATCH_REGS /* recover registers */ 65 j [blink] 66 67/* 68 * start dispatch 69 */ 70 .global start_dispatch 71 .align 4 72start_dispatch: 73/* 74 * this routine is called in the non-task context during the startup of the kernel 75 * , and all the interrupts are locked. 76 * 77 * when the dispatcher is called, the cpu is locked, no nest exception (CPU exception/interrupt). 78 * In target_initialize, all interrupt priority mask should be cleared, cpu should be 79 * locked, the interrupts outside the kernel such as fiq can be 80 * enabled. 81 */ 82 clri 83 mov r0, 0 84 st r0, [exc_nest_count] 85 b dispatcher_0 86/* 87 * dispatcher 88 */ 89dispatcher: 90 ld r1, [ulCriticalNesting] 91 PUSH r1 /* save critical nesting */ 92 st sp, [r0] /* save stack pointer of current task, r0->pxCurrentTCB */ 93 jl vTaskSwitchContext /* change the value of pxCurrentTCB */ 94/* 95 * before dispatcher is called, task context | cpu locked | dispatch enabled 96 * should be satisfied. In this routine, the processor will jump 97 * into the entry of next to run task 98 * 99 * i.e. kernel mode, IRQ disabled, dispatch enabled 100 */ 101dispatcher_0: 102 ld r1, [pxCurrentTCB] 103 ld sp, [r1] /* recover task stack */ 104#if ARC_FEATURE_STACK_CHECK 105#if ARC_FEATURE_SEC_PRESENT 106 lr r0, [AUX_SEC_STAT] 107 bclr r0, r0, AUX_SEC_STAT_BIT_SSC 108 sflag r0 109#else 110 lr r0, [AUX_STATUS32] 111 bclr r0, r0, AUX_STATUS_BIT_SC 112 kflag r0 113#endif 114 jl vPortSetStackCheck 115#if ARC_FEATURE_SEC_PRESENT 116 lr r0, [AUX_SEC_STAT] 117 bset r0, r0, AUX_SEC_STAT_BIT_SSC 118 sflag r0 119#else 120 lr r0, [AUX_STATUS32] 121 bset r0, r0, AUX_STATUS_BIT_SC 122 kflag r0 123#endif 124#endif 125 POP r0 /* get critical nesting */ 126 st r0, [ulCriticalNesting] 127 POP r0 /* get return address */ 128 j [r0] 129 130/* 131 * task startup routine 132 * 133 */ 134 .text 135 .global start_r 136 .align 4 137start_r: 138 seti /* unlock cpu */ 139 mov blink, vPortEndTask /* set return address */ 140 POP r1 /* get task function body */ 141 POP r0 /* get task parameters */ 142 j [r1] 143 144/****** exceptions and interrupts handing ******/ 145/****** entry for exception handling ******/ 146 .global exc_entry_cpu 147 .align 4 148exc_entry_cpu: 149 150 EXCEPTION_PROLOGUE 151 152 mov blink, sp 153 mov r3, sp /* as exception handler's para(p_excinfo) */ 154 155 ld r0, [exc_nest_count] 156 add r1, r0, 1 157 st r1, [exc_nest_count] 158 brne r0, 0, exc_handler_1 159/* change to exception stack if interrupt happened in task context */ 160 mov sp, _e_stack 161exc_handler_1: 162 PUSH blink 163 164 lr r0, [AUX_ECR] 165 lsr r0, r0, 16 166 mov r1, exc_int_handler_table 167 ld.as r2, [r1, r0] 168 169 mov r0, r3 170 jl [r2] /* !!!!jump to exception handler where interrupts are not allowed! */ 171 172/* interrupts are not allowed */ 173ret_exc: 174 POP sp 175 mov r1, exc_nest_count 176 ld r0, [r1] 177 sub r0, r0, 1 178 st r0, [r1] 179 brne r0, 0, ret_exc_1 /* nest exception case */ 180 lr r1, [AUX_IRQ_ACT] /* nest interrupt case */ 181 brne r1, 0, ret_exc_1 182 183 ld r0, [context_switch_reqflg] 184 brne r0, 0, ret_exc_2 185ret_exc_1: /* return from non-task context, interrupts or exceptions are nested */ 186 187 EXCEPTION_EPILOGUE 188 rtie 189 190/* there is a dispatch request */ 191ret_exc_2: 192 /* clear dispatch request */ 193 mov r0, 0 194 st r0, [context_switch_reqflg] 195 196 ld r0, [pxCurrentTCB] 197 breq r0, 0, ret_exc_1 198 199 SAVE_CALLEE_REGS /* save callee save registers */ 200 201 lr r0, [AUX_STATUS32] 202 bclr r0, r0, AUX_STATUS_BIT_AE /* clear exception bit */ 203 kflag r0 204 205 mov r1, ret_exc_r /* save return address */ 206 PUSH r1 207 208 bl dispatcher /* r0->pxCurrentTCB */ 209 210ret_exc_r: 211 /* recover exception status */ 212 lr r0, [AUX_STATUS32] 213 bset r0, r0, AUX_STATUS_BIT_AE 214 kflag r0 215 216 RESTORE_CALLEE_REGS /* recover registers */ 217 EXCEPTION_EPILOGUE 218 rtie 219 220/****** entry for normal interrupt exception handling ******/ 221 .global exc_entry_int /* entry for interrupt handling */ 222 .align 4 223exc_entry_int: 224#if ARC_FEATURE_FIRQ == 1 225#if ARC_FEATURE_RGF_NUM_BANKS > 1 226 lr r0, [AUX_IRQ_ACT] /* check whether it is P0 interrupt */ 227 btst r0, 0 228 jnz exc_entry_firq 229#else 230 PUSH r10 231 lr r10, [AUX_IRQ_ACT] 232 btst r10, 0 233 POP r10 234 jnz exc_entry_firq 235#endif 236#endif 237 INTERRUPT_PROLOGUE 238 239 mov blink, sp 240 241 clri /* disable interrupt */ 242 ld r3, [exc_nest_count] 243 add r2, r3, 1 244 st r2, [exc_nest_count] 245 seti /* enable higher priority interrupt */ 246 247 brne r3, 0, irq_handler_1 248/* change to exception stack if interrupt happened in task context */ 249 mov sp, _e_stack 250#if ARC_FEATURE_STACK_CHECK 251#if ARC_FEATURE_SEC_PRESENT 252 lr r0, [AUX_SEC_STAT] 253 bclr r0, r0, AUX_SEC_STAT_BIT_SSC 254 sflag r0 255#else 256 lr r0, [AUX_STATUS32] 257 bclr r0, r0, AUX_STATUS_BIT_SC 258 kflag r0 259#endif 260#endif 261irq_handler_1: 262 PUSH blink 263 264 lr r0, [AUX_IRQ_CAUSE] 265 mov r1, exc_int_handler_table 266 ld.as r2, [r1, r0] /* r2 = exc_int_handler_table + irqno *4 */ 267/* handle software triggered interrupt */ 268 lr r3, [AUX_IRQ_HINT] 269 cmp r3, r0 270 bne.d irq_hint_handled 271 xor r3, r3, r3 272 sr r3, [AUX_IRQ_HINT] 273irq_hint_handled: 274 275 jl [r2] /* jump to interrupt handler */ 276/* no interrupts are allowed from here */ 277ret_int: 278 clri /* disable interrupt */ 279 280 POP sp 281 mov r1, exc_nest_count 282 ld r0, [r1] 283 sub r0, r0, 1 284 st r0, [r1] 285/* if there are multi-bits set in IRQ_ACT, it's still in nest interrupt */ 286 lr r0, [AUX_IRQ_CAUSE] 287 sr r0, [AUX_IRQ_SELECT] 288 lr r3, [AUX_IRQ_PRIORITY] 289 lr r1, [AUX_IRQ_ACT] 290 bclr r2, r1, r3 291 brne r2, 0, ret_int_1 292 293 ld r0, [context_switch_reqflg] 294 brne r0, 0, ret_int_2 295ret_int_1: /* return from non-task context */ 296 INTERRUPT_EPILOGUE 297 rtie 298/* there is a dispatch request */ 299ret_int_2: 300 /* clear dispatch request */ 301 mov r0, 0 302 st r0, [context_switch_reqflg] 303 304 ld r0, [pxCurrentTCB] 305 breq r0, 0, ret_int_1 306 307/* r1 has old AUX_IRQ_ACT */ 308 PUSH r1 309/* clear related bits in IRQ_ACT manually to simulate a irq return */ 310 sr r2, [AUX_IRQ_ACT] 311 312 SAVE_CALLEE_REGS /* save callee save registers */ 313 mov r1, ret_int_r /* save return address */ 314 PUSH r1 315 316 bl dispatcher /* r0->pxCurrentTCB */ 317 318ret_int_r: 319 RESTORE_CALLEE_REGS /* recover registers */ 320 POPAX AUX_IRQ_ACT 321 INTERRUPT_EPILOGUE 322 rtie 323 324#if ARC_FEATURE_FIRQ == 1 325 .global exc_entry_firq 326 .align 4 327exc_entry_firq: 328#if ARC_FEATURE_STACK_CHECK && ARC_FEATURE_RGF_NUM_BANKS > 1 329#if ARC_FEATURE_SEC_PRESENT 330 lr r0, [AUX_SEC_STAT] 331 bclr r0, r0, AUX_SEC_STAT_BIT_SSC 332 sflag r0 333#else 334 lr r0, [AUX_STATUS32] 335 bclr r0, r0, AUX_STATUS_BIT_SC 336 kflag r0 337#endif 338#endif 339 SAVE_FIQ_EXC_REGS 340 341 mov blink, sp 342 343 ld r3, [exc_nest_count] 344 add r2, r3, 1 345 st r2, [exc_nest_count] 346 347 brne r3, 0, firq_handler_1 348#if ARC_FEATURE_STACK_CHECK && ARC_FEATURE_RGF_NUM_BANKS == 1 349#if ARC_FEATURE_SEC_PRESENT 350 lr r0, [AUX_SEC_STAT] 351 bclr r0, r0, AUX_SEC_STAT_BIT_SSC 352 sflag r0 353#else 354 lr r0, [AUX_STATUS32] 355 bclr r0, r0, AUX_STATUS_BIT_SC 356 kflag r0 357#endif 358#endif 359/* change to exception stack if interrupt happened in task context */ 360 mov sp, _e_stack 361firq_handler_1: 362 PUSH blink 363 364 lr r0, [AUX_IRQ_CAUSE] 365 mov r1, exc_int_handler_table 366 ld.as r2, [r1, r0] /* r2 = exc_int_handler_table + irqno *4 */ 367/* handle software triggered interrupt */ 368 lr r3, [AUX_IRQ_HINT] 369 brne r3, r0, firq_hint_handled 370 xor r3, r3, r3 371 sr r3, [AUX_IRQ_HINT] 372firq_hint_handled: 373 374 jl [r2] /* jump to interrupt handler */ 375/* no interrupts are allowed from here */ 376ret_firq: 377 clri 378 POP sp 379 380 mov r1, exc_nest_count 381 ld r0, [r1] 382 sub r0, r0, 1 383 st r0, [r1] 384/* if there are multi-bits set in IRQ_ACT, it's still in nest interrupt */ 385 lr r1, [AUX_IRQ_ACT] 386 bclr r1, r1, 0 387 brne r1, 0, ret_firq_1 388 389 ld r0, [context_switch_reqflg] 390 brne r0, 0, ret_firq_2 391ret_firq_1: /* return from non-task context */ 392 RESTORE_FIQ_EXC_REGS 393 rtie 394/* there is a dispatch request */ 395ret_firq_2: 396 /* clear dispatch request */ 397 mov r0, 0 398 st r0, [context_switch_reqflg] 399 400 ld r0, [pxCurrentTCB] 401 breq r0, 0, ret_firq_1 402 403/* reconstruct the interruptted context 404 * When ARC_FEATURE_RGF_BANKED_REGS >= 16 (16, 32), sp is banked 405 * so need to restore the fast irq stack. 406 */ 407#if ARC_FEATURE_RGF_BANKED_REGS >= 16 408 RESTORE_LP_REGS 409#if ARC_FEATURE_CODE_DENSITY 410 RESTORE_CODE_DENSITY 411#endif 412 RESTORE_R58_R59 413#endif 414 415/* when BANKED_REGS == 16, r4-r9 wiil be also saved in fast irq stack 416 * so pop them out 417 */ 418#if ARC_FEATURE_RGF_BANKED_REGS == 16 && !defined(ARC_FEATURE_RF16) 419 POP r9 420 POP r8 421 POP r7 422 POP r6 423 POP r5 424 POP r4 425#endif 426 427/* for other cases, unbanked regs are already in interrupted context's stack, 428 * so just need to save and pop the banked regs 429 */ 430 431/* save the interruptted context */ 432#if ARC_FEATURE_RGF_BANKED_REGS > 0 433/* switch back to bank0 */ 434 lr r0, [AUX_STATUS32] 435 bic r0, r0, 0x70000 436 kflag r0 437#endif 438 439#if ARC_FEATURE_RGF_BANKED_REGS == 4 440/* r4 - r12, gp, fp, r30, blink already saved */ 441 PUSH r0 442 PUSH r1 443 PUSH r2 444 PUSH r3 445#elif ARC_FEATURE_RGF_BANKED_REGS == 8 446/* r4 - r9, r0, r11 gp, fp, r30, blink already saved */ 447 PUSH r0 448 PUSH r1 449 PUSH r2 450 PUSH r3 451 PUSH r12 452#elif ARC_FEATURE_RGF_BANKED_REGS >= 16 453/* nothing is saved, */ 454 SAVE_R0_TO_R12 455 456 SAVE_R58_R59 457 PUSH gp 458 PUSH fp 459 PUSH r30 /* general purpose */ 460 PUSH blink 461 462#if ARC_FEATURE_CODE_DENSITY 463 SAVE_CODE_DENSITY 464#endif 465 SAVE_LP_REGS 466#endif 467 PUSH ilink 468 lr r0, [AUX_STATUS32_P0] 469 PUSH r0 470 lr r0, [AUX_IRQ_ACT] 471 PUSH r0 472 bclr r0, r0, 0 473 sr r0, [AUX_IRQ_ACT] 474 475 SAVE_CALLEE_REGS /* save callee save registers */ 476 477 mov r1, ret_firq_r /* save return address */ 478 PUSH r1 479 ld r0, [pxCurrentTCB] 480 bl dispatcher /* r0->pxCurrentTCB */ 481 482ret_firq_r: 483 RESTORE_CALLEE_REGS /* recover registers */ 484 POPAX AUX_IRQ_ACT 485 POPAX AUX_STATUS32_P0 486 POP ilink 487 488#if ARC_FEATURE_RGF_NUM_BANKS > 1 489#if ARC_FEATURE_RGF_BANKED_REGS == 4 490/* r4 - r12, gp, fp, r30, blink already saved */ 491 POP r3 492 POP r2 493 POP r1 494 POP r0 495 RESTORE_FIQ_EXC_REGS 496#elif ARC_FEATURE_RGF_BANKED_REGS == 8 497/* r4 - r9, gp, fp, r30, blink already saved */ 498 POP r12 499 POP r3 500 POP r2 501 POP r1 502 POP r0 503 RESTORE_FIQ_EXC_REGS 504#elif ARC_FEATURE_RGF_BANKED_REGS >= 16 505 RESTORE_LP_REGS 506#if ARC_FEATURE_CODE_DENSITY 507 RESTORE_CODE_DENSITY 508#endif 509 POP blink 510 POP r30 511 POP fp 512 POP gp 513 514 RESTORE_R58_R59 515 RESTORE_R0_TO_R12 516#endif /* ARC_FEATURE_RGF_BANKED_REGS */ 517#else 518 RESTORE_FIQ_EXC_REGS 519#endif /* ARC_FEATURE_RGF_NUM_BANKS */ 520 rtie 521#endif 522/** @endcond */ 523