# This file: http://user.it.uu.se/~embe8573/os/asm.S #include "regdef.h" #include "cp0_regdef.h" #include "asm_regs.h" # data segment #define INIT_STACK_SIZE 0x4000 #define EXCN_STACK_SIZE 0x4000 .data excn_regs: .word 0 cause_reg: .word 0 .space INIT_STACK_SIZE init_stack: .space EXCN_STACK_SIZE excn_stack: # code segment .text .set nomove .globl _start .globl kload_timer .globl get_cause .globl kset_sr .globl kset_registers .globl kget_registers .globl kdebug_magic_break .globl system_call .globl syscall_handler .globl k_system_call .globl get_timer # system_call - user access to the kernel function k_system_call # $a0, $a1, $a2, $a3 = "program name", ARG1, ARG2, ARG3 system_call: la v0, k_system_call # load address of syscall implementation in v0 syscall # enter kernel mode jr ra # back in user mode, return to caller # syscall_handler - enables argument passing syscall_handler: addi v0, a0, 0 # move a0 into v0 lw a0, REG_A0(v0) # load saved a0 (argument 1) into a0 lw a1, REG_A1(v0) # load saved a1 (argument 2) into a1 lw a2, REG_A2(v0) # load saved a2 (argument 3) into a2 lw a3, REG_A3(v0) # load saved a3 (argument 4) into a3 lw v0, REG_V0(v0) # load saved v0 (implementation) into v0 jr v0 # jump to system call implementation # get_cause - returns cause register as v0 get_cause: lw v0, cause_reg(zero) jr ra # kset_registers - set register area used by exception handler kset_registers: sw a0, excn_regs jr ra # kget_registers - get register area used by exception handler kget_registers: lw v0, excn_regs jr ra # kset_sr: set CPU status register # a0 - and mask (clear sr-bits not set in a0) # a1 - or mask (set sr-bits set in a1) kset_sr: mfc0 v0, sr # loads cp0's status reg and v0, v0, a0 or v0, v0, a1 mtc0 v0, sr jr ra # kload_timer: load timer with an interval # a0 - timer compare value kload_timer: mtc0 zero, count # load timer mtc0 a0, compare # load time for next timer interrupt jr ra # get_timer: get timer value # v0 - timer value get_timer: mfc0 v0, count jr ra # kdebug_magic: # "Executes a magic instruction. This will stop Simics simulation if # preceded by the Simics 'magic-break-enable' command." kdebug_magic_break: li zero,0 # this is the Simics magic break instruction for MIPS jr ra # startup _start: la t0, exh_srt la t2, exh_end la t1, 0xa0000180 subu t2, t2, t0 # calculate length of handler copyloop: lw v0, (t0) # copy one word at a time sw v0, (t1) addu t0, 4 addu t1, 4 subu t2, 4 bgez t2, copyloop la gp, 0x80000000 la sp, init_stack-32 j kinit # On exception: jump to the exception handler - # this stub is copied to the exception handler address 0xa0000180 # - it calls 'exception_handler' below when an exception occurs .set noreorder exh_srt: .set noat addi k1, $at, 0 # preserve the $at register .set at mfc0 k0, cause sw k0, cause_reg(zero) # preserve the cause register la k0, exception_handler # jump to the correct segment jr k0 nop exh_end: .set reorder # exception handler exception_handler: lw k0, excn_regs(zero) # save registers sw k1, REG_AT(k0) sw v0, REG_V0(k0) sw v1, REG_V1(k0) sw a0, REG_A0(k0) sw a1, REG_A1(k0) sw a2, REG_A2(k0) sw a3, REG_A3(k0) sw t0, REG_T0(k0) sw t1, REG_T1(k0) sw t2, REG_T2(k0) sw t3, REG_T3(k0) sw t4, REG_T4(k0) sw t5, REG_T5(k0) sw t6, REG_T6(k0) sw t7, REG_T7(k0) sw t8, REG_T8(k0) sw t9, REG_T9(k0) sw s0, REG_S0(k0) sw s1, REG_S1(k0) sw s2, REG_S2(k0) sw s3, REG_S3(k0) sw s4, REG_S4(k0) sw s5, REG_S5(k0) sw s6, REG_S6(k0) sw s7, REG_S7(k0) sw sp, REG_SP(k0) sw fp, REG_FP(k0) sw gp, REG_GP(k0) sw ra, REG_RA(k0) .set noreorder mfc0 k1, epc nop nop nop sw k1, REG_EPC(k0) .set reorder la sp, excn_stack-32 # jump to the C exception handler jal kexception lw k0, excn_regs(zero) # load registers for a new process to run lw v0, REG_V0(k0) lw v1, REG_V1(k0) lw a0, REG_A0(k0) lw a1, REG_A1(k0) lw a2, REG_A2(k0) lw a3, REG_A3(k0) lw t0, REG_T0(k0) lw t1, REG_T1(k0) lw t2, REG_T2(k0) lw t3, REG_T3(k0) lw t4, REG_T4(k0) lw t5, REG_T5(k0) lw t6, REG_T6(k0) lw t7, REG_T7(k0) lw t8, REG_T8(k0) lw t9, REG_T9(k0) lw s0, REG_S0(k0) lw s1, REG_S1(k0) lw s2, REG_S2(k0) lw s3, REG_S3(k0) lw s4, REG_S4(k0) lw s5, REG_S5(k0) lw s6, REG_S6(k0) lw s7, REG_S7(k0) lw sp, REG_SP(k0) lw fp, REG_FP(k0) lw gp, REG_GP(k0) lw ra, REG_RA(k0) lw k1, REG_EPC(k0) lw k0, REG_AT(k0) .set noreorder mtc0 k1, epc # restore EPC .set noat addi $at, k0, 0 nop nop nop eret # restore interrupted state .set at .set reorder