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