Files
OpenCellular/core/nds32/switch.S
Dino Li 11c2c92236 nds32: start_irq_handler() use system stack
[symptom]
The 'vboot_hash_start()' always return busy error and variable 'in_progress'
got a strange value(should be 0 or 1).

'start_irq_handler()' causes scratchpad overflow in first context switch.
It must be called after SP switch to system stack in ISR.

NOTE:
The scratchpad is still also need more size even if
'start_irq_handler()' is using system stack. following is detail:

1. uint32_t scratchpad[19] 0x81d34 ~ 0x81d7f
[__task_start:]
2. /* put the dummy stack pointer at the top of the stack in scratchpad */
   addi $sp, $r3, 4 * 18
   -> SP 0x81d7c
3. syscall push return address (-4)
   -> SP 0x81d78
[ISR:]
4. push r15, fp, lp, and sp (-0x10)
   -> SP 0x81d68
5. push r0 ~ r5 (-0x18)
   -> SP 0x81d50
[__switch_task:]
6. /* save ipsw, ipc, r6, r7, r8, r9, r10 on the current process stack */ (-0x1C)
-> SP 0x81d34

Signed-off-by: Dino Li <dino.li@ite.com.tw>

BRANCH=none
BUG=none
TEST=1. hash done.
     2. console command 'taskinfo'.
     3. the scratchpad does not overflow after first context switch.

Change-Id: If5d89ff5c945a777010492fcfb54bf41f434ed69
Reviewed-on: https://chromium-review.googlesource.com/317468
Commit-Ready: Dino Li <dino.li@ite.com.tw>
Tested-by: Dino Li <dino.li@ite.com.tw>
Reviewed-by: Randall Spangler <rspangler@chromium.org>
2015-12-16 21:49:34 -08:00

102 lines
3.2 KiB
ArmAsm

/* 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 */
/* isr exit */
jal end_irq_handler
/* 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 * 18
/* 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