blob: eae4c96a4e23f797349c43f48de45878ef655f06 [file] [log] [blame]
#include "pstate.h"
#include <asm/asi.h>
#include "cpustate.h"
#define ASI_BP ASI_M_BYPASS
#define REGWIN_SZ 0x40
.globl __switch_context, __switch_context_nosave, __exit_context, halt
.text
.align 4
.register %g2, #scratch
.register %g3, #scratch
.register %g6, #scratch
.register %g7, #scratch
/*
* Switch execution context
* This saves registers in the stack, then
* switches the stack, and restores everything from the new stack.
* This function takes no argument. New stack pointer is
* taken from global variable __context, and old stack pointer
* is also saved to __context. This way we can just jump to
* this routine to get back to the original context.
*/
__switch_context:
/* make sure caller's windows are on caller's stack */
flushw;
/* Save everything in current stack */
stx %g1, [%sp + 2047 - 0x500 + 0x30]
stx %g2, [%sp + 2047 - 0x500 + 0x38]
stx %g3, [%sp + 2047 - 0x500 + 0x40]
stx %g4, [%sp + 2047 - 0x500 + 0x48]
stx %g5, [%sp + 2047 - 0x500 + 0x50]
stx %g6, [%sp + 2047 - 0x500 + 0x58]
stx %g7, [%sp + 2047 - 0x500 + 0x60]
mov %sp, %g1
add %g1, 2047 - 0x500, %g1
/* Return PC value */
mov %o7, %g2
add %g2, 0x8, %g2
stx %g2, [%g1 + 0x4d0]
SAVE_CPU_STATE(switch)
/* swap context */
setx __context, %g2, %g3
ldx [%g3], %g2
stx %g1, [%g3]
mov %g2, %g1
ba __set_context
__switch_context_nosave:
/* Interrupts are not allowed... */
/* make sure caller's windows are on caller's stack */
flushw
/* Load all registers
*/
setx __context, %g2, %g1
ldx [%g1], %g1
__set_context:
RESTORE_CPU_STATE(switch)
/* Restore globals */
mov %g1, %g2
add %g2, 0x30, %g2
stx %g2, [%sp + 2047 - 8]
ldx [%g1 + 0x38], %g2
ldx [%g1 + 0x40], %g3
ldx [%g1 + 0x48], %g4
ldx [%g1 + 0x50], %g5
ldx [%g1 + 0x58], %g6
ldx [%g1 + 0x60], %g7
/* Finally, load new %pc */
ldx [%g1 + 0x4d0], %g1
jmpl %g1, %o7
ldx [%sp + 2047 - 8], %g1
__exit_context:
/* Get back to the original context */
ba __switch_context
nop