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