xref: /f-stack/freebsd/mips/mips/exception.S (revision a9643ea8)
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
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.s"
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	wait
594GLOBAL(MipsWaitEnd)			# MipsWaitStart + 16
595	jr	ra
596	PTR_ADDU        sp, sp, CALLFRAME_SIZ
597END(mips_wait)
598	.set	pop
599
600/*----------------------------------------------------------------------------
601 *
602 * MipsKernIntr --
603 *
604 *	Handle an interrupt from kernel mode.
605 *	Interrupts use the standard kernel stack.
606 *	switch_exit sets up a kernel stack after exit so interrupts won't fail.
607 *
608 * Results:
609 *	None.
610 *
611 * Side effects:
612 *	None.
613 *
614 *----------------------------------------------------------------------------
615 */
616
617NESTED_NOPROFILE(MipsKernIntr, KERN_EXC_FRAME_SIZE, ra)
618	.set	noat
619	PTR_SUBU	sp, sp, KERN_EXC_FRAME_SIZE
620	.mask	0x80000000, (CALLFRAME_RA - KERN_EXC_FRAME_SIZE)
621
622/*
623 * Check for getting interrupts just before wait
624 */
625	MFC0	k0, MIPS_COP_0_EXC_PC
626	ori	k0, 0xf
627	xori	k0, 0xf			# 16 byte align
628	PTR_LA	k1, MipsWaitStart
629	bne	k0, k1, 1f
630	nop
631	PTR_ADDU k1, 16			# skip over wait
632	MTC0	k1, MIPS_COP_0_EXC_PC
6331:
634/*
635 *  Save CPU state, building 'frame'.
636 */
637	SAVE_CPU
638/*
639 *  Call the interrupt handler. a0 points at the saved frame.
640 */
641	PTR_LA	gp, _C_LABEL(_gp)
642#ifdef INTRNG
643	PTR_LA	k0, _C_LABEL(intr_irq_handler)
644#else
645	PTR_LA	k0, _C_LABEL(cpu_intr)
646#endif
647	jalr	k0
648	REG_S	a3, CALLFRAME_RA + KERN_REG_SIZE(sp)		# for debugging
649
650	/*
651	 * Update interrupt and CPU mask in saved status register
652	 * Some of interrupts could be disabled by
653	 * intr filters if interrupts are enabled later
654	 * in trap handler
655	 */
656	mfc0	a0, MIPS_COP_0_STATUS
657	and	a0, a0, (MIPS_SR_INT_MASK|MIPS_SR_COP_USABILITY)
658	RESTORE_REG(a1, SR, sp)
659	and	a1, a1, ~(MIPS_SR_INT_MASK|MIPS_SR_COP_USABILITY)
660	or	a1, a1, a0
661	SAVE_REG(a1, SR, sp)
662	REG_L	v0, CALLFRAME_RA + KERN_REG_SIZE(sp)
663	RESTORE_CPU			# v0 contains the return address.
664	sync
665	eret
666	.set	at
667END(MipsKernIntr)
668
669/*----------------------------------------------------------------------------
670 *
671 * MipsUserIntr --
672 *
673 *	Handle an interrupt from user mode.
674 *	Note: we save minimal state in the u.u_pcb struct and use the standard
675 *	kernel stack since there has to be a u page if we came from user mode.
676 *	If there is a pending software interrupt, then save the remaining state
677 *	and call softintr(). This is all because if we call switch() inside
678 *	interrupt(), not all the user registers have been saved in u.u_pcb.
679 *
680 * Results:
681 *	None.
682 *
683 * Side effects:
684 *	None.
685 *
686 *----------------------------------------------------------------------------
687 */
688NESTED_NOPROFILE(MipsUserIntr, CALLFRAME_SIZ, ra)
689	.set	noat
690	.mask	0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ)
691/*
692 * Save the relevant user registers into the u.u_pcb struct.
693 * We don't need to save s0 - s8 because the compiler does it for us.
694 */
695	GET_CPU_PCPU(k1)
696	PTR_L	k1, PC_CURPCB(k1)
697	SAVE_U_PCB_REG(AT, AST, k1)
698	.set	at
699	SAVE_U_PCB_REG(v0, V0, k1)
700	SAVE_U_PCB_REG(v1, V1, k1)
701	SAVE_U_PCB_REG(a0, A0, k1)
702	SAVE_U_PCB_REG(a1, A1, k1)
703	SAVE_U_PCB_REG(a2, A2, k1)
704	SAVE_U_PCB_REG(a3, A3, k1)
705	SAVE_U_PCB_REG(t0, T0, k1)
706	SAVE_U_PCB_REG(t1, T1, k1)
707	SAVE_U_PCB_REG(t2, T2, k1)
708	SAVE_U_PCB_REG(t3, T3, k1)
709	SAVE_U_PCB_REG(ta0, TA0, k1)
710	SAVE_U_PCB_REG(ta1, TA1, k1)
711	SAVE_U_PCB_REG(ta2, TA2, k1)
712	SAVE_U_PCB_REG(ta3, TA3, k1)
713	SAVE_U_PCB_REG(t8, T8, k1)
714	SAVE_U_PCB_REG(t9, T9, k1)
715	SAVE_U_PCB_REG(gp, GP, k1)
716	SAVE_U_PCB_REG(sp, SP, k1)
717	SAVE_U_PCB_REG(ra, RA, k1)
718/*
719 *  save remaining user state in u.u_pcb.
720 */
721	SAVE_U_PCB_REG(s0, S0, k1)
722	SAVE_U_PCB_REG(s1, S1, k1)
723	SAVE_U_PCB_REG(s2, S2, k1)
724	SAVE_U_PCB_REG(s3, S3, k1)
725	SAVE_U_PCB_REG(s4, S4, k1)
726	SAVE_U_PCB_REG(s5, S5, k1)
727	SAVE_U_PCB_REG(s6, S6, k1)
728	SAVE_U_PCB_REG(s7, S7, k1)
729	SAVE_U_PCB_REG(s8, S8, k1)
730
731	mflo	v0			# get lo/hi late to avoid stall
732	mfhi	v1
733	mfc0	a0, MIPS_COP_0_STATUS
734	mfc0	a1, MIPS_COP_0_CAUSE
735	MFC0	a3, MIPS_COP_0_EXC_PC
736	SAVE_U_PCB_REG(v0, MULLO, k1)
737	SAVE_U_PCB_REG(v1, MULHI, k1)
738	SAVE_U_PCB_REG(a0, SR, k1)
739	SAVE_U_PCB_REG(a1, CAUSE, k1)
740	SAVE_U_PCB_REG(a3, PC, k1)	# PC in a3, note used later!
741	PTR_SUBU	sp, k1, CALLFRAME_SIZ  # switch to kernel SP
742	PTR_LA	gp, _C_LABEL(_gp)	# switch to kernel GP
743
744# Turn off fpu, disable interrupts, set kernel mode kernel mode, clear exception level.
745	and	t0, a0, ~(MIPS_SR_COP_1_BIT | MIPS_SR_EXL | MIPS_SR_INT_IE | MIPS_SR_KSU_MASK)
746#ifdef CPU_CNMIPS
747	and	t0, t0, ~(MIPS_SR_COP_2_BIT)
748	or      t0, t0, (MIPS_SR_KX | MIPS_SR_SX | MIPS_SR_UX | MIPS_SR_PX)
749#elif defined(CPU_RMI)	|| defined(CPU_NLM)
750	or      t0, t0, (MIPS_SR_KX | MIPS_SR_UX | MIPS_SR_COP_2_BIT)
751#endif
752	mtc0	t0, MIPS_COP_0_STATUS
753	ITLBNOPFIX
754	PTR_ADDU a0, k1, U_PCB_REGS
755/*
756 * Call the interrupt handler.
757 */
758#ifdef INTRNG
759	PTR_LA	k0, _C_LABEL(intr_irq_handler)
760#else
761	PTR_LA	k0, _C_LABEL(cpu_intr)
762#endif
763	jalr	k0
764	REG_S	a3, CALLFRAME_RA(sp)	# for debugging
765
766/*
767 * Enable interrupts before doing ast().
768 *
769 * On SMP kernels the AST processing might trigger IPI to other processors.
770 * If that processor is also doing AST processing with interrupts disabled
771 * then we may deadlock.
772 */
773	mfc0	a0, MIPS_COP_0_STATUS
774	or	a0, a0, MIPS_SR_INT_IE
775	mtc0	a0, MIPS_COP_0_STATUS
776	ITLBNOPFIX
777
778/*
779 * DO_AST enabled interrupts
780 */
781	DO_AST
782
783/*
784 * Restore user registers and return.
785 */
786 	CLEAR_STATUS
787
788	GET_CPU_PCPU(k1)
789	PTR_L	k1, PC_CURPCB(k1)
790
791	/*
792	 * Update interrupt mask in saved status register
793	 * Some of interrupts could be disabled by
794	 * intr filters
795	 */
796	mfc0	a0, MIPS_COP_0_STATUS
797	and	a0, a0, MIPS_SR_INT_MASK
798	RESTORE_U_PCB_REG(a1, SR, k1)
799	and	a1, a1, ~MIPS_SR_INT_MASK
800	or	a1, a1, a0
801	SAVE_U_PCB_REG(a1, SR, k1)
802
803	RESTORE_U_PCB_REG(s0, S0, k1)
804	RESTORE_U_PCB_REG(s1, S1, k1)
805	RESTORE_U_PCB_REG(s2, S2, k1)
806	RESTORE_U_PCB_REG(s3, S3, k1)
807	RESTORE_U_PCB_REG(s4, S4, k1)
808	RESTORE_U_PCB_REG(s5, S5, k1)
809	RESTORE_U_PCB_REG(s6, S6, k1)
810	RESTORE_U_PCB_REG(s7, S7, k1)
811	RESTORE_U_PCB_REG(s8, S8, k1)
812	RESTORE_U_PCB_REG(t0, MULLO, k1)
813	RESTORE_U_PCB_REG(t1, MULHI, k1)
814	RESTORE_U_PCB_REG(t2, PC, k1)
815	mtlo	t0
816	mthi	t1
817	MTC0	t2, MIPS_COP_0_EXC_PC	# set return address
818	RESTORE_U_PCB_REG(v0, V0, k1)
819	RESTORE_U_PCB_REG(v1, V1, k1)
820	RESTORE_U_PCB_REG(a0, A0, k1)
821	RESTORE_U_PCB_REG(a1, A1, k1)
822	RESTORE_U_PCB_REG(a2, A2, k1)
823	RESTORE_U_PCB_REG(a3, A3, k1)
824	RESTORE_U_PCB_REG(t0, T0, k1)
825	RESTORE_U_PCB_REG(t1, T1, k1)
826	RESTORE_U_PCB_REG(t2, T2, k1)
827	RESTORE_U_PCB_REG(t3, T3, k1)
828	RESTORE_U_PCB_REG(ta0, TA0, k1)
829	RESTORE_U_PCB_REG(ta1, TA1, k1)
830	RESTORE_U_PCB_REG(ta2, TA2, k1)
831	RESTORE_U_PCB_REG(ta3, TA3, k1)
832	RESTORE_U_PCB_REG(t8, T8, k1)
833	RESTORE_U_PCB_REG(t9, T9, k1)
834	RESTORE_U_PCB_REG(gp, GP, k1)
835	RESTORE_U_PCB_REG(k0, SR, k1)
836	RESTORE_U_PCB_REG(sp, SP, k1)
837	RESTORE_U_PCB_REG(ra, RA, k1)
838	.set	noat
839	RESTORE_U_PCB_REG(AT, AST, k1)
840
841	mtc0	k0, MIPS_COP_0_STATUS	# SR with EXL set.
842	ITLBNOPFIX
843	sync
844	eret
845	.set	at
846END(MipsUserIntr)
847
848LEAF_NOPROFILE(MipsTLBInvalidException)
849	.set push
850	.set noat
851	.set noreorder
852
853	MFC0		k0, MIPS_COP_0_BAD_VADDR
854	PTR_LI		k1, VM_MAXUSER_ADDRESS
855	sltu		k1, k0, k1
856	bnez		k1, 1f
857	nop
858
859	/* Kernel address.  */
860	lui		k1, %hi(kernel_segmap)		# k1=hi of segbase
861	b		2f
862	PTR_L		k1, %lo(kernel_segmap)(k1)	# k1=segment tab base
863
8641:	/* User address.  */
865	GET_CPU_PCPU(k1)
866	PTR_L		k1, PC_SEGBASE(k1)
867
8682:	/* Validate page directory pointer.  */
869	beqz		k1, 3f
870	nop
871
872	PTR_SRL		k0, SEGSHIFT - PTRSHIFT		# k0=seg offset (almost)
873	beq		k1, zero, MipsKernGenException	# ==0 -- no seg tab
874	andi		k0, k0, PDEPTRMASK		#06: k0=seg offset
875	PTR_ADDU	k1, k0, k1			# k1=seg entry address
876	PTR_L		k1, 0(k1)			# k1=seg entry
877
878	/* Validate page table pointer.  */
879	beqz		k1, 3f
880	nop
881
882#ifdef __mips_n64
883	MFC0		k0, MIPS_COP_0_BAD_VADDR
884	PTR_SRL		k0, PDRSHIFT - PTRSHIFT		# k0=pde offset (almost)
885	beq		k1, zero, MipsKernGenException	# ==0 -- no pde tab
886	andi		k0, k0, PDEPTRMASK		# k0=pde offset
887	PTR_ADDU	k1, k0, k1			# k1=pde entry address
888	PTR_L		k1, 0(k1)			# k1=pde entry
889
890	/* Validate pde table pointer.  */
891	beqz		k1, 3f
892	nop
893#endif
894	MFC0		k0, MIPS_COP_0_BAD_VADDR	# k0=bad address (again)
895	PTR_SRL		k0, PAGE_SHIFT - PTESHIFT	# k0=VPN
896	andi		k0, k0, PTEMASK			# k0=page tab offset
897	PTR_ADDU	k1, k1, k0			# k1=pte address
898	PTE_L		k0, 0(k1)			# k0=this PTE
899
900	/* Validate page table entry.  */
901	andi		k0, PTE_V
902	beqz		k0, 3f
903	nop
904
905	/* Check whether this is an even or odd entry.  */
906	andi		k0, k1, PTESIZE
907	bnez		k0, odd_page
908	nop
909
910	PTE_L		k0, 0(k1)
911	PTE_L		k1, PTESIZE(k1)
912	CLEAR_PTE_SWBITS(k0)
913	PTE_MTC0	k0, MIPS_COP_0_TLB_LO0
914	COP0_SYNC
915	CLEAR_PTE_SWBITS(k1)
916	PTE_MTC0	k1, MIPS_COP_0_TLB_LO1
917	COP0_SYNC
918
919	b		tlb_insert_entry
920	nop
921
922odd_page:
923	PTE_L		k0, -PTESIZE(k1)
924	PTE_L		k1, 0(k1)
925	CLEAR_PTE_SWBITS(k0)
926	PTE_MTC0	k0, MIPS_COP_0_TLB_LO0
927	COP0_SYNC
928	CLEAR_PTE_SWBITS(k1)
929	PTE_MTC0	k1, MIPS_COP_0_TLB_LO1
930	COP0_SYNC
931
932tlb_insert_entry:
933	tlbp
934	HAZARD_DELAY
935	mfc0		k0, MIPS_COP_0_TLB_INDEX
936	bltz		k0, tlb_insert_random
937	nop
938	tlbwi
939	eret
940	ssnop
941
942tlb_insert_random:
943	tlbwr
944	eret
945	ssnop
946
9473:
948	/*
949	 * Branch to the comprehensive exception processing.
950	 */
951	mfc0	k1, MIPS_COP_0_STATUS
952	andi	k1, k1, MIPS_SR_KSU_USER
953	bnez	k1, _C_LABEL(MipsUserGenException)
954	nop
955
956	/*
957	 * Check for kernel stack overflow.
958	 */
959	GET_CPU_PCPU(k1)
960	PTR_L	k0, PC_CURTHREAD(k1)
961	PTR_L	k0, TD_KSTACK(k0)
962	sltu	k0, k0, sp
963	bnez	k0, _C_LABEL(MipsKernGenException)
964	nop
965
966	/*
967	 * Kernel stack overflow.
968	 *
969	 * Move to a valid stack before we call panic. We use the boot stack
970	 * for this purpose.
971	 */
972	GET_CPU_PCPU(k1)
973	lw	k1, PC_CPUID(k1)
974	sll	k1, k1, PAGE_SHIFT + 1
975
976	PTR_LA	k0, _C_LABEL(pcpu_space)
977	PTR_ADDU	k0, PAGE_SIZE * 2
978	PTR_ADDU	k0, k0, k1
979
980	/*
981	 * Stash the original value of 'sp' so we can update trapframe later.
982	 * We assume that SAVE_CPU does not trash 'k1'.
983	 */
984	move	k1, sp
985
986	move	sp, k0
987	PTR_SUBU	sp, sp, KERN_EXC_FRAME_SIZE
988
989	move	k0, ra
990	move	ra, zero
991	REG_S	ra, CALLFRAME_RA(sp)	/* stop the ddb backtrace right here */
992	REG_S	zero, CALLFRAME_SP(sp)
993	move	ra, k0
994
995	SAVE_CPU
996
997	/*
998	 * Now restore the value of 'sp' at the time of the tlb exception in
999	 * the trapframe.
1000	 */
1001	SAVE_REG(k1, SP, sp)
1002
1003	/*
1004	 * Squelch any more overflow checks by setting the stack base to 0.
1005	 */
1006	GET_CPU_PCPU(k1)
1007	PTR_L	k0, PC_CURTHREAD(k1)
1008	PTR_S	zero, TD_KSTACK(k0)
1009
1010	move	a1, a0
1011	PANIC("kernel stack overflow - trapframe at %p")
1012
1013	/*
1014	 * This nop is necessary so that the 'ra' remains within the bounds
1015	 * of this handler. Otherwise the ddb backtrace code will think that
1016	 * the panic() was called from MipsTLBMissException.
1017	 */
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	PTR_SUBU	sp, sp, CALLFRAME_SIZ
1100	mfc0	t0, MIPS_COP_0_STATUS
1101	REG_S	ra, CALLFRAME_RA(sp)
1102	.mask	0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ)
1103
1104	or	t1, t0, MIPS_SR_COP_1_BIT
1105	mtc0	t1, MIPS_COP_0_STATUS
1106	ITLBNOPFIX
1107	cfc1	t1, MIPS_FPU_CSR		# stall til FP done
1108	cfc1	t1, MIPS_FPU_CSR		# now get status
1109	nop
1110	sll	t2, t1, (31 - 17)		# unimplemented operation?
1111	bgez	t2, 3f				# no, normal trap
1112	nop
1113/*
1114 * We got an unimplemented operation trap so
1115 * fetch the instruction, compute the next PC and emulate the instruction.
1116 */
1117	bgez	a1, 1f				# Check the branch delay bit.
1118	nop
1119/*
1120 * The instruction is in the branch delay slot so the branch will have to
1121 * be emulated to get the resulting PC.
1122 */
1123	PTR_S	a2, CALLFRAME_SIZ + 8(sp)
1124	GET_CPU_PCPU(a0)
1125#mips64 unsafe?
1126	PTR_L	a0, PC_CURPCB(a0)
1127	PTR_ADDU a0, a0, U_PCB_REGS		# first arg is ptr to CPU registers
1128	move	a1, a2				# second arg is instruction PC
1129	move	a2, t1				# third arg is floating point CSR
1130	PTR_LA	t3, _C_LABEL(MipsEmulateBranch)	# compute PC after branch
1131	jalr	t3				# compute PC after branch
1132	move	a3, zero			# fourth arg is FALSE
1133/*
1134 * Now load the floating-point instruction in the branch delay slot
1135 * to be emulated.
1136 */
1137	PTR_L	a2, CALLFRAME_SIZ + 8(sp)	# restore EXC pc
1138	b	2f
1139	lw	a0, 4(a2)			# a0 = coproc instruction
1140/*
1141 * This is not in the branch delay slot so calculate the resulting
1142 * PC (epc + 4) into v0 and continue to MipsEmulateFP().
1143 */
11441:
1145	lw	a0, 0(a2)			# a0 = coproc instruction
1146#xxx mips64 unsafe?
1147	PTR_ADDU	v0, a2, 4			# v0 = next pc
11482:
1149	GET_CPU_PCPU(t2)
1150	PTR_L	t2, PC_CURPCB(t2)
1151	SAVE_U_PCB_REG(v0, PC, t2)		# save new pc
1152/*
1153 * Check to see if the instruction to be emulated is a floating-point
1154 * instruction.
1155 */
1156	srl	a3, a0, MIPS_OPCODE_SHIFT
1157	beq	a3, MIPS_OPCODE_C1, 4f		# this should never fail
1158	nop
1159/*
1160 * Send a floating point exception signal to the current process.
1161 */
11623:
1163	GET_CPU_PCPU(a0)
1164	PTR_L	a0, PC_CURTHREAD(a0)		# get current thread
1165	cfc1	a2, MIPS_FPU_CSR		# code = FP execptions
1166	ctc1	zero, MIPS_FPU_CSR		# Clear exceptions
1167	PTR_LA	t3, _C_LABEL(trapsignal)
1168	jalr	t3
1169	li	a1, SIGFPE
1170	b	FPReturn
1171	nop
1172
1173/*
1174 * Finally, we can call MipsEmulateFP() where a0 is the instruction to emulate.
1175 */
11764:
1177	PTR_LA	t3, _C_LABEL(MipsEmulateFP)
1178	jalr	t3
1179	nop
1180
1181/*
1182 * Turn off the floating point coprocessor and return.
1183 */
1184FPReturn:
1185	mfc0	t0, MIPS_COP_0_STATUS
1186	PTR_L	ra, CALLFRAME_RA(sp)
1187	and	t0, t0, ~MIPS_SR_COP_1_BIT
1188	mtc0	t0, MIPS_COP_0_STATUS
1189	ITLBNOPFIX
1190	j	ra
1191	PTR_ADDU sp, sp, CALLFRAME_SIZ
1192END(MipsFPTrap)
1193
1194#ifndef INTRNG
1195/*
1196 * Interrupt counters for vmstat.
1197 */
1198	.data
1199	.globl intrcnt
1200	.globl sintrcnt
1201	.globl intrnames
1202	.globl sintrnames
1203intrnames:
1204	.space  INTRCNT_COUNT * (MAXCOMLEN + 1) * 2
1205sintrnames:
1206#ifdef __mips_n64
1207	.quad  INTRCNT_COUNT * (MAXCOMLEN + 1) * 2
1208#else
1209	.int  INTRCNT_COUNT * (MAXCOMLEN + 1) * 2
1210#endif
1211
1212	.align	(_MIPS_SZLONG / 8)
1213intrcnt:
1214	.space  INTRCNT_COUNT * (_MIPS_SZLONG / 8) * 2
1215sintrcnt:
1216#ifdef __mips_n64
1217	.quad  INTRCNT_COUNT * (_MIPS_SZLONG / 8) * 2
1218#else
1219	.int  INTRCNT_COUNT * (_MIPS_SZLONG / 8) * 2
1220#endif
1221#endif /* INTRNG */
1222
1223
1224/*
1225 * Vector to real handler in KSEG1.
1226 */
1227	.text
1228VECTOR(MipsCache, unknown)
1229	PTR_LA	k0, _C_LABEL(MipsCacheException)
1230	li	k1, MIPS_KSEG0_PHYS_MASK
1231	and	k0, k1
1232	PTR_LI	k1, MIPS_KSEG1_START
1233	or	k0, k1
1234	j	k0
1235	nop
1236VECTOR_END(MipsCache)
1237
1238	.set	at
1239
1240
1241/*
1242 * Panic on cache errors.  A lot more could be done to recover
1243 * from some types of errors but it is tricky.
1244 */
1245NESTED_NOPROFILE(MipsCacheException, KERN_EXC_FRAME_SIZE, ra)
1246	.set	noat
1247	.mask	0x80000000, -4
1248	PTR_LA	k0, _C_LABEL(panic)		# return to panic
1249	PTR_LA	a0, 9f				# panicstr
1250	MFC0	a1, MIPS_COP_0_ERROR_PC
1251	mfc0	a2, MIPS_COP_0_CACHE_ERR	# 3rd arg cache error
1252
1253	MTC0	k0, MIPS_COP_0_ERROR_PC		# set return address
1254
1255	mfc0	k0, MIPS_COP_0_STATUS		# restore status
1256	li	k1, MIPS_SR_DIAG_PE		# ignore further errors
1257	or	k0, k1
1258	mtc0	k0, MIPS_COP_0_STATUS		# restore status
1259	COP0_SYNC
1260
1261	eret
1262
1263	MSG("cache error @ EPC 0x%x CachErr 0x%x");
1264	.set	at
1265END(MipsCacheException)
1266