Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
script3r
GitHub Repository: script3r/os161
Path: blob/master/kern/arch/mips/locore/exception-mips1.S
2127 views
1
/*
2
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
3
* The President and Fellows of Harvard College.
4
*
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
7
* are met:
8
* 1. Redistributions of source code must retain the above copyright
9
* notice, this list of conditions and the following disclaimer.
10
* 2. Redistributions in binary form must reproduce the above copyright
11
* notice, this list of conditions and the following disclaimer in the
12
* documentation and/or other materials provided with the distribution.
13
* 3. Neither the name of the University nor the names of its contributors
14
* may be used to endorse or promote products derived from this software
15
* without specific prior written permission.
16
*
17
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
18
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
21
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
* SUCH DAMAGE.
28
*/
29
30
#include <kern/mips/regdefs.h>
31
#include <mips/specialreg.h>
32
33
/*
34
* Entry points for exceptions.
35
*
36
* MIPS-1 (r2000/r3000) style exception handling, with the "rfe"
37
* instruction rather than "eret", and the three sets of status bits.
38
*/
39
40
41
/*
42
* Do not allow the assembler to use $1 (at), because we need to be
43
* able to save it.
44
*/
45
.set noat
46
.set noreorder
47
48
/*
49
* UTLB exception handler.
50
*
51
* This code is copied to address 0x80000000, where the MIPS processor
52
* automatically invokes it.
53
*
54
* To avoid colliding with the other exception code, it must not
55
* exceed 128 bytes (32 instructions).
56
*
57
* This is the special entry point for the fast-path TLB refill for
58
* faults in the user address space. We don't implement fast-path TLB
59
* refill by default. Note that if you do, you either need to make
60
* sure the refill code doesn't fault or write extra code in
61
* common_exception to tidy up after such faults.
62
*/
63
64
.text
65
.globl mips_utlb_handler
66
.type mips_utlb_handler,@function
67
.ent mips_utlb_handler
68
mips_utlb_handler:
69
j common_exception /* Don't need to do anything special */
70
nop /* Delay slot */
71
.globl mips_utlb_end
72
mips_utlb_end:
73
.end mips_utlb_handler
74
75
/*
76
* General exception handler.
77
*
78
* This code is copied to address 0x80000080, where
79
* the MIPS processor automatically invokes it.
80
*/
81
82
.text
83
.globl mips_general_handler
84
.type mips_general_handler,@function
85
.ent mips_general_handler
86
mips_general_handler:
87
j common_exception /* Don't need to do anything special */
88
nop /* Delay slot */
89
.globl mips_general_end
90
mips_general_end:
91
.end mips_general_handler
92
93
/* This keeps gdb from conflating common_exception and mips_general_end */
94
nop /* padding */
95
96
97
/*
98
* Shared exception code for both handlers.
99
*/
100
101
.text
102
.type common_exception,@function
103
.ent common_exception
104
common_exception:
105
mfc0 k0, c0_status /* Get status register */
106
andi k0, k0, CST_KUp /* Check the we-were-in-user-mode bit */
107
beq k0, $0, 1f /* If clear, from kernel, already have stack */
108
nop /* delay slot */
109
110
/* Coming from user mode - find kernel stack */
111
mfc0 k1, c0_context /* we keep the CPU number here */
112
srl k1, k1, CTX_PTBASESHIFT /* shift it to get just the CPU number */
113
sll k1, k1, 2 /* shift it back to make an array index */
114
lui k0, %hi(cpustacks) /* get base address of cpustacks[] */
115
addu k0, k0, k1 /* index it */
116
move k1, sp /* Save previous stack pointer in k1 */
117
b 2f /* Skip to common code */
118
lw sp, %lo(cpustacks)(k0) /* Load kernel stack pointer (in delay slot) */
119
1:
120
/* Coming from kernel mode - just save previous stuff */
121
move k1, sp /* Save previous stack in k1 (delay slot) */
122
2:
123
/*
124
* At this point:
125
* Interrupts are off. (The processor did this for us.)
126
* k0 contains the value for curthread, to go into s7.
127
* k1 contains the old stack pointer.
128
* sp points into the kernel stack.
129
* All other registers are untouched.
130
*/
131
132
/*
133
* Allocate stack space for 37 words to hold the trap frame,
134
* plus four more words for a minimal argument block, plus
135
* one more for proper (64-bit) stack alignment.
136
*/
137
addi sp, sp, -168
138
139
/*
140
* Save general registers.
141
* We exclude k0/k1, which the kernel is free to clobber (and which
142
* we already have clobbered), and $0, whose value is fixed.
143
*
144
* The order here must match mips/include/trapframe.h.
145
*
146
* gdb disassembles this code to try to figure out what registers
147
* are where, and it isn't very bright. So in order to make gdb be
148
* able to trace the stack back through here, we play some silly
149
* games.
150
*
151
* In particular:
152
* (1) We store the return address register into the epc slot,
153
* which makes gdb think it's the return address slot. Then
154
* we store the real epc value over that.
155
* (2) We store the current sp into the sp slot, which makes gdb
156
* think it's the stack pointer slot. Then we store the real
157
* value.
158
* (3) gdb also assumes that saved registers in a function are
159
* saved in order. This is why we put epc where it is, and
160
* handle the real value of ra afterwards.
161
* (4) Because gdb will think we're saving k0 and k1, we need to
162
* leave slots for them in the trap frame, even though the
163
* stuff we save there is useless.
164
*
165
* This logic has not been tested against a recent gdb and has
166
* probably bitrotted. Someone(TM) should figure out what gdb
167
* currently expects -- or maybe even patch gdb to understand a
168
* better form of this that doesn't waste so many cycles.
169
*/
170
sw ra, 160(sp) /* dummy for gdb */
171
sw s8, 156(sp) /* save s8 */
172
sw sp, 152(sp) /* dummy for gdb */
173
sw gp, 148(sp) /* save gp */
174
sw k1, 144(sp) /* dummy for gdb */
175
sw k0, 140(sp) /* dummy for gdb */
176
177
sw k1, 152(sp) /* real saved sp */
178
nop /* delay slot for store */
179
180
mfc0 k1, c0_epc /* Copr.0 reg 13 == PC for exception */
181
sw k1, 160(sp) /* real saved PC */
182
183
sw t9, 136(sp)
184
sw t8, 132(sp)
185
sw s7, 128(sp)
186
sw s6, 124(sp)
187
sw s5, 120(sp)
188
sw s4, 116(sp)
189
sw s3, 112(sp)
190
sw s2, 108(sp)
191
sw s1, 104(sp)
192
sw s0, 100(sp)
193
sw t7, 96(sp)
194
sw t6, 92(sp)
195
sw t5, 88(sp)
196
sw t4, 84(sp)
197
sw t3, 80(sp)
198
sw t2, 76(sp)
199
sw t1, 72(sp)
200
sw t0, 68(sp)
201
sw a3, 64(sp)
202
sw a2, 60(sp)
203
sw a1, 56(sp)
204
sw a0, 52(sp)
205
sw v1, 48(sp)
206
sw v0, 44(sp)
207
sw AT, 40(sp)
208
209
sw ra, 36(sp)
210
211
/*
212
* Save special registers.
213
*/
214
mfhi t0
215
mflo t1
216
sw t0, 32(sp)
217
sw t1, 28(sp)
218
219
/*
220
* Save remaining exception context information.
221
*/
222
223
mfc0 t2, c0_status /* Copr.0 reg 11 == status */
224
sw t2, 20(sp)
225
mfc0 t3, c0_vaddr /* Copr.0 reg 8 == faulting vaddr */
226
sw t3, 16(sp)
227
mfc0 t4, c0_cause
228
sw t4, 24(sp) /* Copr.0 reg 13 == exception cause */
229
230
/*
231
* Pretend to save $0 for gdb's benefit.
232
*/
233
sw $0, 12(sp)
234
235
/*
236
* Load the curthread register if coming from user mode.
237
*/
238
andi k0, t2, CST_KUp /* Check the we-were-in-user-mode bit */
239
beq k0, $0, 3f /* If clear, were in kernel, skip ahead */
240
nop /* delay slot */
241
242
mfc0 k1, c0_context /* we keep the CPU number here */
243
srl k1, k1, CTX_PTBASESHIFT /* shift it to get just the CPU number */
244
sll k1, k1, 2 /* shift it back to make an array index */
245
lui k0, %hi(cputhreads) /* get base address of cputhreads[] */
246
addu k0, k0, k1 /* index it */
247
lw s7, %lo(cputhreads)(k0) /* Load curthread value */
248
3:
249
250
/*
251
* Load the kernel GP value.
252
*/
253
la gp, _gp
254
255
/*
256
* Prepare to call mips_trap(struct trapframe *)
257
*/
258
259
addiu a0, sp, 16 /* set argument - pointer to the trapframe */
260
jal mips_trap /* call it */
261
nop /* delay slot */
262
263
/* Something must be here or gdb doesn't find the stack frame. */
264
nop
265
266
/*
267
* Now restore stuff and return from the exception.
268
* Interrupts should be off.
269
*/
270
exception_return:
271
272
/* 16(sp) no need to restore tf_vaddr */
273
lw t0, 20(sp) /* load status register value into t0 */
274
nop /* load delay slot */
275
mtc0 t0, c0_status /* store it back to coprocessor 0 */
276
/* 24(sp) no need to restore tf_cause */
277
278
/* restore special registers */
279
lw t1, 28(sp)
280
lw t0, 32(sp)
281
mtlo t1
282
mthi t0
283
284
/* load the general registers */
285
lw ra, 36(sp)
286
287
lw AT, 40(sp)
288
lw v0, 44(sp)
289
lw v1, 48(sp)
290
lw a0, 52(sp)
291
lw a1, 56(sp)
292
lw a2, 60(sp)
293
lw a3, 64(sp)
294
lw t0, 68(sp)
295
lw t1, 72(sp)
296
lw t2, 76(sp)
297
lw t3, 80(sp)
298
lw t4, 84(sp)
299
lw t5, 88(sp)
300
lw t6, 92(sp)
301
lw t7, 96(sp)
302
lw s0, 100(sp)
303
lw s1, 104(sp)
304
lw s2, 108(sp)
305
lw s3, 112(sp)
306
lw s4, 116(sp)
307
lw s5, 120(sp)
308
lw s6, 124(sp)
309
lw s7, 128(sp)
310
lw t8, 132(sp)
311
lw t9, 136(sp)
312
313
/* 140(sp) "saved" k0 was dummy garbage anyway */
314
/* 144(sp) "saved" k1 was dummy garbage anyway */
315
316
lw gp, 148(sp) /* restore gp */
317
/* 152(sp) stack pointer - below */
318
lw s8, 156(sp) /* restore s8 */
319
lw k0, 160(sp) /* fetch exception return PC into k0 */
320
321
lw sp, 152(sp) /* fetch saved sp (must be last) */
322
323
/* done */
324
jr k0 /* jump back */
325
rfe /* in delay slot */
326
.end common_exception
327
328
/*
329
* Code to enter user mode for the first time.
330
* Does not return.
331
*
332
* This is called from mips_usermode().
333
* Interrupts on this processor should be off.
334
*/
335
336
.text
337
.globl asm_usermode
338
.type asm_usermode,@function
339
.ent asm_usermode
340
asm_usermode:
341
/*
342
* a0 is the address of a trapframe to use for exception "return".
343
* It's allocated on our stack.
344
*
345
* Move it to the stack pointer - we don't need the actual stack
346
* position any more. (When we come back from usermode, cpustacks[]
347
* will be used to reinitialize our stack pointer, and that was
348
* set by mips_usermode.)
349
*
350
* Then just jump to the exception return code above.
351
*/
352
353
j exception_return
354
addiu sp, a0, -16 /* in delay slot */
355
.end asm_usermode
356
357