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