-
Notifications
You must be signed in to change notification settings - Fork 2
/
kernel.s
144 lines (127 loc) · 4.49 KB
/
kernel.s
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# Tim Henderson
# A generalized exception handler adapted from exception.s
######## MASTER INCLUDE LIST ########
#include kernel_data.s
#include memory_manager.s
#include stack_mgr.s
#include proc_manager.s
#include start.s
#include interrupt_handler.s
#include context_mgr.s
.globl __save_a0
.globl __save_a1
.globl __save_a2
.globl __save_a3
.globl __save_v0
.globl __save_v1
.kdata # stores the save values of these reg's since the stack
# may be unsafe
__m1_: .asciiz " Exception "
__m2_: .asciiz " occurred and ignored\n"
__e0_: .asciiz " [Interrupt] \n"
__e1_: .asciiz " [TLB]"
__e2_: .asciiz " [TLB]"
__e3_: .asciiz " [TLB]"
__e4_: .asciiz " [Address error in inst/data fetch] \n"
__e5_: .asciiz " [Address error in store] \n"
__e6_: .asciiz " [Bad instruction address] \n"
__e7_: .asciiz " [Bad data address] \n"
__e8_: .asciiz " [Error in syscall] \n"
__e9_: .asciiz " [Breakpoint] \n"
__e10_: .asciiz " [Reserved instruction] "
__e11_: .asciiz " "
__e12_: .asciiz " [Arithmetic overflow] \n"
__e13_: .asciiz " [Trap] "
__e14_: .asciiz ""
__e15_: .asciiz " [Floating point] "
__e16_: .asciiz ""
__e17_: .asciiz ""
__e18_: .asciiz " [Coproc 2]"
__e19_: .asciiz ""
__e20_: .asciiz ""
__e21_: .asciiz ""
__e22_: .asciiz " [MDMX]"
__e23_: .asciiz " [Watch]"
__e24_: .asciiz " [Machine check]"
__e25_: .asciiz ""
__e26_: .asciiz ""
__e27_: .asciiz ""
__e28_: .asciiz ""
__e29_: .asciiz ""
__e30_: .asciiz " [Cache]"
__e31_: .asciiz ""
__excp:
.word __e0_, __e1_, __e2_, __e3_, __e4_, __e5_, __e6_, __e7_, __e8_, __e9_
.word __e10_, __e11_, __e12_, __e13_, __e14_, __e15_, __e16_, __e17_, __e18_
.word __e19_, __e20_, __e21_, __e22_, __e23_, __e24_, __e25_, __e26_, __e27_
.word __e28_, __e29_, __e30_, __e31_
__save_at: .word 0
__save_a0: .word 0
__save_a1: .word 0
__save_a2: .word 0
__save_a3: .word 0
__save_v0: .word 0
__save_v1: .word 0
exception_msg: .asciiz "exception handler entered\n"
.ktext 0x80000180 # must go at this address
exception_handler: # exception handler
# first store state
.set noat # stops spim from complaining that you are touching $at
sw $at __save_at
.set at # re-ables $at complaints
sw $a0 __save_a0
sw $a1 __save_a1
sw $a2 __save_a2
sw $a3 __save_a3
sw $v0 __save_v0
sw $v1 __save_v1
mfc0 $a0 $14 # get the EPC register
# call println_hex
mfc0 $k0 $13 # Cause register
andi $a0 $k0 0x7C
srl $a0 $a0 2 # Extract ExcCode Field
# We don't use syscalls for I/O anymore, and we never bothered to replace this.
# li $v0 1 # syscall 1 (print_int)
# syscall
# If everything is ok, go ahead and do the context switch
# Otherwise, do error-ish things
bnez $a0 skip_interrupt_handler
la $a0 interrupt_handler
jr $a0
skip_interrupt_handler:
andi $a0 $k0 0x7C
srl $a0 $a0 2 # Extract ExcCode Field
addu $k1 $a0 $0 # set $k1 to the error number so user program can access it
mul $a0 $a0 4
lw $a0 __excp($a0)
#Yeah, so sometimes we do syscalls for I/O anyway, but we don't trust them.
li $v0 4 # syscall 4 (print_str)
nop
syscall
la $a0 __m1_
li $v0 4 # syscall 4 (print_str)
syscall
.globl interrupt_return
interrupt_return:
exception_finished:
mfc0 $k0, $14 # get the EPC register
addiu $k0, $k0, 4 # increment it (so we don't keep repeating the same instruction
mtc0 $k0, $14 # push it back to the EPC
mtc0 $0, $13 # clear cause reg
mfc0 $k0, $12 # get status register
xori $k0, $k0, 0x2 # set exception level to 0 this re-enables interrupts
mtc0 $k0, $12 # push status register
# mfc0 $a0, $9 # get the current clock value
# add $a0, $a0, 1 # add 2
# mtc0 $a0, $11 # push to compare
# restore state
lw $a0 __save_a0
lw $a1 __save_a1
lw $a2 __save_a2
lw $a3 __save_a3
lw $v0 __save_v0
lw $v1 __save_v1
.set noat
lw $at __save_at
.set at
eret # return from exception handler