diff options
Diffstat (limited to 'core/nds32/switch.S')
-rw-r--r-- | core/nds32/switch.S | 99 |
1 files changed, 99 insertions, 0 deletions
diff --git a/core/nds32/switch.S b/core/nds32/switch.S new file mode 100644 index 0000000000..2c4ce0c273 --- /dev/null +++ b/core/nds32/switch.S @@ -0,0 +1,99 @@ +/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Context switching + */ + +#include "config.h" + +.text + +/** + * Task context switching + * + * Change the task scheduled after returning from an interruption. + * + * This function must be called in interrupt context. + * + * Save the registers of the current task below the interrupt context on + * its task, then restore the live registers of the next task and set the + * process stack pointer to the new stack. + * + * $r0: pointer to the task to switch from + * $r1: pointer to the task to switch to + * $r2: pointer to the stack where the interrupt entry context is saved + * + * the structure of the saved context on the stack is : + * (top to bottom) + * sp, lp, fp, r15, r5, r4, r3, r2, r1, r0, r10, r9, r8, r7, r6, ipc, ipsw + * interrupt entry frame <|> + */ +.global __switch_task +__switch_task: + /* get the (new) highest priority task pointer in r0 */ + jal next_sched_task + movi55 $r3, 0 + /* pointer to the current task (which are switching from) */ + lwi.gp $r1, [ + current_task] + /* reset the re-scheduling request */ + swi.gp $r3, [ + need_resched] + /* Nothing to do: let's return to keep the same task scheduled */ + beq $r1, $r0, 1f + /* save our new scheduled task */ + swi.gp $r0, [ + current_task] + /* get the program status word saved at exception entry */ + mfsr $r4, $IPSW /* to save SP_ADJ bit */ + /* get the task program counter saved at exception entry */ + mfsr $r5, $IPC + /* get the new scheduled task stack pointer */ + lw $r3, [$r0] + /* save ipsw, ipc, r6, r7, r8, r9, r10 on the current process stack */ + smw.adm $r4, [$fp], $r10, 0 + /* restore ipsw, ipc, r6, r7, r8, r9, r10 from the next stack context */ + lmw.bim $r4, [$r3], $r10, 0 + /* set the program status word to restore SP_ADJ bit */ + mtsr $r4, $IPSW + /* set the task program counter to restore at exception exit */ + mtsr $r5, $IPC + /* save the task stack pointer in its context */ + sw $fp, [$r1] + /* barrier: ensure IPC is taken into account before IRET */ + dsb + /* exception frame pointer for the new task */ + mov55 $fp, $r3 +1: /* un-pile the interruption entry context */ + /* restore r0-r5 */ + lmw.bim $r0, [$fp], $r5, 0 + /* restore r15, fp, lp and sp */ + lmw.bi $r15, [$fp], $r15, 0xb + /* restore PC and PSW */ + iret + +/** + * Start the task scheduling. + * + * $r0 is a pointer to task_stack_ready, which is set to 1 after + * the task stack is set up. + */ +.global __task_start +__task_start: + /* area used as dummy thread stack for the first switch */ + la $r3, scratchpad + + movi55 $r4, 1 + movi55 $r2, 0 /* syscall 3rd parameter : not an IRQ emulation */ + movi55 $r1, 0 /* syscall 2nd parameter : re-schedule nothing */ + movi55 $r0, 0 /* syscall 1st parameter : de-schedule nothing */ + + /* put the dummy stack pointer at the top of the stack in scratchpad */ + addi $sp, $r3, 4 * 16 + /* we are ready to re-schedule */ + swi.gp $r4, [ + need_resched] + + /* trigger scheduling to execute the task with the highest priority */ + syscall 0 + /* we should never return here: set code to EC_ERROR_UNKNOWN */ + movi55 $r0, 0x1 + ret5 $lp + |