1 /* $OpenBSD: locore.S,v 1.18 1998/09/15 10:58:53 pefo Exp $ */
3 * Copyright (c) 1992, 1993
4 * The Regents of the University of California. All rights reserved.
6 * This code is derived from software contributed to Berkeley by
7 * Digital Equipment Corporation and Ralph Campbell.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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.
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
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.
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
53 * Contains code that is the first executed at boot time plus
54 * assembly language support routines.
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 #include <machine/pcb.h>
68 .set noreorder # Noreorder is default style!
72 .globl dtrace_invop_jump_addr
74 .type dtrace_invop_jump_addr, @object
75 .size dtrace_invop_jump_addr, 8
76 dtrace_invop_jump_addr:
79 .globl dtrace_invop_calltrap_addr
81 .type dtrace_invop_calltrap_addr, @object
82 .size dtrace_invop_calltrap_addr, 8
83 dtrace_invop_calltrap_addr:
93 #define INTRCNT_COUNT 256
97 *----------------------------------------------------------------------------
101 * Vector code for the TLB-miss exception vector 0x80000000.
103 * This code is copied to the TLB exception vector address to
104 * which the CPU jumps in response to an exception or a TLB miss.
105 * NOTE: This code must be position independent!!!
109 VECTOR(MipsTLBMiss, unknown)
113 MFC0 k0, MIPS_COP_0_BAD_VADDR # get the fault address
115 VECTOR_END(MipsTLBMiss)
118 *----------------------------------------------------------------------------
122 * This is the real TLB Miss Handler code.
123 * 'segbase' points to the base of the segment table for user processes.
125 * Don't check for invalid pte's here. We load them as well and
126 * let the processor trap to load the correct value after service.
127 *----------------------------------------------------------------------------
132 bltz k0, 1f #02: k0<0 -> 1f (kernel fault)
133 PTR_SRL k0, k0, SEGSHIFT - PTRSHIFT #03: k0=seg offset (almost)
136 PTR_L k1, PC_SEGBASE(k1)
137 beqz k1, 2f #05: make sure segbase is not null
138 andi k0, k0, PDEPTRMASK #06: k0=seg offset
139 PTR_ADDU k1, k0, k1 #07: k1=seg entry address
141 PTR_L k1, 0(k1) #08: k1=seg entry
142 MFC0 k0, MIPS_COP_0_BAD_VADDR #09: k0=bad address (again)
143 beq k1, zero, 2f #0a: ==0 -- no page table
145 PTR_SRL k0, PDRSHIFT - PTRSHIFT # k0=VPN
146 andi k0, k0, PDEPTRMASK # k0=pde offset
147 PTR_ADDU k1, k0, k1 # k1=pde entry address
148 PTR_L k1, 0(k1) # k1=pde entry
149 MFC0 k0, MIPS_COP_0_BAD_VADDR # k0=bad address (again)
150 beq k1, zero, 2f # ==0 -- no page table
152 PTR_SRL k0, PAGE_SHIFT - PTESHIFT #0b: k0=VPN (aka va>>10)
153 andi k0, k0, PTE2MASK #0c: k0=page tab offset
154 PTR_ADDU k1, k1, k0 #0d: k1=pte address
155 PTE_L k0, 0(k1) #0e: k0=lo0 pte
156 PTE_L k1, PTESIZE(k1) #0f: k1=lo0 pte
158 PTE_MTC0 k0, MIPS_COP_0_TLB_LO0 #12: lo0 is loaded
161 PTE_MTC0 k1, MIPS_COP_0_TLB_LO1 #15: lo1 is loaded
163 tlbwr #1a: write to tlb
165 eret #1f: retUrn from exception
166 1: j MipsTLBMissException #20: kernel exception
167 nop #21: branch delay slot
168 2: j SlowFault #22: no page table present
169 nop #23: branch delay slot
173 * This code is copied to the general exception vector address to
174 * handle all execptions except RESET and TLBMiss.
175 * NOTE: This code must be position independent!!!
177 VECTOR(MipsException, unknown)
179 * Find out what mode we came from and jump to the proper handler.
182 mfc0 k0, MIPS_COP_0_STATUS # Get the status register
183 mfc0 k1, MIPS_COP_0_CAUSE # Get the cause register value.
184 and k0, k0, MIPS_SR_KSU_USER # test for user mode
185 # sneaky but the bits are
187 sll k0, k0, 3 # shift user bit for cause index
188 and k1, k1, MIPS_CR_EXC_CODE # Mask out the cause bits.
189 or k1, k1, k0 # change index to user table
190 #if defined(__mips_n64)
191 PTR_SLL k1, k1, 1 # shift to get 8-byte offset
194 PTR_LA k0, _C_LABEL(machExceptionTable) # get base of the jump table
195 PTR_ADDU k0, k0, k1 # Get the address of the
196 # function entry. Note that
197 # the cause is already
198 # shifted left by 2 bits so
199 # we dont have to shift.
200 PTR_L k0, 0(k0) # Get the function address
202 j k0 # Jump to the function.
205 VECTOR_END(MipsException)
208 * We couldn't find a TLB entry.
209 * Find out what mode we came from and call the appropriate handler.
213 mfc0 k0, MIPS_COP_0_STATUS
215 and k0, k0, MIPS_SR_KSU_USER
216 bne k0, zero, _C_LABEL(MipsUserGenException)
223 /*----------------------------------------------------------------------------
225 * MipsKernGenException --
227 * Handle an exception from kernel mode.
235 *----------------------------------------------------------------------------
238 #define SAVE_REG(reg, offs, base) \
239 REG_S reg, CALLFRAME_SIZ + (SZREG * offs) (base)
241 #if defined(CPU_CNMIPS)
242 #define CLEAR_STATUS \
243 mfc0 a0, MIPS_COP_0_STATUS ;\
244 li a2, (MIPS_SR_KX | MIPS_SR_SX | MIPS_SR_UX) ; \
246 li a2, ~(MIPS_SR_INT_IE | MIPS_SR_EXL | MIPS_SR_KSU_USER) ; \
248 mtc0 a0, MIPS_COP_0_STATUS ; \
250 #elif defined(CPU_RMI) || defined(CPU_NLM)
251 #define CLEAR_STATUS \
252 mfc0 a0, MIPS_COP_0_STATUS ;\
253 li a2, (MIPS_SR_KX | MIPS_SR_UX | MIPS_SR_COP_2_BIT) ; \
255 li a2, ~(MIPS_SR_INT_IE | MIPS_SR_EXL | MIPS_SR_KSU_USER) ; \
257 mtc0 a0, MIPS_COP_0_STATUS ; \
260 #define CLEAR_STATUS \
261 mfc0 a0, MIPS_COP_0_STATUS ;\
262 li a2, ~(MIPS_SR_INT_IE | MIPS_SR_EXL | MIPS_SR_KSU_USER) ; \
264 mtc0 a0, MIPS_COP_0_STATUS ; \
269 * Save CPU and CP0 register state.
271 * This is straightforward except for saving the exception program
272 * counter. The ddb backtrace code looks for the first instruction
273 * matching the form "sw ra, (off)sp" to figure out the address of the
274 * calling function. So we must make sure that we save the exception
275 * PC by staging it through 'ra' as opposed to any other register.
278 SAVE_REG(AT, AST, sp) ;\
280 SAVE_REG(v0, V0, sp) ;\
281 SAVE_REG(v1, V1, sp) ;\
282 SAVE_REG(a0, A0, sp) ;\
283 SAVE_REG(a1, A1, sp) ;\
284 SAVE_REG(a2, A2, sp) ;\
285 SAVE_REG(a3, A3, sp) ;\
286 SAVE_REG(t0, T0, sp) ;\
287 SAVE_REG(t1, T1, sp) ;\
288 SAVE_REG(t2, T2, sp) ;\
289 SAVE_REG(t3, T3, sp) ;\
290 SAVE_REG(ta0, TA0, sp) ;\
291 SAVE_REG(ta1, TA1, sp) ;\
292 SAVE_REG(ta2, TA2, sp) ;\
293 SAVE_REG(ta3, TA3, sp) ;\
294 SAVE_REG(t8, T8, sp) ;\
295 SAVE_REG(t9, T9, sp) ;\
296 SAVE_REG(gp, GP, sp) ;\
297 SAVE_REG(s0, S0, sp) ;\
298 SAVE_REG(s1, S1, sp) ;\
299 SAVE_REG(s2, S2, sp) ;\
300 SAVE_REG(s3, S3, sp) ;\
301 SAVE_REG(s4, S4, sp) ;\
302 SAVE_REG(s5, S5, sp) ;\
303 SAVE_REG(s6, S6, sp) ;\
304 SAVE_REG(s7, S7, sp) ;\
305 SAVE_REG(s8, S8, sp) ;\
308 mfc0 a0, MIPS_COP_0_STATUS ;\
309 mfc0 a1, MIPS_COP_0_CAUSE ;\
310 MFC0 a2, MIPS_COP_0_BAD_VADDR;\
311 MFC0 a3, MIPS_COP_0_EXC_PC ;\
312 SAVE_REG(v0, MULLO, sp) ;\
313 SAVE_REG(v1, MULHI, sp) ;\
314 SAVE_REG(a0, SR, sp) ;\
315 SAVE_REG(a1, CAUSE, sp) ;\
316 SAVE_REG(a2, BADVADDR, sp) ;\
319 SAVE_REG(ra, PC, sp) ;\
321 SAVE_REG(ra, RA, sp) ;\
322 PTR_ADDU v0, sp, KERN_EXC_FRAME_SIZE ;\
323 SAVE_REG(v0, SP, sp) ;\
325 PTR_ADDU a0, sp, CALLFRAME_SIZ ;\
328 #define RESTORE_REG(reg, offs, base) \
329 REG_L reg, CALLFRAME_SIZ + (SZREG * offs) (base)
331 #define RESTORE_CPU \
333 RESTORE_REG(k0, SR, sp) ;\
334 RESTORE_REG(t0, MULLO, sp) ;\
335 RESTORE_REG(t1, MULHI, sp) ;\
338 MTC0 v0, MIPS_COP_0_EXC_PC ;\
340 RESTORE_REG(AT, AST, sp) ;\
341 RESTORE_REG(v0, V0, sp) ;\
342 RESTORE_REG(v1, V1, sp) ;\
343 RESTORE_REG(a0, A0, sp) ;\
344 RESTORE_REG(a1, A1, sp) ;\
345 RESTORE_REG(a2, A2, sp) ;\
346 RESTORE_REG(a3, A3, sp) ;\
347 RESTORE_REG(t0, T0, sp) ;\
348 RESTORE_REG(t1, T1, sp) ;\
349 RESTORE_REG(t2, T2, sp) ;\
350 RESTORE_REG(t3, T3, sp) ;\
351 RESTORE_REG(ta0, TA0, sp) ;\
352 RESTORE_REG(ta1, TA1, sp) ;\
353 RESTORE_REG(ta2, TA2, sp) ;\
354 RESTORE_REG(ta3, TA3, sp) ;\
355 RESTORE_REG(t8, T8, sp) ;\
356 RESTORE_REG(t9, T9, sp) ;\
357 RESTORE_REG(s0, S0, sp) ;\
358 RESTORE_REG(s1, S1, sp) ;\
359 RESTORE_REG(s2, S2, sp) ;\
360 RESTORE_REG(s3, S3, sp) ;\
361 RESTORE_REG(s4, S4, sp) ;\
362 RESTORE_REG(s5, S5, sp) ;\
363 RESTORE_REG(s6, S6, sp) ;\
364 RESTORE_REG(s7, S7, sp) ;\
365 RESTORE_REG(s8, S8, sp) ;\
366 RESTORE_REG(gp, GP, sp) ;\
367 RESTORE_REG(ra, RA, sp) ;\
368 PTR_ADDU sp, sp, KERN_EXC_FRAME_SIZE;\
369 mtc0 k0, MIPS_COP_0_STATUS
373 * The kernel exception stack contains 18 saved general registers,
374 * the status register and the multiply lo and high registers.
375 * In addition, we set this up for linkage conventions.
377 #define KERN_REG_SIZE (NUMSAVEREGS * SZREG)
378 #define KERN_EXC_FRAME_SIZE (CALLFRAME_SIZ + KERN_REG_SIZE + 16)
380 NESTED_NOPROFILE(MipsKernGenException, KERN_EXC_FRAME_SIZE, ra)
382 PTR_SUBU sp, sp, KERN_EXC_FRAME_SIZE
383 .mask 0x80000000, (CALLFRAME_RA - KERN_EXC_FRAME_SIZE)
385 * Save CPU state, building 'frame'.
389 * Call the exception handler. a0 points at the saved frame.
391 PTR_LA gp, _C_LABEL(_gp)
392 PTR_LA k0, _C_LABEL(trap)
394 REG_S a3, CALLFRAME_RA + KERN_REG_SIZE(sp) # for debugging
397 * Update interrupt and CPU mask in saved status register
398 * Some of interrupts could be disabled by
399 * intr filters if interrupts are enabled later
402 mfc0 a0, MIPS_COP_0_STATUS
403 and a0, a0, (MIPS_SR_INT_MASK|MIPS_SR_COP_USABILITY)
404 RESTORE_REG(a1, SR, sp)
405 and a1, a1, ~(MIPS_SR_INT_MASK|MIPS_SR_COP_USABILITY)
408 RESTORE_CPU # v0 contains the return address.
412 END(MipsKernGenException)
415 /*----------------------------------------------------------------------------
417 * MipsUserGenException --
419 * Handle an exception from user mode.
427 *----------------------------------------------------------------------------
429 NESTED_NOPROFILE(MipsUserGenException, CALLFRAME_SIZ, ra)
431 .mask 0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ)
433 * Save all of the registers except for the kernel temporaries in u.u_pcb.
436 PTR_L k1, PC_CURPCB(k1)
437 SAVE_U_PCB_REG(AT, AST, k1)
439 SAVE_U_PCB_REG(v0, V0, k1)
440 SAVE_U_PCB_REG(v1, V1, k1)
441 SAVE_U_PCB_REG(a0, A0, k1)
443 SAVE_U_PCB_REG(a1, A1, k1)
444 SAVE_U_PCB_REG(a2, A2, k1)
445 SAVE_U_PCB_REG(a3, A3, k1)
446 SAVE_U_PCB_REG(t0, T0, k1)
448 SAVE_U_PCB_REG(t1, T1, k1)
449 SAVE_U_PCB_REG(t2, T2, k1)
450 SAVE_U_PCB_REG(t3, T3, k1)
451 SAVE_U_PCB_REG(ta0, TA0, k1)
452 mfc0 a0, MIPS_COP_0_STATUS # First arg is the status reg.
453 SAVE_U_PCB_REG(ta1, TA1, k1)
454 SAVE_U_PCB_REG(ta2, TA2, k1)
455 SAVE_U_PCB_REG(ta3, TA3, k1)
456 SAVE_U_PCB_REG(s0, S0, k1)
457 mfc0 a1, MIPS_COP_0_CAUSE # Second arg is the cause reg.
458 SAVE_U_PCB_REG(s1, S1, k1)
459 SAVE_U_PCB_REG(s2, S2, k1)
460 SAVE_U_PCB_REG(s3, S3, k1)
461 SAVE_U_PCB_REG(s4, S4, k1)
462 MFC0 a2, MIPS_COP_0_BAD_VADDR # Third arg is the fault addr
463 SAVE_U_PCB_REG(s5, S5, k1)
464 SAVE_U_PCB_REG(s6, S6, k1)
465 SAVE_U_PCB_REG(s7, S7, k1)
466 SAVE_U_PCB_REG(t8, T8, k1)
467 MFC0 a3, MIPS_COP_0_EXC_PC # Fourth arg is the pc.
468 SAVE_U_PCB_REG(t9, T9, k1)
469 SAVE_U_PCB_REG(gp, GP, k1)
470 SAVE_U_PCB_REG(sp, SP, k1)
471 SAVE_U_PCB_REG(s8, S8, k1)
472 PTR_SUBU sp, k1, CALLFRAME_SIZ # switch to kernel SP
473 SAVE_U_PCB_REG(ra, RA, k1)
474 SAVE_U_PCB_REG(v0, MULLO, k1)
475 SAVE_U_PCB_REG(v1, MULHI, k1)
476 SAVE_U_PCB_REG(a0, SR, k1)
477 SAVE_U_PCB_REG(a1, CAUSE, k1)
478 SAVE_U_PCB_REG(a2, BADVADDR, k1)
479 SAVE_U_PCB_REG(a3, PC, k1)
480 REG_S a3, CALLFRAME_RA(sp) # for debugging
481 PTR_LA gp, _C_LABEL(_gp) # switch to kernel GP
482 # Turn off fpu and enter kernel mode
483 and t0, a0, ~(MIPS_SR_COP_1_BIT | MIPS_SR_EXL | MIPS_SR_KSU_MASK | MIPS_SR_INT_IE)
484 #if defined(CPU_CNMIPS)
485 and t0, t0, ~(MIPS_SR_COP_2_BIT)
486 or t0, t0, (MIPS_SR_KX | MIPS_SR_SX | MIPS_SR_UX | MIPS_SR_PX)
487 #elif defined(CPU_RMI) || defined(CPU_NLM)
488 or t0, t0, (MIPS_SR_KX | MIPS_SR_UX | MIPS_SR_COP_2_BIT)
490 mtc0 t0, MIPS_COP_0_STATUS
491 PTR_ADDU a0, k1, U_PCB_REGS
495 * Call the exception handler.
497 PTR_LA k0, _C_LABEL(trap)
502 * Restore user registers and return.
503 * First disable interrupts and set exeption level.
510 * The use of k1 for storing the PCB pointer must be done only
511 * after interrupts are disabled. Otherwise it will get overwritten
512 * by the interrupt code.
515 PTR_L k1, PC_CURPCB(k1)
518 * Update interrupt mask in saved status register
519 * Some of interrupts could be enabled by ithread
522 mfc0 a0, MIPS_COP_0_STATUS
523 and a0, a0, MIPS_SR_INT_MASK
524 RESTORE_U_PCB_REG(a1, SR, k1)
525 and a1, a1, ~MIPS_SR_INT_MASK
527 SAVE_U_PCB_REG(a1, SR, k1)
529 RESTORE_U_PCB_REG(t0, MULLO, k1)
530 RESTORE_U_PCB_REG(t1, MULHI, k1)
533 RESTORE_U_PCB_REG(a0, PC, k1)
534 RESTORE_U_PCB_REG(v0, V0, k1)
535 MTC0 a0, MIPS_COP_0_EXC_PC # set return address
536 RESTORE_U_PCB_REG(v1, V1, k1)
537 RESTORE_U_PCB_REG(a0, A0, k1)
538 RESTORE_U_PCB_REG(a1, A1, k1)
539 RESTORE_U_PCB_REG(a2, A2, k1)
540 RESTORE_U_PCB_REG(a3, A3, k1)
541 RESTORE_U_PCB_REG(t0, T0, k1)
542 RESTORE_U_PCB_REG(t1, T1, k1)
543 RESTORE_U_PCB_REG(t2, T2, k1)
544 RESTORE_U_PCB_REG(t3, T3, k1)
545 RESTORE_U_PCB_REG(ta0, TA0, k1)
546 RESTORE_U_PCB_REG(ta1, TA1, k1)
547 RESTORE_U_PCB_REG(ta2, TA2, k1)
548 RESTORE_U_PCB_REG(ta3, TA3, k1)
549 RESTORE_U_PCB_REG(s0, S0, k1)
550 RESTORE_U_PCB_REG(s1, S1, k1)
551 RESTORE_U_PCB_REG(s2, S2, k1)
552 RESTORE_U_PCB_REG(s3, S3, k1)
553 RESTORE_U_PCB_REG(s4, S4, k1)
554 RESTORE_U_PCB_REG(s5, S5, k1)
555 RESTORE_U_PCB_REG(s6, S6, k1)
556 RESTORE_U_PCB_REG(s7, S7, k1)
557 RESTORE_U_PCB_REG(t8, T8, k1)
558 RESTORE_U_PCB_REG(t9, T9, k1)
559 RESTORE_U_PCB_REG(gp, GP, k1)
560 RESTORE_U_PCB_REG(sp, SP, k1)
561 RESTORE_U_PCB_REG(k0, SR, k1)
562 RESTORE_U_PCB_REG(s8, S8, k1)
563 RESTORE_U_PCB_REG(ra, RA, k1)
565 RESTORE_U_PCB_REG(AT, AST, k1)
567 mtc0 k0, MIPS_COP_0_STATUS # still exception level
572 END(MipsUserGenException)
576 NESTED(mips_wait, CALLFRAME_SIZ, ra)
577 PTR_SUBU sp, sp, CALLFRAME_SIZ
578 .mask 0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ)
579 REG_S ra, CALLFRAME_RA(sp) # save RA
580 mfc0 t0, MIPS_COP_0_STATUS
581 xori t1, t0, MIPS_SR_INT_IE
582 mtc0 t1, MIPS_COP_0_STATUS
586 REG_L ra, CALLFRAME_RA(sp)
587 mfc0 t0, MIPS_COP_0_STATUS
588 ori t1, t0, MIPS_SR_INT_IE
590 GLOBAL(MipsWaitStart) # this is 16 byte aligned
591 mtc0 t1, MIPS_COP_0_STATUS
595 GLOBAL(MipsWaitEnd) # MipsWaitStart + 16
597 PTR_ADDU sp, sp, CALLFRAME_SIZ
601 /*----------------------------------------------------------------------------
605 * Handle an interrupt from kernel mode.
606 * Interrupts use the standard kernel stack.
607 * switch_exit sets up a kernel stack after exit so interrupts won't fail.
615 *----------------------------------------------------------------------------
618 NESTED_NOPROFILE(MipsKernIntr, KERN_EXC_FRAME_SIZE, ra)
620 PTR_SUBU sp, sp, KERN_EXC_FRAME_SIZE
621 .mask 0x80000000, (CALLFRAME_RA - KERN_EXC_FRAME_SIZE)
624 * Check for getting interrupts just before wait
626 MFC0 k0, MIPS_COP_0_EXC_PC
628 xori k0, 0xf # 16 byte align
629 PTR_LA k1, MipsWaitStart
632 PTR_ADDU k1, 16 # skip over wait
633 MTC0 k1, MIPS_COP_0_EXC_PC
636 * Save CPU state, building 'frame'.
640 * Call the interrupt handler. a0 points at the saved frame.
642 PTR_LA gp, _C_LABEL(_gp)
643 PTR_LA k0, _C_LABEL(cpu_intr)
645 REG_S a3, CALLFRAME_RA + KERN_REG_SIZE(sp) # for debugging
648 * Update interrupt and CPU mask in saved status register
649 * Some of interrupts could be disabled by
650 * intr filters if interrupts are enabled later
653 mfc0 a0, MIPS_COP_0_STATUS
654 and a0, a0, (MIPS_SR_INT_MASK|MIPS_SR_COP_USABILITY)
655 RESTORE_REG(a1, SR, sp)
656 and a1, a1, ~(MIPS_SR_INT_MASK|MIPS_SR_COP_USABILITY)
659 REG_L v0, CALLFRAME_RA + KERN_REG_SIZE(sp)
660 RESTORE_CPU # v0 contains the return address.
666 /*----------------------------------------------------------------------------
670 * Handle an interrupt from user mode.
671 * Note: we save minimal state in the u.u_pcb struct and use the standard
672 * kernel stack since there has to be a u page if we came from user mode.
673 * If there is a pending software interrupt, then save the remaining state
674 * and call softintr(). This is all because if we call switch() inside
675 * interrupt(), not all the user registers have been saved in u.u_pcb.
683 *----------------------------------------------------------------------------
685 NESTED_NOPROFILE(MipsUserIntr, CALLFRAME_SIZ, ra)
687 .mask 0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ)
689 * Save the relevant user registers into the u.u_pcb struct.
690 * We don't need to save s0 - s8 because the compiler does it for us.
693 PTR_L k1, PC_CURPCB(k1)
694 SAVE_U_PCB_REG(AT, AST, k1)
696 SAVE_U_PCB_REG(v0, V0, k1)
697 SAVE_U_PCB_REG(v1, V1, k1)
698 SAVE_U_PCB_REG(a0, A0, k1)
699 SAVE_U_PCB_REG(a1, A1, k1)
700 SAVE_U_PCB_REG(a2, A2, k1)
701 SAVE_U_PCB_REG(a3, A3, k1)
702 SAVE_U_PCB_REG(t0, T0, k1)
703 SAVE_U_PCB_REG(t1, T1, k1)
704 SAVE_U_PCB_REG(t2, T2, k1)
705 SAVE_U_PCB_REG(t3, T3, k1)
706 SAVE_U_PCB_REG(ta0, TA0, k1)
707 SAVE_U_PCB_REG(ta1, TA1, k1)
708 SAVE_U_PCB_REG(ta2, TA2, k1)
709 SAVE_U_PCB_REG(ta3, TA3, k1)
710 SAVE_U_PCB_REG(t8, T8, k1)
711 SAVE_U_PCB_REG(t9, T9, k1)
712 SAVE_U_PCB_REG(gp, GP, k1)
713 SAVE_U_PCB_REG(sp, SP, k1)
714 SAVE_U_PCB_REG(ra, RA, k1)
716 * save remaining user state in u.u_pcb.
718 SAVE_U_PCB_REG(s0, S0, k1)
719 SAVE_U_PCB_REG(s1, S1, k1)
720 SAVE_U_PCB_REG(s2, S2, k1)
721 SAVE_U_PCB_REG(s3, S3, k1)
722 SAVE_U_PCB_REG(s4, S4, k1)
723 SAVE_U_PCB_REG(s5, S5, k1)
724 SAVE_U_PCB_REG(s6, S6, k1)
725 SAVE_U_PCB_REG(s7, S7, k1)
726 SAVE_U_PCB_REG(s8, S8, k1)
728 mflo v0 # get lo/hi late to avoid stall
730 mfc0 a0, MIPS_COP_0_STATUS
731 mfc0 a1, MIPS_COP_0_CAUSE
732 MFC0 a3, MIPS_COP_0_EXC_PC
733 SAVE_U_PCB_REG(v0, MULLO, k1)
734 SAVE_U_PCB_REG(v1, MULHI, k1)
735 SAVE_U_PCB_REG(a0, SR, k1)
736 SAVE_U_PCB_REG(a1, CAUSE, k1)
737 SAVE_U_PCB_REG(a3, PC, k1) # PC in a3, note used later!
738 PTR_SUBU sp, k1, CALLFRAME_SIZ # switch to kernel SP
739 PTR_LA gp, _C_LABEL(_gp) # switch to kernel GP
741 # Turn off fpu, disable interrupts, set kernel mode kernel mode, clear exception level.
742 and t0, a0, ~(MIPS_SR_COP_1_BIT | MIPS_SR_EXL | MIPS_SR_INT_IE | MIPS_SR_KSU_MASK)
744 and t0, t0, ~(MIPS_SR_COP_2_BIT)
745 or t0, t0, (MIPS_SR_KX | MIPS_SR_SX | MIPS_SR_UX | MIPS_SR_PX)
746 #elif defined(CPU_RMI) || defined(CPU_NLM)
747 or t0, t0, (MIPS_SR_KX | MIPS_SR_UX | MIPS_SR_COP_2_BIT)
749 mtc0 t0, MIPS_COP_0_STATUS
751 PTR_ADDU a0, k1, U_PCB_REGS
753 * Call the interrupt handler.
755 PTR_LA k0, _C_LABEL(cpu_intr)
757 REG_S a3, CALLFRAME_RA(sp) # for debugging
760 * Enable interrupts before doing ast().
762 * On SMP kernels the AST processing might trigger IPI to other processors.
763 * If that processor is also doing AST processing with interrupts disabled
764 * then we may deadlock.
766 mfc0 a0, MIPS_COP_0_STATUS
767 or a0, a0, MIPS_SR_INT_IE
768 mtc0 a0, MIPS_COP_0_STATUS
772 * DO_AST enabled interrupts
777 * Restore user registers and return.
782 PTR_L k1, PC_CURPCB(k1)
785 * Update interrupt mask in saved status register
786 * Some of interrupts could be disabled by
789 mfc0 a0, MIPS_COP_0_STATUS
790 and a0, a0, MIPS_SR_INT_MASK
791 RESTORE_U_PCB_REG(a1, SR, k1)
792 and a1, a1, ~MIPS_SR_INT_MASK
794 SAVE_U_PCB_REG(a1, SR, k1)
796 RESTORE_U_PCB_REG(s0, S0, k1)
797 RESTORE_U_PCB_REG(s1, S1, k1)
798 RESTORE_U_PCB_REG(s2, S2, k1)
799 RESTORE_U_PCB_REG(s3, S3, k1)
800 RESTORE_U_PCB_REG(s4, S4, k1)
801 RESTORE_U_PCB_REG(s5, S5, k1)
802 RESTORE_U_PCB_REG(s6, S6, k1)
803 RESTORE_U_PCB_REG(s7, S7, k1)
804 RESTORE_U_PCB_REG(s8, S8, k1)
805 RESTORE_U_PCB_REG(t0, MULLO, k1)
806 RESTORE_U_PCB_REG(t1, MULHI, k1)
807 RESTORE_U_PCB_REG(t2, PC, k1)
810 MTC0 t2, MIPS_COP_0_EXC_PC # set return address
811 RESTORE_U_PCB_REG(v0, V0, k1)
812 RESTORE_U_PCB_REG(v1, V1, k1)
813 RESTORE_U_PCB_REG(a0, A0, k1)
814 RESTORE_U_PCB_REG(a1, A1, k1)
815 RESTORE_U_PCB_REG(a2, A2, k1)
816 RESTORE_U_PCB_REG(a3, A3, k1)
817 RESTORE_U_PCB_REG(t0, T0, k1)
818 RESTORE_U_PCB_REG(t1, T1, k1)
819 RESTORE_U_PCB_REG(t2, T2, k1)
820 RESTORE_U_PCB_REG(t3, T3, k1)
821 RESTORE_U_PCB_REG(ta0, TA0, k1)
822 RESTORE_U_PCB_REG(ta1, TA1, k1)
823 RESTORE_U_PCB_REG(ta2, TA2, k1)
824 RESTORE_U_PCB_REG(ta3, TA3, k1)
825 RESTORE_U_PCB_REG(t8, T8, k1)
826 RESTORE_U_PCB_REG(t9, T9, k1)
827 RESTORE_U_PCB_REG(gp, GP, k1)
828 RESTORE_U_PCB_REG(k0, SR, k1)
829 RESTORE_U_PCB_REG(sp, SP, k1)
830 RESTORE_U_PCB_REG(ra, RA, k1)
832 RESTORE_U_PCB_REG(AT, AST, k1)
834 mtc0 k0, MIPS_COP_0_STATUS # SR with EXL set.
841 LEAF_NOPROFILE(MipsTLBInvalidException)
846 MFC0 k0, MIPS_COP_0_BAD_VADDR
847 PTR_LI k1, VM_MAXUSER_ADDRESS
852 /* Kernel address. */
853 lui k1, %hi(kernel_segmap) # k1=hi of segbase
855 PTR_L k1, %lo(kernel_segmap)(k1) # k1=segment tab base
857 1: /* User address. */
859 PTR_L k1, PC_SEGBASE(k1)
861 2: /* Validate page directory pointer. */
865 PTR_SRL k0, SEGSHIFT - PTRSHIFT # k0=seg offset (almost)
866 beq k1, zero, MipsKernGenException # ==0 -- no seg tab
867 andi k0, k0, PDEPTRMASK #06: k0=seg offset
868 PTR_ADDU k1, k0, k1 # k1=seg entry address
869 PTR_L k1, 0(k1) # k1=seg entry
871 /* Validate page table pointer. */
876 MFC0 k0, MIPS_COP_0_BAD_VADDR
877 PTR_SRL k0, PDRSHIFT - PTRSHIFT # k0=pde offset (almost)
878 beq k1, zero, MipsKernGenException # ==0 -- no pde tab
879 andi k0, k0, PDEPTRMASK # k0=pde offset
880 PTR_ADDU k1, k0, k1 # k1=pde entry address
881 PTR_L k1, 0(k1) # k1=pde entry
883 /* Validate pde table pointer. */
887 MFC0 k0, MIPS_COP_0_BAD_VADDR # k0=bad address (again)
888 PTR_SRL k0, PAGE_SHIFT - PTESHIFT # k0=VPN
889 andi k0, k0, PTEMASK # k0=page tab offset
890 PTR_ADDU k1, k1, k0 # k1=pte address
891 PTE_L k0, 0(k1) # k0=this PTE
893 /* Validate page table entry. */
898 /* Check whether this is an even or odd entry. */
904 PTE_L k1, PTESIZE(k1)
906 PTE_MTC0 k0, MIPS_COP_0_TLB_LO0
909 PTE_MTC0 k1, MIPS_COP_0_TLB_LO1
916 PTE_L k0, -PTESIZE(k1)
919 PTE_MTC0 k0, MIPS_COP_0_TLB_LO0
922 PTE_MTC0 k1, MIPS_COP_0_TLB_LO1
928 mfc0 k0, MIPS_COP_0_TLB_INDEX
929 bltz k0, tlb_insert_random
942 * Branch to the comprehensive exception processing.
944 mfc0 k1, MIPS_COP_0_STATUS
945 andi k1, k1, MIPS_SR_KSU_USER
946 bnez k1, _C_LABEL(MipsUserGenException)
950 * Check for kernel stack overflow.
953 PTR_L k0, PC_CURTHREAD(k1)
954 PTR_L k0, TD_KSTACK(k0)
956 bnez k0, _C_LABEL(MipsKernGenException)
960 * Kernel stack overflow.
962 * Move to a valid stack before we call panic. We use the boot stack
967 sll k1, k1, PAGE_SHIFT + 1
969 PTR_LA k0, _C_LABEL(pcpu_space)
970 PTR_ADDU k0, PAGE_SIZE * 2
974 * Stash the original value of 'sp' so we can update trapframe later.
975 * We assume that SAVE_CPU does not trash 'k1'.
980 PTR_SUBU sp, sp, KERN_EXC_FRAME_SIZE
984 REG_S ra, CALLFRAME_RA(sp) /* stop the ddb backtrace right here */
985 REG_S zero, CALLFRAME_SP(sp)
991 * Now restore the value of 'sp' at the time of the tlb exception in
997 * Squelch any more overflow checks by setting the stack base to 0.
1000 PTR_L k0, PC_CURTHREAD(k1)
1001 PTR_S zero, TD_KSTACK(k0)
1004 PANIC("kernel stack overflow - trapframe at %p")
1007 * This nop is necessary so that the 'ra' remains within the bounds
1008 * of this handler. Otherwise the ddb backtrace code will think that
1009 * the panic() was called from MipsTLBMissException.
1014 END(MipsTLBInvalidException)
1016 /*----------------------------------------------------------------------------
1018 * MipsTLBMissException --
1020 * Handle a TLB miss exception from kernel mode in kernel space.
1021 * The BaddVAddr, Context, and EntryHi registers contain the failed
1030 *----------------------------------------------------------------------------
1032 LEAF_NOPROFILE(MipsTLBMissException)
1034 MFC0 k0, MIPS_COP_0_BAD_VADDR # k0=bad address
1035 PTR_LI k1, VM_MAX_KERNEL_ADDRESS # check fault address against
1036 sltu k1, k1, k0 # upper bound of kernel_segmap
1037 bnez k1, MipsKernGenException # out of bound
1038 lui k1, %hi(kernel_segmap) # k1=hi of segbase
1039 PTR_SRL k0, SEGSHIFT - PTRSHIFT # k0=seg offset (almost)
1040 PTR_L k1, %lo(kernel_segmap)(k1) # k1=segment tab base
1041 beq k1, zero, MipsKernGenException # ==0 -- no seg tab
1042 andi k0, k0, PDEPTRMASK #06: k0=seg offset
1043 PTR_ADDU k1, k0, k1 # k1=seg entry address
1044 PTR_L k1, 0(k1) # k1=seg entry
1045 MFC0 k0, MIPS_COP_0_BAD_VADDR # k0=bad address (again)
1046 beq k1, zero, MipsKernGenException # ==0 -- no page table
1048 PTR_SRL k0, PDRSHIFT - PTRSHIFT # k0=VPN
1049 andi k0, k0, PDEPTRMASK # k0=pde offset
1050 PTR_ADDU k1, k0, k1 # k1=pde entry address
1051 PTR_L k1, 0(k1) # k1=pde entry
1052 MFC0 k0, MIPS_COP_0_BAD_VADDR # k0=bad address (again)
1053 beq k1, zero, MipsKernGenException # ==0 -- no page table
1055 PTR_SRL k0, PAGE_SHIFT - PTESHIFT # k0=VPN
1056 andi k0, k0, PTE2MASK # k0=page tab offset
1057 PTR_ADDU k1, k1, k0 # k1=pte address
1058 PTE_L k0, 0(k1) # k0=lo0 pte
1059 PTE_L k1, PTESIZE(k1) # k1=lo1 pte
1060 CLEAR_PTE_SWBITS(k0)
1061 PTE_MTC0 k0, MIPS_COP_0_TLB_LO0 # lo0 is loaded
1063 CLEAR_PTE_SWBITS(k1)
1064 PTE_MTC0 k1, MIPS_COP_0_TLB_LO1 # lo1 is loaded
1066 tlbwr # write to tlb
1068 eret # return from exception
1070 END(MipsTLBMissException)
1072 /*----------------------------------------------------------------------------
1076 * Handle a floating point Trap.
1078 * MipsFPTrap(statusReg, causeReg, pc)
1079 * unsigned statusReg;
1080 * unsigned causeReg;
1089 *----------------------------------------------------------------------------
1091 NESTED(MipsFPTrap, CALLFRAME_SIZ, ra)
1092 PTR_SUBU sp, sp, CALLFRAME_SIZ
1093 mfc0 t0, MIPS_COP_0_STATUS
1094 REG_S ra, CALLFRAME_RA(sp)
1095 .mask 0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ)
1097 or t1, t0, MIPS_SR_COP_1_BIT
1098 mtc0 t1, MIPS_COP_0_STATUS
1100 cfc1 t1, MIPS_FPU_CSR # stall til FP done
1101 cfc1 t1, MIPS_FPU_CSR # now get status
1103 sll t2, t1, (31 - 17) # unimplemented operation?
1104 bgez t2, 3f # no, normal trap
1107 * We got an unimplemented operation trap so
1108 * fetch the instruction, compute the next PC and emulate the instruction.
1110 bgez a1, 1f # Check the branch delay bit.
1113 * The instruction is in the branch delay slot so the branch will have to
1114 * be emulated to get the resulting PC.
1116 PTR_S a2, CALLFRAME_SIZ + 8(sp)
1119 PTR_L a0, PC_CURPCB(a0)
1120 PTR_ADDU a0, a0, U_PCB_REGS # first arg is ptr to CPU registers
1121 move a1, a2 # second arg is instruction PC
1122 move a2, t1 # third arg is floating point CSR
1123 PTR_LA t3, _C_LABEL(MipsEmulateBranch) # compute PC after branch
1124 jalr t3 # compute PC after branch
1125 move a3, zero # fourth arg is FALSE
1127 * Now load the floating-point instruction in the branch delay slot
1130 PTR_L a2, CALLFRAME_SIZ + 8(sp) # restore EXC pc
1132 lw a0, 4(a2) # a0 = coproc instruction
1134 * This is not in the branch delay slot so calculate the resulting
1135 * PC (epc + 4) into v0 and continue to MipsEmulateFP().
1138 lw a0, 0(a2) # a0 = coproc instruction
1140 PTR_ADDU v0, a2, 4 # v0 = next pc
1143 PTR_L t2, PC_CURPCB(t2)
1144 SAVE_U_PCB_REG(v0, PC, t2) # save new pc
1146 * Check to see if the instruction to be emulated is a floating-point
1149 srl a3, a0, MIPS_OPCODE_SHIFT
1150 beq a3, MIPS_OPCODE_C1, 4f # this should never fail
1153 * Send a floating point exception signal to the current process.
1157 PTR_L a0, PC_CURTHREAD(a0) # get current thread
1158 cfc1 a2, MIPS_FPU_CSR # code = FP execptions
1159 ctc1 zero, MIPS_FPU_CSR # Clear exceptions
1160 PTR_LA t3, _C_LABEL(trapsignal)
1167 * Finally, we can call MipsEmulateFP() where a0 is the instruction to emulate.
1170 PTR_LA t3, _C_LABEL(MipsEmulateFP)
1175 * Turn off the floating point coprocessor and return.
1178 mfc0 t0, MIPS_COP_0_STATUS
1179 PTR_L ra, CALLFRAME_RA(sp)
1180 and t0, t0, ~MIPS_SR_COP_1_BIT
1181 mtc0 t0, MIPS_COP_0_STATUS
1184 PTR_ADDU sp, sp, CALLFRAME_SIZ
1188 * Interrupt counters for vmstat.
1196 .space INTRCNT_COUNT * (MAXCOMLEN + 1) * 2
1199 .quad INTRCNT_COUNT * (MAXCOMLEN + 1) * 2
1201 .int INTRCNT_COUNT * (MAXCOMLEN + 1) * 2
1204 .align (_MIPS_SZLONG / 8)
1206 .space INTRCNT_COUNT * (_MIPS_SZLONG / 8) * 2
1209 .quad INTRCNT_COUNT * (_MIPS_SZLONG / 8) * 2
1211 .int INTRCNT_COUNT * (_MIPS_SZLONG / 8) * 2
1216 * Vector to real handler in KSEG1.
1219 VECTOR(MipsCache, unknown)
1220 PTR_LA k0, _C_LABEL(MipsCacheException)
1221 li k1, MIPS_KSEG0_PHYS_MASK
1223 PTR_LI k1, MIPS_KSEG1_START
1227 VECTOR_END(MipsCache)
1233 * Panic on cache errors. A lot more could be done to recover
1234 * from some types of errors but it is tricky.
1236 NESTED_NOPROFILE(MipsCacheException, KERN_EXC_FRAME_SIZE, ra)
1238 .mask 0x80000000, -4
1239 PTR_LA k0, _C_LABEL(panic) # return to panic
1240 PTR_LA a0, 9f # panicstr
1241 MFC0 a1, MIPS_COP_0_ERROR_PC
1242 mfc0 a2, MIPS_COP_0_CACHE_ERR # 3rd arg cache error
1244 MTC0 k0, MIPS_COP_0_ERROR_PC # set return address
1246 mfc0 k0, MIPS_COP_0_STATUS # restore status
1247 li k1, MIPS_SR_DIAG_PE # ignore further errors
1249 mtc0 k0, MIPS_COP_0_STATUS # restore status
1254 MSG("cache error @ EPC 0x%x CachErr 0x%x");
1256 END(MipsCacheException)