.kdata __m1_: .asciiz " Exception " __m2_: .asciiz " occurred and ignored\n" __e0_: .asciiz " [Interrupt] " __e1_: .asciiz "" __e2_: .asciiz "" __e3_: .asciiz "" __e4_: .asciiz " [Unaligned address in inst/data fetch] " __e5_: .asciiz " [Unaligned address in store] " __e6_: .asciiz " [Bad address in text read] " __e7_: .asciiz " [Bad address in data/stack read] " __e8_: .asciiz " [Error in syscall] " __e9_: .asciiz " [Breakpoint] " __e10_: .asciiz " [Reserved instruction] " __e11_: .asciiz "" __e12_: .asciiz " [Arithmetic overflow] " __e13_: .asciiz " [Inexact floating point result] " __e14_: .asciiz " [Invalid floating point result] " __e15_: .asciiz " [Divide by 0] " __e16_: .asciiz " [Floating point overflow] " __e17_: .asciiz " [Floating point underflow] " __excp: .word __e0_,__e1_,__e2_,__e3_,__e4_,__e5_,__e6_,__e7_,__e8_,__e9_ .word __e10_,__e11_,__e12_,__e13_,__e14_,__e15_,__e16_,__e17_ s1: .word 0 s2: .word 0 .ktext 0x80000080 .set noat # Because we are running in the kernel, we can use $k0/$k1 without # saving their old values. move $k1 $at # Save $at .set at sw $v0 s1 # Not re-entrent and we can't trust $sp sw $a0 s2 mfc0 $k0 $13 # Cause sgt $v0 $k0 0x44 # ignore interrupt exceptions bgtz $v0 ret addu $0 $0 0 li $v0 4 # syscall 4 (print_str) la $a0 __m1_ syscall li $v0 1 # syscall 1 (print_int) srl $a0 $k0 2 # shift Cause reg syscall li $v0 4 # syscall 4 (print_str) lw $a0 __excp($k0) syscall bne $k0 0x18 ok_pc # Bad PC requires special checks mfc0 $a0, $14 # EPC and $a0, $a0, 0x3 # Is EPC word-aligned? beq $a0, 0, ok_pc li $v0 10 # Exit on really bad PC (out of text) syscall ok_pc: li $v0 4 # syscall 4 (print_str) la $a0 __m2_ syscall mtc0 $0, $13 # Clear Cause register ret: mfc0 $t0, $12 ori $t0, $t0, 257 mtc0 $t0, $12 la $t1, 0xffff0000 lw $t2, 0($t1) ori $t2, $t2, 2 sw $t2, 0xffff0000 lw $v0 s1 lw $a0 s2 mfc0 $k0 $14 # EPC .set noat move $at $k1 # Restore $at .set at la $s2,0xffff0004 lb $s3,0($s2) lw $s5,buffer srl $s5,$s5,1 sw $s5,buffer sb $s3,buffer lw $s0,buffer rfe # Return from exception handler addiu $k0 $k0 4 # Return to next instruction jr $k0 # Standard startup code. Invoke the routine main with no arguments. .text .globl __start __start: lw $a0, 0($sp) # argc addiu $a1, $sp, 4 # argv addiu $a2, $a1, 4 # envp sll $v0, $a0, 2 addu $a2, $a2, $v0 jal main li $v0 10 syscall # syscall 10 (exit)