2.2.1.1.2.1. Kalisto MIPS Processor Context Switching
.macro SAVE_REGISTERS base
sw $zero, REGS_OFFSET_ZERO(\base)
sw $at, REGS_OFFSET_AT(\base)
sw $v0, REGS_OFFSET_V0(\base)
sw $v1, REGS_OFFSET_V1(\base)
sw $a0, REGS_OFFSET_A0(\base)
sw $a1, REGS_OFFSET_A1(\base)
sw $a2, REGS_OFFSET_A2(\base)
sw $a3, REGS_OFFSET_A3(\base)
...
sw $gp, REGS_OFFSET_GP(\base)
sw $fp, REGS_OFFSET_FP(\base)
sw $ra, REGS_OFFSET_RA(\base)
.endm SAVE_REGISTERS
.macro LOAD_REGISTERS base
lw $ra, REGS_OFFSET_RA(\base)
lw $fp, REGS_OFFSET_FP(\base)
lw $gp, REGS_OFFSET_GP(\base)
...
lw $a3, REGS_OFFSET_A3(\base)
lw $a2, REGS_OFFSET_A2(\base)
lw $a1, REGS_OFFSET_A1(\base)
lw $a0, REGS_OFFSET_A0(\base)
lw $v1, REGS_OFFSET_V1(\base)
lw $v0, REGS_OFFSET_V0(\base)
lw $at, REGS_OFFSET_AT(\base)
lw $zero, REGS_OFFSET_ZERO(\base)
.endm LOAD_REGISTERS
switch_cpu_context:
/* Allocate a frame on the stack of the old thread and update
the address of the stack top of the old thread. */
addiu $sp, -CONTEXT_SIZE ;Allocate space on stack
sw $sp, ($a0) ;Save the old stack
SAVE_REGISTERS $sp ;Save general registers
mflo $t0 ;Few other registers that
mfhi $t1 ;the macro does not handle
sw $t0, REGS_OFFSET_LO($sp) ;need to be saved as well
sw $t1, REGS_OFFSET_HI($sp)
mfc0 $t0, $status
sw $t0, REGS_OFFSET_STATUS($sp)
la $t1, ~CP0_STATUS_IE_MASK
and $t0, $t1
mtc0 $t0, $status ;Disable interrupts
lw $sp, ($a1) ;Switch to the new stack
lw $t0, REGS_OFFSET_LO($sp) ;Restore the registers in
lw $t1, REGS_OFFSET_HI($sp) ;roughly the opposite
mtlo $t0 ;order to fit the
mthi $t1 ;stack semantics
LOAD_REGISTERS $sp
lw $k0, REGS_OFFSET_STATUS($sp)
addiu $sp, CONTEXT_SIZE ;Free space on stack
j $ra ;Return to the newly
mtc0 $k0, $status ;restored context