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$
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#include "opt_kdtrace.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 "assym.s"
66
67	.set	noreorder		# Noreorder is default style!
68
69#ifdef KDTRACE_HOOKS
70	.data
71	.globl	dtrace_invop_jump_addr
72	.align	4
73	.type	dtrace_invop_jump_addr, @object
74        .size	dtrace_invop_jump_addr, 8
75dtrace_invop_jump_addr:
76	.word	0
77	.word	0
78	.globl	dtrace_invop_calltrap_addr
79	.align	4
80	.type	dtrace_invop_calltrap_addr, @object
81        .size	dtrace_invop_calltrap_addr, 8
82dtrace_invop_calltrap_addr:
83	.word	0
84	.word	0
85
86	.text
87#endif
88
89/*
90 * Reasonable limit
91 */
92#define	INTRCNT_COUNT	256
93
94
95/*
96 *----------------------------------------------------------------------------
97 *
98 * MipsTLBMiss --
99 *
100 *	Vector code for the TLB-miss exception vector 0x80000000.
101 *
102 * This code is copied to the TLB exception vector address to
103 * which the CPU jumps in response to an exception or a TLB miss.
104 * NOTE: This code must be position independent!!!
105 *
106 *
107 */
108VECTOR(MipsTLBMiss, unknown)
109	.set push
110	.set noat
111	j	MipsDoTLBMiss
112	MFC0	k0, MIPS_COP_0_BAD_VADDR	# get the fault address
113	.set pop
114VECTOR_END(MipsTLBMiss)
115
116/*
117 *----------------------------------------------------------------------------
118 *
119 * MipsDoTLBMiss --
120 *
121 * This is the real TLB Miss Handler code.
122 * 'segbase' points to the base of the segment table for user processes.
123 *
124 * Don't check for invalid pte's here. We load them as well and
125 * let the processor trap to load the correct value after service.
126 *----------------------------------------------------------------------------
127 */
128 	.set push
129	.set noat
130MipsDoTLBMiss:
131	bltz		k0, 1f				#02: k0<0 -> 1f (kernel fault)
132	PTR_SRL		k0, k0, SEGSHIFT - PTRSHIFT	#03: k0=seg offset (almost)
133
134	GET_CPU_PCPU(k1)
135	PTR_L		k1, PC_SEGBASE(k1)
136	beqz		k1, 2f				#05: make sure segbase is not null
137	andi		k0, k0, PDEPTRMASK		#06: k0=seg offset
138	PTR_ADDU	k1, k0, k1			#07: k1=seg entry address
139
140	PTR_L		k1, 0(k1)			#08: k1=seg entry
141	MFC0		k0, MIPS_COP_0_BAD_VADDR	#09: k0=bad address (again)
142	beq		k1, zero, 2f			#0a: ==0 -- no page table
143#ifdef __mips_n64
144	PTR_SRL		k0, PDRSHIFT - PTRSHIFT		# k0=VPN
145	andi		k0, k0, PDEPTRMASK		# k0=pde offset
146	PTR_ADDU	k1, k0, k1			# k1=pde entry address
147	PTR_L		k1, 0(k1)			# k1=pde entry
148	MFC0		k0, MIPS_COP_0_BAD_VADDR	# k0=bad address (again)
149	beq		k1, zero, 2f			# ==0 -- no page table
150#endif
151	PTR_SRL		k0, PAGE_SHIFT - PTESHIFT	#0b: k0=VPN (aka va>>10)
152	andi		k0, k0, PTE2MASK		#0c: k0=page tab offset
153	PTR_ADDU	k1, k1, k0			#0d: k1=pte address
154	PTE_L		k0, 0(k1)			#0e: k0=lo0 pte
155	PTE_L		k1, PTESIZE(k1)			#0f: k1=lo0 pte
156	CLEAR_PTE_SWBITS(k0)
157	PTE_MTC0	k0, MIPS_COP_0_TLB_LO0		#12: lo0 is loaded
158	COP0_SYNC
159	CLEAR_PTE_SWBITS(k1)
160	PTE_MTC0	k1, MIPS_COP_0_TLB_LO1		#15: lo1 is loaded
161	COP0_SYNC
162	tlbwr						#1a: write to tlb
163	HAZARD_DELAY
164	eret						#1f: retUrn from exception
1651:	j		MipsTLBMissException		#20: kernel exception
166	nop						#21: branch delay slot
1672:	j		SlowFault			#22: no page table present
168	nop						#23: branch delay slot
169	.set pop
170
171/*
172 * This code is copied to the general exception vector address to
173 * handle all execptions except RESET and TLBMiss.
174 * NOTE: This code must be position independent!!!
175 */
176VECTOR(MipsException, unknown)
177/*
178 * Find out what mode we came from and jump to the proper handler.
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
1921:
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
204VECTOR_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 */
210SlowFault:
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
379NNON_LEAF(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
411END(MipsKernGenException)
412
413
414#define	SAVE_U_PCB_REG(reg, offs, base) \
415	REG_S	reg, U_PCB_REGS + (SZREG * offs) (base)
416
417#define	RESTORE_U_PCB_REG(reg, offs, base) \
418	REG_L	reg, U_PCB_REGS + (SZREG * offs) (base)
419
420/*----------------------------------------------------------------------------
421 *
422 * MipsUserGenException --
423 *
424 *	Handle an exception from user mode.
425 *
426 * Results:
427 *	None.
428 *
429 * Side effects:
430 *	None.
431 *
432 *----------------------------------------------------------------------------
433 */
434NNON_LEAF(MipsUserGenException, CALLFRAME_SIZ, ra)
435	.set	noat
436	.mask	0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ)
437/*
438 * Save all of the registers except for the kernel temporaries in u.u_pcb.
439 */
440	GET_CPU_PCPU(k1)
441	PTR_L	k1, PC_CURPCB(k1)
442	SAVE_U_PCB_REG(AT, AST, k1)
443	.set	at
444	SAVE_U_PCB_REG(v0, V0, k1)
445	SAVE_U_PCB_REG(v1, V1, k1)
446	SAVE_U_PCB_REG(a0, A0, k1)
447	mflo	v0
448	SAVE_U_PCB_REG(a1, A1, k1)
449	SAVE_U_PCB_REG(a2, A2, k1)
450	SAVE_U_PCB_REG(a3, A3, k1)
451	SAVE_U_PCB_REG(t0, T0, k1)
452	mfhi	v1
453	SAVE_U_PCB_REG(t1, T1, k1)
454	SAVE_U_PCB_REG(t2, T2, k1)
455	SAVE_U_PCB_REG(t3, T3, k1)
456	SAVE_U_PCB_REG(ta0, TA0, k1)
457	mfc0	a0, MIPS_COP_0_STATUS		# First arg is the status reg.
458	SAVE_U_PCB_REG(ta1, TA1, k1)
459	SAVE_U_PCB_REG(ta2, TA2, k1)
460	SAVE_U_PCB_REG(ta3, TA3, k1)
461	SAVE_U_PCB_REG(s0, S0, k1)
462	mfc0	a1, MIPS_COP_0_CAUSE		# Second arg is the cause reg.
463	SAVE_U_PCB_REG(s1, S1, k1)
464	SAVE_U_PCB_REG(s2, S2, k1)
465	SAVE_U_PCB_REG(s3, S3, k1)
466	SAVE_U_PCB_REG(s4, S4, k1)
467	MFC0	a2, MIPS_COP_0_BAD_VADDR	# Third arg is the fault addr
468	SAVE_U_PCB_REG(s5, S5, k1)
469	SAVE_U_PCB_REG(s6, S6, k1)
470	SAVE_U_PCB_REG(s7, S7, k1)
471	SAVE_U_PCB_REG(t8, T8, k1)
472	MFC0	a3, MIPS_COP_0_EXC_PC		# Fourth arg is the pc.
473	SAVE_U_PCB_REG(t9, T9, k1)
474	SAVE_U_PCB_REG(gp, GP, k1)
475	SAVE_U_PCB_REG(sp, SP, k1)
476	SAVE_U_PCB_REG(s8, S8, k1)
477	PTR_SUBU	sp, k1, CALLFRAME_SIZ	 # switch to kernel SP
478	SAVE_U_PCB_REG(ra, RA, k1)
479	SAVE_U_PCB_REG(v0, MULLO, k1)
480	SAVE_U_PCB_REG(v1, MULHI, k1)
481	SAVE_U_PCB_REG(a0, SR, k1)
482	SAVE_U_PCB_REG(a1, CAUSE, k1)
483	SAVE_U_PCB_REG(a2, BADVADDR, k1)
484	SAVE_U_PCB_REG(a3, PC, k1)
485	REG_S	a3, CALLFRAME_RA(sp)	# for debugging
486	PTR_LA	gp, _C_LABEL(_gp)	# switch to kernel GP
487# Turn off fpu and enter kernel mode
488	and	t0, a0, ~(MIPS_SR_COP_1_BIT | MIPS_SR_EXL | MIPS_SR_KSU_MASK | MIPS_SR_INT_IE)
489#if defined(CPU_CNMIPS)
490	and	t0, t0, ~(MIPS_SR_COP_2_BIT)
491	or      t0, t0, (MIPS_SR_KX | MIPS_SR_SX | MIPS_SR_UX | MIPS_SR_PX)
492#elif defined(CPU_RMI)	|| defined(CPU_NLM)
493	or      t0, t0, (MIPS_SR_KX | MIPS_SR_UX | MIPS_SR_COP_2_BIT)
494#endif
495	mtc0	t0, MIPS_COP_0_STATUS
496	PTR_ADDU a0, k1, U_PCB_REGS
497	ITLBNOPFIX
498
499/*
500 * Call the exception handler.
501 */
502	PTR_LA	k0, _C_LABEL(trap)
503	jalr	k0
504	nop
505
506/*
507 * Restore user registers and return.
508 * First disable interrupts and set exeption level.
509 */
510	DO_AST
511
512	CLEAR_STATUS
513
514/*
515 * The use of k1 for storing the PCB pointer must be done only
516 * after interrupts are disabled.  Otherwise it will get overwritten
517 * by the interrupt code.
518 */
519	GET_CPU_PCPU(k1)
520	PTR_L	k1, PC_CURPCB(k1)
521
522	/*
523	 * Update interrupt mask in saved status register
524	 * Some of interrupts could be enabled by ithread
525	 * scheduled by ast()
526	 */
527	mfc0	a0, MIPS_COP_0_STATUS
528	and	a0, a0, MIPS_SR_INT_MASK
529	RESTORE_U_PCB_REG(a1, SR, k1)
530	and	a1, a1, ~MIPS_SR_INT_MASK
531	or	a1, a1, a0
532	SAVE_U_PCB_REG(a1, SR, k1)
533
534	RESTORE_U_PCB_REG(t0, MULLO, k1)
535	RESTORE_U_PCB_REG(t1, MULHI, k1)
536	mtlo	t0
537	mthi	t1
538	RESTORE_U_PCB_REG(a0, PC, k1)
539	RESTORE_U_PCB_REG(v0, V0, k1)
540        MTC0	a0, MIPS_COP_0_EXC_PC	# set return address
541	RESTORE_U_PCB_REG(v1, V1, k1)
542	RESTORE_U_PCB_REG(a0, A0, k1)
543	RESTORE_U_PCB_REG(a1, A1, k1)
544	RESTORE_U_PCB_REG(a2, A2, k1)
545	RESTORE_U_PCB_REG(a3, A3, k1)
546	RESTORE_U_PCB_REG(t0, T0, k1)
547	RESTORE_U_PCB_REG(t1, T1, k1)
548	RESTORE_U_PCB_REG(t2, T2, k1)
549	RESTORE_U_PCB_REG(t3, T3, k1)
550	RESTORE_U_PCB_REG(ta0, TA0, k1)
551	RESTORE_U_PCB_REG(ta1, TA1, k1)
552	RESTORE_U_PCB_REG(ta2, TA2, k1)
553	RESTORE_U_PCB_REG(ta3, TA3, k1)
554	RESTORE_U_PCB_REG(s0, S0, k1)
555	RESTORE_U_PCB_REG(s1, S1, k1)
556	RESTORE_U_PCB_REG(s2, S2, k1)
557	RESTORE_U_PCB_REG(s3, S3, k1)
558	RESTORE_U_PCB_REG(s4, S4, k1)
559	RESTORE_U_PCB_REG(s5, S5, k1)
560	RESTORE_U_PCB_REG(s6, S6, k1)
561	RESTORE_U_PCB_REG(s7, S7, k1)
562	RESTORE_U_PCB_REG(t8, T8, k1)
563	RESTORE_U_PCB_REG(t9, T9, k1)
564	RESTORE_U_PCB_REG(gp, GP, k1)
565	RESTORE_U_PCB_REG(sp, SP, k1)
566	RESTORE_U_PCB_REG(k0, SR, k1)
567	RESTORE_U_PCB_REG(s8, S8, k1)
568	RESTORE_U_PCB_REG(ra, RA, k1)
569	.set noat
570	RESTORE_U_PCB_REG(AT, AST, k1)
571
572	mtc0	k0, MIPS_COP_0_STATUS	# still exception level
573	ITLBNOPFIX
574	sync
575	eret
576	.set	at
577END(MipsUserGenException)
578
579	.set	push
580	.set	noat
581NON_LEAF(mips_wait, CALLFRAME_SIZ, ra)
582	PTR_SUBU        sp, sp, CALLFRAME_SIZ
583	.mask   0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ)
584	REG_S   ra, CALLFRAME_RA(sp)		# save RA
585	mfc0	t0, MIPS_COP_0_STATUS
586	xori	t1, t0, MIPS_SR_INT_IE
587	mtc0	t1, MIPS_COP_0_STATUS
588	COP0_SYNC
589	jal	sched_runnable
590	nop
591	REG_L   ra, CALLFRAME_RA(sp)
592	mfc0	t0, MIPS_COP_0_STATUS
593	ori	t1, t0, MIPS_SR_INT_IE
594	.align 4
595GLOBAL(MipsWaitStart)			# this is 16 byte aligned
596	mtc0	t1, MIPS_COP_0_STATUS
597	bnez	v0, MipsWaitEnd
598	nop
599	wait
600GLOBAL(MipsWaitEnd)			# MipsWaitStart + 16
601	jr	ra
602	PTR_ADDU        sp, sp, CALLFRAME_SIZ
603END(mips_wait)
604	.set	pop
605
606/*----------------------------------------------------------------------------
607 *
608 * MipsKernIntr --
609 *
610 *	Handle an interrupt from kernel mode.
611 *	Interrupts use the standard kernel stack.
612 *	switch_exit sets up a kernel stack after exit so interrupts won't fail.
613 *
614 * Results:
615 *	None.
616 *
617 * Side effects:
618 *	None.
619 *
620 *----------------------------------------------------------------------------
621 */
622
623NNON_LEAF(MipsKernIntr, KERN_EXC_FRAME_SIZE, ra)
624	.set	noat
625	PTR_SUBU	sp, sp, KERN_EXC_FRAME_SIZE
626	.mask	0x80000000, (CALLFRAME_RA - KERN_EXC_FRAME_SIZE)
627
628/*
629 * Check for getting interrupts just before wait
630 */
631	MFC0	k0, MIPS_COP_0_EXC_PC
632	ori	k0, 0xf
633	xori	k0, 0xf			# 16 byte align
634	PTR_LA	k1, MipsWaitStart
635	bne	k0, k1, 1f
636	nop
637	PTR_ADDU k1, 16			# skip over wait
638	MTC0	k1, MIPS_COP_0_EXC_PC
6391:
640/*
641 *  Save CPU state, building 'frame'.
642 */
643	SAVE_CPU
644/*
645 *  Call the interrupt handler. a0 points at the saved frame.
646 */
647	PTR_LA	gp, _C_LABEL(_gp)
648	PTR_LA	k0, _C_LABEL(cpu_intr)
649	jalr	k0
650	REG_S	a3, CALLFRAME_RA + KERN_REG_SIZE(sp)		# for debugging
651
652	/*
653	 * Update interrupt and CPU mask in saved status register
654	 * Some of interrupts could be disabled by
655	 * intr filters if interrupts are enabled later
656	 * in trap handler
657	 */
658	mfc0	a0, MIPS_COP_0_STATUS
659	and	a0, a0, (MIPS_SR_INT_MASK|MIPS_SR_COP_USABILITY)
660	RESTORE_REG(a1, SR, sp)
661	and	a1, a1, ~(MIPS_SR_INT_MASK|MIPS_SR_COP_USABILITY)
662	or	a1, a1, a0
663	SAVE_REG(a1, SR, sp)
664	REG_L	v0, CALLFRAME_RA + KERN_REG_SIZE(sp)
665	RESTORE_CPU			# v0 contains the return address.
666	sync
667	eret
668	.set	at
669END(MipsKernIntr)
670
671/*----------------------------------------------------------------------------
672 *
673 * MipsUserIntr --
674 *
675 *	Handle an interrupt from user mode.
676 *	Note: we save minimal state in the u.u_pcb struct and use the standard
677 *	kernel stack since there has to be a u page if we came from user mode.
678 *	If there is a pending software interrupt, then save the remaining state
679 *	and call softintr(). This is all because if we call switch() inside
680 *	interrupt(), not all the user registers have been saved in u.u_pcb.
681 *
682 * Results:
683 *	None.
684 *
685 * Side effects:
686 *	None.
687 *
688 *----------------------------------------------------------------------------
689 */
690NNON_LEAF(MipsUserIntr, CALLFRAME_SIZ, ra)
691	.set	noat
692	.mask	0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ)
693/*
694 * Save the relevant user registers into the u.u_pcb struct.
695 * We don't need to save s0 - s8 because the compiler does it for us.
696 */
697	GET_CPU_PCPU(k1)
698	PTR_L	k1, PC_CURPCB(k1)
699	SAVE_U_PCB_REG(AT, AST, k1)
700	.set	at
701	SAVE_U_PCB_REG(v0, V0, k1)
702	SAVE_U_PCB_REG(v1, V1, k1)
703	SAVE_U_PCB_REG(a0, A0, k1)
704	SAVE_U_PCB_REG(a1, A1, k1)
705	SAVE_U_PCB_REG(a2, A2, k1)
706	SAVE_U_PCB_REG(a3, A3, k1)
707	SAVE_U_PCB_REG(t0, T0, k1)
708	SAVE_U_PCB_REG(t1, T1, k1)
709	SAVE_U_PCB_REG(t2, T2, k1)
710	SAVE_U_PCB_REG(t3, T3, k1)
711	SAVE_U_PCB_REG(ta0, TA0, k1)
712	SAVE_U_PCB_REG(ta1, TA1, k1)
713	SAVE_U_PCB_REG(ta2, TA2, k1)
714	SAVE_U_PCB_REG(ta3, TA3, k1)
715	SAVE_U_PCB_REG(t8, T8, k1)
716	SAVE_U_PCB_REG(t9, T9, k1)
717	SAVE_U_PCB_REG(gp, GP, k1)
718	SAVE_U_PCB_REG(sp, SP, k1)
719	SAVE_U_PCB_REG(ra, RA, k1)
720/*
721 *  save remaining user state in u.u_pcb.
722 */
723	SAVE_U_PCB_REG(s0, S0, k1)
724	SAVE_U_PCB_REG(s1, S1, k1)
725	SAVE_U_PCB_REG(s2, S2, k1)
726	SAVE_U_PCB_REG(s3, S3, k1)
727	SAVE_U_PCB_REG(s4, S4, k1)
728	SAVE_U_PCB_REG(s5, S5, k1)
729	SAVE_U_PCB_REG(s6, S6, k1)
730	SAVE_U_PCB_REG(s7, S7, k1)
731	SAVE_U_PCB_REG(s8, S8, k1)
732
733	mflo	v0			# get lo/hi late to avoid stall
734	mfhi	v1
735	mfc0	a0, MIPS_COP_0_STATUS
736	mfc0	a1, MIPS_COP_0_CAUSE
737	MFC0	a3, MIPS_COP_0_EXC_PC
738	SAVE_U_PCB_REG(v0, MULLO, k1)
739	SAVE_U_PCB_REG(v1, MULHI, k1)
740	SAVE_U_PCB_REG(a0, SR, k1)
741	SAVE_U_PCB_REG(a1, CAUSE, k1)
742	SAVE_U_PCB_REG(a3, PC, k1)	# PC in a3, note used later!
743	PTR_SUBU	sp, k1, CALLFRAME_SIZ  # switch to kernel SP
744	PTR_LA	gp, _C_LABEL(_gp)	# switch to kernel GP
745
746# Turn off fpu, disable interrupts, set kernel mode kernel mode, clear exception level.
747	and	t0, a0, ~(MIPS_SR_COP_1_BIT | MIPS_SR_EXL | MIPS_SR_INT_IE | MIPS_SR_KSU_MASK)
748#ifdef CPU_CNMIPS
749	and	t0, t0, ~(MIPS_SR_COP_2_BIT)
750	or      t0, t0, (MIPS_SR_KX | MIPS_SR_SX | MIPS_SR_UX | MIPS_SR_PX)
751#elif defined(CPU_RMI)	|| defined(CPU_NLM)
752	or      t0, t0, (MIPS_SR_KX | MIPS_SR_UX | MIPS_SR_COP_2_BIT)
753#endif
754	mtc0	t0, MIPS_COP_0_STATUS
755	ITLBNOPFIX
756	PTR_ADDU a0, k1, U_PCB_REGS
757/*
758 * Call the interrupt handler.
759 */
760	PTR_LA	k0, _C_LABEL(cpu_intr)
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
844END(MipsUserIntr)
845
846NLEAF(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
8621:	/* User address.  */
863	GET_CPU_PCPU(k1)
864	PTR_L		k1, PC_SEGBASE(k1)
865
8662:	/* 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
920odd_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
930tlb_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
940tlb_insert_random:
941	tlbwr
942	eret
943	ssnop
944
9453:
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	nop
1017
1018	.set pop
1019END(MipsTLBInvalidException)
1020
1021/*----------------------------------------------------------------------------
1022 *
1023 * MipsTLBMissException --
1024 *
1025 *	Handle a TLB miss exception from kernel mode in kernel space.
1026 *	The BaddVAddr, Context, and EntryHi registers contain the failed
1027 *	virtual address.
1028 *
1029 * Results:
1030 *	None.
1031 *
1032 * Side effects:
1033 *	None.
1034 *
1035 *----------------------------------------------------------------------------
1036 */
1037NLEAF(MipsTLBMissException)
1038	.set	noat
1039	MFC0		k0, MIPS_COP_0_BAD_VADDR	# k0=bad address
1040	PTR_LI		k1, VM_MAX_KERNEL_ADDRESS	# check fault address against
1041	sltu		k1, k1, k0			# upper bound of kernel_segmap
1042	bnez		k1, MipsKernGenException	# out of bound
1043	lui		k1, %hi(kernel_segmap)		# k1=hi of segbase
1044	PTR_SRL		k0, SEGSHIFT - PTRSHIFT		# k0=seg offset (almost)
1045	PTR_L		k1, %lo(kernel_segmap)(k1)	# k1=segment tab base
1046	beq		k1, zero, MipsKernGenException	# ==0 -- no seg tab
1047	andi		k0, k0, PDEPTRMASK		#06: k0=seg offset
1048	PTR_ADDU	k1, k0, k1			# k1=seg entry address
1049	PTR_L		k1, 0(k1)			# k1=seg entry
1050	MFC0		k0, MIPS_COP_0_BAD_VADDR	# k0=bad address (again)
1051	beq		k1, zero, MipsKernGenException	# ==0 -- no page table
1052#ifdef __mips_n64
1053	PTR_SRL		k0, PDRSHIFT - PTRSHIFT		# k0=VPN
1054	andi		k0, k0, PDEPTRMASK		# k0=pde offset
1055	PTR_ADDU	k1, k0, k1			# k1=pde entry address
1056	PTR_L		k1, 0(k1)			# k1=pde entry
1057	MFC0		k0, MIPS_COP_0_BAD_VADDR	# k0=bad address (again)
1058  	beq		k1, zero, MipsKernGenException	# ==0 -- no page table
1059#endif
1060	PTR_SRL		k0, PAGE_SHIFT - PTESHIFT	# k0=VPN
1061	andi		k0, k0, PTE2MASK		# k0=page tab offset
1062	PTR_ADDU	k1, k1, k0			# k1=pte address
1063	PTE_L		k0, 0(k1)			# k0=lo0 pte
1064	PTE_L		k1, PTESIZE(k1)			# k1=lo1 pte
1065	CLEAR_PTE_SWBITS(k0)
1066	PTE_MTC0	k0, MIPS_COP_0_TLB_LO0		# lo0 is loaded
1067	COP0_SYNC
1068	CLEAR_PTE_SWBITS(k1)
1069	PTE_MTC0	k1, MIPS_COP_0_TLB_LO1		# lo1 is loaded
1070	COP0_SYNC
1071	tlbwr					# write to tlb
1072	HAZARD_DELAY
1073	eret					# return from exception
1074	.set	at
1075END(MipsTLBMissException)
1076
1077/*----------------------------------------------------------------------------
1078 *
1079 * MipsFPTrap --
1080 *
1081 *	Handle a floating point Trap.
1082 *
1083 *	MipsFPTrap(statusReg, causeReg, pc)
1084 *		unsigned statusReg;
1085 *		unsigned causeReg;
1086 *		unsigned pc;
1087 *
1088 * Results:
1089 *	None.
1090 *
1091 * Side effects:
1092 *	None.
1093 *
1094 *----------------------------------------------------------------------------
1095 */
1096NON_LEAF(MipsFPTrap, CALLFRAME_SIZ, ra)
1097	PTR_SUBU	sp, sp, CALLFRAME_SIZ
1098	mfc0	t0, MIPS_COP_0_STATUS
1099	REG_S	ra, CALLFRAME_RA(sp)
1100	.mask	0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ)
1101
1102	or	t1, t0, MIPS_SR_COP_1_BIT
1103	mtc0	t1, MIPS_COP_0_STATUS
1104	ITLBNOPFIX
1105	cfc1	t1, MIPS_FPU_CSR		# stall til FP done
1106	cfc1	t1, MIPS_FPU_CSR		# now get status
1107	nop
1108	sll	t2, t1, (31 - 17)		# unimplemented operation?
1109	bgez	t2, 3f				# no, normal trap
1110	nop
1111/*
1112 * We got an unimplemented operation trap so
1113 * fetch the instruction, compute the next PC and emulate the instruction.
1114 */
1115	bgez	a1, 1f				# Check the branch delay bit.
1116	nop
1117/*
1118 * The instruction is in the branch delay slot so the branch will have to
1119 * be emulated to get the resulting PC.
1120 */
1121	PTR_S	a2, CALLFRAME_SIZ + 8(sp)
1122	GET_CPU_PCPU(a0)
1123#mips64 unsafe?
1124	PTR_L	a0, PC_CURPCB(a0)
1125	PTR_ADDU a0, a0, U_PCB_REGS		# first arg is ptr to CPU registers
1126	move	a1, a2				# second arg is instruction PC
1127	move	a2, t1				# third arg is floating point CSR
1128	PTR_LA	t3, _C_LABEL(MipsEmulateBranch)	# compute PC after branch
1129	jalr	t3				# compute PC after branch
1130	move	a3, zero			# fourth arg is FALSE
1131/*
1132 * Now load the floating-point instruction in the branch delay slot
1133 * to be emulated.
1134 */
1135	PTR_L	a2, CALLFRAME_SIZ + 8(sp)	# restore EXC pc
1136	b	2f
1137	lw	a0, 4(a2)			# a0 = coproc instruction
1138/*
1139 * This is not in the branch delay slot so calculate the resulting
1140 * PC (epc + 4) into v0 and continue to MipsEmulateFP().
1141 */
11421:
1143	lw	a0, 0(a2)			# a0 = coproc instruction
1144#xxx mips64 unsafe?
1145	PTR_ADDU	v0, a2, 4			# v0 = next pc
11462:
1147	GET_CPU_PCPU(t2)
1148	PTR_L	t2, PC_CURPCB(t2)
1149	SAVE_U_PCB_REG(v0, PC, t2)		# save new pc
1150/*
1151 * Check to see if the instruction to be emulated is a floating-point
1152 * instruction.
1153 */
1154	srl	a3, a0, MIPS_OPCODE_SHIFT
1155	beq	a3, MIPS_OPCODE_C1, 4f		# this should never fail
1156	nop
1157/*
1158 * Send a floating point exception signal to the current process.
1159 */
11603:
1161	GET_CPU_PCPU(a0)
1162	PTR_L	a0, PC_CURTHREAD(a0)		# get current thread
1163	cfc1	a2, MIPS_FPU_CSR		# code = FP execptions
1164	ctc1	zero, MIPS_FPU_CSR		# Clear exceptions
1165	PTR_LA	t3, _C_LABEL(trapsignal)
1166	jalr	t3
1167	li	a1, SIGFPE
1168	b	FPReturn
1169	nop
1170
1171/*
1172 * Finally, we can call MipsEmulateFP() where a0 is the instruction to emulate.
1173 */
11744:
1175	PTR_LA	t3, _C_LABEL(MipsEmulateFP)
1176	jalr	t3
1177	nop
1178
1179/*
1180 * Turn off the floating point coprocessor and return.
1181 */
1182FPReturn:
1183	mfc0	t0, MIPS_COP_0_STATUS
1184	PTR_L	ra, CALLFRAME_RA(sp)
1185	and	t0, t0, ~MIPS_SR_COP_1_BIT
1186	mtc0	t0, MIPS_COP_0_STATUS
1187	ITLBNOPFIX
1188	j	ra
1189	PTR_ADDU sp, sp, CALLFRAME_SIZ
1190END(MipsFPTrap)
1191
1192/*
1193 * Interrupt counters for vmstat.
1194 */
1195	.data
1196	.globl intrcnt
1197	.globl sintrcnt
1198	.globl intrnames
1199	.globl sintrnames
1200intrnames:
1201	.space  INTRCNT_COUNT * (MAXCOMLEN + 1) * 2
1202sintrnames:
1203#ifdef __mips_n64
1204	.quad  INTRCNT_COUNT * (MAXCOMLEN + 1) * 2
1205#else
1206	.int  INTRCNT_COUNT * (MAXCOMLEN + 1) * 2
1207#endif
1208
1209	.align	(_MIPS_SZLONG / 8)
1210intrcnt:
1211	.space  INTRCNT_COUNT * (_MIPS_SZLONG / 8) * 2
1212sintrcnt:
1213#ifdef __mips_n64
1214	.quad  INTRCNT_COUNT * (_MIPS_SZLONG / 8) * 2
1215#else
1216	.int  INTRCNT_COUNT * (_MIPS_SZLONG / 8) * 2
1217#endif
1218
1219
1220/*
1221 * Vector to real handler in KSEG1.
1222 */
1223	.text
1224VECTOR(MipsCache, unknown)
1225	PTR_LA	k0, _C_LABEL(MipsCacheException)
1226	li	k1, MIPS_KSEG0_PHYS_MASK
1227	and	k0, k1
1228	PTR_LI	k1, MIPS_KSEG1_START
1229	or	k0, k1
1230	j	k0
1231	nop
1232VECTOR_END(MipsCache)
1233
1234	.set	at
1235
1236
1237/*
1238 * Panic on cache errors.  A lot more could be done to recover
1239 * from some types of errors but it is tricky.
1240 */
1241NESTED_NOPROFILE(MipsCacheException, KERN_EXC_FRAME_SIZE, ra)
1242	.set	noat
1243	.mask	0x80000000, -4
1244	PTR_LA	k0, _C_LABEL(panic)		# return to panic
1245	PTR_LA	a0, 9f				# panicstr
1246	MFC0	a1, MIPS_COP_0_ERROR_PC
1247	mfc0	a2, MIPS_COP_0_CACHE_ERR	# 3rd arg cache error
1248
1249	MTC0	k0, MIPS_COP_0_ERROR_PC		# set return address
1250
1251	mfc0	k0, MIPS_COP_0_STATUS		# restore status
1252	li	k1, MIPS_SR_DIAG_PE		# ignore further errors
1253	or	k0, k1
1254	mtc0	k0, MIPS_COP_0_STATUS		# restore status
1255	COP0_SYNC
1256
1257	eret
1258
1259	MSG("cache error @ EPC 0x%x CachErr 0x%x");
1260	.set	at
1261END(MipsCacheException)
1262