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