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