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>
67 #if defined(ISA_MIPS32)
69 #elif defined(ISA_MIPS64)
70 #define WITH_64BIT_CP0
71 #elif defined(ISA_MIPS3)
72 #define WITH_64BIT_CP0
74 #error "Please write the code for this ISA"
82 #define WIRED_SHIFT 34
90 .set noreorder # Noreorder is default style!
91 #if defined(ISA_MIPS32)
93 #elif defined(ISA_MIPS64)
95 #elif defined(ISA_MIPS3)
100 * Assume that w alaways need nops to escape CP0 hazard
101 * TODO: Make hazard delays configurable. Stuck with 5 cycles on the moment
102 * For more info on CP0 hazards see Chapter 7 (p.99) of "MIPS32 Architecture
103 * For Programmers Volume III: The MIPS32 Privileged Resource Architecture"
105 #define ITLBNOPFIX nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;
106 #define HAZARD_DELAY nop;nop;nop;nop;nop;
109 *----------------------------------------------------------------------------
113 * Vector code for the TLB-miss exception vector 0x80000000.
115 * This code is copied to the TLB exception vector address to
116 * which the CPU jumps in response to an exception or a TLB miss.
117 * NOTE: This code must be position independent!!!
123 VECTOR(MipsTLBMiss, unknown)
124 j _C_LABEL(MipsDoTLBMiss)
125 mfc0 k0, COP_0_BAD_VADDR # get the fault address
127 VECTOR_END(MipsTLBMiss)
130 *----------------------------------------------------------------------------
134 * This is the real TLB Miss Handler code.
135 * 'segbase' points to the base of the segment table for user processes.
137 * Don't check for invalid pte's here. We load them as well and
138 * let the processor trap to load the correct value after service.
139 *----------------------------------------------------------------------------
143 lui k1, %hi(_C_LABEL(pcpup))
145 #k0 already has BadVA
146 bltz k0, 1f #02: k0<0 -> 1f (kernel fault)
147 srl k0, k0, SEGSHIFT - 2 #03: k0=seg offset (almost)
151 lw k1, %lo(_C_LABEL(pcpup))(k1)
153 lw k1, PC_SEGBASE(k1)
154 beqz k1, 2f #05: make sure segbase is not null
155 andi k0, k0, 0x7fc #06: k0=seg offset (mask 0x3)
156 addu k1, k0, k1 #07: k1=seg entry address
157 lw k1, 0(k1) #08: k1=seg entry
158 mfc0 k0, COP_0_BAD_VADDR #09: k0=bad address (again)
159 beq k1, zero, 2f #0a: ==0 -- no page table
160 srl k0, PGSHIFT - 2 #0b: k0=VPN (aka va>>10)
162 andi k0, k0, ((NPTEPG/2) - 1) << 3 #0c: k0=page tab offset
163 addu k1, k1, k0 #0d: k1=pte address
164 lw k0, 0(k1) #0e: k0=lo0 pte
165 lw k1, 4(k1) #0f: k1=lo1 pte
166 _SLL k0, k0, WIRED_SHIFT #10: keep bottom 30 bits
167 _SRL k0, k0, WIRED_SHIFT #11: keep bottom 30 bits
168 _MTC0 k0, COP_0_TLB_LO0 #12: lo0 is loaded
169 _SLL k1, k1, WIRED_SHIFT #13: keep bottom 30 bits
170 _SRL k1, k1, WIRED_SHIFT #14: keep bottom 30 bits
171 _MTC0 k1, COP_0_TLB_LO1 #15: lo1 is loaded
173 tlbwr #1a: write to tlb
175 eret #1f: retUrn from exception
176 1: j _C_LABEL(MipsTLBMissException) #20: kernel exception
177 nop #21: branch delay slot
178 2: j SlowFault #22: no page table present
179 nop #23: branch delay slot
184 * This code is copied to the general exception vector address to
185 * handle all execptions except RESET and TLBMiss.
186 * NOTE: This code must be position independent!!!
188 VECTOR(MipsException, unknown)
190 * Find out what mode we came from and jump to the proper handler.
193 mfc0 k0, COP_0_STATUS_REG # Get the status register
194 mfc0 k1, COP_0_CAUSE_REG # Get the cause register value.
195 and k0, k0, SR_KSU_USER # test for user mode
196 # sneaky but the bits are
198 sll k0, k0, 3 # shift user bit for cause index
199 and k1, k1, CR_EXC_CODE # Mask out the cause bits.
200 or k1, k1, k0 # change index to user table
202 la k0, _C_LABEL(machExceptionTable) # get base of the jump table
203 addu k0, k0, k1 # Get the address of the
204 # function entry. Note that
205 # the cause is already
206 # shifted left by 2 bits so
207 # we dont have to shift.
208 lw k0, 0(k0) # Get the function address
210 j k0 # Jump to the function.
213 VECTOR_END(MipsException)
216 * We couldn't find a TLB entry.
217 * Find out what mode we came from and call the appropriate handler.
221 mfc0 k0, COP_0_STATUS_REG
223 and k0, k0, SR_KSU_USER
224 bne k0, zero, _C_LABEL(MipsUserGenException)
231 /*----------------------------------------------------------------------------
233 * MipsKernGenException --
235 * Handle an exception from kernel mode.
243 *----------------------------------------------------------------------------
245 #if defined(ISA_MIPS32)
246 #define STORE sw /* 32 bit mode regsave instruction */
247 #define LOAD lw /* 32 bit mode regload instruction */
248 #define RSIZE 4 /* 32 bit mode register size */
249 #elif defined(ISA_MIPS64)
250 #define STORE sd /* 64 bit mode regsave instruction */
251 #define LOAD ld /* 64 bit mode regload instruction */
252 #define RSIZE 8 /* 64 bit mode register size */
254 #error "Please write code for this isa."
257 #define SAVE_REG(reg, offs, base) \
258 STORE reg, STAND_ARG_SIZE + (RSIZE * offs) (base)
261 #define CLEAR_STATUS \
262 mfc0 a0, COP_0_STATUS_REG ;\
263 li a2, (MIPS_SR_KX | MIPS_SR_SX | MIPS_SR_UX) ; \
265 li a2, ~(MIPS_SR_INT_IE|MIPS_SR_EXL) ; \
267 mtc0 a0, COP_0_STATUS_REG
269 #define CLEAR_STATUS \
270 mfc0 a0, COP_0_STATUS_REG ;\
271 li a2, ~(MIPS_SR_INT_IE|MIPS_SR_EXL) ; \
273 mtc0 a0, COP_0_STATUS_REG
277 SAVE_REG(AT, AST, sp) ;\
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(t4, T4, sp) ;\
290 SAVE_REG(t5, T5, sp) ;\
291 SAVE_REG(t6, T6, sp) ;\
292 SAVE_REG(t7, T7, 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) ;\
307 mfc0 a0, COP_0_STATUS_REG ;\
308 mfc0 a1, COP_0_CAUSE_REG ;\
309 mfc0 a2, COP_0_BAD_VADDR ;\
310 mfc0 a3, 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(ra, RA, sp) ;\
316 SAVE_REG(a2, BADVADDR, sp) ;\
317 SAVE_REG(a3, PC, sp) ;\
318 addu v0, sp, KERN_EXC_FRAME_SIZE ;\
319 SAVE_REG(v0, SP, sp) ;\
321 addu a0, sp, STAND_ARG_SIZE ;\
324 #define RESTORE_REG(reg, offs, base) \
325 LOAD reg, STAND_ARG_SIZE + (RSIZE * offs) (base)
327 #define RESTORE_CPU \
328 mtc0 zero,COP_0_STATUS_REG ;\
329 RESTORE_REG(a0, SR, sp) ;\
330 RESTORE_REG(t0, MULLO, sp) ;\
331 RESTORE_REG(t1, MULHI, sp) ;\
332 mtc0 a0, COP_0_STATUS_REG ;\
335 _MTC0 v0, COP_0_EXC_PC ;\
337 RESTORE_REG(AT, AST, sp) ;\
338 RESTORE_REG(v0, V0, sp) ;\
339 RESTORE_REG(v1, V1, sp) ;\
340 RESTORE_REG(a0, A0, sp) ;\
341 RESTORE_REG(a1, A1, sp) ;\
342 RESTORE_REG(a2, A2, sp) ;\
343 RESTORE_REG(a3, A3, sp) ;\
344 RESTORE_REG(t0, T0, sp) ;\
345 RESTORE_REG(t1, T1, sp) ;\
346 RESTORE_REG(t2, T2, sp) ;\
347 RESTORE_REG(t3, T3, sp) ;\
348 RESTORE_REG(t4, T4, sp) ;\
349 RESTORE_REG(t5, T5, sp) ;\
350 RESTORE_REG(t6, T6, sp) ;\
351 RESTORE_REG(t7, T7, sp) ;\
352 RESTORE_REG(t8, T8, sp) ;\
353 RESTORE_REG(t9, T9, sp) ;\
354 RESTORE_REG(s0, S0, sp) ;\
355 RESTORE_REG(s1, S1, sp) ;\
356 RESTORE_REG(s2, S2, sp) ;\
357 RESTORE_REG(s3, S3, sp) ;\
358 RESTORE_REG(s4, S4, sp) ;\
359 RESTORE_REG(s5, S5, sp) ;\
360 RESTORE_REG(s6, S6, sp) ;\
361 RESTORE_REG(s7, S7, sp) ;\
362 RESTORE_REG(s8, S8, sp) ;\
363 RESTORE_REG(gp, GP, sp) ;\
364 RESTORE_REG(ra, RA, sp) ;\
365 addu sp, sp, KERN_EXC_FRAME_SIZE
369 * The kernel exception stack contains 18 saved general registers,
370 * the status register and the multiply lo and high registers.
371 * In addition, we set this up for linkage conventions.
373 #define KERN_REG_SIZE (NUMSAVEREGS * RSIZE)
374 #define KERN_EXC_FRAME_SIZE (STAND_FRAME_SIZE + KERN_REG_SIZE + 16)
376 NNON_LEAF(MipsKernGenException, KERN_EXC_FRAME_SIZE, ra)
378 subu sp, sp, KERN_EXC_FRAME_SIZE
379 .mask 0x80000000, (STAND_RA_OFFSET - KERN_EXC_FRAME_SIZE)
381 * Save CPU state, building 'frame'.
385 * Call the exception handler. a0 points at the saved frame.
388 la k0, _C_LABEL(trap)
390 sw a3, STAND_RA_OFFSET + KERN_REG_SIZE(sp) # for debugging
392 RESTORE_CPU # v0 contains the return address.
396 END(MipsKernGenException)
399 #define SAVE_U_PCB_REG(reg, offs, base) \
400 STORE reg, U_PCB_REGS + (RSIZE * offs) (base)
402 #define RESTORE_U_PCB_REG(reg, offs, base) \
403 LOAD reg, U_PCB_REGS + (RSIZE * offs) (base)
405 /*----------------------------------------------------------------------------
407 * MipsUserGenException --
409 * Handle an exception from user mode.
417 *----------------------------------------------------------------------------
419 NNON_LEAF(MipsUserGenException, STAND_FRAME_SIZE, ra)
421 .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
423 * Save all of the registers except for the kernel temporaries in u.u_pcb.
427 SAVE_U_PCB_REG(AT, AST, k1)
429 SAVE_U_PCB_REG(v0, V0, k1)
430 SAVE_U_PCB_REG(v1, V1, k1)
431 SAVE_U_PCB_REG(a0, A0, k1)
433 SAVE_U_PCB_REG(a1, A1, k1)
434 SAVE_U_PCB_REG(a2, A2, k1)
435 SAVE_U_PCB_REG(a3, A3, k1)
436 SAVE_U_PCB_REG(t0, T0, k1)
438 SAVE_U_PCB_REG(t1, T1, k1)
439 SAVE_U_PCB_REG(t2, T2, k1)
440 SAVE_U_PCB_REG(t3, T3, k1)
441 SAVE_U_PCB_REG(t4, T4, k1)
442 mfc0 a0, COP_0_STATUS_REG # First arg is the status reg.
443 SAVE_U_PCB_REG(t5, T5, k1)
444 SAVE_U_PCB_REG(t6, T6, k1)
445 SAVE_U_PCB_REG(t7, T7, k1)
446 SAVE_U_PCB_REG(s0, S0, k1)
447 mfc0 a1, COP_0_CAUSE_REG # Second arg is the cause reg.
448 SAVE_U_PCB_REG(s1, S1, k1)
449 SAVE_U_PCB_REG(s2, S2, k1)
450 SAVE_U_PCB_REG(s3, S3, k1)
451 SAVE_U_PCB_REG(s4, S4, k1)
452 mfc0 a2, COP_0_BAD_VADDR # Third arg is the fault addr
453 SAVE_U_PCB_REG(s5, S5, k1)
454 SAVE_U_PCB_REG(s6, S6, k1)
455 SAVE_U_PCB_REG(s7, S7, k1)
456 SAVE_U_PCB_REG(t8, T8, k1)
457 mfc0 a3, COP_0_EXC_PC # Fourth arg is the pc.
458 SAVE_U_PCB_REG(t9, T9, k1)
459 SAVE_U_PCB_REG(gp, GP, k1)
460 SAVE_U_PCB_REG(sp, SP, k1)
461 SAVE_U_PCB_REG(s8, S8, k1)
462 subu sp, k1, STAND_FRAME_SIZE # switch to kernel SP
463 SAVE_U_PCB_REG(ra, RA, k1)
464 SAVE_U_PCB_REG(v0, MULLO, k1)
465 SAVE_U_PCB_REG(v1, MULHI, k1)
466 SAVE_U_PCB_REG(a0, SR, k1)
467 SAVE_U_PCB_REG(a1, CAUSE, k1)
468 SAVE_U_PCB_REG(a2, BADVADDR, k1)
469 SAVE_U_PCB_REG(a3, PC, k1)
470 sw a3, STAND_RA_OFFSET(sp) # for debugging
471 la gp, _C_LABEL(_gp) # switch to kernel GP
472 # Turn off fpu and enter kernel mode
473 and t0, a0, ~(SR_COP_1_BIT | SR_EXL | SR_KSU_MASK | SR_INT_ENAB)
475 or t0, t0, (MIPS_SR_KX | MIPS_SR_SX | MIPS_SR_UX)
477 mtc0 t0, COP_0_STATUS_REG
478 addu a0, k1, U_PCB_REGS
482 * Call the exception handler.
484 la k0, _C_LABEL(trap)
488 * Restore user registers and return.
489 * First disable interrupts and set exeption level.
493 mtc0 zero, COP_0_STATUS_REG # disable int
496 mtc0 v0, COP_0_STATUS_REG # set exeption level
500 * The use of k1 for storing the PCB pointer must be done only
501 * after interrupts are disabled. Otherwise it will get overwritten
502 * by the interrupt code.
507 RESTORE_U_PCB_REG(t0, MULLO, k1)
508 RESTORE_U_PCB_REG(t1, MULHI, k1)
511 RESTORE_U_PCB_REG(a0, PC, k1)
512 RESTORE_U_PCB_REG(v0, V0, k1)
513 _MTC0 a0, COP_0_EXC_PC # set return address
514 RESTORE_U_PCB_REG(v1, V1, k1)
515 RESTORE_U_PCB_REG(a0, A0, k1)
516 RESTORE_U_PCB_REG(a1, A1, k1)
517 RESTORE_U_PCB_REG(a2, A2, k1)
518 RESTORE_U_PCB_REG(a3, A3, k1)
519 RESTORE_U_PCB_REG(t0, T0, k1)
520 RESTORE_U_PCB_REG(t1, T1, k1)
521 RESTORE_U_PCB_REG(t2, T2, k1)
522 RESTORE_U_PCB_REG(t3, T3, k1)
523 RESTORE_U_PCB_REG(t4, T4, k1)
524 RESTORE_U_PCB_REG(t5, T5, k1)
525 RESTORE_U_PCB_REG(t6, T6, k1)
526 RESTORE_U_PCB_REG(t7, T7, k1)
527 RESTORE_U_PCB_REG(s0, S0, k1)
528 RESTORE_U_PCB_REG(s1, S1, k1)
529 RESTORE_U_PCB_REG(s2, S2, k1)
530 RESTORE_U_PCB_REG(s3, S3, k1)
531 RESTORE_U_PCB_REG(s4, S4, k1)
532 RESTORE_U_PCB_REG(s5, S5, k1)
533 RESTORE_U_PCB_REG(s6, S6, k1)
534 RESTORE_U_PCB_REG(s7, S7, k1)
535 RESTORE_U_PCB_REG(t8, T8, k1)
536 RESTORE_U_PCB_REG(t9, T9, k1)
537 RESTORE_U_PCB_REG(gp, GP, k1)
538 RESTORE_U_PCB_REG(sp, SP, k1)
539 RESTORE_U_PCB_REG(k0, SR, k1)
540 RESTORE_U_PCB_REG(s8, S8, k1)
541 RESTORE_U_PCB_REG(ra, RA, k1)
543 and k0, k0, ~(MIPS_SR_KX | MIPS_SR_SX | MIPS_SR_UX)
545 or k0, k0, (MIPS_SR_INT_IE)
547 RESTORE_U_PCB_REG(AT, AST, k1)
550 * The restoration of the user SR must be done only after
551 * k1 is no longer needed. Otherwise, k1 will get clobbered after
552 * interrupts are enabled.
554 mtc0 k0, COP_0_STATUS_REG # still exeption level
559 END(MipsUserGenException)
561 /*----------------------------------------------------------------------------
565 * Handle an interrupt from kernel mode.
566 * Interrupts use the standard kernel stack.
567 * switch_exit sets up a kernel stack after exit so interrupts won't fail.
575 *----------------------------------------------------------------------------
578 NNON_LEAF(MipsKernIntr, KERN_EXC_FRAME_SIZE, ra)
580 subu sp, sp, KERN_EXC_FRAME_SIZE
581 .mask 0x80000000, (STAND_RA_OFFSET - KERN_EXC_FRAME_SIZE)
583 * Save the relevant kernel registers onto the stack.
588 * Call the interrupt handler.
591 addu a0, sp, STAND_ARG_SIZE
592 la k0, _C_LABEL(cpu_intr)
594 sw a3, STAND_RA_OFFSET + KERN_REG_SIZE(sp)
595 /* Why no AST processing here? */
597 * Restore registers and return from the interrupt.
599 lw v0, STAND_RA_OFFSET + KERN_REG_SIZE(sp)
606 /*----------------------------------------------------------------------------
610 * Handle an interrupt from user mode.
611 * Note: we save minimal state in the u.u_pcb struct and use the standard
612 * kernel stack since there has to be a u page if we came from user mode.
613 * If there is a pending software interrupt, then save the remaining state
614 * and call softintr(). This is all because if we call switch() inside
615 * interrupt(), not all the user registers have been saved in u.u_pcb.
623 *----------------------------------------------------------------------------
625 NNON_LEAF(MipsUserIntr, STAND_FRAME_SIZE, ra)
627 .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
629 * Save the relevant user registers into the u.u_pcb struct.
630 * We don't need to save s0 - s8 because the compiler does it for us.
634 SAVE_U_PCB_REG(AT, AST, k1)
636 SAVE_U_PCB_REG(v0, V0, k1)
637 SAVE_U_PCB_REG(v1, V1, k1)
638 SAVE_U_PCB_REG(a0, A0, k1)
639 SAVE_U_PCB_REG(a1, A1, k1)
640 SAVE_U_PCB_REG(a2, A2, k1)
641 SAVE_U_PCB_REG(a3, A3, k1)
642 SAVE_U_PCB_REG(t0, T0, k1)
643 SAVE_U_PCB_REG(t1, T1, k1)
644 SAVE_U_PCB_REG(t2, T2, k1)
645 SAVE_U_PCB_REG(t3, T3, k1)
646 SAVE_U_PCB_REG(t4, T4, k1)
647 SAVE_U_PCB_REG(t5, T5, k1)
648 SAVE_U_PCB_REG(t6, T6, k1)
649 SAVE_U_PCB_REG(t7, T7, k1)
650 SAVE_U_PCB_REG(t8, T8, k1)
651 SAVE_U_PCB_REG(t9, T9, k1)
652 SAVE_U_PCB_REG(gp, GP, k1)
653 SAVE_U_PCB_REG(sp, SP, k1)
654 SAVE_U_PCB_REG(ra, RA, k1)
656 * save remaining user state in u.u_pcb.
658 SAVE_U_PCB_REG(s0, S0, k1)
659 SAVE_U_PCB_REG(s1, S1, k1)
660 SAVE_U_PCB_REG(s2, S2, k1)
661 SAVE_U_PCB_REG(s3, S3, k1)
662 SAVE_U_PCB_REG(s4, S4, k1)
663 SAVE_U_PCB_REG(s5, S5, k1)
664 SAVE_U_PCB_REG(s6, S6, k1)
665 SAVE_U_PCB_REG(s7, S7, k1)
666 SAVE_U_PCB_REG(s8, S8, k1)
668 mflo v0 # get lo/hi late to avoid stall
670 mfc0 a0, COP_0_STATUS_REG
671 mfc0 a1, COP_0_CAUSE_REG
672 mfc0 a3, COP_0_EXC_PC
673 SAVE_U_PCB_REG(v0, MULLO, k1)
674 SAVE_U_PCB_REG(v1, MULHI, k1)
675 SAVE_U_PCB_REG(a0, SR, k1)
676 SAVE_U_PCB_REG(a1, CAUSE, k1)
677 SAVE_U_PCB_REG(a3, PC, k1) # PC in a3, note used later!
678 subu sp, k1, STAND_FRAME_SIZE # switch to kernel SP
679 la gp, _C_LABEL(_gp) # switch to kernel GP
681 # Turn off fpu, disable interrupts, set kernel mode kernel mode, clear exception level.
682 and t0, a0, ~(SR_COP_1_BIT | SR_EXL | SR_INT_ENAB | SR_KSU_MASK)
684 or t0, t0, (MIPS_SR_KX | MIPS_SR_SX | MIPS_SR_UX)
686 mtc0 t0, COP_0_STATUS_REG
688 addu a0, k1, U_PCB_REGS
690 * Call the interrupt handler.
692 la k0, _C_LABEL(cpu_intr)
694 sw a3, STAND_RA_OFFSET(sp) # for debugging
696 * Since interrupts are enabled at this point, we use a1 instead of
697 * k0 or k1 to store the PCB pointer. This is because k0 and k1
698 * are not preserved across interrupts. ** RRS - And how did the
699 * get enabled? cpu_intr clears the cause register but it does
700 * not touch the sr as far as I can see thus intr are still
706 * Restore user registers and return. NOTE: interrupts are enabled.
710 * Since interrupts are enabled at this point, we use a1 instead of
711 * k0 or k1 to store the PCB pointer. This is because k0 and k1
712 * are not preserved across interrupts.
714 mtc0 zero, COP_0_STATUS_REG
717 mtc0 v0, COP_0_STATUS_REG # set exeption level bit.
722 RESTORE_U_PCB_REG(s0, S0, k1)
723 RESTORE_U_PCB_REG(s1, S1, k1)
724 RESTORE_U_PCB_REG(s2, S2, k1)
725 RESTORE_U_PCB_REG(s3, S3, k1)
726 RESTORE_U_PCB_REG(s4, S4, k1)
727 RESTORE_U_PCB_REG(s5, S5, k1)
728 RESTORE_U_PCB_REG(s6, S6, k1)
729 RESTORE_U_PCB_REG(s7, S7, k1)
730 RESTORE_U_PCB_REG(s8, S8, k1)
731 RESTORE_U_PCB_REG(t0, MULLO, k1)
732 RESTORE_U_PCB_REG(t1, MULHI, k1)
733 RESTORE_U_PCB_REG(t2, PC, k1)
736 _MTC0 t2, COP_0_EXC_PC # set return address
737 RESTORE_U_PCB_REG(v0, V0, k1)
738 RESTORE_U_PCB_REG(v1, V1, k1)
739 RESTORE_U_PCB_REG(a0, A0, k1)
740 RESTORE_U_PCB_REG(a1, A1, k1)
741 RESTORE_U_PCB_REG(a2, A2, k1)
742 RESTORE_U_PCB_REG(a3, A3, k1)
743 RESTORE_U_PCB_REG(t0, T0, k1)
744 RESTORE_U_PCB_REG(t1, T1, k1)
745 RESTORE_U_PCB_REG(t2, T2, k1)
746 RESTORE_U_PCB_REG(t3, T3, k1)
747 RESTORE_U_PCB_REG(t4, T4, k1)
748 RESTORE_U_PCB_REG(t5, T5, k1)
749 RESTORE_U_PCB_REG(t6, T6, k1)
750 RESTORE_U_PCB_REG(t7, T7, k1)
751 RESTORE_U_PCB_REG(t8, T8, k1)
752 RESTORE_U_PCB_REG(t9, T9, k1)
753 RESTORE_U_PCB_REG(gp, GP, k1)
754 RESTORE_U_PCB_REG(k0, SR, k1)
755 RESTORE_U_PCB_REG(sp, SP, k1)
756 RESTORE_U_PCB_REG(ra, RA, k1)
758 and k0, k0, ~(MIPS_SR_KX | MIPS_SR_SX | MIPS_SR_UX)
760 or k0, k0, (MIPS_SR_INT_IE|SR_EXL)
762 RESTORE_U_PCB_REG(AT, AST, k1)
765 * The restoration of the user SR must be done only after
766 * k1 is no longer needed. Otherwise, k1 will get clobbered after
767 * interrupts are enabled.
769 mtc0 k0, COP_0_STATUS_REG # SR with EXL set.
776 /*----------------------------------------------------------------------------
778 * MipsTLBInvalidException --
780 * Handle a TLB invalid exception.
781 * The BaddVAddr, Context, and EntryHi registers contain the failed
790 *----------------------------------------------------------------------------
792 NLEAF(MipsTLBInvalidException)
794 mfc0 k0, COP_0_STATUS_REG
796 and k0, k0, SR_KSU_USER
797 bne k0, zero, _C_LABEL(MipsUserTLBInvalidException)
800 END(MipsTLBInvalidException)
805 NLEAF(MipsKernTLBInvalidException)
807 mfc0 k0, COP_0_BAD_VADDR # get the fault address
810 li k1, VM_MAXUSER_ADDRESS
817 lui k1, %hi(_C_LABEL(pcpup))
818 lw k1, %lo(_C_LABEL(pcpup))(k1)
820 lw k1, PC_SEGBASE(k1) # works for single cpu????
821 beqz k1, _C_LABEL(MipsKernGenException) # seg tab is null
826 li k1, (VM_MAX_KERNEL_ADDRESS)
827 bgez k0, _C_LABEL(MipsKernGenException) # full trap processing
828 sltu k1, k1, k0 # check fault address against
829 bnez k1, _C_LABEL(MipsKernGenException) # kernel_segmap upper bound
830 lui k1, %hi(_C_LABEL(kernel_segmap)) # k1=hi of segbase
831 lw k1, %lo(_C_LABEL(kernel_segmap))(k1) # k1=segment tab base
832 beqz k1, _C_LABEL(MipsKernGenException) # seg tab is null
834 srl k0, 20 # k0=seg offset (almost)
835 andi k0, k0, 0xffc # k0=seg offset (mask 0x3)
836 addu k1, k0, k1 # k1=seg entry address
837 lw k1, 0(k1) # k1=seg entry
838 mfc0 k0, COP_0_BAD_VADDR # k0=bad address (again)
839 beq k1, zero, _C_LABEL(MipsKernGenException) # ==0 -- no page table
840 srl k0, k0, PGSHIFT-2
841 andi k0, k0, 0xffc # compute offset from index
842 tlbp # Probe the invalid entry
844 and k0, k0, 4 # check even/odd page
845 nop # required for QED 5230
846 bne k0, zero, KernTLBIOdd
849 mfc0 k0, COP_0_TLB_INDEX
853 sltiu k0, k0, VMWIRED_ENTRIES # index below wired entries?
854 bne k0, zero, sys_stk_chk
855 lw k0, 0(k1) # get PTE entry
857 _SLL k0, k0, WIRED_SHIFT # get rid of "wired" bit
858 _SRL k0, k0, WIRED_SHIFT
859 _MTC0 k0, COP_0_TLB_LO0 # load PTE entry
860 and k0, k0, PTE_V # check for valid entry
861 nop # required for QED5230
862 beq k0, zero, _C_LABEL(MipsKernGenException) # PTE invalid
863 lw k0, 4(k1) # get odd PTE entry
864 _SLL k0, k0, WIRED_SHIFT
865 _SRL k0, k0, WIRED_SHIFT
866 _MTC0 k0, COP_0_TLB_LO1 # load PTE entry
873 mfc0 k0, COP_0_TLB_INDEX
877 sltiu k0, k0, VMWIRED_ENTRIES # index below wired entries?
878 bne k0, zero, sys_stk_chk
879 lw k0, 0(k1) # get PTE entry
881 _SLL k0, k0, WIRED_SHIFT # get rid of wired bit
882 _SRL k0, k0, WIRED_SHIFT
883 _MTC0 k0, COP_0_TLB_LO1 # save PTE entry
884 and k0, k0, PTE_V # check for valid entry
885 nop # required for QED5230
886 beq k0, zero, _C_LABEL(MipsKernGenException) # PTE invalid
887 lw k0, -4(k1) # get even PTE entry
888 _SLL k0, k0, WIRED_SHIFT
889 _SRL k0, k0, WIRED_SHIFT
890 _MTC0 k0, COP_0_TLB_LO0 # save PTE entry
897 END(MipsKernTLBInvalidException)
900 NLEAF(MipsUserTLBInvalidException)
902 mfc0 k0, COP_0_BAD_VADDR # get the fault address
904 li k1, VM_MAXUSER_ADDRESS
906 beqz k1, _C_LABEL(MipsUserGenException)
911 lui k1, %hi(_C_LABEL(pcpup))
912 lw k1, %lo(_C_LABEL(pcpup))(k1)
914 lw k1, PC_SEGBASE(k1) # works for single cpu????
915 beqz k1, _C_LABEL(MipsUserGenException) # seg tab is null
918 srl k0, 20 # k0=seg offset (almost)
919 andi k0, k0, 0xffc # k0=seg offset (mask 0x3)
920 addu k1, k0, k1 # k1=seg entry address
921 lw k1, 0(k1) # k1=seg entry
922 mfc0 k0, COP_0_BAD_VADDR # k0=bad address (again)
923 beq k1, zero, _C_LABEL(MipsUserGenException) # ==0 -- no page table
924 srl k0, k0, PGSHIFT-2
925 andi k0, k0, 0xffc # compute offset from index
926 tlbp # Probe the invalid entry
928 and k0, k0, 4 # check even/odd page
929 nop # required for QED 5230
930 bne k0, zero, UserTLBIOdd
933 mfc0 k0, COP_0_TLB_INDEX
935 bltz k0, _C_LABEL(MipsUserGenException)
937 sltiu k0, k0, VMWIRED_ENTRIES # index below wired entries?
938 bne k0, zero, _C_LABEL(MipsUserGenException)
939 lw k0, 0(k1) # get PTE entry
941 _SLL k0, k0, WIRED_SHIFT # get rid of "wired" bit
942 _SRL k0, k0, WIRED_SHIFT
943 _MTC0 k0, COP_0_TLB_LO0 # load PTE entry
944 and k0, k0, PTE_V # check for valid entry
945 nop # required for QED5230
946 beq k0, zero, _C_LABEL(MipsUserGenException) # PTE invalid
947 lw k0, 4(k1) # get odd PTE entry
948 _SLL k0, k0, WIRED_SHIFT
949 _SRL k0, k0, WIRED_SHIFT
950 _MTC0 k0, COP_0_TLB_LO1 # load PTE entry
957 mfc0 k0, COP_0_TLB_INDEX
959 bltz k0, _C_LABEL(MipsUserGenException)
960 sltiu k0, k0, VMWIRED_ENTRIES # index below wired entries?
962 bne k0, zero, _C_LABEL(MipsUserGenException)
963 lw k0, 0(k1) # get PTE entry
965 _SLL k0, k0, WIRED_SHIFT # get rid of wired bit
966 _SRL k0, k0, WIRED_SHIFT
967 _MTC0 k0, COP_0_TLB_LO1 # save PTE entry
968 and k0, k0, PTE_V # check for valid entry
969 nop # required for QED5230
970 beq k0, zero, _C_LABEL(MipsUserGenException) # PTE invalid
971 lw k0, -4(k1) # get even PTE entry
972 _SLL k0, k0, WIRED_SHIFT
973 _SRL k0, k0, WIRED_SHIFT
974 _MTC0 k0, COP_0_TLB_LO0 # save PTE entry
981 END(MipsUserTLBInvalidException)
983 /*----------------------------------------------------------------------------
985 * MipsTLBMissException --
987 * Handle a TLB miss exception from kernel mode in kernel space.
988 * The BaddVAddr, Context, and EntryHi registers contain the failed
997 *----------------------------------------------------------------------------
999 NLEAF(MipsTLBMissException)
1001 mfc0 k0, COP_0_BAD_VADDR # k0=bad address
1002 li k1, (VM_MAX_KERNEL_ADDRESS) # check fault address against
1003 sltu k1, k1, k0 # upper bound of kernel_segmap
1004 bnez k1, _C_LABEL(MipsKernGenException) # out of bound
1005 lui k1, %hi(_C_LABEL(kernel_segmap)) # k1=hi of segbase
1006 srl k0, 20 # k0=seg offset (almost)
1007 lw k1, %lo(_C_LABEL(kernel_segmap))(k1) # k1=segment tab base
1008 beq k1, zero, _C_LABEL(MipsKernGenException) # ==0 -- no seg tab
1009 andi k0, k0, 0xffc # k0=seg offset (mask 0x3)
1010 addu k1, k0, k1 # k1=seg entry address
1011 lw k1, 0(k1) # k1=seg entry
1012 mfc0 k0, COP_0_BAD_VADDR # k0=bad address (again)
1013 beq k1, zero, _C_LABEL(MipsKernGenException) # ==0 -- no page table
1014 srl k0, 10 # k0=VPN (aka va>>10)
1015 andi k0, k0, 0xff8 # k0=page tab offset
1016 addu k1, k1, k0 # k1=pte address
1017 lw k0, 0(k1) # k0=lo0 pte
1018 lw k1, 4(k1) # k1=lo1 pte
1019 _SLL k0, WIRED_SHIFT # chop bits [31..30]
1020 _SRL k0, WIRED_SHIFT # chop bits [31..30]
1021 _MTC0 k0, COP_0_TLB_LO0 # lo0 is loaded
1022 _SLL k1, WIRED_SHIFT # chop bits [31..30]
1023 _SRL k1, WIRED_SHIFT # chop bits [31..30]
1024 _MTC0 k1, COP_0_TLB_LO1 # lo1 is loaded
1027 tlbwr # write to tlb
1029 eret # return from exception
1033 lw k0, PC_CURTHREAD(k0)
1034 lw k0, TD_REALKSTACK(k0)
1035 sltu k0, sp, k0 # check for stack overflow
1036 beqz k0, _C_LABEL(MipsKernGenException) # not stack overflow
1040 la a0, _C_LABEL(_start) - START_FRAME - 8 # set sp to a valid place
1044 mfc0 a2, COP_0_STATUS_REG
1045 mfc0 a3, COP_0_CAUSE_REG
1046 _MFC0 a1, COP_0_EXC_PC
1050 la k0, _C_LABEL(printf)
1052 mfc0 a3, COP_0_BAD_VADDR
1054 la sp, _C_LABEL(_start) - START_FRAME # set sp to a valid place
1056 #if !defined(SMP) && defined(DDB)
1058 la k0, _C_LABEL(trapDump)
1063 lw a1, _C_LABEL(num_tlbentries)
1064 la k0, _C_LABEL(db_dump_tlb)
1073 PANIC("kernel stack overflow")
1087 .asciiz "ktlbmiss: PC %x RA %x ADR %x\nSR %x CR %x SP %x\n"
1093 END(MipsTLBMissException)
1095 /*----------------------------------------------------------------------------
1099 * Handle a floating point Trap.
1101 * MipsFPTrap(statusReg, causeReg, pc)
1102 * unsigned statusReg;
1103 * unsigned causeReg;
1112 *----------------------------------------------------------------------------
1114 NON_LEAF(MipsFPTrap, STAND_FRAME_SIZE, ra)
1115 subu sp, sp, STAND_FRAME_SIZE
1116 mfc0 t0, COP_0_STATUS_REG
1117 sw ra, STAND_RA_OFFSET(sp)
1118 .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
1120 or t1, t0, SR_COP_1_BIT
1121 mtc0 t1, COP_0_STATUS_REG
1123 cfc1 t1, FPC_CSR # stall til FP done
1124 cfc1 t1, FPC_CSR # now get status
1126 sll t2, t1, (31 - 17) # unimplemented operation?
1127 bgez t2, 3f # no, normal trap
1130 * We got an unimplemented operation trap so
1131 * fetch the instruction, compute the next PC and emulate the instruction.
1133 bgez a1, 1f # Check the branch delay bit.
1136 * The instruction is in the branch delay slot so the branch will have to
1137 * be emulated to get the resulting PC.
1139 sw a2, STAND_FRAME_SIZE + 8(sp)
1141 lw a0, PC_CURPCB(a0)
1142 addu a0, a0, U_PCB_REGS # first arg is ptr to CPU registers
1143 move a1, a2 # second arg is instruction PC
1144 move a2, t1 # third arg is floating point CSR
1145 la t3, _C_LABEL(MipsEmulateBranch) # compute PC after branch
1146 jalr t3 # compute PC after branch
1147 move a3, zero # fourth arg is FALSE
1149 * Now load the floating-point instruction in the branch delay slot
1152 lw a2, STAND_FRAME_SIZE + 8(sp) # restore EXC pc
1154 lw a0, 4(a2) # a0 = coproc instruction
1156 * This is not in the branch delay slot so calculate the resulting
1157 * PC (epc + 4) into v0 and continue to MipsEmulateFP().
1160 lw a0, 0(a2) # a0 = coproc instruction
1161 addu v0, a2, 4 # v0 = next pc
1164 lw t2, PC_CURPCB(t2)
1165 SAVE_U_PCB_REG(v0, PC, t2) # save new pc
1167 * Check to see if the instruction to be emulated is a floating-point
1170 srl a3, a0, OPCODE_SHIFT
1171 beq a3, OPCODE_C1, 4f # this should never fail
1174 * Send a floating point exception signal to the current process.
1178 lw a0, PC_CURTHREAD(a0) # get current thread
1179 cfc1 a2, FPC_CSR # code = FP execptions
1180 ctc1 zero, FPC_CSR # Clear exceptions
1181 la t3, _C_LABEL(trapsignal)
1188 * Finally, we can call MipsEmulateFP() where a0 is the instruction to emulate.
1191 la t3, _C_LABEL(MipsEmulateFP)
1196 * Turn off the floating point coprocessor and return.
1199 mfc0 t0, COP_0_STATUS_REG
1200 lw ra, STAND_RA_OFFSET(sp)
1201 and t0, t0, ~SR_COP_1_BIT
1202 mtc0 t0, COP_0_STATUS_REG
1205 addu sp, sp, STAND_FRAME_SIZE
1211 * Atomic ipending update
1226 * Interrupt counters for vmstat.
1247 * Vector to real handler in KSEG1.
1250 VECTOR(MipsCache, unknown)
1251 la k0, _C_LABEL(MipsCacheException)
1252 li k1, MIPS_PHYS_MASK
1254 li k1, MIPS_UNCACHED_MEMORY_ADDR
1258 VECTOR_END(MipsCache)
1264 * Panic on cache errors. A lot more could be done to recover
1265 * from some types of errors but it is tricky.
1267 NESTED_NOPROFILE(MipsCacheException, KERN_EXC_FRAME_SIZE, ra)
1269 .mask 0x80000000, -4
1270 la k0, _C_LABEL(panic) # return to panic
1271 la a0, 9f # panicstr
1272 _MFC0 a1, COP_0_ERROR_PC
1273 mfc0 a2, COP_0_CACHE_ERR # 3rd arg cache error
1275 _MTC0 k0, COP_0_ERROR_PC # set return address
1277 mfc0 k0, COP_0_STATUS_REG # restore status
1278 li k1, SR_DIAG_DE # ignore further errors
1280 mtc0 k0, COP_0_STATUS_REG # restore status
1285 MSG("cache error @ EPC 0x%x CachErr 0x%x");
1287 END(MipsCacheException)