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