1 | /* |
---|
2 | * Authors: Frédéric Pétrot and Denis Hommais |
---|
3 | * $Log: exception.s,v $ |
---|
4 | * Revision 1.1 2005/03/02 12:37:22 buchmann |
---|
5 | * Add "soft" directory. |
---|
6 | * It allows to generate MIPS binary using cross compiler. |
---|
7 | * |
---|
8 | * Revision 1.2 2003/07/18 16:21:30 fred |
---|
9 | * Now interprets the instruction that causes a DBE in order to print the |
---|
10 | * address responsible for the failure. |
---|
11 | * Cleaned up the code a little (mainly comments :) |
---|
12 | * |
---|
13 | * Revision 1.1 2003/03/10 13:39:07 fred |
---|
14 | * Adding the hardware dependent stuff to smoothly handle multi |
---|
15 | * architecture compilation of this kernel |
---|
16 | * |
---|
17 | * Revision 1.1.1.1 2002/02/28 12:58:55 disydent |
---|
18 | * Creation of Disydent CVS Tree |
---|
19 | * |
---|
20 | * Revision 1.1.1.1 2001/11/19 16:55:37 pwet |
---|
21 | * Changing the CVS tree structure of disydent |
---|
22 | * |
---|
23 | * Revision 1.3 2001/11/14 12:08:45 fred |
---|
24 | * Making the ldscript being generated for correct path accesses |
---|
25 | * Removing the syscall entry of the exception handler for now |
---|
26 | * |
---|
27 | * Revision 1.2 2001/11/09 14:51:03 fred |
---|
28 | * Remove the reset executable and make the assembler be piped through |
---|
29 | * cpp. |
---|
30 | * The ldscript is not usable. I have to think before going on |
---|
31 | * |
---|
32 | * $Id: exception.S,v 1.1 2003/03/10 13:39:07 fred Exp |
---|
33 | * Note : we do not check BD at any time yet! Beware, ... |
---|
34 | * Rev 0 : minimal handler to support syscall for system calls |
---|
35 | * implementation |
---|
36 | * Rev 1 : added correct exception/interruption detection and messages |
---|
37 | * Rev 2 : added mult and div interpretation in illegal instruction |
---|
38 | * Rev 3 : Makes it compliant with multi-thread/multi-processor |
---|
39 | * Stack is thread stack now (it must at least for preemptive |
---|
40 | * scheduling stuffs |
---|
41 | */ |
---|
42 | .rdata |
---|
43 | .align 2 |
---|
44 | msg : .ascii "An exception occurred with the following cause :\n\000" |
---|
45 | |
---|
46 | jmptable: |
---|
47 | .word Int |
---|
48 | .word Uimp |
---|
49 | .word Uimp |
---|
50 | .word Uimp |
---|
51 | .word AdEL |
---|
52 | .word AdES |
---|
53 | .word IBE |
---|
54 | .word DBE |
---|
55 | .word Sys |
---|
56 | .word Bp |
---|
57 | .word RI |
---|
58 | .word CpU |
---|
59 | .word Ovf |
---|
60 | .word Ukn |
---|
61 | .word Ukn |
---|
62 | |
---|
63 | .text |
---|
64 | .align 2 |
---|
65 | .ent excep |
---|
66 | excep: |
---|
67 | /* |
---|
68 | * Here I save the whole C compatible register context, which is a |
---|
69 | * waste of time if only assembly functions are to be used |
---|
70 | * A more optimized way to do things would be to check for critical |
---|
71 | * events (typically external interrupts) and do the saving only |
---|
72 | * when an other events took place |
---|
73 | * Note that this implies to check which registers to save according |
---|
74 | * to the interrupt handling routines, that are usually user defined! |
---|
75 | * |
---|
76 | * Reminder: $26 and $27 are kernel registers that need not be saved |
---|
77 | * This shall be executed in critical section since the stack pointer |
---|
78 | * is not properly set until the subu! |
---|
79 | */ |
---|
80 | .set noreorder |
---|
81 | /* Shall not touch $1 until it is saved */ |
---|
82 | .set noat |
---|
83 | |
---|
84 | subu $29, $29, 26*4 /* Load kernel stack addr + stack update */ |
---|
85 | sw $1, 1*4($29) /* save all temporaries*/ |
---|
86 | .set at |
---|
87 | sw $2, 2*4($29) /* others are saved when calling procedures*/ |
---|
88 | sw $3, 3*4($29) |
---|
89 | sw $4, 4*4($29) |
---|
90 | sw $5, 5*4($29) |
---|
91 | sw $6, 6*4($29) |
---|
92 | sw $7, 7*4($29) |
---|
93 | sw $8, 8*4($29) |
---|
94 | sw $9, 9*4($29) |
---|
95 | sw $10, 10*4($29) |
---|
96 | sw $11, 11*4($29) |
---|
97 | sw $12, 12*4($29) |
---|
98 | sw $13, 13*4($29) |
---|
99 | sw $14, 14*4($29) |
---|
100 | sw $15, 15*4($29) |
---|
101 | sw $24, 16*4($29) |
---|
102 | sw $25, 17*4($29) |
---|
103 | mfc0 $26, $14 /* load EPC into k0 (two cycles befor use)*/ |
---|
104 | sw $29, 18*4($29) |
---|
105 | sw $30, 19*4($29) |
---|
106 | sw $31, 20*4($29) |
---|
107 | sw $26, 21*4($29) /* and store it to be recallable*/ |
---|
108 | mfhi $26 |
---|
109 | sw $26, 22*4($29) |
---|
110 | mflo $26 |
---|
111 | sw $26, 23*4($29) |
---|
112 | |
---|
113 | /* Check the cause of the arrival in this code */ |
---|
114 | |
---|
115 | mfc0 $27, $13 /* load CAUSE into $27*/ |
---|
116 | nop |
---|
117 | andi $27, $27, 0x3c /* get the exception code (ExcCode)*/ |
---|
118 | beqz $27, Int /* Test if it is an interrupt. If so*/ |
---|
119 | sw $0, 24*4($29) /* return address is epc + 0 */ |
---|
120 | /* it's faster.*/ |
---|
121 | la $26, jmptable /* load the base of the jump table*/ |
---|
122 | /* get the exception code (ExcCode)*/ |
---|
123 | addu $26, $26, $27 /* load the offset in the table*/ |
---|
124 | lw $27, ($26) /* load the pointed value*/ |
---|
125 | li $26, 4 |
---|
126 | j $27 /* and jump there*/ |
---|
127 | sw $26, 24*4($29) /* faulty insn is at epc - 4 */ |
---|
128 | nop /* delayed slot too*/ |
---|
129 | |
---|
130 | /* |
---|
131 | * External interupts: |
---|
132 | * The meaning of these interupts is for sure system dependent, so |
---|
133 | * this routine must be adapted to each system particularities |
---|
134 | * |
---|
135 | * Right now we just find out what interrupt lead us here, and print |
---|
136 | * a small message about it. |
---|
137 | */ |
---|
138 | .rdata |
---|
139 | .align 2 |
---|
140 | .text |
---|
141 | Int : |
---|
142 | .set noat |
---|
143 | mfc0 $4, $13 /* load CAUSE into $27*/ |
---|
144 | mfc0 $26, $12 /* load STATUS into $26*/ |
---|
145 | andi $4, $4, 0xFF00 /* mask CAUSE to get the ITs only*/ |
---|
146 | and $4, $4, $26 /* keep only the enabled ITs*/ |
---|
147 | srl $4, $4, 8 /* and put them in the LSBees*/ |
---|
148 | beqz $4, _endit /* If none, then what are we doing here? */ |
---|
149 | nop |
---|
150 | |
---|
151 | .extern SwitchOnIt |
---|
152 | |
---|
153 | la $26, SwitchOnIt |
---|
154 | jal $26 |
---|
155 | nop |
---|
156 | |
---|
157 | _endit: |
---|
158 | j _return /* go back to user*/ |
---|
159 | nop |
---|
160 | .set at |
---|
161 | |
---|
162 | /* |
---|
163 | * Clearly fatal exceptions as far as we're concerned, ... |
---|
164 | */ |
---|
165 | .rdata |
---|
166 | .align 2 |
---|
167 | m2 : .ascii "Unimplemented TLB Exception!\n\000" |
---|
168 | m2k : .ascii "Reserved Exception!\n\000" |
---|
169 | m2o : .ascii "Integer Arithmetic Overflow!\n\000" |
---|
170 | |
---|
171 | .text |
---|
172 | .align 2 |
---|
173 | .set reorder |
---|
174 | Uimp : la $4, m2 /* load the appropriate message,...*/ |
---|
175 | j U /* */ |
---|
176 | Ukn : la $4, m2k /* */ |
---|
177 | j U /* */ |
---|
178 | Ovf : la $4, m2o /* */ |
---|
179 | U : la $2, uputs |
---|
180 | jal $2 /* and print it!*/ |
---|
181 | j _exit /* */ |
---|
182 | .set noreorder |
---|
183 | |
---|
184 | /* |
---|
185 | * Illegal instructions: |
---|
186 | * we interpret mult/div and lwl/lwr here, and exit on an other code |
---|
187 | * Before modifing this code think that NO REGISTER CONTENT should |
---|
188 | * be touched before the end of the register loading routine |
---|
189 | * This explains why some code seems duplicated (several mfc0) |
---|
190 | */ |
---|
191 | .rdata |
---|
192 | m2i : .ascii "Illegal or Reserved Instruction!\n\000" |
---|
193 | .text |
---|
194 | .set noat |
---|
195 | RI : mfc0 $26, $14 /* load EPC into $26*/ |
---|
196 | nop /* */ |
---|
197 | nop /* */ |
---|
198 | lw $26, ($26) /* $26 contains the faulty ins*/ |
---|
199 | lui $27, 0xFC00 /* mask for special*/ |
---|
200 | and $27, $26, $27 /* */ |
---|
201 | bne $27, $0, Ilg /* this is not a special trap*/ |
---|
202 | |
---|
203 | /* |
---|
204 | * I do not handle the mult/div trap, as we have added the |
---|
205 | * instructions in our R3000 model |
---|
206 | */ |
---|
207 | nop |
---|
208 | |
---|
209 | Ilg: la $4, m2i |
---|
210 | la $2, uputs |
---|
211 | jal $2 /* we got an illegal ins, so we quit*/ |
---|
212 | nop |
---|
213 | j _exit /* */ |
---|
214 | nop |
---|
215 | |
---|
216 | /* |
---|
217 | * Unaligned access: |
---|
218 | * Quite fatal, I'm afraid |
---|
219 | */ |
---|
220 | .rdata |
---|
221 | .align 2 |
---|
222 | m3 : .ascii "Unaligned/unallowed Access while %s address 0x%x at pc 0x%x!\n\000" |
---|
223 | m3l : .ascii "reading\000" |
---|
224 | m3e : .ascii "writing\000" |
---|
225 | |
---|
226 | .text |
---|
227 | .align 2 |
---|
228 | .set reorder |
---|
229 | AdEL : la $5, m3l |
---|
230 | j AdE |
---|
231 | AdES : la $5, m3e |
---|
232 | AdE : la $4, m3 |
---|
233 | .set noreorder |
---|
234 | mfc0 $6, $8 /* load BAR into thrid arg ($6)*/ |
---|
235 | mfc0 $7, $14 /* load EPC into fourth arg ($7)*/ |
---|
236 | la $2, uputs |
---|
237 | jal $2 /* print all that stuff*/ |
---|
238 | nop |
---|
239 | j _exit |
---|
240 | nop |
---|
241 | |
---|
242 | /* |
---|
243 | * Synchronous bus error |
---|
244 | */ |
---|
245 | .rdata |
---|
246 | .align 2 |
---|
247 | m4i: .ascii "Bus error while loading the instrunction at pc 0x%x!\n\000" |
---|
248 | m4d: .ascii "Bus error while loading the datum at pc 0x%x for addr 0x%x!\n\000" |
---|
249 | .data |
---|
250 | .text |
---|
251 | |
---|
252 | .align 2 |
---|
253 | .set reorder |
---|
254 | IBE : mfc0 $5, $14 /* load EPC */ |
---|
255 | la $4, m4i |
---|
256 | j BE |
---|
257 | .set noreorder |
---|
258 | DBE : la $4, m4d |
---|
259 | /* |
---|
260 | * The instruction at EPC must be interpreted to get the |
---|
261 | * address that caused the fault. |
---|
262 | * The register value must be reloaded from the stack, and |
---|
263 | * since the storage of the registers is quite exotic right |
---|
264 | * now, this will work only for registers 1 to 15! |
---|
265 | */ |
---|
266 | mfc0 $5, $14 /* load EPC */ |
---|
267 | lw $6, 0($5) /* load faulty insn */ |
---|
268 | andi $8, $6, 0xFFFF /* get the imm field of it */ |
---|
269 | srl $9, $6, 19 |
---|
270 | andi $9, $9, 0x7c /* get the rs register index times 4 */ |
---|
271 | add $9, $29, $9 /* compute the stack index of this register */ |
---|
272 | lw $9, 0($9) |
---|
273 | addu $6, $9, $8 /* get the address as computed */ |
---|
274 | |
---|
275 | BE : la $2, uputs |
---|
276 | jal $2 /* print all that stuff*/ |
---|
277 | nop |
---|
278 | j _exit |
---|
279 | nop |
---|
280 | |
---|
281 | /* |
---|
282 | * Syscall: simple and straightforward. |
---|
283 | * Even elegant : nothing's done at all anymore |
---|
284 | */ |
---|
285 | .rdata |
---|
286 | .align 2 |
---|
287 | m5 : .ascii "Syscall : no actions performed anymore\000" |
---|
288 | .text |
---|
289 | .align 2 |
---|
290 | Sys : |
---|
291 | la $4, m5 |
---|
292 | la $2, uputs |
---|
293 | jalr $2 |
---|
294 | nop |
---|
295 | j _ret_sys /* get back to caller */ |
---|
296 | nop |
---|
297 | #endif |
---|
298 | |
---|
299 | /* |
---|
300 | * |
---|
301 | * We just indicate we got a breakpoint |
---|
302 | * This shall be filled on a system per system basis |
---|
303 | * |
---|
304 | */ |
---|
305 | .rdata |
---|
306 | .align 2 |
---|
307 | m6 : .ascii "Breakpoint of code %d!\n\000" |
---|
308 | |
---|
309 | .text |
---|
310 | .align 2 |
---|
311 | Bp : la $4, m6 |
---|
312 | mfc0 $3, $14 /* load EPC*/ |
---|
313 | nop |
---|
314 | nop |
---|
315 | lw $5, ($3) /* load the 'break' instruction*/ |
---|
316 | li $3, 0xF /* filled delayed slot (load a mask)*/ |
---|
317 | srl $5, $5, 16 /* shift it*/ |
---|
318 | and $5, $5, $3 /* and get the code from the insn*/ |
---|
319 | la $2, uputs |
---|
320 | jal $2 /* print the string*/ |
---|
321 | nop |
---|
322 | j _return |
---|
323 | nop |
---|
324 | |
---|
325 | /* |
---|
326 | * |
---|
327 | * Kernel/user violation, or coprocessor unusable. |
---|
328 | * that's pretty fatal, ain't it ? |
---|
329 | * |
---|
330 | */ |
---|
331 | .rdata |
---|
332 | .align 2 |
---|
333 | m7 : .ascii "Unusable Coprocessor %d!\n\000" |
---|
334 | m70: .ascii "Trying to use a kernel instruction in user mode!\n\000" |
---|
335 | |
---|
336 | .text |
---|
337 | .align 2 |
---|
338 | CpU : mfc0 $3, $13 /* load CAUSE*/ |
---|
339 | nop |
---|
340 | li $2, 0x30000000/* */ |
---|
341 | and $2, $2, $3 /* mask to get the CE bits */ |
---|
342 | bnez $2, cun /* not zero, so it is a CUN*/ |
---|
343 | nop /* cannot put a 'la' here,...*/ |
---|
344 | .set reorder |
---|
345 | la $4, m70 /* here, it is a kernel violation*/ |
---|
346 | j C |
---|
347 | .set noreorder |
---|
348 | cun: la $4, m7 |
---|
349 | srl $5, $2, 28 /* LSByte contains now the copro number*/ |
---|
350 | C: la $2, uputs |
---|
351 | jal $2 |
---|
352 | nop |
---|
353 | j _exit |
---|
354 | nop |
---|
355 | |
---|
356 | _exit: li $2, 100000 |
---|
357 | _exit_l: bne $2, $0, _exit_l |
---|
358 | addiu $2, $2, -1 |
---|
359 | c0 00 |
---|
360 | nop |
---|
361 | |
---|
362 | _return : |
---|
363 | lw $2, 2*4($29) |
---|
364 | j tmp |
---|
365 | nop |
---|
366 | _ret_sys: /* Special case for syscall : $2 is not restored */ |
---|
367 | tmp: .set noat |
---|
368 | lw $1, 1*4($29) |
---|
369 | .set at |
---|
370 | lw $3, 3*4($29) |
---|
371 | lw $4, 4*4($29) |
---|
372 | lw $5, 5*4($29) |
---|
373 | lw $6, 6*4($29) |
---|
374 | lw $7, 7*4($29) |
---|
375 | lw $8, 8*4($29) |
---|
376 | lw $9, 9*4($29) |
---|
377 | lw $10, 10*4($29) |
---|
378 | lw $11, 11*4($29) |
---|
379 | lw $12, 12*4($29) |
---|
380 | lw $13, 13*4($29) |
---|
381 | lw $14, 14*4($29) |
---|
382 | lw $15, 15*4($29) |
---|
383 | lw $24, 16*4($29) |
---|
384 | lw $25, 17*4($29) |
---|
385 | lw $29, 18*4($29) |
---|
386 | lw $30, 19*4($29) |
---|
387 | lw $31, 20*4($29) |
---|
388 | |
---|
389 | /* Take care of hi and lo also */ |
---|
390 | lw $26, 22*4($29) |
---|
391 | mthi $26 |
---|
392 | lw $26, 23*4($29) |
---|
393 | mtlo $26 |
---|
394 | |
---|
395 | lw $26, 21*4($29) /* This is the epc of this context */ |
---|
396 | lw $27, 24*4($29) /* This is the offset: 4 excep, 0 int */ |
---|
397 | addu $29, $29, 26*4 /* Stack update : fill lw stall */ |
---|
398 | addu $26, $26, $27 /* Addr for return from excep */ |
---|
399 | j $26 /* Jump back where the exception occured*/ |
---|
400 | rfe /* And restore the original mode*/ |
---|
401 | .set reorder |
---|
402 | .end excep |
---|