1 /* $OpenBSD: locore.S,v 1.18 1998/09/15 10:58:53 pefo Exp $ */
2 /*-
3 * Copyright (c) 1992, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Digital Equipment Corporation and Ralph Campbell.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * Copyright (C) 1989 Digital Equipment Corporation.
34 * Permission to use, copy, modify, and distribute this software and
35 * its documentation for any purpose and without fee is hereby granted,
36 * provided that the above copyright notice appears in all copies.
37 * Digital Equipment Corporation makes no representations about the
38 * suitability of this software for any purpose. It is provided "as is"
39 * without express or implied warranty.
40 *
41 * from: Header: /sprite/src/kernel/mach/ds3100.md/RCS/loMem.s,
42 * v 1.1 89/07/11 17:55:04 nelson Exp SPRITE (DECWRL)
43 * from: Header: /sprite/src/kernel/mach/ds3100.md/RCS/machAsm.s,
44 * v 9.2 90/01/29 18:00:39 shirriff Exp SPRITE (DECWRL)
45 * from: Header: /sprite/src/kernel/vm/ds3100.md/vmPmaxAsm.s,
46 * v 1.1 89/07/10 14:27:41 nelson Exp SPRITE (DECWRL)
47 * from: @(#)locore.s 8.5 (Berkeley) 1/4/94
48 * JNPR: exception.S,v 1.5 2007/01/08 04:58:37 katta
49 * $FreeBSD: releng/8.4/sys/mips/mips/exception.S 215938 2010-11-27 12:26:40Z jchandra $
50 */
51
52 /*
53 * Contains code that is the first executed at boot time plus
54 * assembly language support routines.
55 */
56
57 #include "opt_cputype.h"
58 #include "opt_ddb.h"
59 #include <machine/asm.h>
60 #include <machine/cpu.h>
61 #include <machine/regnum.h>
62 #include <machine/cpuregs.h>
63 #include <machine/pte.h>
64
65 #include "opt_cputype.h"
66
67 #include "assym.s"
68
69 /*
70 * Clear the software-managed bits in a PTE in register pr.
71 */
72 #define CLEAR_PTE_SWBITS(pr) \
73 sll pr, 2 ; \
74 srl pr, 2 # keep bottom 30 bits
75
76 .set noreorder # Noreorder is default style!
77
78 /*
79 * Reasonable limit
80 */
81 #define INTRCNT_COUNT 128
82
83 /* Pointer size and mask for n64 */
84 #if defined(__mips_n64)
85 #define PTRSHIFT 3
86 #define PTRMASK 0xff8
87 #else
88 #define PTRSHIFT 2
89 #define PTRMASK 0xffc
90 #endif
91
92 /*
93 *----------------------------------------------------------------------------
94 *
95 * MipsTLBMiss --
96 *
97 * Vector code for the TLB-miss exception vector 0x80000000.
98 *
99 * This code is copied to the TLB exception vector address to
100 * which the CPU jumps in response to an exception or a TLB miss.
101 * NOTE: This code must be position independent!!!
102 *
103 *
104 */
105 VECTOR(MipsTLBMiss, unknown)
106 .set push
107 .set noat
108 j MipsDoTLBMiss
109 MFC0 k0, MIPS_COP_0_BAD_VADDR # get the fault address
110 .set pop
111 VECTOR_END(MipsTLBMiss)
112
113 /*
114 *----------------------------------------------------------------------------
115 *
116 * MipsDoTLBMiss --
117 *
118 * This is the real TLB Miss Handler code.
119 * 'segbase' points to the base of the segment table for user processes.
120 *
121 * Don't check for invalid pte's here. We load them as well and
122 * let the processor trap to load the correct value after service.
123 *----------------------------------------------------------------------------
124 */
125 .set push
126 .set noat
127 MipsDoTLBMiss:
128 bltz k0, 1f #02: k0<0 -> 1f (kernel fault)
129 PTR_SRL k0, k0, SEGSHIFT - PTRSHIFT #03: k0=seg offset (almost)
130
131 GET_CPU_PCPU(k1)
132 PTR_L k1, PC_SEGBASE(k1)
133 beqz k1, 2f #05: make sure segbase is not null
134 andi k0, k0, PTRMASK #06: k0=seg offset
135 PTR_ADDU k1, k0, k1 #07: k1=seg entry address
136
137 PTR_L k1, 0(k1) #08: k1=seg entry
138 MFC0 k0, MIPS_COP_0_BAD_VADDR #09: k0=bad address (again)
139 beq k1, zero, 2f #0a: ==0 -- no page table
140 #ifdef __mips_n64
141 PTR_SRL k0, PDRSHIFT - PTRSHIFT # k0=VPN
142 andi k0, k0, PTRMASK # k0=pde offset
143 PTR_ADDU k1, k0, k1 # k1=pde entry address
144 PTR_L k1, 0(k1) # k1=pde entry
145 MFC0 k0, MIPS_COP_0_BAD_VADDR # k0=bad address (again)
146 beq k1, zero, 2f # ==0 -- no page table
147 #endif
148 PTR_SRL k0, PAGE_SHIFT - 2 #0b: k0=VPN (aka va>>10)
149 andi k0, k0, 0xff8 #0c: k0=page tab offset
150 PTR_ADDU k1, k1, k0 #0d: k1=pte address
151 lw k0, 0(k1) #0e: k0=lo0 pte
152 lw k1, 4(k1) #0f: k1=lo0 pte
153 CLEAR_PTE_SWBITS(k0)
154 MTC0 k0, MIPS_COP_0_TLB_LO0 #12: lo0 is loaded
155 COP0_SYNC
156 CLEAR_PTE_SWBITS(k1)
157 MTC0 k1, MIPS_COP_0_TLB_LO1 #15: lo1 is loaded
158 COP0_SYNC
159 tlbwr #1a: write to tlb
160 HAZARD_DELAY
161 eret #1f: retUrn from exception
162 1: j MipsTLBMissException #20: kernel exception
163 nop #21: branch delay slot
164 2: j SlowFault #22: no page table present
165 nop #23: branch delay slot
166 .set pop
167
168 /*
169 * This code is copied to the general exception vector address to
170 * handle all execptions except RESET and TLBMiss.
171 * NOTE: This code must be position independent!!!
172 */
173 VECTOR(MipsException, unknown)
174 /*
175 * Find out what mode we came from and jump to the proper handler.
176 */
177 .set noat
178 mfc0 k0, MIPS_COP_0_STATUS # Get the status register
179 mfc0 k1, MIPS_COP_0_CAUSE # Get the cause register value.
180 and k0, k0, SR_KSU_USER # test for user mode
181 # sneaky but the bits are
182 # with us........
183 sll k0, k0, 3 # shift user bit for cause index
184 and k1, k1, MIPS3_CR_EXC_CODE # Mask out the cause bits.
185 or k1, k1, k0 # change index to user table
186 #if defined(__mips_n64)
187 PTR_SLL k1, k1, 1 # shift to get 8-byte offset
188 #endif
189 1:
190 PTR_LA k0, _C_LABEL(machExceptionTable) # get base of the jump table
191 PTR_ADDU k0, k0, k1 # Get the address of the
192 # function entry. Note that
193 # the cause is already
194 # shifted left by 2 bits so
195 # we dont have to shift.
196 PTR_L k0, 0(k0) # Get the function address
197 nop
198 j k0 # Jump to the function.
199 nop
200 .set at
201 VECTOR_END(MipsException)
202
203 /*
204 * We couldn't find a TLB entry.
205 * Find out what mode we came from and call the appropriate handler.
206 */
207 SlowFault:
208 .set noat
209 mfc0 k0, MIPS_COP_0_STATUS
210 nop
211 and k0, k0, SR_KSU_USER
212 bne k0, zero, _C_LABEL(MipsUserGenException)
213 nop
214 .set at
215 /*
216 * Fall though ...
217 */
218
219 /*----------------------------------------------------------------------------
220 *
221 * MipsKernGenException --
222 *
223 * Handle an exception from kernel mode.
224 *
225 * Results:
226 * None.
227 *
228 * Side effects:
229 * None.
230 *
231 *----------------------------------------------------------------------------
232 */
233
234 #define SAVE_REG(reg, offs, base) \
235 REG_S reg, CALLFRAME_SIZ + (SZREG * offs) (base)
236
237 #if defined(CPU_CNMIPS)
238 #define CLEAR_STATUS \
239 mfc0 a0, MIPS_COP_0_STATUS ;\
240 li a2, (MIPS_SR_KX | MIPS_SR_SX | MIPS_SR_UX) ; \
241 or a0, a0, a2 ; \
242 li a2, ~(MIPS_SR_INT_IE | MIPS_SR_EXL | SR_KSU_USER) ; \
243 and a0, a0, a2 ; \
244 mtc0 a0, MIPS_COP_0_STATUS ; \
245 ITLBNOPFIX
246 #elif defined(CPU_RMI)
247 #define CLEAR_STATUS \
248 mfc0 a0, MIPS_COP_0_STATUS ;\
249 li a2, (MIPS_SR_KX | MIPS_SR_UX | MIPS_SR_COP_2_BIT) ; \
250 or a0, a0, a2 ; \
251 li a2, ~(MIPS_SR_INT_IE | MIPS_SR_EXL | SR_KSU_USER) ; \
252 and a0, a0, a2 ; \
253 mtc0 a0, MIPS_COP_0_STATUS ; \
254 ITLBNOPFIX
255 #else
256 #define CLEAR_STATUS \
257 mfc0 a0, MIPS_COP_0_STATUS ;\
258 li a2, ~(MIPS_SR_INT_IE | MIPS_SR_EXL | SR_KSU_USER) ; \
259 and a0, a0, a2 ; \
260 mtc0 a0, MIPS_COP_0_STATUS ; \
261 ITLBNOPFIX
262 #endif
263
264 /*
265 * Save CPU and CP0 register state.
266 *
267 * This is straightforward except for saving the exception program
268 * counter. The ddb backtrace code looks for the first instruction
269 * matching the form "sw ra, (off)sp" to figure out the address of the
270 * calling function. So we must make sure that we save the exception
271 * PC by staging it through 'ra' as opposed to any other register.
272 */
273 #define SAVE_CPU \
274 SAVE_REG(AT, AST, sp) ;\
275 .set at ; \
276 SAVE_REG(v0, V0, sp) ;\
277 SAVE_REG(v1, V1, sp) ;\
278 SAVE_REG(a0, A0, sp) ;\
279 SAVE_REG(a1, A1, sp) ;\
280 SAVE_REG(a2, A2, sp) ;\
281 SAVE_REG(a3, A3, sp) ;\
282 SAVE_REG(t0, T0, sp) ;\
283 SAVE_REG(t1, T1, sp) ;\
284 SAVE_REG(t2, T2, sp) ;\
285 SAVE_REG(t3, T3, sp) ;\
286 SAVE_REG(ta0, TA0, sp) ;\
287 SAVE_REG(ta1, TA1, sp) ;\
288 SAVE_REG(ta2, TA2, sp) ;\
289 SAVE_REG(ta3, TA3, sp) ;\
290 SAVE_REG(t8, T8, sp) ;\
291 SAVE_REG(t9, T9, sp) ;\
292 SAVE_REG(gp, GP, sp) ;\
293 SAVE_REG(s0, S0, sp) ;\
294 SAVE_REG(s1, S1, sp) ;\
295 SAVE_REG(s2, S2, sp) ;\
296 SAVE_REG(s3, S3, sp) ;\
297 SAVE_REG(s4, S4, sp) ;\
298 SAVE_REG(s5, S5, sp) ;\
299 SAVE_REG(s6, S6, sp) ;\
300 SAVE_REG(s7, S7, sp) ;\
301 SAVE_REG(s8, S8, sp) ;\
302 mflo v0 ;\
303 mfhi v1 ;\
304 mfc0 a0, MIPS_COP_0_STATUS ;\
305 mfc0 a1, MIPS_COP_0_CAUSE ;\
306 MFC0 a2, MIPS_COP_0_BAD_VADDR;\
307 MFC0 a3, MIPS_COP_0_EXC_PC ;\
308 SAVE_REG(v0, MULLO, sp) ;\
309 SAVE_REG(v1, MULHI, sp) ;\
310 SAVE_REG(a0, SR, sp) ;\
311 SAVE_REG(a1, CAUSE, sp) ;\
312 SAVE_REG(a2, BADVADDR, sp) ;\
313 move t0, ra ;\
314 move ra, a3 ;\
315 SAVE_REG(ra, PC, sp) ;\
316 move ra, t0 ;\
317 SAVE_REG(ra, RA, sp) ;\
318 PTR_ADDU v0, sp, KERN_EXC_FRAME_SIZE ;\
319 SAVE_REG(v0, SP, sp) ;\
320 CLEAR_STATUS ;\
321 PTR_ADDU a0, sp, CALLFRAME_SIZ ;\
322 ITLBNOPFIX
323
324 #define RESTORE_REG(reg, offs, base) \
325 REG_L reg, CALLFRAME_SIZ + (SZREG * offs) (base)
326
327 #define RESTORE_CPU \
328 CLEAR_STATUS ;\
329 RESTORE_REG(k0, SR, sp) ;\
330 RESTORE_REG(t0, MULLO, sp) ;\
331 RESTORE_REG(t1, MULHI, sp) ;\
332 mtlo t0 ;\
333 mthi t1 ;\
334 MTC0 v0, MIPS_COP_0_EXC_PC ;\
335 .set noat ;\
336 RESTORE_REG(AT, AST, sp) ;\
337 RESTORE_REG(v0, V0, sp) ;\
338 RESTORE_REG(v1, V1, sp) ;\
339 RESTORE_REG(a0, A0, sp) ;\
340 RESTORE_REG(a1, A1, sp) ;\
341 RESTORE_REG(a2, A2, sp) ;\
342 RESTORE_REG(a3, A3, sp) ;\
343 RESTORE_REG(t0, T0, sp) ;\
344 RESTORE_REG(t1, T1, sp) ;\
345 RESTORE_REG(t2, T2, sp) ;\
346 RESTORE_REG(t3, T3, sp) ;\
347 RESTORE_REG(ta0, TA0, sp) ;\
348 RESTORE_REG(ta1, TA1, sp) ;\
349 RESTORE_REG(ta2, TA2, sp) ;\
350 RESTORE_REG(ta3, TA3, sp) ;\
351 RESTORE_REG(t8, T8, sp) ;\
352 RESTORE_REG(t9, T9, sp) ;\
353 RESTORE_REG(s0, S0, sp) ;\
354 RESTORE_REG(s1, S1, sp) ;\
355 RESTORE_REG(s2, S2, sp) ;\
356 RESTORE_REG(s3, S3, sp) ;\
357 RESTORE_REG(s4, S4, sp) ;\
358 RESTORE_REG(s5, S5, sp) ;\
359 RESTORE_REG(s6, S6, sp) ;\
360 RESTORE_REG(s7, S7, sp) ;\
361 RESTORE_REG(s8, S8, sp) ;\
362 RESTORE_REG(gp, GP, sp) ;\
363 RESTORE_REG(ra, RA, sp) ;\
364 PTR_ADDU sp, sp, KERN_EXC_FRAME_SIZE;\
365 mtc0 k0, MIPS_COP_0_STATUS
366
367
368 /*
369 * The kernel exception stack contains 18 saved general registers,
370 * the status register and the multiply lo and high registers.
371 * In addition, we set this up for linkage conventions.
372 */
373 #define KERN_REG_SIZE (NUMSAVEREGS * SZREG)
374 #define KERN_EXC_FRAME_SIZE (CALLFRAME_SIZ + KERN_REG_SIZE + 16)
375
376 NNON_LEAF(MipsKernGenException, KERN_EXC_FRAME_SIZE, ra)
377 .set noat
378 PTR_SUBU sp, sp, KERN_EXC_FRAME_SIZE
379 .mask 0x80000000, (CALLFRAME_RA - KERN_EXC_FRAME_SIZE)
380 /*
381 * Save CPU state, building 'frame'.
382 */
383 SAVE_CPU
384 /*
385 * Call the exception handler. a0 points at the saved frame.
386 */
387 PTR_LA gp, _C_LABEL(_gp)
388 PTR_LA k0, _C_LABEL(trap)
389 jalr k0
390 REG_S a3, CALLFRAME_RA + KERN_REG_SIZE(sp) # for debugging
391
392 /*
393 * Update interrupt mask in saved status register
394 * Some of interrupts could be disabled by
395 * intr filters if interrupts are enabled later
396 * in trap handler
397 */
398 mfc0 a0, MIPS_COP_0_STATUS
399 and a0, a0, MIPS_SR_INT_MASK
400 RESTORE_REG(a1, SR, sp)
401 and a1, a1, ~MIPS_SR_INT_MASK
402 or a1, a1, a0
403 SAVE_REG(a1, SR, sp)
404 RESTORE_CPU # v0 contains the return address.
405 sync
406 eret
407 .set at
408 END(MipsKernGenException)
409
410
411 #define SAVE_U_PCB_REG(reg, offs, base) \
412 REG_S reg, U_PCB_REGS + (SZREG * offs) (base)
413
414 #define RESTORE_U_PCB_REG(reg, offs, base) \
415 REG_L reg, U_PCB_REGS + (SZREG * offs) (base)
416
417 /*----------------------------------------------------------------------------
418 *
419 * MipsUserGenException --
420 *
421 * Handle an exception from user mode.
422 *
423 * Results:
424 * None.
425 *
426 * Side effects:
427 * None.
428 *
429 *----------------------------------------------------------------------------
430 */
431 NNON_LEAF(MipsUserGenException, CALLFRAME_SIZ, ra)
432 .set noat
433 .mask 0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ)
434 /*
435 * Save all of the registers except for the kernel temporaries in u.u_pcb.
436 */
437 GET_CPU_PCPU(k1)
438 PTR_L k1, PC_CURPCB(k1)
439 SAVE_U_PCB_REG(AT, AST, k1)
440 .set at
441 SAVE_U_PCB_REG(v0, V0, k1)
442 SAVE_U_PCB_REG(v1, V1, k1)
443 SAVE_U_PCB_REG(a0, A0, k1)
444 mflo v0
445 SAVE_U_PCB_REG(a1, A1, k1)
446 SAVE_U_PCB_REG(a2, A2, k1)
447 SAVE_U_PCB_REG(a3, A3, k1)
448 SAVE_U_PCB_REG(t0, T0, k1)
449 mfhi v1
450 SAVE_U_PCB_REG(t1, T1, k1)
451 SAVE_U_PCB_REG(t2, T2, k1)
452 SAVE_U_PCB_REG(t3, T3, k1)
453 SAVE_U_PCB_REG(ta0, TA0, k1)
454 mfc0 a0, MIPS_COP_0_STATUS # First arg is the status reg.
455 SAVE_U_PCB_REG(ta1, TA1, k1)
456 SAVE_U_PCB_REG(ta2, TA2, k1)
457 SAVE_U_PCB_REG(ta3, TA3, k1)
458 SAVE_U_PCB_REG(s0, S0, k1)
459 mfc0 a1, MIPS_COP_0_CAUSE # Second arg is the cause reg.
460 SAVE_U_PCB_REG(s1, S1, k1)
461 SAVE_U_PCB_REG(s2, S2, k1)
462 SAVE_U_PCB_REG(s3, S3, k1)
463 SAVE_U_PCB_REG(s4, S4, k1)
464 MFC0 a2, MIPS_COP_0_BAD_VADDR # Third arg is the fault addr
465 SAVE_U_PCB_REG(s5, S5, k1)
466 SAVE_U_PCB_REG(s6, S6, k1)
467 SAVE_U_PCB_REG(s7, S7, k1)
468 SAVE_U_PCB_REG(t8, T8, k1)
469 MFC0 a3, MIPS_COP_0_EXC_PC # Fourth arg is the pc.
470 SAVE_U_PCB_REG(t9, T9, k1)
471 SAVE_U_PCB_REG(gp, GP, k1)
472 SAVE_U_PCB_REG(sp, SP, k1)
473 SAVE_U_PCB_REG(s8, S8, k1)
474 PTR_SUBU sp, k1, CALLFRAME_SIZ # switch to kernel SP
475 SAVE_U_PCB_REG(ra, RA, k1)
476 SAVE_U_PCB_REG(v0, MULLO, k1)
477 SAVE_U_PCB_REG(v1, MULHI, k1)
478 SAVE_U_PCB_REG(a0, SR, k1)
479 SAVE_U_PCB_REG(a1, CAUSE, k1)
480 SAVE_U_PCB_REG(a2, BADVADDR, k1)
481 SAVE_U_PCB_REG(a3, PC, k1)
482 REG_S a3, CALLFRAME_RA(sp) # for debugging
483 PTR_LA gp, _C_LABEL(_gp) # switch to kernel GP
484 # Turn off fpu and enter kernel mode
485 and t0, a0, ~(MIPS_SR_COP_1_BIT | MIPS_SR_EXL | MIPS3_SR_KSU_MASK | MIPS_SR_INT_IE)
486 #if defined(CPU_CNMIPS)
487 or t0, t0, (MIPS_SR_KX | MIPS_SR_SX | MIPS_SR_UX | MIPS_SR_PX)
488 #elif defined(CPU_RMI)
489 or t0, t0, (MIPS_SR_KX | MIPS_SR_UX | MIPS_SR_COP_2_BIT)
490 #endif
491 mtc0 t0, MIPS_COP_0_STATUS
492 PTR_ADDU a0, k1, U_PCB_REGS
493 ITLBNOPFIX
494
495 /*
496 * Call the exception handler.
497 */
498 PTR_LA k0, _C_LABEL(trap)
499 jalr k0
500 nop
501
502 /*
503 * Restore user registers and return.
504 * First disable interrupts and set exeption level.
505 */
506 DO_AST
507
508 CLEAR_STATUS
509
510 /*
511 * The use of k1 for storing the PCB pointer must be done only
512 * after interrupts are disabled. Otherwise it will get overwritten
513 * by the interrupt code.
514 */
515 GET_CPU_PCPU(k1)
516 PTR_L k1, PC_CURPCB(k1)
517
518 /*
519 * Update interrupt mask in saved status register
520 * Some of interrupts could be enabled by ithread
521 * scheduled by ast()
522 */
523 mfc0 a0, MIPS_COP_0_STATUS
524 and a0, a0, MIPS_SR_INT_MASK
525 RESTORE_U_PCB_REG(a1, SR, k1)
526 and a1, a1, ~MIPS_SR_INT_MASK
527 or a1, a1, a0
528 SAVE_U_PCB_REG(a1, SR, k1)
529
530 RESTORE_U_PCB_REG(t0, MULLO, k1)
531 RESTORE_U_PCB_REG(t1, MULHI, k1)
532 mtlo t0
533 mthi t1
534 RESTORE_U_PCB_REG(a0, PC, k1)
535 RESTORE_U_PCB_REG(v0, V0, k1)
536 MTC0 a0, MIPS_COP_0_EXC_PC # set return address
537 RESTORE_U_PCB_REG(v1, V1, k1)
538 RESTORE_U_PCB_REG(a0, A0, k1)
539 RESTORE_U_PCB_REG(a1, A1, k1)
540 RESTORE_U_PCB_REG(a2, A2, k1)
541 RESTORE_U_PCB_REG(a3, A3, k1)
542 RESTORE_U_PCB_REG(t0, T0, k1)
543 RESTORE_U_PCB_REG(t1, T1, k1)
544 RESTORE_U_PCB_REG(t2, T2, k1)
545 RESTORE_U_PCB_REG(t3, T3, k1)
546 RESTORE_U_PCB_REG(ta0, TA0, k1)
547 RESTORE_U_PCB_REG(ta1, TA1, k1)
548 RESTORE_U_PCB_REG(ta2, TA2, k1)
549 RESTORE_U_PCB_REG(ta3, TA3, k1)
550 RESTORE_U_PCB_REG(s0, S0, k1)
551 RESTORE_U_PCB_REG(s1, S1, k1)
552 RESTORE_U_PCB_REG(s2, S2, k1)
553 RESTORE_U_PCB_REG(s3, S3, k1)
554 RESTORE_U_PCB_REG(s4, S4, k1)
555 RESTORE_U_PCB_REG(s5, S5, k1)
556 RESTORE_U_PCB_REG(s6, S6, k1)
557 RESTORE_U_PCB_REG(s7, S7, k1)
558 RESTORE_U_PCB_REG(t8, T8, k1)
559 RESTORE_U_PCB_REG(t9, T9, k1)
560 RESTORE_U_PCB_REG(gp, GP, k1)
561 RESTORE_U_PCB_REG(sp, SP, k1)
562 RESTORE_U_PCB_REG(k0, SR, k1)
563 RESTORE_U_PCB_REG(s8, S8, k1)
564 RESTORE_U_PCB_REG(ra, RA, k1)
565 .set noat
566 RESTORE_U_PCB_REG(AT, AST, k1)
567
568 mtc0 k0, MIPS_COP_0_STATUS # still exception level
569 ITLBNOPFIX
570 sync
571 eret
572 .set at
573 END(MipsUserGenException)
574
575 /*----------------------------------------------------------------------------
576 *
577 * MipsKernIntr --
578 *
579 * Handle an interrupt from kernel mode.
580 * Interrupts use the standard kernel stack.
581 * switch_exit sets up a kernel stack after exit so interrupts won't fail.
582 *
583 * Results:
584 * None.
585 *
586 * Side effects:
587 * None.
588 *
589 *----------------------------------------------------------------------------
590 */
591
592 NNON_LEAF(MipsKernIntr, KERN_EXC_FRAME_SIZE, ra)
593 .set noat
594 PTR_SUBU sp, sp, KERN_EXC_FRAME_SIZE
595 .mask 0x80000000, (CALLFRAME_RA - KERN_EXC_FRAME_SIZE)
596 /*
597 * Save CPU state, building 'frame'.
598 */
599 SAVE_CPU
600 /*
601 * Call the interrupt handler. a0 points at the saved frame.
602 */
603 PTR_LA gp, _C_LABEL(_gp)
604 PTR_LA k0, _C_LABEL(cpu_intr)
605 jalr k0
606 REG_S a3, CALLFRAME_RA + KERN_REG_SIZE(sp) # for debugging
607
608 /*
609 * Update interrupt mask in saved status register
610 * Some of interrupts could be disabled by
611 * intr filters if interrupts are enabled later
612 * in trap handler
613 */
614 mfc0 a0, MIPS_COP_0_STATUS
615 and a0, a0, MIPS_SR_INT_MASK
616 RESTORE_REG(a1, SR, sp)
617 and a1, a1, ~MIPS_SR_INT_MASK
618 or a1, a1, a0
619 SAVE_REG(a1, SR, sp)
620 REG_L v0, CALLFRAME_RA + KERN_REG_SIZE(sp)
621 RESTORE_CPU # v0 contains the return address.
622 sync
623 eret
624 .set at
625 END(MipsKernIntr)
626
627 /*----------------------------------------------------------------------------
628 *
629 * MipsUserIntr --
630 *
631 * Handle an interrupt from user mode.
632 * Note: we save minimal state in the u.u_pcb struct and use the standard
633 * kernel stack since there has to be a u page if we came from user mode.
634 * If there is a pending software interrupt, then save the remaining state
635 * and call softintr(). This is all because if we call switch() inside
636 * interrupt(), not all the user registers have been saved in u.u_pcb.
637 *
638 * Results:
639 * None.
640 *
641 * Side effects:
642 * None.
643 *
644 *----------------------------------------------------------------------------
645 */
646 NNON_LEAF(MipsUserIntr, CALLFRAME_SIZ, ra)
647 .set noat
648 .mask 0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ)
649 /*
650 * Save the relevant user registers into the u.u_pcb struct.
651 * We don't need to save s0 - s8 because the compiler does it for us.
652 */
653 GET_CPU_PCPU(k1)
654 PTR_L k1, PC_CURPCB(k1)
655 SAVE_U_PCB_REG(AT, AST, k1)
656 .set at
657 SAVE_U_PCB_REG(v0, V0, k1)
658 SAVE_U_PCB_REG(v1, V1, k1)
659 SAVE_U_PCB_REG(a0, A0, k1)
660 SAVE_U_PCB_REG(a1, A1, k1)
661 SAVE_U_PCB_REG(a2, A2, k1)
662 SAVE_U_PCB_REG(a3, A3, k1)
663 SAVE_U_PCB_REG(t0, T0, k1)
664 SAVE_U_PCB_REG(t1, T1, k1)
665 SAVE_U_PCB_REG(t2, T2, k1)
666 SAVE_U_PCB_REG(t3, T3, k1)
667 SAVE_U_PCB_REG(ta0, TA0, k1)
668 SAVE_U_PCB_REG(ta1, TA1, k1)
669 SAVE_U_PCB_REG(ta2, TA2, k1)
670 SAVE_U_PCB_REG(ta3, TA3, k1)
671 SAVE_U_PCB_REG(t8, T8, k1)
672 SAVE_U_PCB_REG(t9, T9, k1)
673 SAVE_U_PCB_REG(gp, GP, k1)
674 SAVE_U_PCB_REG(sp, SP, k1)
675 SAVE_U_PCB_REG(ra, RA, k1)
676 /*
677 * save remaining user state in u.u_pcb.
678 */
679 SAVE_U_PCB_REG(s0, S0, k1)
680 SAVE_U_PCB_REG(s1, S1, k1)
681 SAVE_U_PCB_REG(s2, S2, k1)
682 SAVE_U_PCB_REG(s3, S3, k1)
683 SAVE_U_PCB_REG(s4, S4, k1)
684 SAVE_U_PCB_REG(s5, S5, k1)
685 SAVE_U_PCB_REG(s6, S6, k1)
686 SAVE_U_PCB_REG(s7, S7, k1)
687 SAVE_U_PCB_REG(s8, S8, k1)
688
689 mflo v0 # get lo/hi late to avoid stall
690 mfhi v1
691 mfc0 a0, MIPS_COP_0_STATUS
692 mfc0 a1, MIPS_COP_0_CAUSE
693 MFC0 a3, MIPS_COP_0_EXC_PC
694 SAVE_U_PCB_REG(v0, MULLO, k1)
695 SAVE_U_PCB_REG(v1, MULHI, k1)
696 SAVE_U_PCB_REG(a0, SR, k1)
697 SAVE_U_PCB_REG(a1, CAUSE, k1)
698 SAVE_U_PCB_REG(a3, PC, k1) # PC in a3, note used later!
699 PTR_SUBU sp, k1, CALLFRAME_SIZ # switch to kernel SP
700 PTR_LA gp, _C_LABEL(_gp) # switch to kernel GP
701
702 # Turn off fpu, disable interrupts, set kernel mode kernel mode, clear exception level.
703 and t0, a0, ~(MIPS_SR_COP_1_BIT | MIPS_SR_EXL | MIPS_SR_INT_IE | MIPS3_SR_KSU_MASK)
704 #ifdef CPU_CNMIPS
705 or t0, t0, (MIPS_SR_KX | MIPS_SR_SX | MIPS_SR_UX | MIPS_SR_PX)
706 #elif defined(CPU_RMI)
707 or t0, t0, (MIPS_SR_KX | MIPS_SR_UX | MIPS_SR_COP_2_BIT)
708 #endif
709 mtc0 t0, MIPS_COP_0_STATUS
710 ITLBNOPFIX
711 PTR_ADDU a0, k1, U_PCB_REGS
712 /*
713 * Call the interrupt handler.
714 */
715 PTR_LA k0, _C_LABEL(cpu_intr)
716 jalr k0
717 REG_S a3, CALLFRAME_RA(sp) # for debugging
718
719 /*
720 * Enable interrupts before doing ast().
721 *
722 * On SMP kernels the AST processing might trigger IPI to other processors.
723 * If that processor is also doing AST processing with interrupts disabled
724 * then we may deadlock.
725 */
726 mfc0 a0, MIPS_COP_0_STATUS
727 or a0, a0, MIPS_SR_INT_IE
728 mtc0 a0, MIPS_COP_0_STATUS
729 ITLBNOPFIX
730
731 /*
732 * DO_AST enabled interrupts
733 */
734 DO_AST
735
736 /*
737 * Restore user registers and return.
738 */
739 CLEAR_STATUS
740
741 GET_CPU_PCPU(k1)
742 PTR_L k1, PC_CURPCB(k1)
743
744 /*
745 * Update interrupt mask in saved status register
746 * Some of interrupts could be disabled by
747 * intr filters
748 */
749 mfc0 a0, MIPS_COP_0_STATUS
750 and a0, a0, MIPS_SR_INT_MASK
751 RESTORE_U_PCB_REG(a1, SR, k1)
752 and a1, a1, ~MIPS_SR_INT_MASK
753 or a1, a1, a0
754 SAVE_U_PCB_REG(a1, SR, k1)
755
756 RESTORE_U_PCB_REG(s0, S0, k1)
757 RESTORE_U_PCB_REG(s1, S1, k1)
758 RESTORE_U_PCB_REG(s2, S2, k1)
759 RESTORE_U_PCB_REG(s3, S3, k1)
760 RESTORE_U_PCB_REG(s4, S4, k1)
761 RESTORE_U_PCB_REG(s5, S5, k1)
762 RESTORE_U_PCB_REG(s6, S6, k1)
763 RESTORE_U_PCB_REG(s7, S7, k1)
764 RESTORE_U_PCB_REG(s8, S8, k1)
765 RESTORE_U_PCB_REG(t0, MULLO, k1)
766 RESTORE_U_PCB_REG(t1, MULHI, k1)
767 RESTORE_U_PCB_REG(t2, PC, k1)
768 mtlo t0
769 mthi t1
770 MTC0 t2, MIPS_COP_0_EXC_PC # set return address
771 RESTORE_U_PCB_REG(v0, V0, k1)
772 RESTORE_U_PCB_REG(v1, V1, k1)
773 RESTORE_U_PCB_REG(a0, A0, k1)
774 RESTORE_U_PCB_REG(a1, A1, k1)
775 RESTORE_U_PCB_REG(a2, A2, k1)
776 RESTORE_U_PCB_REG(a3, A3, k1)
777 RESTORE_U_PCB_REG(t0, T0, k1)
778 RESTORE_U_PCB_REG(t1, T1, k1)
779 RESTORE_U_PCB_REG(t2, T2, k1)
780 RESTORE_U_PCB_REG(t3, T3, k1)
781 RESTORE_U_PCB_REG(ta0, TA0, k1)
782 RESTORE_U_PCB_REG(ta1, TA1, k1)
783 RESTORE_U_PCB_REG(ta2, TA2, k1)
784 RESTORE_U_PCB_REG(ta3, TA3, k1)
785 RESTORE_U_PCB_REG(t8, T8, k1)
786 RESTORE_U_PCB_REG(t9, T9, k1)
787 RESTORE_U_PCB_REG(gp, GP, k1)
788 RESTORE_U_PCB_REG(k0, SR, k1)
789 RESTORE_U_PCB_REG(sp, SP, k1)
790 RESTORE_U_PCB_REG(ra, RA, k1)
791 .set noat
792 RESTORE_U_PCB_REG(AT, AST, k1)
793
794 mtc0 k0, MIPS_COP_0_STATUS # SR with EXL set.
795 ITLBNOPFIX
796 sync
797 eret
798 .set at
799 END(MipsUserIntr)
800
801 NLEAF(MipsTLBInvalidException)
802 .set push
803 .set noat
804 .set noreorder
805
806 MFC0 k0, MIPS_COP_0_BAD_VADDR
807 PTR_LI k1, VM_MAXUSER_ADDRESS
808 sltu k1, k0, k1
809 bnez k1, 1f
810 nop
811
812 /* Kernel address. */
813 lui k1, %hi(kernel_segmap) # k1=hi of segbase
814 b 2f
815 PTR_L k1, %lo(kernel_segmap)(k1) # k1=segment tab base
816
817 1: /* User address. */
818 GET_CPU_PCPU(k1)
819 PTR_L k1, PC_SEGBASE(k1)
820
821 2: /* Validate page directory pointer. */
822 beqz k1, 3f
823 nop
824
825 PTR_SRL k0, SEGSHIFT - PTRSHIFT # k0=seg offset (almost)
826 beq k1, zero, MipsKernGenException # ==0 -- no seg tab
827 andi k0, k0, PTRMASK # k0=seg offset
828 PTR_ADDU k1, k0, k1 # k1=seg entry address
829 PTR_L k1, 0(k1) # k1=seg entry
830
831 /* Validate page table pointer. */
832 beqz k1, 3f
833 nop
834
835 #ifdef __mips_n64
836 MFC0 k0, MIPS_COP_0_BAD_VADDR
837 PTR_SRL k0, PDRSHIFT - PTRSHIFT # k0=pde offset (almost)
838 beq k1, zero, MipsKernGenException # ==0 -- no pde tab
839 andi k0, k0, PTRMASK # k0=pde offset
840 PTR_ADDU k1, k0, k1 # k1=pde entry address
841 PTR_L k1, 0(k1) # k1=pde entry
842
843 /* Validate pde table pointer. */
844 beqz k1, 3f
845 nop
846 #endif
847 MFC0 k0, MIPS_COP_0_BAD_VADDR # k0=bad address (again)
848 PTR_SRL k0, PAGE_SHIFT - 2 # k0=VPN
849 andi k0, k0, 0xffc # k0=page tab offset
850 PTR_ADDU k1, k1, k0 # k1=pte address
851 lw k0, 0(k1) # k0=this PTE
852
853 /* Validate page table entry. */
854 andi k0, PTE_V
855 beqz k0, 3f
856 nop
857
858 /* Check whether this is an even or odd entry. */
859 andi k0, k1, 4
860 bnez k0, odd_page
861 nop
862
863 lw k0, 0(k1)
864 lw k1, 4(k1)
865 CLEAR_PTE_SWBITS(k0)
866 MTC0 k0, MIPS_COP_0_TLB_LO0
867 COP0_SYNC
868 CLEAR_PTE_SWBITS(k1)
869 MTC0 k1, MIPS_COP_0_TLB_LO1
870 COP0_SYNC
871
872 b tlb_insert_entry
873 nop
874
875 odd_page:
876 lw k0, -4(k1)
877 lw k1, 0(k1)
878 CLEAR_PTE_SWBITS(k0)
879 MTC0 k0, MIPS_COP_0_TLB_LO0
880 COP0_SYNC
881 CLEAR_PTE_SWBITS(k1)
882 MTC0 k1, MIPS_COP_0_TLB_LO1
883 COP0_SYNC
884
885 tlb_insert_entry:
886 tlbp
887 HAZARD_DELAY
888 mfc0 k0, MIPS_COP_0_TLB_INDEX
889 bltz k0, tlb_insert_random
890 nop
891 tlbwi
892 eret
893 ssnop
894
895 tlb_insert_random:
896 tlbwr
897 eret
898 ssnop
899
900 3:
901 /*
902 * Branch to the comprehensive exception processing.
903 */
904 mfc0 k1, MIPS_COP_0_STATUS
905 andi k1, k1, SR_KSU_USER
906 bnez k1, _C_LABEL(MipsUserGenException)
907 nop
908
909 /*
910 * Check for kernel stack overflow.
911 */
912 GET_CPU_PCPU(k1)
913 PTR_L k0, PC_CURTHREAD(k1)
914 PTR_L k0, TD_KSTACK(k0)
915 sltu k0, k0, sp
916 bnez k0, _C_LABEL(MipsKernGenException)
917 nop
918
919 /*
920 * Kernel stack overflow.
921 *
922 * Move to a valid stack before we call panic. We use the boot stack
923 * for this purpose.
924 */
925 GET_CPU_PCPU(k1)
926 lw k1, PC_CPUID(k1)
927 sll k1, k1, PAGE_SHIFT + 1
928
929 PTR_LA k0, _C_LABEL(pcpu_space)
930 PTR_ADDU k0, PAGE_SIZE * 2
931 PTR_ADDU k0, k0, k1
932
933 /*
934 * Stash the original value of 'sp' so we can update trapframe later.
935 * We assume that SAVE_CPU does not trash 'k1'.
936 */
937 move k1, sp
938
939 move sp, k0
940 PTR_SUBU sp, sp, KERN_EXC_FRAME_SIZE
941
942 move k0, ra
943 move ra, zero
944 REG_S ra, CALLFRAME_RA(sp) /* stop the ddb backtrace right here */
945 REG_S zero, CALLFRAME_SP(sp)
946 move ra, k0
947
948 SAVE_CPU
949
950 /*
951 * Now restore the value of 'sp' at the time of the tlb exception in
952 * the trapframe.
953 */
954 SAVE_REG(k1, SP, sp)
955
956 /*
957 * Squelch any more overflow checks by setting the stack base to 0.
958 */
959 GET_CPU_PCPU(k1)
960 PTR_L k0, PC_CURTHREAD(k1)
961 PTR_S zero, TD_KSTACK(k0)
962
963 move a1, a0
964 PANIC("kernel stack overflow - trapframe at %p")
965
966 /*
967 * This nop is necessary so that the 'ra' remains within the bounds
968 * of this handler. Otherwise the ddb backtrace code will think that
969 * the panic() was called from MipsTLBMissException.
970 */
971 nop
972
973 .set pop
974 END(MipsTLBInvalidException)
975
976 /*----------------------------------------------------------------------------
977 *
978 * MipsTLBMissException --
979 *
980 * Handle a TLB miss exception from kernel mode in kernel space.
981 * The BaddVAddr, Context, and EntryHi registers contain the failed
982 * virtual address.
983 *
984 * Results:
985 * None.
986 *
987 * Side effects:
988 * None.
989 *
990 *----------------------------------------------------------------------------
991 */
992 NLEAF(MipsTLBMissException)
993 .set noat
994 MFC0 k0, MIPS_COP_0_BAD_VADDR # k0=bad address
995 PTR_LI k1, VM_MAX_KERNEL_ADDRESS # check fault address against
996 sltu k1, k1, k0 # upper bound of kernel_segmap
997 bnez k1, MipsKernGenException # out of bound
998 lui k1, %hi(kernel_segmap) # k1=hi of segbase
999 PTR_SRL k0, SEGSHIFT - PTRSHIFT # k0=seg offset (almost)
1000 PTR_L k1, %lo(kernel_segmap)(k1) # k1=segment tab base
1001 beq k1, zero, MipsKernGenException # ==0 -- no seg tab
1002 andi k0, k0, PTRMASK # k0=seg offset
1003 PTR_ADDU k1, k0, k1 # k1=seg entry address
1004 PTR_L k1, 0(k1) # k1=seg entry
1005 MFC0 k0, MIPS_COP_0_BAD_VADDR # k0=bad address (again)
1006 beq k1, zero, MipsKernGenException # ==0 -- no page table
1007 #ifdef __mips_n64
1008 PTR_SRL k0, PDRSHIFT - PTRSHIFT # k0=VPN
1009 andi k0, k0, PTRMASK # k0=pde offset
1010 PTR_ADDU k1, k0, k1 # k1=pde entry address
1011 PTR_L k1, 0(k1) # k1=pde entry
1012 MFC0 k0, MIPS_COP_0_BAD_VADDR # k0=bad address (again)
1013 beq k1, zero, MipsKernGenException # ==0 -- no page table
1014 #endif
1015 PTR_SRL k0, PAGE_SHIFT - 2 # k0=VPN
1016 andi k0, k0, 0xff8 # k0=page tab offset
1017 PTR_ADDU k1, k1, k0 # k1=pte address
1018 lw k0, 0(k1) # k0=lo0 pte
1019 lw k1, 4(k1) # k1=lo1 pte
1020 CLEAR_PTE_SWBITS(k0)
1021 MTC0 k0, MIPS_COP_0_TLB_LO0 # lo0 is loaded
1022 COP0_SYNC
1023 CLEAR_PTE_SWBITS(k1)
1024 MTC0 k1, MIPS_COP_0_TLB_LO1 # lo1 is loaded
1025 COP0_SYNC
1026 tlbwr # write to tlb
1027 HAZARD_DELAY
1028 eret # return from exception
1029 .set at
1030 END(MipsTLBMissException)
1031
1032 /*----------------------------------------------------------------------------
1033 *
1034 * MipsFPTrap --
1035 *
1036 * Handle a floating point Trap.
1037 *
1038 * MipsFPTrap(statusReg, causeReg, pc)
1039 * unsigned statusReg;
1040 * unsigned causeReg;
1041 * unsigned pc;
1042 *
1043 * Results:
1044 * None.
1045 *
1046 * Side effects:
1047 * None.
1048 *
1049 *----------------------------------------------------------------------------
1050 */
1051 NON_LEAF(MipsFPTrap, CALLFRAME_SIZ, ra)
1052 PTR_SUBU sp, sp, CALLFRAME_SIZ
1053 mfc0 t0, MIPS_COP_0_STATUS
1054 REG_S ra, CALLFRAME_RA(sp)
1055 .mask 0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ)
1056
1057 or t1, t0, MIPS_SR_COP_1_BIT
1058 mtc0 t1, MIPS_COP_0_STATUS
1059 ITLBNOPFIX
1060 cfc1 t1, MIPS_FPU_CSR # stall til FP done
1061 cfc1 t1, MIPS_FPU_CSR # now get status
1062 nop
1063 sll t2, t1, (31 - 17) # unimplemented operation?
1064 bgez t2, 3f # no, normal trap
1065 nop
1066 /*
1067 * We got an unimplemented operation trap so
1068 * fetch the instruction, compute the next PC and emulate the instruction.
1069 */
1070 bgez a1, 1f # Check the branch delay bit.
1071 nop
1072 /*
1073 * The instruction is in the branch delay slot so the branch will have to
1074 * be emulated to get the resulting PC.
1075 */
1076 PTR_S a2, CALLFRAME_SIZ + 8(sp)
1077 GET_CPU_PCPU(a0)
1078 #mips64 unsafe?
1079 PTR_L a0, PC_CURPCB(a0)
1080 PTR_ADDU a0, a0, U_PCB_REGS # first arg is ptr to CPU registers
1081 move a1, a2 # second arg is instruction PC
1082 move a2, t1 # third arg is floating point CSR
1083 PTR_LA t3, _C_LABEL(MipsEmulateBranch) # compute PC after branch
1084 jalr t3 # compute PC after branch
1085 move a3, zero # fourth arg is FALSE
1086 /*
1087 * Now load the floating-point instruction in the branch delay slot
1088 * to be emulated.
1089 */
1090 PTR_L a2, CALLFRAME_SIZ + 8(sp) # restore EXC pc
1091 b 2f
1092 lw a0, 4(a2) # a0 = coproc instruction
1093 /*
1094 * This is not in the branch delay slot so calculate the resulting
1095 * PC (epc + 4) into v0 and continue to MipsEmulateFP().
1096 */
1097 1:
1098 lw a0, 0(a2) # a0 = coproc instruction
1099 #xxx mips64 unsafe?
1100 PTR_ADDU v0, a2, 4 # v0 = next pc
1101 2:
1102 GET_CPU_PCPU(t2)
1103 PTR_L t2, PC_CURPCB(t2)
1104 SAVE_U_PCB_REG(v0, PC, t2) # save new pc
1105 /*
1106 * Check to see if the instruction to be emulated is a floating-point
1107 * instruction.
1108 */
1109 srl a3, a0, MIPS_OPCODE_SHIFT
1110 beq a3, MIPS_OPCODE_C1, 4f # this should never fail
1111 nop
1112 /*
1113 * Send a floating point exception signal to the current process.
1114 */
1115 3:
1116 GET_CPU_PCPU(a0)
1117 PTR_L a0, PC_CURTHREAD(a0) # get current thread
1118 cfc1 a2, MIPS_FPU_CSR # code = FP execptions
1119 ctc1 zero, MIPS_FPU_CSR # Clear exceptions
1120 PTR_LA t3, _C_LABEL(trapsignal)
1121 jalr t3
1122 li a1, SIGFPE
1123 b FPReturn
1124 nop
1125
1126 /*
1127 * Finally, we can call MipsEmulateFP() where a0 is the instruction to emulate.
1128 */
1129 4:
1130 PTR_LA t3, _C_LABEL(MipsEmulateFP)
1131 jalr t3
1132 nop
1133
1134 /*
1135 * Turn off the floating point coprocessor and return.
1136 */
1137 FPReturn:
1138 mfc0 t0, MIPS_COP_0_STATUS
1139 PTR_L ra, CALLFRAME_RA(sp)
1140 and t0, t0, ~MIPS_SR_COP_1_BIT
1141 mtc0 t0, MIPS_COP_0_STATUS
1142 ITLBNOPFIX
1143 j ra
1144 PTR_ADDU sp, sp, CALLFRAME_SIZ
1145 END(MipsFPTrap)
1146
1147 /*
1148 * Interrupt counters for vmstat.
1149 */
1150 .data
1151 .globl intrcnt
1152 .globl eintrcnt
1153 .globl intrnames
1154 .globl eintrnames
1155 intrnames:
1156 .space INTRCNT_COUNT * (MAXCOMLEN + 1) * 2
1157 eintrnames:
1158 .align 4
1159 intrcnt:
1160 .space INTRCNT_COUNT * 4 * 2
1161 eintrcnt:
1162
1163
1164 /*
1165 * Vector to real handler in KSEG1.
1166 */
1167 .text
1168 VECTOR(MipsCache, unknown)
1169 PTR_LA k0, _C_LABEL(MipsCacheException)
1170 li k1, MIPS_KSEG0_PHYS_MASK
1171 and k0, k1
1172 PTR_LI k1, MIPS_KSEG1_START
1173 or k0, k1
1174 j k0
1175 nop
1176 VECTOR_END(MipsCache)
1177
1178 .set at
1179
1180
1181 /*
1182 * Panic on cache errors. A lot more could be done to recover
1183 * from some types of errors but it is tricky.
1184 */
1185 NESTED_NOPROFILE(MipsCacheException, KERN_EXC_FRAME_SIZE, ra)
1186 .set noat
1187 .mask 0x80000000, -4
1188 PTR_LA k0, _C_LABEL(panic) # return to panic
1189 PTR_LA a0, 9f # panicstr
1190 MFC0 a1, MIPS_COP_0_ERROR_PC
1191 mfc0 a2, MIPS_COP_0_CACHE_ERR # 3rd arg cache error
1192
1193 MTC0 k0, MIPS_COP_0_ERROR_PC # set return address
1194
1195 mfc0 k0, MIPS_COP_0_STATUS # restore status
1196 li k1, MIPS_SR_DIAG_PE # ignore further errors
1197 or k0, k1
1198 mtc0 k0, MIPS_COP_0_STATUS # restore status
1199 COP0_SYNC
1200
1201 eret
1202
1203 MSG("cache error @ EPC 0x%x CachErr 0x%x");
1204 .set at
1205 END(MipsCacheException)
Cache object: 7e3328ac412cd9d9a7ceab749799041f
|