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