xref: /netbsd/sys/arch/mips/mips/locore_mips1.S (revision c4a72b64)
1/*	$NetBSD: locore_mips1.S,v 1.55 2002/11/12 14:00:41 nisimura Exp $	*/
2
3/*
4 * Copyright (c) 1992, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Digital Equipment Corporation and Ralph Campbell.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permited provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 *    must display the following acknowledgement:
20 *	This product includes software developed by the University of
21 *	California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 *    may be used to endorse or promote products derived from this software
24 *    without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 *
38 * Copyright (C) 1989 Digital Equipment Corporation.
39 * Permission to use, copy, modify, and distribute this software and
40 * its documentation for any purpose and without fee is hereby granted,
41 * provided that the above copyright notice appears in all copies.
42 * Digital Equipment Corporation makes no representations about the
43 * suitability of this software for any purpose.  It is provided "as is"
44 * without express or implied warranty.
45 *
46 * from: Header: /sprite/src/kernel/mach/ds3100.md/RCS/loMem.s,
47 *	v 1.1 89/07/11 17:55:04 nelson Exp  SPRITE (DECWRL)
48 * from: Header: /sprite/src/kernel/mach/ds3100.md/RCS/machAsm.s,
49 *	v 9.2 90/01/29 18:00:39 shirriff Exp  SPRITE (DECWRL)
50 * from: Header: /sprite/src/kernel/vm/ds3100.md/vmPmaxAsm.s,
51 *	v 1.1 89/07/10 14:27:41 nelson Exp  SPRITE (DECWRL)
52 *
53 *	@(#)locore.s	8.5 (Berkeley) 1/4/94
54 */
55#include "opt_cputype.h"
56#include "opt_ddb.h"
57#include "opt_kgdb.h"
58
59#include <sys/cdefs.h>
60
61#include <mips/asm.h>
62#include <mips/cpuregs.h>
63#include <machine/param.h>
64
65#include "assym.h"
66
67	.set	noreorder
68	.text
69
70EXPORT(mips1_exceptionentry_start)
71
72/*
73 * mips1_UTLBMiss
74 *
75 * A reference is made (in either kernel or user mode) to a page in
76 * kuseg that has no matching TLB entry.  This routine is copied down
77 * at 0x80000000 and total length must be less than 32 instructions.
78 * No pc relative jump instruction is allowed.
79 */
80VECTOR(mips1_UTLBMiss, unknown)
81	.set	noat
82	mfc0	k0, MIPS_COP_0_BAD_VADDR	# get the virtual address
83	lw	k1, _C_LABEL(segbase)		# get the current segment table
84	bltz	k0, 1f				# R3000 chip bug
85	srl	k0, k0, SEGSHIFT		# compute segment table index
86	sll	k0, k0, 2
87	addu	k1, k1, k0
88	mfc0	k0, MIPS_COP_0_BAD_VADDR	# get the virtual address
89	lw	k1, 0(k1)			# get pointer to segment map
90	srl	k0, k0, PGSHIFT - 2		# compute segment map index
91	and	k0, k0, (NPTEPG - 1) << 2
92	beq	k1, zero, 2f			# invalid segment map
93	addu	k1, k1, k0			# index into segment map
94	lw	k0, 0(k1)			# get page PTE
95	nop
96	beq	k0, zero, 2f			# dont load invalid entries
97	mtc0	k0, MIPS_COP_0_TLB_LOW
98	nop
99	tlbwr					# update TLB
1001:
101	mfc0	k1, MIPS_COP_0_EXC_PC		# get return address
102	nop
103	j	k1
104	rfe
1052:
106	j	mips1_SlowFault			# handle the rest
107	nop
108	.set	at
109VECTOR_END(mips1_UTLBMiss)
110
111
112/*
113 * mips1_exception
114 *
115 * Handles any exceptions other than reset and UTLB miss.  This routine
116 * is copied down at 0x80000080 and total length must be less than 32
117 * instructions.  No pc relative jump instruction is allowed.
118 */
119VECTOR(mips1_exception, unknown)
120/*
121 * Find out what mode we came from and jump to the proper handler.
122 */
123	.set	noat
124	mfc0	k0, MIPS_COP_0_STATUS		# get the status register
125	mfc0	k1, MIPS_COP_0_CAUSE		# get the cause register
126	and	k0, k0, MIPS1_SR_KU_PREV	# test for user mode
127	sll	k0, k0, 4			# shift user bit for cause index
128	and	k1, k1, MIPS1_CR_EXC_CODE	# mask out the cause bits
129	or	k1, k1, k0			# change index to user table
1301:
131	la	k0, mips1_excpt_sw		# get base of the jump table
132	addu	k0, k0, k1			# get the address of the
133						#  function entry.  Note that
134						#  the cause is already
135						#  shifted left by 2 bits so
136						#  we dont have to shift
137	lw	k0, 0(k0)			# get the function address
138	nop
139	j	k0				# jump to the function
140	nop
141	.set	at
142VECTOR_END(mips1_exception)
143
144
145/*
146 * mips1_SlowFault
147 *
148 * UTLBMiss handler could not find out a TLB entry for the user process.
149 * Dispatch a general case exception handler.
150 */
151mips1_SlowFault:
152	.set	noat
153	mfc0	k1, MIPS_COP_0_STATUS
154	la	k0, _C_LABEL(mips1_KernGenException)
155	and	k1, k1, MIPS1_SR_KU_PREV
156	beq	k1, zero, 1f
157	nop
158	la	k0, _C_LABEL(mips1_UserGenException)
1591:	j	k0
160	nop
161	.set	at
162
163/*
164 * mips1_KernGenException
165 *
166 * Handle an exception during kernel mode.
167 * Build trapframe on stack to hold interrupted kernel context, then
168 * call trap() to process the condition.
169 *
170 * trapframe is now pointed by 5th arg {
171 *	register_t cf_args[4 + 1];
172 *	register_t cf_pad;
173 *	register_t cf_sp;
174 *	register_t cf_ra;
175 *	mips_reg_t tf_regs[17];		- trapframe begins here
176 * 	mips_reg_t tf_sr;		-
177 * 	mips_reg_t tf_mullo;		-
178 * 	mips_reg_t tf_mulhi;		-
179 * 	register_t tf_epc;		- may be changed by trap() call
180 * };
181 */
182NESTED_NOPROFILE(mips1_KernGenException, KERNFRAME_SIZ, ra)
183	.set	noat
184	.mask	0x80000000, -4
185#if defined(DDB) || defined(KGDB)
186	la	k0, _C_LABEL(kdbaux)
187	sw	s0, SF_REG_S0(k0)
188	sw	s1, SF_REG_S1(k0)
189	sw	s2, SF_REG_S2(k0)
190	sw	s3, SF_REG_S3(k0)
191	sw	s4, SF_REG_S4(k0)
192	sw	s5, SF_REG_S5(k0)
193	sw	s6, SF_REG_S6(k0)
194	sw	s7, SF_REG_S7(k0)
195	sw	sp, SF_REG_SP(k0)
196	sw	s8, SF_REG_S8(k0)
197	sw	gp, SF_REG_RA(k0)
198#endif
199/*
200 * Save the relevant kernel registers onto the stack.
201 * We don't need to save s0 - s8, sp and gp because
202 * the compiler does it for us.
203 */
204	subu	sp, sp, KERNFRAME_SIZ
205	sw	AT, TF_BASE+TF_REG_AST(sp)
206	sw	v0, TF_BASE+TF_REG_V0(sp)
207	sw	v1, TF_BASE+TF_REG_V1(sp)
208	mflo	v0
209	mfhi	v1
210	sw	a0, TF_BASE+TF_REG_A0(sp)
211	sw	a1, TF_BASE+TF_REG_A1(sp)
212	sw	a2, TF_BASE+TF_REG_A2(sp)
213	sw	a3, TF_BASE+TF_REG_A3(sp)
214	mfc0	a0, MIPS_COP_0_STATUS		# 1st arg is STATUS
215	sw	t0, TF_BASE+TF_REG_T0(sp)
216	sw	t1, TF_BASE+TF_REG_T1(sp)
217	sw	t2, TF_BASE+TF_REG_T2(sp)
218	sw	t3, TF_BASE+TF_REG_T3(sp)
219	mfc0	a1, MIPS_COP_0_CAUSE		# 2nd arg is CAUSE
220	sw	t4, TF_BASE+TF_REG_T4(sp)
221	sw	t5, TF_BASE+TF_REG_T5(sp)
222	sw	t6, TF_BASE+TF_REG_T6(sp)
223	sw	t7, TF_BASE+TF_REG_T7(sp)
224	mfc0	a2, MIPS_COP_0_BAD_VADDR	# 3rd arg is fault address
225	sw	t8, TF_BASE+TF_REG_T8(sp)
226	sw	t9, TF_BASE+TF_REG_T9(sp)
227	sw	ra, TF_BASE+TF_REG_RA(sp)
228	sw	a0, TF_BASE+TF_REG_SR(sp)
229	mfc0	a3, MIPS_COP_0_EXC_PC		# 4th arg is exception PC
230	sw	v0, TF_BASE+TF_REG_MULLO(sp)
231	sw	v1, TF_BASE+TF_REG_MULHI(sp)
232	sw	a3, TF_BASE+TF_REG_EPC(sp)
233	addu	v0, sp, TF_BASE
234	sw	v0, KERNFRAME_ARG5(sp)		# 5th arg is p. to trapframe
235/*
236 * Call the trap handler.
237 */
238#if defined(DDB) || defined(DEBUG) || defined(KGDB)
239	addu	v0, sp, KERNFRAME_SIZ
240	sw	v0, KERNFRAME_SP(sp)
241#endif
242	jal	_C_LABEL(trap)
243	sw	a3,	KERNFRAME_RA(sp)	# for debugging
244
245/*
246 * Restore registers and return from the exception.
247 */
248	lw	a0, TF_BASE+TF_REG_SR(sp)
249	lw	t0, TF_BASE+TF_REG_MULLO(sp)
250	lw	t1, TF_BASE+TF_REG_MULHI(sp)
251	mtc0	a0, MIPS_COP_0_STATUS
252	mtlo	t0
253	mthi	t1
254	lw	k0, TF_BASE+TF_REG_EPC(sp)
255	lw	AT, TF_BASE+TF_REG_AST(sp)
256	lw	v0, TF_BASE+TF_REG_V0(sp)
257	lw	v1, TF_BASE+TF_REG_V1(sp)
258	lw	a0, TF_BASE+TF_REG_A0(sp)
259	lw	a1, TF_BASE+TF_REG_A1(sp)
260	lw	a2, TF_BASE+TF_REG_A2(sp)
261	lw	a3, TF_BASE+TF_REG_A3(sp)
262	lw	t0, TF_BASE+TF_REG_T0(sp)
263	lw	t1, TF_BASE+TF_REG_T1(sp)
264	lw	t2, TF_BASE+TF_REG_T2(sp)
265	lw	t3, TF_BASE+TF_REG_T3(sp)
266	lw	t4, TF_BASE+TF_REG_T4(sp)
267	lw	t5, TF_BASE+TF_REG_T5(sp)
268	lw	t6, TF_BASE+TF_REG_T6(sp)
269	lw	t7, TF_BASE+TF_REG_T7(sp)
270	lw	t8, TF_BASE+TF_REG_T8(sp)
271	lw	t9, TF_BASE+TF_REG_T9(sp)
272	lw	ra, TF_BASE+TF_REG_RA(sp)
273	addu	sp, sp, KERNFRAME_SIZ
274#ifdef DDBnotyet
275	la	k1, _C_LABEL(kdbaux)
276	lw	s0, SF_REG_S0(k1)
277	lw	s1, SF_REG_S1(k1)
278	lw	s2, SF_REG_S2(k1)
279	lw	s3, SF_REG_S3(k1)
280	lw	s4, SF_REG_S4(k1)
281	lw	s5, SF_REG_S5(k1)
282	lw	s6, SF_REG_S6(k1)
283	lw	s7, SF_REG_S7(k1)
284	lw	sp, SF_REG_SP(k1)
285	lw	s8, SF_REG_S8(k1)
286	lw	gp, SF_REG_RA(k1)
287#endif
288	j	k0				# return to interrupted point
289	rfe
290	.set	at
291END(mips1_KernGenException)
292
293/*
294 * mips1_UserGenException
295 *
296 * Handle an exception during user mode.
297 * Save user context atop of kernel stack, then call trap() to process
298 * the condition.  The context can be manipulated alternatively via
299 * curproc->p_md.md_regs.
300 */
301NESTED_NOPROFILE(mips1_UserGenException, CALLFRAME_SIZ, ra)
302	.set	noat
303	.mask	0x80000000, -4
304/*
305 * Save all the registers but the kernel temporaries onto stack.
306 */
307	lw	k1, _C_LABEL(curpcb)
308	nop
309	addu	k1, k1, USPACE - FRAME_SIZ
310	sw	AT, FRAME_AST(k1)
311	sw	v0, FRAME_V0(k1)
312	sw	v1, FRAME_V1(k1)
313	mflo	v0
314	sw	a0, FRAME_A0(k1)
315	sw	a1, FRAME_A1(k1)
316	sw	a2, FRAME_A2(k1)
317	sw	a3, FRAME_A3(k1)
318	mfhi	v1
319	sw	t0, FRAME_T0(k1)
320	sw	t1, FRAME_T1(k1)
321	sw	t2, FRAME_T2(k1)
322	sw	t3, FRAME_T3(k1)
323	mfc0	a0, MIPS_COP_0_STATUS		# 1st arg is STATUS
324	sw	t4, FRAME_T4(k1)
325	sw	t5, FRAME_T5(k1)
326	sw	t6, FRAME_T6(k1)
327	sw	t7, FRAME_T7(k1)
328	mfc0	a1, MIPS_COP_0_CAUSE		# 2nd arg is CAUSE
329	sw	s0, FRAME_S0(k1)
330	sw	s1, FRAME_S1(k1)
331	sw	s2, FRAME_S2(k1)
332	sw	s3, FRAME_S3(k1)
333	mfc0	a2, MIPS_COP_0_BAD_VADDR	# 3rd arg is fault address
334	sw	s4, FRAME_S4(k1)
335	sw	s5, FRAME_S5(k1)
336	sw	s6, FRAME_S6(k1)
337	sw	s7, FRAME_S7(k1)
338	mfc0	a3, MIPS_COP_0_EXC_PC		# 4th arg is exception PC
339	sw	t8, FRAME_T8(k1)
340	sw	t9, FRAME_T9(k1)
341	sw	gp, FRAME_GP(k1)
342	sw	sp, FRAME_SP(k1)
343	sw	s8, FRAME_S8(k1)
344	sw	ra, FRAME_RA(k1)
345	sw	a0, FRAME_SR(k1)
346	sw	v0, FRAME_MULLO(k1)
347	sw	v1, FRAME_MULHI(k1)
348	sw	a3, FRAME_EPC(k1)
349	addu	sp, k1, -CALLFRAME_SIZ		# switch to kernel SP
350#ifdef __GP_SUPPORT__
351	la	gp, _C_LABEL(_gp)		# switch to kernel GP
352#endif
353	.set	at
354	and	t0, a0, ~MIPS_SR_COP_1_BIT	# turn off the FPU
355	.set	noat
356#if defined(DDB) || defined(DEBUG) || defined(KGDB)
357	move	ra, a3
358	sw	ra, CALLFRAME_RA(sp)
359#endif
360/*
361 * Call the exception handler.
362 */
363	jal	_C_LABEL(trap)
364	mtc0	t0, MIPS_COP_0_STATUS
365/*
366 * Check pending asynchronous traps.
367 */
368	lw	t0, _C_LABEL(curproc)		# t0 = curproc
369	nop
370	lw	t0, P_MD_ASTPENDING(t0)		# any pending ast?
371	nop
372	beq	t0, zero, 1f			# if no, skip ast processing
373	nop
374/*
375 * We have pending asynchronous traps; all the state is already saved.
376 */
377	jal	_C_LABEL(ast)
378	lw	a0, CALLFRAME_SIZ + FRAME_EPC(sp)
3791:
380	la	ra, _C_LABEL(mips1_xcpt_return)
381	j	ra				# pretend function return
382	nop
383	.set	at
384END(mips1_UserGenException)
385
386/*
387 * mips1_SystemCall
388 *
389 * Save user context atop of kernel stack, then call syscall() to process
390 * the condition.  The context can be manipulated alternatively via
391 * curproc->p_md.md_regs.
392 */
393NESTED_NOPROFILE(mips1_SystemCall, CALLFRAME_SIZ, ra)
394	.set	noat
395	.mask	0x80000000, -4
396/*
397 * Save all the registers but kernel temporaries onto stack.
398 */
399	lw	k1, _C_LABEL(curpcb)
400	nop
401	addu	k1, k1, USPACE - FRAME_SIZ
402	#sw	AT, FRAME_AST(k1)
403	.set	at
404	sw	v0, FRAME_V0(k1)		# syscall #
405	sw	v1, FRAME_V1(k1)		# used by syscall()
406	mflo	v0
407	sw	a0, FRAME_A0(k1)
408	sw	a1, FRAME_A1(k1)
409	sw	a2, FRAME_A2(k1)
410	sw	a3, FRAME_A3(k1)
411	lw	a0, _C_LABEL(curproc)		# 1st arg is curproc
412	mfhi	v1
413	#sw	t0, FRAME_T0(k1)		# no need to save temp regs
414	#sw	t1, FRAME_T1(k1)
415	#sw	t2, FRAME_T2(k1)
416	#sw	t3, FRAME_T3(k1)
417	mfc0	a1, MIPS_COP_0_STATUS		# 2nd arg is STATUS
418	#sw	t4, FRAME_T4(k1)
419	#sw	t5, FRAME_T5(k1)
420	#sw	t6, FRAME_T6(k1)
421	sw	t7, FRAME_T7(k1)
422	mfc0	a2, MIPS_COP_0_CAUSE		# 3rd arg is CAUSE
423	sw	s0, FRAME_S0(k1)
424	sw	s1, FRAME_S1(k1)
425	sw	s2, FRAME_S2(k1)
426	sw	s3, FRAME_S3(k1)
427	mfc0	a3, MIPS_COP_0_EXC_PC		# 4th arg is PC
428	sw	s4, FRAME_S4(k1)
429	sw	s5, FRAME_S5(k1)
430	sw	s6, FRAME_S6(k1)
431	sw	s7, FRAME_S7(k1)
432	#sw	t8, FRAME_T8(k1)
433	#sw	t9, FRAME_T9(k1)
434	sw	gp, FRAME_GP(k1)
435	sw	sp, FRAME_SP(k1)
436	sw	s8, FRAME_S8(k1)
437	sw	ra, FRAME_RA(k1)
438	sw	a1, FRAME_SR(k1)
439	sw	v0, FRAME_MULLO(k1)
440	sw	v1, FRAME_MULHI(k1)
441	sw	a3, FRAME_EPC(k1)
442	addu	sp, k1, -CALLFRAME_SIZ		# switch to kernel SP
443#ifdef __GP_SUPPORT__
444	la	gp, _C_LABEL(_gp)		# switch to kernel GP
445#endif
446#if defined(DDB) || defined(DEBUG) || defined(KGDB)
447	move	ra, a3
448	sw	ra, CALLFRAME_RA(sp)
449#endif
450	lw	t1, P_MD_SYSCALL(a0)		# t1 = syscall
451	ori	t0, a1, MIPS_SR_INT_IE		# turn on IEc, enable intr.
452	and	t0, t0, ~MIPS_SR_COP_1_BIT	# turn off FPU
453/*
454 * Call the system call handler.
455 */
456	jal	t1
457	mtc0	t0, MIPS_COP_0_STATUS
458/*
459 * Check pending asynchronous traps.
460 */
461	lw	t0, _C_LABEL(curproc)		# t0 = curproc
462	nop
463	lw	t0, P_MD_ASTPENDING(t0)		# any pending ast?
464	nop
465	beq	t0, zero, 1f
466	nop
467/*
468 * We have pending asynchronous traps; all the state is already saved.
469 */
470	jal	_C_LABEL(ast)
471	lw	a0, CALLFRAME_SIZ + FRAME_EPC(sp)
4721:
473	la	ra, _C_LABEL(mips1_xcpt_return)
474	j	ra				# pretend function return
475	nop
476END(mips1_SystemCall)
477
478/*
479 * mips1_KernIntr
480 *
481 * Handle an interrupt from kernel mode.
482 * Build kernframe on stack to hold interrupted kernel context, then
483 * call cpu_intr() to process it.
484 *
485 */
486NESTED_NOPROFILE(mips1_KernIntr, KERNFRAME_SIZ, ra)
487	.set	noat
488	.mask	0x80000000, (CALLFRAME_RA - KERNFRAME_SIZ)
489	subu	sp, sp, KERNFRAME_SIZ
490/*
491 * Save the relevant kernel registers onto the stack.
492 * We don't need to save s0 - s8 and sp because
493 * the compiler does it for us.
494 */
495	sw	AT, TF_BASE+TF_REG_AST(sp)
496	sw	v0, TF_BASE+TF_REG_V0(sp)
497	sw	v1, TF_BASE+TF_REG_V1(sp)
498	mflo	v0
499	mfhi	v1
500	sw	a0, TF_BASE+TF_REG_A0(sp)
501	sw	a1, TF_BASE+TF_REG_A1(sp)
502	sw	a2, TF_BASE+TF_REG_A2(sp)
503	sw	a3, TF_BASE+TF_REG_A3(sp)
504	mfc0	a0, MIPS_COP_0_STATUS		# 1st arg is STATUS
505	sw	t0, TF_BASE+TF_REG_T0(sp)
506	sw	t1, TF_BASE+TF_REG_T1(sp)
507	sw	t2, TF_BASE+TF_REG_T2(sp)
508	sw	t3, TF_BASE+TF_REG_T3(sp)
509	mfc0	a1, MIPS_COP_0_CAUSE		# 2nd arg is CAUSE
510	sw	t4, TF_BASE+TF_REG_T4(sp)
511	sw	t5, TF_BASE+TF_REG_T5(sp)
512	sw	t6, TF_BASE+TF_REG_T6(sp)
513	sw	t7, TF_BASE+TF_REG_T7(sp)
514	mfc0	a2, MIPS_COP_0_EXC_PC		# 3rd arg is exception PC
515	sw	t8, TF_BASE+TF_REG_T8(sp)
516	sw	t9, TF_BASE+TF_REG_T9(sp)
517	sw	ra, TF_BASE+TF_REG_RA(sp)
518	sw	a0, TF_BASE+TF_REG_SR(sp)
519	and	a3, a0, a1			# 4th is STATUS & CAUSE
520	sw	v0, TF_BASE+TF_REG_MULLO(sp)
521	sw	v1, TF_BASE+TF_REG_MULHI(sp)
522	sw	a2, TF_BASE+TF_REG_EPC(sp)
523#if defined(DDB) || defined(DEBUG) || defined(KGDB)
524	move	ra, a2
525	sw	ra, KERNFRAME_RA(sp)		# for debugging
526#endif
527/*
528 * Call the interrupt handler.
529 */
530	jal	_C_LABEL(cpu_intr)
531	nop
532/*
533 * Restore registers and return from the interrupt.
534 */
535	lw	a0, TF_BASE+TF_REG_SR(sp)
536	lw	t0, TF_BASE+TF_REG_MULLO(sp)
537	lw	t1, TF_BASE+TF_REG_MULHI(sp)
538	mtc0	a0, MIPS_COP_0_STATUS		# this should disable interrupts
539	mtlo	t0
540	mthi	t1
541	lw	k0, TF_BASE+TF_REG_EPC(sp)	# restore exception PC
542	lw	AT, TF_BASE+TF_REG_AST(sp)
543	lw	v0, TF_BASE+TF_REG_V0(sp)
544	lw	v1, TF_BASE+TF_REG_V1(sp)
545	lw	a0, TF_BASE+TF_REG_A0(sp)
546	lw	a1, TF_BASE+TF_REG_A1(sp)
547	lw	a2, TF_BASE+TF_REG_A2(sp)
548	lw	a3, TF_BASE+TF_REG_A3(sp)
549	lw	t0, TF_BASE+TF_REG_T0(sp)
550	lw	t1, TF_BASE+TF_REG_T1(sp)
551	lw	t2, TF_BASE+TF_REG_T2(sp)
552	lw	t3, TF_BASE+TF_REG_T3(sp)
553	lw	t4, TF_BASE+TF_REG_T4(sp)
554	lw	t5, TF_BASE+TF_REG_T5(sp)
555	lw	t6, TF_BASE+TF_REG_T6(sp)
556	lw	t7, TF_BASE+TF_REG_T7(sp)
557	lw	t8, TF_BASE+TF_REG_T8(sp)
558	lw	t9, TF_BASE+TF_REG_T9(sp)
559	lw	ra, TF_BASE+TF_REG_RA(sp)
560	addu	sp, sp, KERNFRAME_SIZ		# restore kernel SP
561	j	k0				# return to interrupted point
562	rfe
563	.set	at
564END(mips1_KernIntr)
565
566/*----------------------------------------------------------------------------
567 * XXX this comment block should be updated XXX
568 * mips1_UserIntr --
569 *
570 *	Handle an interrupt from user mode.
571 *	Note: we save minimal state in the u.u_pcb struct and use the standard
572 *	kernel stack since there has to be a u page if we came from user mode.
573 *	If there is a pending software interrupt, then save the remaining state
574 *	and call softintr(). This is all because if we call switch() inside
575 *	cpu_intr(), not all the user registers have been saved in u.u_pcb.
576 *
577 * Results:
578 * 	None.
579 *
580 * Side effects:
581 *	None.
582 *
583 *----------------------------------------------------------------------------
584 */
585NESTED_NOPROFILE(mips1_UserIntr, CALLFRAME_SIZ, ra)
586	.set	noat
587	.mask	0x80000000, -4
588/*
589 * Save the relevant user registers onto the stack.
590 * We don't need to save s0 - s8 because the compiler does it for us.
591 */
592	lw	k1, _C_LABEL(curpcb)
593	nop
594	addu	k1, k1, USPACE - FRAME_SIZ
595	sw	AT, FRAME_AST(k1)
596	sw	v0, FRAME_V0(k1)
597	sw	v1, FRAME_V1(k1)
598	mflo	v0
599	sw	a0, FRAME_A0(k1)
600	sw	a1, FRAME_A1(k1)
601	sw	a2, FRAME_A2(k1)
602	sw	a3, FRAME_A3(k1)
603	mfhi	v1
604	sw	t0, FRAME_T0(k1)
605	sw	t1, FRAME_T1(k1)
606	sw	t2, FRAME_T2(k1)
607	sw	t3, FRAME_T3(k1)
608	mfc0	a0, MIPS_COP_0_STATUS		# 1st arg is STATUS
609	sw	t4, FRAME_T4(k1)
610	sw	t5, FRAME_T5(k1)
611	sw	t6, FRAME_T6(k1)
612	sw	t7, FRAME_T7(k1)
613	mfc0	a1, MIPS_COP_0_CAUSE		# 2nd arg is CAUSE
614	sw	t8, FRAME_T8(k1)
615	sw	t9, FRAME_T9(k1)
616	sw	gp, FRAME_GP(k1)
617	sw	sp, FRAME_SP(k1)
618	mfc0	a2, MIPS_COP_0_EXC_PC		# 3rd arg is exception PC
619	sw	ra, FRAME_RA(k1)
620	sw	a0, FRAME_SR(k1)
621	sw	v0, FRAME_MULLO(k1)
622	sw	v1, FRAME_MULHI(k1)
623	and	a3, a0, a1			# 4th is STATUS & CAUSE
624	sw	a2, FRAME_EPC(k1)
625	addu	sp, k1, -CALLFRAME_SIZ		# switch to kernel SP
626#ifdef __GP_SUPPORT__
627	la	gp, _C_LABEL(_gp)		# switch to kernel GP
628#endif
629	.set	at
630	and	t0, a0, ~MIPS_SR_COP_1_BIT	# turn off the FPU
631	.set	noat
632#if defined(DDB) || defined(DEBUG) || defined(KGDB)
633	move	ra, a2
634	sw	ra, CALLFRAME_RA(sp)		# for debugging
635#endif
636/*
637 * Call the interrupt handler.
638 */
639	jal	_C_LABEL(cpu_intr)
640	mtc0	t0, MIPS_COP_0_STATUS
641/*
642 * Check pending asynchoronous traps.
643 */
644	lw	v0, _C_LABEL(curproc)		# v0 = curproc
645	addu	a1, sp, CALLFRAME_SIZ
646	lw	a0, FRAME_SR(a1)
647	lw	v0, P_MD_ASTPENDING(v0)		# any pending ast?
648	mtc0	a0, MIPS_COP_0_STATUS		# restore SR, disable intrs
649	beq	v0, zero, 1f			# if no, skip ast processing
650	nop					# -delay slot-
651/*
652 * We have pending asynchronous traps; save remaining user state in stack.
653 */
654	sw	s0, FRAME_S0(a1)
655	sw	s1, FRAME_S1(a1)
656	sw	s2, FRAME_S2(a1)
657	sw	s3, FRAME_S3(a1)
658	sw	s4, FRAME_S4(a1)
659	sw	s5, FRAME_S5(a1)
660	sw	s6, FRAME_S6(a1)
661	sw	s7, FRAME_S7(a1)
662	sw	s8, FRAME_S8(a1)
663
664	lw	a0, FRAME_EPC(a1)		# argument is interrupted PC
665	li	t0, MIPS_HARD_INT_MASK | MIPS_SR_INT_IE
666	jal	_C_LABEL(ast)
667	mtc0	t0, MIPS_COP_0_STATUS		# enable interrupts (spl0)
668
669	addu	a1, sp, CALLFRAME_SIZ
670	lw	a0, FRAME_SR(a1)
671	lw	s0, FRAME_S0(a1)
672	mtc0	a0, MIPS_COP_0_STATUS		# this should disable interrupts
673	lw	s1, FRAME_S1(a1)
674	lw	s2, FRAME_S2(a1)
675	lw	s3, FRAME_S3(a1)
676	lw	s4, FRAME_S4(a1)
677	lw	s5, FRAME_S5(a1)
678	lw	s6, FRAME_S6(a1)
679	lw	s7, FRAME_S7(a1)
680	lw	s8, FRAME_S8(a1)
6811:
682	lw	v0, FRAME_MULLO(a1)
683	lw	v1, FRAME_MULHI(a1)
684	mtlo	v0
685	mthi	v1
686	move	k1, a1
687	lw	k0, FRAME_EPC(k1)		# exception PC
688	lw	AT, FRAME_AST(k1)
689	lw	v0, FRAME_V0(k1)
690	lw	v1, FRAME_V1(k1)
691	lw	a0, FRAME_A0(k1)
692	lw	a1, FRAME_A1(k1)
693	lw	a2, FRAME_A2(k1)
694	lw	a3, FRAME_A3(k1)
695	lw	t0, FRAME_T0(k1)
696	lw	t1, FRAME_T1(k1)
697	lw	t2, FRAME_T2(k1)
698	lw	t3, FRAME_T3(k1)
699	lw	t4, FRAME_T4(k1)
700	lw	t5, FRAME_T5(k1)
701	lw	t6, FRAME_T6(k1)
702	lw	t7, FRAME_T7(k1)
703	lw	t8, FRAME_T8(k1)
704	lw	t9, FRAME_T9(k1)
705	lw	gp, FRAME_GP(k1)
706	lw	sp, FRAME_SP(k1)
707	lw	ra, FRAME_RA(k1)
708	j	k0				# return to interrupted point
709	rfe
710	.set	at
711END(mips1_UserIntr)
712
713/*
714 * Mark where code entreed from exception hander jumptable
715 * ends, for stack traceback code.
716 */
717
718	.globl	_C_LABEL(mips1_exceptionentry_end)
719_C_LABEL(mips1_exceptionentry_end):
720
721
722#if 0
723/*----------------------------------------------------------------------------
724 *
725 * mips1_TLBModException --
726 *
727 *	Handle a TLB modified exception.
728 *	The BaddVAddr, Context, and EntryHi registers contain the failed
729 *	virtual address.
730 *
731 * Results:
732 *	None.
733 *
734 * Side effects:
735 *	None.
736 *
737 *----------------------------------------------------------------------------
738 */
739LEAF_NOPROFILE(mips1_TLBModException)
740	.set	noat
741	tlbp					# find the TLB entry
742	mfc0	k0, MIPS_COP_0_TLB_LOW		# get the physical address
743	mfc0	k1, MIPS_COP_0_TLB_INDEX	# check to be sure its valid
744	or	k0, k0, MIPS1_TLB_DIRTY_BIT	# update TLB
745	blt	k1, zero, 4f			# not found!!!
746	mtc0	k0, MIPS_COP_0_TLB_LOW
747	li	k1, MIPS_KSEG0_START
748	subu	k0, k0, k1
749	srl	k0, k0, MIPS1_TLB_PHYS_PAGE_SHIFT
750	la	k1, pmap_attributes
751	addu	k0, k0, k1
752	lbu	k1, 0(k0)			# fetch old value
753	nop
754	or	k1, k1, 1			# set modified bit
755	sb	k1, 0(k0)			# save new value
756	mfc0	k0, MIPS_COP_0_EXC_PC		# get return address
757	nop
758	j	k0
759	rfe
7604:
761	break	0				# panic
762	.set	at
763END(mips1_TLBModException)
764#endif
765
766/*----------------------------------------------------------------------------
767 *
768 * mips1_TLBMissException --
769 *
770 *	Handle a TLB miss exception from kernel mode.
771 *	The BaddVAddr, Context, and EntryHi registers contain the failed
772 *	virtual address.
773 *
774 * Results:
775 *	None.
776 *
777 * Side effects:
778 *	None.
779 *
780 *----------------------------------------------------------------------------
781 */
782LEAF_NOPROFILE(mips1_TLBMissException)
783	.set	noat
784	mfc0	k0, MIPS_COP_0_BAD_VADDR	# get the fault address
785	li	k1, VM_MIN_KERNEL_ADDRESS	# compute index
786	subu	k0, k0, k1
787	lw	k1, _C_LABEL(Sysmapsize)	# index within range?
788	srl	k0, k0, PGSHIFT
789	sltu	k1, k0, k1
790	beq	k1, zero, outofworld		# No. falling beyond...
791	nop
792	lw	k1, _C_LABEL(Sysmap)
793	sll	k0, k0, 2			# compute offset from index
794	addu	k1, k1, k0
795	lw	k0, 0(k1)			# get PTE entry
796	mfc0	k1, MIPS_COP_0_EXC_PC		# get return address
797	mtc0	k0, MIPS_COP_0_TLB_LOW		# save PTE entry
798	and	k0, k0, MIPS1_PG_V		# check for valid entry
799	beq	k0, zero, _C_LABEL(mips1_KernGenException) # PTE invalid
800	nop
801	tlbwr					# update TLB
802	j	k1
803	rfe
804
805outofworld:
806	/* Ensure we have a valid sp so panic has a chance */
807	move	a1, sp
808	la	sp, start			# set sp to a valid place
809	PANIC("TLB out of universe: ksp was %p")
810	.set	at
811END(mips1_TLBMissException)
812
813
814/*--------------------------------------------------------------------------
815 *
816 * mips1_SetPID --
817 *
818 *	Write the given pid into the TLB pid reg.
819 *
820 *	mips1_SetPID(pid)
821 *		int pid;
822 *
823 * Results:
824 *	None.
825 *
826 * Side effects:
827 *	PID set in the entry hi register.
828 *
829 *--------------------------------------------------------------------------
830 */
831LEAF(mips1_SetPID)
832	sll	a0, a0, MIPS1_TLB_PID_SHIFT	# put PID in right spot
833	mtc0	a0, MIPS_COP_0_TLB_HI		# Write the hi reg value
834	j	ra
835	nop
836END(mips1_SetPID)
837
838
839/*--------------------------------------------------------------------------
840 *
841 * mips1_TLBUpdate --
842 *
843 *	Update the TLB if highreg is found; otherwise, enter the data.
844 *
845 *	mips1_TLBUpdate(highreg, lowreg)
846 *		unsigned highreg, lowreg;
847 *
848 * Results:
849 *	None.
850 *
851 * Side effects:
852 *	None.
853 *
854 *--------------------------------------------------------------------------
855 */
856LEAF(mips1_TLBUpdate)
857	mfc0	v1, MIPS_COP_0_STATUS		# save the status register
858	mtc0	zero, MIPS_COP_0_STATUS		# disable interrupts
859	nop
860	mfc0	t0, MIPS_COP_0_TLB_HI		# save current PID
861	nop
862	mtc0	a0, MIPS_COP_0_TLB_HI		# set entryhi
863	nop
864	tlbp					# probe the existence
865	mfc0	v0, MIPS_COP_0_TLB_INDEX	# see what we got
866	mtc0	a1, MIPS_COP_0_TLB_LOW		# set new entrylo
867	bgez	v0, 2f				# index < 0 => !found
868	nop
869	b	3f
870	tlbwr					# add vicitimizing another
8712:
872	tlbwi					# update the existing one
8733:
874	mtc0	t0, MIPS_COP_0_TLB_HI		# restore current PID
875	j	ra
876	mtc0	v1, MIPS_COP_0_STATUS
877END(mips1_TLBUpdate)
878
879/*--------------------------------------------------------------------------
880 *
881 * mips1_TLBRead --
882 *
883 *	Read the TLB entry.
884 *
885 *	mips1_TLBRead(entry, tlb)
886 *		unsigned entry;
887 *		struct mips1_tlb *tlb;
888 *
889 * Results:
890 *	Returns MIPS1 TLB HI/LO in a pair.
891 *
892 *--------------------------------------------------------------------------
893 */
894LEAF(mips1_TLBRead)
895	mfc0	v1, MIPS_COP_0_STATUS		# Save the status register.
896	mtc0	zero, MIPS_COP_0_STATUS		# Disable interrupts
897	mfc0	t0, MIPS_COP_0_TLB_HI		# Get current PID
898
899	sll	a0, a0, MIPS1_TLB_INDEX_SHIFT
900	mtc0	a0, MIPS_COP_0_TLB_INDEX	# Set the index register
901	nop
902	tlbr					# Read from the TLB
903	mfc0	t2, MIPS_COP_0_TLB_HI		# fetch the hi entry
904	mfc0	t3, MIPS_COP_0_TLB_LOW		# fetch the low entry
905	sw	t2, 0(a1)
906	sw	t3, 4(a1)
907
908	mtc0	t0, MIPS_COP_0_TLB_HI		# restore PID
909	j	ra
910	mtc0	v1, MIPS_COP_0_STATUS		# Restore the status register
911END(mips1_TLBRead)
912
913/*----------------------------------------------------------------------------
914 *
915 *	R3000 cache sizing and flushing code.
916 *
917 *----------------------------------------------------------------------------
918 */
919#ifndef ENABLE_MIPS_TX3900
920/*
921 * void mips1_wbflush(void)
922 *
923 * Drain processor's write buffer, normally used to ensure any I/O
924 * register write operations are done before subsequent manipulations.
925 *
926 * Some hardware implementations have a WB chip independent from CPU
927 * core, and CU0 (Coprocessor Usability #0) bit of CP0 status register
928 * is wired to indicate writebuffer condition.  This code does busy-loop
929 * while CU0 bit indicates false condition.
930 *
931 * For other hardwares which have the writebuffer logic is implemented
932 * in a system controller ASIC chip, wbflush operation would done
933 * differently.
934 */
935LEAF(mips1_wbflush)
936	nop
937	nop
938	nop
939	nop
9401:	bc0f	1b
941	nop
942	j	ra
943	nop
944END(mips1_wbflush)
945#else /* !ENABLE_MIPS_TX3900 */
946/*
947 *	The differences between R3900 and R3000.
948 *	1. Cache system
949 *		Physical-index physical-tag
950 *		fixed line-size
951 *		refil-size 4/8/16/32 words (set in config register)
952 *		TX3912
953 *		       Write-through
954 *		       I-cache 4KB/16B direct mapped (256line)
955 *		       D-cache 1KB/4B 2-way sa (128line)
956 *		       Cache snoop
957 *		TX3922
958 *		       Write-through/write-back (set in config register)
959 *		       I-cache 16KB/16B 2-way sa
960 *		       D-cache 8KB/16B 2-way sa
961 *		       Cache snoop
962 *
963 *	2. Coprocessor1
964 *	2.1	cache operation.
965 *		R3900 uses MIPSIII cache op like method.
966 *	2.2	R3900 specific CP0 register.
967 *		(mips/include/r3900regs.h overrides cpuregs.h)
968 *	2.3	# of TLB entries
969 *		TX3912 32 entries
970 *		TX3922 64 entries
971 *
972 *	3. System address map
973 *		kseg2 0xff000000-0xfffeffff is reserved.
974 *		(mips/include/vmparam.h)
975 *
976 *  + If defined both MIPS1 and ENABLE_MIPS_TX3900, it generates kernel for
977 * R3900. If defined MIPS1 only, No R3900 feature include.
978 *  + R3920 core has write-back mode. but it is always disabled in NetBSD.
979 */
980
981LEAF_NOPROFILE(tx3900_cp0_config_read)
982	mfc0	v0, R3900_COP_0_CONFIG
983	j	ra
984	nop
985END(tx3900_cp0_config_read)
986
987LEAF(mips1_wbflush)
988	sync
989	j	ra
990	nop
991END(mips1_wbflush)
992#endif /* !ENABLE_MIPS_TX3900 */
993
994/*
995 * mips1_proc_trampoline
996 *
997 * Special arrangement for a process about to go user mode right after
998 * fork() system call.  When the first CPU tick is scheduled to the
999 * forked child, it starts running from here.  Then, a service function
1000 * is called with one argument supplied to complete final preparations,
1001 * and the process returns to user mode as if the fork() system call is
1002 * handled in a normal way.  No need to save any registers although this
1003 * calls another.
1004 */
1005LEAF(mips1_proc_trampoline)
1006	addu	sp, sp, -CALLFRAME_SIZ
1007	jal	ra, s0
1008	move	a0, s1
1009	.set	noat
1010XLEAF(mips1_xcpt_return)
1011	addu	a1, sp, CALLFRAME_SIZ	# a1 points exception frame
1012	lw	a0, FRAME_SR(a1)
1013	lw	t0, FRAME_MULLO(a1)
1014	lw	t1, FRAME_MULHI(a1)
1015	mtc0	a0, MIPS_COP_0_STATUS	# this should disable interrupts
1016	mtlo	t0
1017	mthi	t1
1018	nop
1019	move	k1, a1
1020	lw	k0, FRAME_EPC(k1)
1021	lw	AT, FRAME_AST(k1)
1022	lw	v0, FRAME_V0(k1)
1023	lw	v1, FRAME_V1(k1)
1024	lw	a0, FRAME_A0(k1)
1025	lw	a1, FRAME_A1(k1)
1026	lw	a2, FRAME_A2(k1)
1027	lw	a3, FRAME_A3(k1)
1028	lw	t0, FRAME_T0(k1)
1029	lw	t1, FRAME_T1(k1)
1030	lw	t2, FRAME_T2(k1)
1031	lw	t3, FRAME_T3(k1)
1032	lw	t4, FRAME_T4(k1)
1033	lw	t5, FRAME_T5(k1)
1034	lw	t6, FRAME_T6(k1)
1035	lw	t7, FRAME_T7(k1)
1036	lw	s0, FRAME_S0(k1)
1037	lw	s1, FRAME_S1(k1)
1038	lw	s2, FRAME_S2(k1)
1039	lw	s3, FRAME_S3(k1)
1040	lw	s4, FRAME_S4(k1)
1041	lw	s5, FRAME_S5(k1)
1042	lw	s6, FRAME_S6(k1)
1043	lw	s7, FRAME_S7(k1)
1044	lw	t8, FRAME_T8(k1)
1045	lw	t9, FRAME_T9(k1)
1046	lw	gp, FRAME_GP(k1)
1047	lw	s8, FRAME_S8(k1)
1048	lw	ra, FRAME_RA(k1)
1049	lw	sp, FRAME_SP(k1)
1050	nop
1051	j	k0
1052	rfe
1053	.set	at
1054END(mips1_proc_trampoline)
1055
1056/*
1057 * void mips1_cpu_switch_resume(struct proc *newproc)
1058 *
1059 * Wiredown the USPACE of newproc with TLB entry#0 and #1.  Check
1060 * if target USPACE is already refered by any TLB entry before
1061 * doing that, and make sure TBIS(them) in the case.
1062 */
1063LEAF_NOPROFILE(mips1_cpu_switch_resume)
1064	lw	a1, P_MD_UPTE_0(a0)		# a1 = upte[0]
1065	lw	a2, P_MD_UPTE_1(a0)		# a2 = upte[1]
1066	lw	s0, P_ADDR(a0)			# va = p->p_addr
1067	li	s2, MIPS_KSEG2_START
1068	blt	s0, s2, resume
1069	nop
1070
1071	mtc0	s0, MIPS_COP_0_TLB_HI		# VPN = va
1072	nop
1073	tlbp					# probe 1st VPN
1074	mfc0	s1, MIPS_COP_0_TLB_INDEX
1075	nop
1076	bltz	s1, entry0set
1077	li	s1, MIPS_KSEG0_START		# found, then
1078	mtc0	s1, MIPS_COP_0_TLB_HI
1079	mtc0	zero, MIPS_COP_0_TLB_LOW
1080	nop
1081	tlbwi					# TBIS(va)
1082	nop
1083	mtc0	s0, MIPS_COP_0_TLB_HI		# set 1st VPN again
1084entry0set:
1085	mtc0	zero, MIPS_COP_0_TLB_INDEX	# TLB index #0
1086	ori	a1, a1, MIPS1_PG_G
1087	mtc0	a1, MIPS_COP_0_TLB_LOW		# 1st PFN w/ PG_G
1088	nop
1089	tlbwi					# set TLB entry #0
1090
1091	addu	s0, s0, NBPG
1092	mtc0	s0, MIPS_COP_0_TLB_HI		# VPN = va+NBPG
1093	nop
1094	tlbp					# probe 2nd VPN
1095	mfc0	s1, MIPS_COP_0_TLB_INDEX
1096	nop
1097	bltz	s1, entry1set
1098	li	s1, MIPS_KSEG0_START		# found, then
1099	mtc0	s1, MIPS_COP_0_TLB_HI
1100	mtc0	zero, MIPS_COP_0_TLB_LOW
1101	nop
1102	tlbwi					# TBIS(va+NBPG)
1103	nop
1104	mtc0	s0, MIPS_COP_0_TLB_HI		# set 2nd VPN again
1105entry1set:
1106	li	s1, 1 << MIPS1_TLB_INDEX_SHIFT
1107	mtc0	s1, MIPS_COP_0_TLB_INDEX	# TLB index #1
1108	ori	a2, a2, MIPS1_PG_G
1109	mtc0	a2, MIPS_COP_0_TLB_LOW		# 2nd PFN w/ PG_G
1110	nop
1111	tlbwi					# set TLB entry #1
1112
1113resume:
1114	j	ra
1115	nop
1116	END(mips1_cpu_switch_resume)
1117
1118/*
1119 * void mips1_TBIS(vaddr_t va)
1120 *
1121 * Invalidate a TLB entry for given virtual address if found in TLB.
1122 */
1123LEAF(mips1_TBIS)
1124	mfc0	v1, MIPS_COP_0_STATUS		# save status register
1125	mtc0	zero, MIPS_COP_0_STATUS		# disable interrupts
1126	mfc0	t0, MIPS_COP_0_TLB_HI		# save current PID
1127	nop
1128
1129	mtc0	a0, MIPS_COP_0_TLB_HI		# look for addr & PID
1130	nop
1131	tlbp					# probe the entry in question
1132	mfc0	a0, MIPS_COP_0_TLB_INDEX	# see what we got
1133	li	t1, MIPS_KSEG0_START		# load invalid address
1134	bltz	a0, 1f				# index < 0 then skip
1135	mtc0	t1, MIPS_COP_0_TLB_HI		# make entryHi invalid
1136	mtc0	zero, MIPS_COP_0_TLB_LOW	# zero out entryLo
1137	nop
1138	tlbwi
11391:
1140	mtc0	t0, MIPS_COP_0_TLB_HI		# restore PID
1141	j	ra
1142	mtc0	v1, MIPS_COP_0_STATUS		# restore the status register
1143	END(mips1_TBIS)
1144
1145/*
1146 * void mips1_TBIAP(int sizeofTLB)
1147 *
1148 * Invalidate TLB entries belong to per process user spaces while
1149 * leaving entries for kernel space marked global intact.
1150 */
1151LEAF(mips1_TBIAP)
1152	mfc0	v1, MIPS_COP_0_STATUS		# save status register
1153	mtc0	zero, MIPS_COP_0_STATUS		# disable interrupts
1154
1155	li	t1, MIPS1_TLB_FIRST_RAND_ENTRY << MIPS1_TLB_INDEX_SHIFT
1156	sll	t2, a0, MIPS1_TLB_INDEX_SHIFT
1157	li	v0, MIPS_KSEG0_START		# invalid address
1158
1159	# do {} while (t1 < t2)
11601:
1161	mtc0	t1, MIPS_COP_0_TLB_INDEX	# set index
1162	nop
1163	tlbr					# obtain an entry
1164	mfc0	a0, MIPS_COP_0_TLB_LOW
1165	nop
1166	and	a0, a0, MIPS1_PG_G		# check to see it has G bit
1167	bnez	a0, 2f
1168	nop
1169	mtc0	v0, MIPS_COP_0_TLB_HI		# make entryHi invalid
1170	mtc0	zero, MIPS_COP_0_TLB_LOW	# zero out entryLo
1171	nop
1172	tlbwi					# invalidate the TLB entry
11732:
1174	addu	t1, t1, 1 << MIPS1_TLB_INDEX_SHIFT	# increment index
1175	bne	t1, t2, 1b
1176	nop
1177
1178	j	ra				# new TLBpid will be set soon
1179	mtc0	v1, MIPS_COP_0_STATUS		# restore status register
1180	END(mips1_TBIAP)
1181
1182/*
1183 * void mips1_TBIA(int sizeofTLB)
1184 *
1185 * Invalidate TLB entirely.
1186 */
1187LEAF(mips1_TBIA)
1188	mfc0	v1, MIPS_COP_0_STATUS		# save the status register.
1189	mtc0	zero, MIPS_COP_0_STATUS		# disable interrupts
1190
1191	li	t1, MIPS_KSEG0_START
1192	mtc0	t1, MIPS_COP_0_TLB_HI		# make entryHi invalid
1193	mtc0	zero, MIPS_COP_0_TLB_LOW	# zero out entryLo
1194
1195	move	t1, zero
1196	sll	a0, a0, MIPS1_TLB_INDEX_SHIFT
1197
1198	# do {} while (t1 < a0)
11991:
1200	mtc0	t1, MIPS_COP_0_TLB_INDEX	# set TLBindex
1201	addu	t1, t1, 1 << MIPS1_TLB_INDEX_SHIFT	# increment index
1202	bne	t1, a0, 1b
1203	tlbwi					# invalidate the entry
1204
1205	j	ra
1206	mtc0	v1, MIPS_COP_0_STATUS		# restore status register
1207	END(mips1_TBIA)
1208
1209	.data
1210
1211	.globl _C_LABEL(mips1_locoresw)
1212_C_LABEL(mips1_locoresw):
1213	.word _C_LABEL(mips1_cpu_switch_resume)
1214	.word _C_LABEL(mips1_proc_trampoline)
1215	.word _C_LABEL(mips_idle)
1216
1217mips1_excpt_sw:
1218	####
1219	#### The kernel exception handlers.
1220	####
1221	.word _C_LABEL(mips1_KernIntr)		# 0 external interrupt
1222	.word _C_LABEL(mips1_KernGenException)	# 1 TLB modification
1223	.word _C_LABEL(mips1_TLBMissException)	# 2 TLB miss (LW/I-fetch)
1224	.word _C_LABEL(mips1_TLBMissException)	# 3 TLB miss (SW)
1225	.word _C_LABEL(mips1_KernGenException)	# 4 address error (LW/I-fetch)
1226	.word _C_LABEL(mips1_KernGenException)	# 5 address error (SW)
1227	.word _C_LABEL(mips1_KernGenException)	# 6 bus error (I-fetch)
1228	.word _C_LABEL(mips1_KernGenException)	# 7 bus error (load or store)
1229	.word _C_LABEL(mips1_KernGenException)	# 8 system call
1230	.word _C_LABEL(mips1_KernGenException)	# 9 breakpoint
1231	.word _C_LABEL(mips1_KernGenException)	# 10 reserved instruction
1232	.word _C_LABEL(mips1_KernGenException)	# 11 coprocessor unusable
1233	.word _C_LABEL(mips1_KernGenException)	# 12 arithmetic overflow
1234	.word _C_LABEL(mips1_KernGenException)	# 13 r3k reserved
1235	.word _C_LABEL(mips1_KernGenException)	# 14 r3k reserved
1236	.word _C_LABEL(mips1_KernGenException)	# 15 r3k reserved
1237	.word _C_LABEL(mips1_KernGenException)	# 16 never happens w/ MIPS1
1238	.word _C_LABEL(mips1_KernGenException)	# 17 never happens w/ MIPS1
1239	.word _C_LABEL(mips1_KernGenException)	# 18 never happens w/ MIPS1
1240	.word _C_LABEL(mips1_KernGenException)	# 19 never happens w/ MIPS1
1241	.word _C_LABEL(mips1_KernGenException)	# 20 never happens w/ MIPS1
1242	.word _C_LABEL(mips1_KernGenException)	# 21 never happens w/ MIPS1
1243	.word _C_LABEL(mips1_KernGenException)	# 22 never happens w/ MIPS1
1244	.word _C_LABEL(mips1_KernGenException)	# 23 never happens w/ MIPS1
1245	.word _C_LABEL(mips1_KernGenException)	# 24 never happens w/ MIPS1
1246	.word _C_LABEL(mips1_KernGenException)	# 25 never happens w/ MIPS1
1247	.word _C_LABEL(mips1_KernGenException)	# 26 never happens w/ MIPS1
1248	.word _C_LABEL(mips1_KernGenException)	# 27 never happens w/ MIPS1
1249	.word _C_LABEL(mips1_KernGenException)	# 28 never happens w/ MIPS1
1250	.word _C_LABEL(mips1_KernGenException)	# 29 never happens w/ MIPS1
1251	.word _C_LABEL(mips1_KernGenException)	# 30 never happens w/ MIPS1
1252	.word _C_LABEL(mips1_KernGenException)	# 31 never happens w/ MIPS1
1253	#####
1254	##### The user exception handlers.
1255	#####
1256	.word _C_LABEL(mips1_UserIntr)		#  0
1257	.word _C_LABEL(mips1_UserGenException)	#  1
1258	.word _C_LABEL(mips1_UserGenException)	#  2
1259	.word _C_LABEL(mips1_UserGenException)	#  3
1260	.word _C_LABEL(mips1_UserGenException)	#  4
1261	.word _C_LABEL(mips1_UserGenException)	#  5
1262	.word _C_LABEL(mips1_UserGenException)	#  6
1263	.word _C_LABEL(mips1_UserGenException)	#  7
1264	.word _C_LABEL(mips1_SystemCall)	#  8
1265	.word _C_LABEL(mips1_UserGenException)	#  9
1266	.word _C_LABEL(mips1_UserGenException)	# 10
1267	.word _C_LABEL(mips1_UserGenException)	# 11
1268	.word _C_LABEL(mips1_UserGenException)	# 12
1269	.word _C_LABEL(mips1_UserGenException)	# 13
1270	.word _C_LABEL(mips1_UserGenException)	# 14
1271	.word _C_LABEL(mips1_UserGenException)	# 15
1272	.word _C_LABEL(mips1_UserGenException)	# 16
1273	.word _C_LABEL(mips1_UserGenException)	# 17
1274	.word _C_LABEL(mips1_UserGenException)	# 18
1275	.word _C_LABEL(mips1_UserGenException)	# 19
1276	.word _C_LABEL(mips1_UserGenException)	# 20
1277	.word _C_LABEL(mips1_UserGenException)	# 21
1278	.word _C_LABEL(mips1_UserGenException)	# 22
1279	.word _C_LABEL(mips1_UserGenException)	# 23
1280	.word _C_LABEL(mips1_UserGenException)	# 24
1281	.word _C_LABEL(mips1_UserGenException)	# 25
1282	.word _C_LABEL(mips1_UserGenException)	# 26
1283	.word _C_LABEL(mips1_UserGenException)	# 27
1284	.word _C_LABEL(mips1_UserGenException)	# 28
1285	.word _C_LABEL(mips1_UserGenException)	# 29
1286	.word _C_LABEL(mips1_UserGenException)	# 20
1287	.word _C_LABEL(mips1_UserGenException)	# 31
1288