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.
57 #include "opt_cputype.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>
65 #include "opt_cputype.h"
69 .set noreorder # Noreorder is default style!
74 #define INTRCNT_COUNT 128
78 *----------------------------------------------------------------------------
82 * Vector code for the TLB-miss exception vector 0x80000000.
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!!!
90 VECTOR(MipsTLBMiss, unknown)
94 MFC0 k0, MIPS_COP_0_BAD_VADDR # get the fault address
96 VECTOR_END(MipsTLBMiss)
99 *----------------------------------------------------------------------------
103 * This is the real TLB Miss Handler code.
104 * 'segbase' points to the base of the segment table for user processes.
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 *----------------------------------------------------------------------------
113 bltz k0, 1f #02: k0<0 -> 1f (kernel fault)
114 PTR_SRL k0, k0, SEGSHIFT - PTRSHIFT #03: k0=seg offset (almost)
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
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
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
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
139 PTE_MTC0 k0, MIPS_COP_0_TLB_LO0 #12: lo0 is loaded
142 PTE_MTC0 k1, MIPS_COP_0_TLB_LO1 #15: lo1 is loaded
144 tlbwr #1a: write to tlb
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
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!!!
158 VECTOR(MipsException, unknown)
160 * Find out what mode we came from and jump to the proper handler.
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
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
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
183 j k0 # Jump to the function.
186 VECTOR_END(MipsException)
189 * We couldn't find a TLB entry.
190 * Find out what mode we came from and call the appropriate handler.
194 mfc0 k0, MIPS_COP_0_STATUS
196 and k0, k0, SR_KSU_USER
197 bne k0, zero, _C_LABEL(MipsUserGenException)
204 /*----------------------------------------------------------------------------
206 * MipsKernGenException --
208 * Handle an exception from kernel mode.
216 *----------------------------------------------------------------------------
219 #define SAVE_REG(reg, offs, base) \
220 REG_S reg, CALLFRAME_SIZ + (SZREG * offs) (base)
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) ; \
227 li a2, ~(MIPS_SR_INT_IE | MIPS_SR_EXL | SR_KSU_USER) ; \
229 mtc0 a0, MIPS_COP_0_STATUS ; \
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) ; \
236 li a2, ~(MIPS_SR_INT_IE | MIPS_SR_EXL | SR_KSU_USER) ; \
238 mtc0 a0, MIPS_COP_0_STATUS ; \
241 #define CLEAR_STATUS \
242 mfc0 a0, MIPS_COP_0_STATUS ;\
243 li a2, ~(MIPS_SR_INT_IE | MIPS_SR_EXL | SR_KSU_USER) ; \
245 mtc0 a0, MIPS_COP_0_STATUS ; \
250 * Save CPU and CP0 register state.
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.
259 SAVE_REG(AT, AST, sp) ;\
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) ;\
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) ;\
300 SAVE_REG(ra, PC, sp) ;\
302 SAVE_REG(ra, RA, sp) ;\
303 PTR_ADDU v0, sp, KERN_EXC_FRAME_SIZE ;\
304 SAVE_REG(v0, SP, sp) ;\
306 PTR_ADDU a0, sp, CALLFRAME_SIZ ;\
309 #define RESTORE_REG(reg, offs, base) \
310 REG_L reg, CALLFRAME_SIZ + (SZREG * offs) (base)
312 #define RESTORE_CPU \
314 RESTORE_REG(k0, SR, sp) ;\
315 RESTORE_REG(t0, MULLO, sp) ;\
316 RESTORE_REG(t1, MULHI, sp) ;\
319 MTC0 v0, MIPS_COP_0_EXC_PC ;\
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
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.
358 #define KERN_REG_SIZE (NUMSAVEREGS * SZREG)
359 #define KERN_EXC_FRAME_SIZE (CALLFRAME_SIZ + KERN_REG_SIZE + 16)
361 NNON_LEAF(MipsKernGenException, KERN_EXC_FRAME_SIZE, ra)
363 PTR_SUBU sp, sp, KERN_EXC_FRAME_SIZE
364 .mask 0x80000000, (CALLFRAME_RA - KERN_EXC_FRAME_SIZE)
366 * Save CPU state, building 'frame'.
370 * Call the exception handler. a0 points at the saved frame.
372 PTR_LA gp, _C_LABEL(_gp)
373 PTR_LA k0, _C_LABEL(trap)
375 REG_S a3, CALLFRAME_RA + KERN_REG_SIZE(sp) # for debugging
378 * Update interrupt mask in saved status register
379 * Some of interrupts could be disabled by
380 * intr filters if interrupts are enabled later
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
389 RESTORE_CPU # v0 contains the return address.
393 END(MipsKernGenException)
396 #define SAVE_U_PCB_REG(reg, offs, base) \
397 REG_S reg, U_PCB_REGS + (SZREG * offs) (base)
399 #define RESTORE_U_PCB_REG(reg, offs, base) \
400 REG_L reg, U_PCB_REGS + (SZREG * offs) (base)
402 /*----------------------------------------------------------------------------
404 * MipsUserGenException --
406 * Handle an exception from user mode.
414 *----------------------------------------------------------------------------
416 NNON_LEAF(MipsUserGenException, CALLFRAME_SIZ, ra)
418 .mask 0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ)
420 * Save all of the registers except for the kernel temporaries in u.u_pcb.
423 PTR_L k1, PC_CURPCB(k1)
424 SAVE_U_PCB_REG(AT, AST, k1)
426 SAVE_U_PCB_REG(v0, V0, k1)
427 SAVE_U_PCB_REG(v1, V1, k1)
428 SAVE_U_PCB_REG(a0, A0, k1)
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)
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)
476 mtc0 t0, MIPS_COP_0_STATUS
477 PTR_ADDU a0, k1, U_PCB_REGS
481 * Call the exception handler.
483 PTR_LA k0, _C_LABEL(trap)
488 * Restore user registers and return.
489 * First disable interrupts and set exeption level.
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.
501 PTR_L k1, PC_CURPCB(k1)
504 * Update interrupt mask in saved status register
505 * Some of interrupts could be enabled by ithread
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
513 SAVE_U_PCB_REG(a1, SR, k1)
515 RESTORE_U_PCB_REG(t0, MULLO, k1)
516 RESTORE_U_PCB_REG(t1, MULHI, k1)
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)
551 RESTORE_U_PCB_REG(AT, AST, k1)
553 mtc0 k0, MIPS_COP_0_STATUS # still exception level
558 END(MipsUserGenException)
560 /*----------------------------------------------------------------------------
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.
574 *----------------------------------------------------------------------------
577 NNON_LEAF(MipsKernIntr, KERN_EXC_FRAME_SIZE, ra)
579 PTR_SUBU sp, sp, KERN_EXC_FRAME_SIZE
580 .mask 0x80000000, (CALLFRAME_RA - KERN_EXC_FRAME_SIZE)
582 * Save CPU state, building 'frame'.
586 * Call the interrupt handler. a0 points at the saved frame.
588 PTR_LA gp, _C_LABEL(_gp)
589 PTR_LA k0, _C_LABEL(cpu_intr)
591 REG_S a3, CALLFRAME_RA + KERN_REG_SIZE(sp) # for debugging
594 * Update interrupt mask in saved status register
595 * Some of interrupts could be disabled by
596 * intr filters if interrupts are enabled later
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
605 REG_L v0, CALLFRAME_RA + KERN_REG_SIZE(sp)
606 RESTORE_CPU # v0 contains the return address.
612 /*----------------------------------------------------------------------------
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.
629 *----------------------------------------------------------------------------
631 NNON_LEAF(MipsUserIntr, CALLFRAME_SIZ, ra)
633 .mask 0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ)
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.
639 PTR_L k1, PC_CURPCB(k1)
640 SAVE_U_PCB_REG(AT, AST, k1)
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)
662 * save remaining user state in u.u_pcb.
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)
674 mflo v0 # get lo/hi late to avoid stall
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
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)
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)
694 mtc0 t0, MIPS_COP_0_STATUS
696 PTR_ADDU a0, k1, U_PCB_REGS
698 * Call the interrupt handler.
700 PTR_LA k0, _C_LABEL(cpu_intr)
702 REG_S a3, CALLFRAME_RA(sp) # for debugging
705 * Enable interrupts before doing ast().
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.
711 mfc0 a0, MIPS_COP_0_STATUS
712 or a0, a0, MIPS_SR_INT_IE
713 mtc0 a0, MIPS_COP_0_STATUS
717 * DO_AST enabled interrupts
722 * Restore user registers and return.
727 PTR_L k1, PC_CURPCB(k1)
730 * Update interrupt mask in saved status register
731 * Some of interrupts could be disabled by
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
739 SAVE_U_PCB_REG(a1, SR, k1)
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)
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)
777 RESTORE_U_PCB_REG(AT, AST, k1)
779 mtc0 k0, MIPS_COP_0_STATUS # SR with EXL set.
786 NLEAF(MipsTLBInvalidException)
791 MFC0 k0, MIPS_COP_0_BAD_VADDR
792 PTR_LI k1, VM_MAXUSER_ADDRESS
797 /* Kernel address. */
798 lui k1, %hi(kernel_segmap) # k1=hi of segbase
800 PTR_L k1, %lo(kernel_segmap)(k1) # k1=segment tab base
802 1: /* User address. */
804 PTR_L k1, PC_SEGBASE(k1)
806 2: /* Validate page directory pointer. */
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
816 /* Validate page table pointer. */
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
828 /* Validate pde table pointer. */
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
838 /* Validate page table entry. */
843 /* Check whether this is an even or odd entry. */
849 PTE_L k1, PTESIZE(k1)
851 PTE_MTC0 k0, MIPS_COP_0_TLB_LO0
854 PTE_MTC0 k1, MIPS_COP_0_TLB_LO1
861 PTE_L k0, -PTESIZE(k1)
864 PTE_MTC0 k0, MIPS_COP_0_TLB_LO0
867 PTE_MTC0 k1, MIPS_COP_0_TLB_LO1
873 mfc0 k0, MIPS_COP_0_TLB_INDEX
874 bltz k0, tlb_insert_random
887 * Branch to the comprehensive exception processing.
889 mfc0 k1, MIPS_COP_0_STATUS
890 andi k1, k1, SR_KSU_USER
891 bnez k1, _C_LABEL(MipsUserGenException)
895 * Check for kernel stack overflow.
898 PTR_L k0, PC_CURTHREAD(k1)
899 PTR_L k0, TD_KSTACK(k0)
901 bnez k0, _C_LABEL(MipsKernGenException)
905 * Kernel stack overflow.
907 * Move to a valid stack before we call panic. We use the boot stack
912 sll k1, k1, PAGE_SHIFT + 1
914 PTR_LA k0, _C_LABEL(pcpu_space)
915 PTR_ADDU k0, PAGE_SIZE * 2
919 * Stash the original value of 'sp' so we can update trapframe later.
920 * We assume that SAVE_CPU does not trash 'k1'.
925 PTR_SUBU sp, sp, KERN_EXC_FRAME_SIZE
929 REG_S ra, CALLFRAME_RA(sp) /* stop the ddb backtrace right here */
930 REG_S zero, CALLFRAME_SP(sp)
936 * Now restore the value of 'sp' at the time of the tlb exception in
942 * Squelch any more overflow checks by setting the stack base to 0.
945 PTR_L k0, PC_CURTHREAD(k1)
946 PTR_S zero, TD_KSTACK(k0)
949 PANIC("kernel stack overflow - trapframe at %p")
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.
959 END(MipsTLBInvalidException)
961 /*----------------------------------------------------------------------------
963 * MipsTLBMissException --
965 * Handle a TLB miss exception from kernel mode in kernel space.
966 * The BaddVAddr, Context, and EntryHi registers contain the failed
975 *----------------------------------------------------------------------------
977 NLEAF(MipsTLBMissException)
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
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
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
1008 CLEAR_PTE_SWBITS(k1)
1009 PTE_MTC0 k1, MIPS_COP_0_TLB_LO1 # lo1 is loaded
1011 tlbwr # write to tlb
1013 eret # return from exception
1015 END(MipsTLBMissException)
1017 /*----------------------------------------------------------------------------
1021 * Handle a floating point Trap.
1023 * MipsFPTrap(statusReg, causeReg, pc)
1024 * unsigned statusReg;
1025 * unsigned causeReg;
1034 *----------------------------------------------------------------------------
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)
1042 or t1, t0, MIPS_SR_COP_1_BIT
1043 mtc0 t1, MIPS_COP_0_STATUS
1045 cfc1 t1, MIPS_FPU_CSR # stall til FP done
1046 cfc1 t1, MIPS_FPU_CSR # now get status
1048 sll t2, t1, (31 - 17) # unimplemented operation?
1049 bgez t2, 3f # no, normal trap
1052 * We got an unimplemented operation trap so
1053 * fetch the instruction, compute the next PC and emulate the instruction.
1055 bgez a1, 1f # Check the branch delay bit.
1058 * The instruction is in the branch delay slot so the branch will have to
1059 * be emulated to get the resulting PC.
1061 PTR_S a2, CALLFRAME_SIZ + 8(sp)
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
1072 * Now load the floating-point instruction in the branch delay slot
1075 PTR_L a2, CALLFRAME_SIZ + 8(sp) # restore EXC pc
1077 lw a0, 4(a2) # a0 = coproc instruction
1079 * This is not in the branch delay slot so calculate the resulting
1080 * PC (epc + 4) into v0 and continue to MipsEmulateFP().
1083 lw a0, 0(a2) # a0 = coproc instruction
1085 PTR_ADDU v0, a2, 4 # v0 = next pc
1088 PTR_L t2, PC_CURPCB(t2)
1089 SAVE_U_PCB_REG(v0, PC, t2) # save new pc
1091 * Check to see if the instruction to be emulated is a floating-point
1094 srl a3, a0, MIPS_OPCODE_SHIFT
1095 beq a3, MIPS_OPCODE_C1, 4f # this should never fail
1098 * Send a floating point exception signal to the current process.
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)
1112 * Finally, we can call MipsEmulateFP() where a0 is the instruction to emulate.
1115 PTR_LA t3, _C_LABEL(MipsEmulateFP)
1120 * Turn off the floating point coprocessor and return.
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
1129 PTR_ADDU sp, sp, CALLFRAME_SIZ
1133 * Interrupt counters for vmstat.
1141 .space INTRCNT_COUNT * (MAXCOMLEN + 1) * 2
1144 .quad INTRCNT_COUNT * (MAXCOMLEN + 1) * 2
1146 .int INTRCNT_COUNT * (MAXCOMLEN + 1) * 2
1151 .space INTRCNT_COUNT * 4 * 2
1154 .quad INTRCNT_COUNT * 4 * 2
1156 .int INTRCNT_COUNT * 4 * 2
1161 * Vector to real handler in KSEG1.
1164 VECTOR(MipsCache, unknown)
1165 PTR_LA k0, _C_LABEL(MipsCacheException)
1166 li k1, MIPS_KSEG0_PHYS_MASK
1168 PTR_LI k1, MIPS_KSEG1_START
1172 VECTOR_END(MipsCache)
1178 * Panic on cache errors. A lot more could be done to recover
1179 * from some types of errors but it is tricky.
1181 NESTED_NOPROFILE(MipsCacheException, KERN_EXC_FRAME_SIZE, ra)
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
1189 MTC0 k0, MIPS_COP_0_ERROR_PC # set return address
1191 mfc0 k0, MIPS_COP_0_STATUS # restore status
1192 li k1, MIPS_SR_DIAG_PE # ignore further errors
1194 mtc0 k0, MIPS_COP_0_STATUS # restore status
1199 MSG("cache error @ EPC 0x%x CachErr 0x%x");
1201 END(MipsCacheException)