xref: /netbsd-src/sys/arch/mips/mips/locore_mips1.S (revision 100a3398b8d3c64e571cff36b46c23431b410e09)
1/*	$NetBSD: locore_mips1.S,v 1.99 2024/02/09 22:08:32 andvar 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 permitted 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. Neither the name of the University nor the names of its contributors
19 *    may be used to endorse or promote products derived from this software
20 *    without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 * Copyright (C) 1989 Digital Equipment Corporation.
35 * Permission to use, copy, modify, and distribute this software and
36 * its documentation for any purpose and without fee is hereby granted,
37 * provided that the above copyright notice appears in all copies.
38 * Digital Equipment Corporation makes no representations about the
39 * suitability of this software for any purpose.  It is provided "as is"
40 * without express or implied warranty.
41 *
42 * from: Header: /sprite/src/kernel/mach/ds3100.md/RCS/loMem.s,
43 *	v 1.1 89/07/11 17:55:04 nelson Exp  SPRITE (DECWRL)
44 * from: Header: /sprite/src/kernel/mach/ds3100.md/RCS/machAsm.s,
45 *	v 9.2 90/01/29 18:00:39 shirriff Exp  SPRITE (DECWRL)
46 * from: Header: /sprite/src/kernel/vm/ds3100.md/vmPmaxAsm.s,
47 *	v 1.1 89/07/10 14:27:41 nelson Exp  SPRITE (DECWRL)
48 *
49 *	@(#)locore.s	8.5 (Berkeley) 1/4/94
50 */
51#include "opt_cputype.h"
52#include "opt_ddb.h"
53#include "opt_kgdb.h"
54
55#include <sys/cdefs.h>
56
57#include <mips/asm.h>
58#include <mips/cpuregs.h>
59
60RCSID("$NetBSD: locore_mips1.S,v 1.99 2024/02/09 22:08:32 andvar Exp $")
61
62#include "assym.h"
63
64#define	_SLLV		sllv
65
66#define	_SLL		sll
67#define	_SRL		srl
68#define	WIRED_SHIFT	2
69
70/*
71 * Use correct-sized m?c0/dm?c0 opcodes.
72 */
73#define	_MFC0	mfc0
74#define	_MTC0	mtc0
75
76#if defined(__mips_n32) || defined(__mips_n64)
77#error MIPS1 does not support N32/N64.
78#endif
79
80#define MIPSX(name)	__CONCAT(mips1_,name)
81
82	.set	noreorder
83	.text
84
85EXPORT(MIPSX(exceptionentry_start))
86
87/*
88 * mipsN_utlb_miss
89 *
90 * A reference is made (in either kernel or user mode) to a page in
91 * kuseg that has no matching TLB entry.  This routine is copied down
92 * at 0x80000000 and total length must be less than 32 instructions.
93 * No pc relative jump instruction is allowed.
94 */
95VECTOR(MIPSX(utlb_miss), unknown)
96	.set	noat
97	_MFC0	k0, MIPS_COP_0_BAD_VADDR	#00: k0=bad address
98	lui	k1, %hi(CPUVAR(PMAP_SEG0TAB))	#01: k1=hi of seg0tab
99	bltz	k0, 1f				# R3000 chip bug
100	 PTR_SRL k0, SEGSHIFT-PTR_SCALESHIFT	#03: k0=seg offset (almost)
101	PTR_L	k1, %lo(CPUVAR(PMAP_SEG0TAB))(k1) #04: k1=seg0tab
102	andi	k0, (NSEGPG-1)<<PTR_SCALESHIFT	#07: k0=seg offset (mask 0x3)
103	PTR_ADDU k1, k0				#08: k1=seg entry address
104	PTR_L	k1, 0(k1)			#09: k1=seg entry
105	_MFC0	k0, MIPS_COP_0_BAD_VADDR	#0a: k0=bad address (again)
106	beqz	k1, MIPSX(nopagetable)		#0b: ==0 -- no page table
107	 PTR_SRL k0, (PGSHIFT-PTPSHIFT)		#0c: k0=VPN (aka va>>10)
108	andi	k0, (NPTEPG-1) << PTPSHIFT	#0d: k0=page table offset
109	PTR_ADDU k1, k0				#0e: k1=pte address
110	INT_L	k0, 0(k1)			#0f: k0=lo0 pte
111	nop					#10: load delay
112	beqz	k0, MIPSX(invalidpte)		#11: dont load invalid entries
113	 nop					#12  branch delay
114	mtc0	k0, MIPS_COP_0_TLB_LOW		#13: lo0 is loaded
115	nop					#14: load delay
116	tlbwr					#15: update TLB
1171:
118	_MFC0	k1, MIPS_COP_0_EXC_PC		#16: get return address
119	nop					#17: load delay
120	j	k1				#18: return from
121	 rfe					#19:    exception
122MIPSX(nopagetable):
123MIPSX(invalidpte):
124	j	MIPSX(slowfault)		#1a: handle the rest
125	 nop					#1b: branch delay
126	.set	at
127VECTOR_END(MIPSX(utlb_miss))
128
129
130/*
131 * mipsN_exception
132 *
133 * Handles any exceptions other than reset and UTLB miss.  This routine
134 * is copied down at 0x80000080 and total length must be less than 32
135 * instructions.  No pc relative jump instruction is allowed.
136 */
137	.org	MIPSX(utlb_miss) + 0x80
138VECTOR(MIPSX(exception), unknown)
139/*
140 * Find out what mode we came from and jump to the proper handler.
141 */
142	.set	noat
143	mfc0	k0, MIPS_COP_0_STATUS		#00: get the status register
144	mfc0	k1, MIPS_COP_0_CAUSE		#01: get the cause register
145	and	k0, MIPS1_SR_KU_PREV		#02: test for user mode
146	sll	k0, 4				#03: shift user bit for cause index
147	and	k1, MIPS1_CR_EXC_CODE		#04: mask out the cause bits
148	or	k1, k0				#05: change index to user table
149	PTR_LA	k0, MIPSX(excpt_sw)		#06: get base of the jump table
150	PTR_ADDU k0, k1				#08: get the address of the
151						#  function entry.  Note that
152						#  the cause is already
153						#  shifted left by 2 bits so
154						#  we dont have to shift.
155	PTR_L	k0, 0(k0)			#09: get the function address
156	nop					#0a: load delay
157	j	k0				#0b: jump to the function
158	 nop					#0c
159	nop					#0d
160	nop					#0e
161	nop					#0f
162	.set	at
163VECTOR_END(MIPSX(exception))
164
165
166/*----------------------------------------------------------------------------
167 *
168 * mipsN_slowfault
169 *
170 * Alternate entry point into the mipsN_user_gen_exception or
171 * mipsN_kern_gen_exception, when the UTLB miss handler couldn't
172 * find a TLB entry.
173 *
174 * Find out what mode we came from and call the appropriate handler.
175 *
176 *----------------------------------------------------------------------------
177 */
178MIPSX(slowfault):
179	.set	noat
180	mfc0	k0, MIPS_COP_0_STATUS
181	nop
182	and	k0, MIPS1_SR_KU_PREV
183	bnez	k0, _C_LABEL(MIPSX(user_gen_exception))
184	 nop
185	.set	at
186/*
187 * Fall through ...
188 */
189
190/*
191 * mipsN_kern_gen_exception
192 *
193 * Handle an exception during kernel mode.
194 * Build trapframe on stack to hold interrupted kernel context, then
195 * call trap() to process the condition.
196 *
197 * trapframe is pointed to by the 5th arg and a dummy sixth argument is used
198 * to avoid alignment problems
199 * {
200 *	register_t cf_args[4 + 1];
201 *	register_t cf_pad;		(for 8 word alignment)
202 *	register_t cf_sp;
203 *	register_t cf_ra;
204 *	struct reg cf_tf;
205 * };
206 */
207NESTED_NOPROFILE(MIPSX(kern_gen_exception), KERNFRAME_SIZ, ra)
208	.set	noat
209	.mask	0x80000000, -4
210#ifdef PARANOIA
211	PTR_L	k0, L_PCB(MIPS_CURLWP)
212	nop
213	slt	k0, k0, sp		# k0 = L_PCB(MIPS_CURLWP) < sp
2141:	beqz	k0, 1b			# loop forever if false
215	 nop
216	PTR_L	k0, L_PCB(MIPS_CURLWP)
217	nop
218	PTR_ADDU k0, USPACE
219	slt	k0, sp, k0		# k0 = sp < L_PCB(MIPS_CURLWP) + USPACE
2202:	beqz	k0, 2b			# loop forever if false
221	 nop
222#endif /* PARANOIA
223/*
224 * Save the relevant kernel registers onto the stack.
225 * We don't need to save s0 - s8, sp and gp because
226 * the compiler does it for us.
227 */
228	PTR_SUBU sp, KERNFRAME_SIZ
229	REG_S	AT, TF_BASE+TF_REG_AST(sp)
230	REG_S	v0, TF_BASE+TF_REG_V0(sp)
231	REG_S	v1, TF_BASE+TF_REG_V1(sp)
232	mflo	v0
233	mfhi	v1
234	REG_S	a0, TF_BASE+TF_REG_A0(sp)
235	REG_S	a1, TF_BASE+TF_REG_A1(sp)
236	REG_S	a2, TF_BASE+TF_REG_A2(sp)
237	REG_S	a3, TF_BASE+TF_REG_A3(sp)
238	mfc0	a0, MIPS_COP_0_STATUS		# 1st arg is STATUS
239	REG_S	t0, TF_BASE+TF_REG_T0(sp)
240	REG_S	t1, TF_BASE+TF_REG_T1(sp)
241	REG_S	t2, TF_BASE+TF_REG_T2(sp)
242	REG_S	t3, TF_BASE+TF_REG_T3(sp)
243	mfc0	a1, MIPS_COP_0_CAUSE		# 2nd arg is CAUSE
244	REG_S	ta0, TF_BASE+TF_REG_TA0(sp)
245	REG_S	ta1, TF_BASE+TF_REG_TA1(sp)
246	REG_S	ta2, TF_BASE+TF_REG_TA2(sp)
247	REG_S	ta3, TF_BASE+TF_REG_TA3(sp)
248	_MFC0	a2, MIPS_COP_0_BAD_VADDR	# 3rd arg is fault address
249	#REG_S	t8, TF_BASE+TF_REG_T8(sp)	# is MIPS_CURLWP
250	REG_S	t9, TF_BASE+TF_REG_T9(sp)
251	REG_S	ra, TF_BASE+TF_REG_RA(sp)
252	REG_S	a0, TF_BASE+TF_REG_SR(sp)
253	_MFC0	a3, MIPS_COP_0_EXC_PC		# 4th arg is exception PC
254	REG_S	v0, TF_BASE+TF_REG_MULLO(sp)
255	REG_S	v1, TF_BASE+TF_REG_MULHI(sp)
256	REG_S	a3, TF_BASE+TF_REG_EPC(sp)
257	REG_S	a1, TF_BASE+TF_REG_CAUSE(sp)
258#if defined(DDB) || defined(KGDB)
259	REG_S	s0, TF_BASE+TF_REG_S0(sp)
260	REG_S	s1, TF_BASE+TF_REG_S1(sp)
261	REG_S	s2, TF_BASE+TF_REG_S2(sp)
262	REG_S	s3, TF_BASE+TF_REG_S3(sp)
263	REG_S	s4, TF_BASE+TF_REG_S4(sp)
264	REG_S	s5, TF_BASE+TF_REG_S5(sp)
265	REG_S	s6, TF_BASE+TF_REG_S6(sp)
266	REG_S	s7, TF_BASE+TF_REG_S7(sp)
267	PTR_ADDU v0, sp, KERNFRAME_SIZ
268	REG_S	v0, TF_BASE+TF_REG_SP(sp)
269	REG_S	s8, TF_BASE+TF_REG_S8(sp)
270	REG_S	gp, TF_BASE+TF_REG_GP(sp)
271#endif
272	PTR_ADDU v0, sp, TF_BASE
273	REG_S	v0, KERNFRAME_ARG5(sp)		# 5th arg is p. to trapframe
274#ifdef PARANOIA
275	/*
276	 * save PPL in trapframe
277	 */
278	PTR_L	t0, L_CPU(MIPS_CURLWP)
279	nop
280	INT_L	t1, CPU_INFO_CPL(t0)		# get current priority level
281	nop
282	INT_S	t1, TF_BASE+TF_PPL(sp)		# save priority level
283#endif /* PARANOIA */
284
285#if defined(DDB) || defined(DEBUG) || defined(KGDB)
286	PTR_ADDU v0, sp, KERNFRAME_SIZ
287	REG_S	v0, KERNFRAME_SP(sp)
288#endif
289
290#ifdef PARANOIA
291	/*
292	 * Verify our existing interrupt level.
293	 */
294	jal	_C_LABEL(splcheck)
295	 nop
296#endif /* PARANOIA */
297
298	/*
299	 * Call the trap handler.
300	 */
301	jal	_C_LABEL(trap)
302	 REG_S	a3, KERNFRAME_RA(sp)		# for debugging
303
304	/*
305	 * Restore registers and return from the exception.
306	 */
307	REG_L	a0, TF_BASE+TF_REG_SR(sp)
308	nop
309	mtc0	a0, MIPS_COP_0_STATUS		# restore the SR, disable intrs
310
311	/*
312	 * Start of common kernel exception return code for both
313	 * mipxN_kern_gen_exception and mipsN_kern_intr.
314	 */
315MIPSX(kern_return):
316	REG_L	t0, TF_BASE+TF_REG_MULLO(sp)
317	REG_L	t1, TF_BASE+TF_REG_MULHI(sp)
318	REG_L	k1, TF_BASE+TF_REG_EPC(sp)	# might be changed inside trap
319	mtlo	t0
320	mthi	t1
321
322#ifdef PARANOIA
323	INT_L	t2, TF_BASE+TF_PPL(sp)		# get saved priority level
324	PTR_L	t0, L_CPU(MIPS_CURLWP)
325	nop
326	INT_L	t1, CPU_INFO_CPL(t0)		# get current priority level
327	nop
32811:	bne	t2, t1, 11b			# loop forever if unequal
329	 nop
330
331	/*
332	 * Verify our existing interrupt level.
333	 */
334	jal	_C_LABEL(splcheck)
335	 nop
336#endif /* PARANOIA */
337
338	/*
339	 * Check for kernel restartable atomic sequences.
340	 */
341	PTR_LA	t0, _C_LABEL(_lock_ras_start)
342	li	t1, -MIPS_LOCK_RAS_SIZE
343	and	t1, k1
344	bne	t1, t0, 1f			# exception PC in RAS area?
345	 nop
346	jal	_C_LABEL(_restart_lock_ras)	# fix the pc (k1)
347	 nop
3481:
349
350	REG_L	AT, TF_BASE+TF_REG_AST(sp)
351	REG_L	v0, TF_BASE+TF_REG_V0(sp)
352	REG_L	v1, TF_BASE+TF_REG_V1(sp)
353	REG_L	a0, TF_BASE+TF_REG_A0(sp)
354	REG_L	a1, TF_BASE+TF_REG_A1(sp)
355	REG_L	a2, TF_BASE+TF_REG_A2(sp)
356	REG_L	a3, TF_BASE+TF_REG_A3(sp)
357	REG_L	t0, TF_BASE+TF_REG_T0(sp)
358	REG_L	t1, TF_BASE+TF_REG_T1(sp)
359	REG_L	t2, TF_BASE+TF_REG_T2(sp)
360	REG_L	t3, TF_BASE+TF_REG_T3(sp)
361	REG_L	ta0, TF_BASE+TF_REG_TA0(sp)
362	REG_L	ta1, TF_BASE+TF_REG_TA1(sp)
363	REG_L	ta2, TF_BASE+TF_REG_TA2(sp)
364	REG_L	ta3, TF_BASE+TF_REG_TA3(sp)
365	#REG_L	t8, TF_BASE+TF_REG_T8(sp)	# is MIPS_CURLWP
366	REG_L	t9, TF_BASE+TF_REG_T9(sp)
367	REG_L	ra, TF_BASE+TF_REG_RA(sp)
368#ifdef DDBnotyet
369	REG_L	s0, TF_BASE+TF_REG_S0(sp)
370	REG_L	s1, TF_BASE+TF_REG_S1(sp)
371	REG_L	s2, TF_BASE+TF_REG_S2(sp)
372	REG_L	s3, TF_BASE+TF_REG_S3(sp)
373	REG_L	s4, TF_BASE+TF_REG_S4(sp)
374	REG_L	s5, TF_BASE+TF_REG_S5(sp)
375	REG_L	s6, TF_BASE+TF_REG_S6(sp)
376	REG_L	s7, TF_BASE+TF_REG_S7(sp)
377	REG_L	s8, TF_BASE+TF_REG_S8(sp)
378#endif
379	PTR_ADDU sp, KERNFRAME_SIZ
380	j	k1				# return to interrupted point
381	rfe
382	.set	at
383END(MIPSX(kern_gen_exception))
384
385/*
386 * mipsN_kern_intr
387 *
388 * Handle an interrupt from kernel mode.
389 * Build kernframe on stack to hold interrupted kernel context, then
390 * call cpu_intr() to process it.
391 *
392 */
393NESTED_NOPROFILE(MIPSX(kern_intr), KERNFRAME_SIZ, ra)
394	.set	noat
395	.mask	0x80000000, -4
396#ifdef PARANOIA
397	PTR_L	k0, L_PCB(MIPS_CURLWP)
398	nop
399	slt	k0, k0, sp			# k0 = L_PCB(MIPS_CURLWP) < sp
4001:	beqz	k0, 1b				# loop forever if false
401	 nop
402	PTR_L	k0, L_PCB(MIPS_CURLWP)
403	nop
404	PTR_ADDU k0, USPACE
405	slt	k0, sp, k0			# k0 = sp < L_PCB(MIPS_CURLWP) + USPACE
4062:	beqz	k0, 2b				# loop forever if false
407	 nop
408	PTR_L	k0, L_CPU(MIPS_CURLWP)
409	nop
410	INT_L	k0, CPU_INFO_IDEPTH(k0)		# grab interrupt depth
411	nop
412	sltu	k0, k0, 3			# must be < 3
4133:	beqz	k0, 3b				# loop forever if false
414	 nop
415#endif
416	/*
417	 * Save the relevant kernel registers onto the stack.  We don't need
418	 * to save s0 - s8, sp, and gp because the compiler does it for us.
419	 * But we use s0-s2 so need to save them.
420	 */
421	PTR_SUBU sp, KERNFRAME_SIZ
422	REG_S	AT, TF_BASE+TF_REG_AST(sp)
423	REG_S	v0, TF_BASE+TF_REG_V0(sp)
424	REG_S	v1, TF_BASE+TF_REG_V1(sp)
425	mflo	v0
426	mfhi	v1
427	REG_S	a0, TF_BASE+TF_REG_A0(sp)
428	REG_S	a1, TF_BASE+TF_REG_A1(sp)
429	REG_S	a2, TF_BASE+TF_REG_A2(sp)
430	REG_S	a3, TF_BASE+TF_REG_A3(sp)
431	REG_S	t0, TF_BASE+TF_REG_T0(sp)
432	REG_S	t1, TF_BASE+TF_REG_T1(sp)
433	REG_S	t2, TF_BASE+TF_REG_T2(sp)
434	REG_S	t3, TF_BASE+TF_REG_T3(sp)
435	REG_S	ta0, TF_BASE+TF_REG_TA0(sp)
436	REG_S	ta1, TF_BASE+TF_REG_TA1(sp)
437	REG_S	ta2, TF_BASE+TF_REG_TA2(sp)
438	REG_S	ta3, TF_BASE+TF_REG_TA3(sp)
439	REG_S	s0, TF_BASE+TF_REG_S0(sp)	# used for saved ipl/idepth
440	REG_S	s1, TF_BASE+TF_REG_S1(sp)	# used for initial status
441	mfc0	s1, MIPS_COP_0_STATUS
442	REG_S	s2, TF_BASE+TF_REG_S2(sp)	# used for cpu_info
443	#REG_S	t8, TF_BASE+TF_REG_T8(sp)	# already contains MIPS_CURLWP
444	REG_S	t9, TF_BASE+TF_REG_T9(sp)
445	REG_S	ra, TF_BASE+TF_REG_RA(sp)
446	REG_S	s1, TF_BASE+TF_REG_SR(sp)
447	REG_S	v0, TF_BASE+TF_REG_MULLO(sp)
448	REG_S	v1, TF_BASE+TF_REG_MULHI(sp)
449/*
450 * Call the interrupt handler.
451 */
452	_MFC0	ta0, MIPS_COP_0_EXC_PC		# grab exception PC
453	PTR_L	s2, L_CPU(MIPS_CURLWP)		# delay slot
454	REG_S	ta0, TF_BASE+TF_REG_EPC(sp)	# and save it
455
456#if defined(DDB) || defined(DEBUG) || defined(KGDB)
457	REG_S	ta0, KERNFRAME_RA(sp)		# for debugging
458#endif
459
460#ifdef PARANOIA
461	INT_L	s0, CPU_INFO_CPL(s2)
462	nop					# load delay
463	INT_S	s0, TF_BASE+TF_PPL(sp)		# save priority level
464
465	/*
466	 * Verify the current interrupt level
467	 */
468	jal	_C_LABEL(splcheck)
469	 nop
470#endif /* PARANOIA */
471
472	/*
473	 * We first need to get to IPL_HIGH so that interrupts are masked.
474	 */
475	jal	_C_LABEL(splhigh_noprof)
476	 nop
477
478#ifdef PARANOIA
4791:	bne	s0, v0, 1b
480	 nop
481#endif /* PARANOIA */
482
483	sll	s0, v0, 8			# remember previous priority
484						# low 8 bits used for idepth
485
486#ifdef PARANOIA
487	/*
488	 * Interrupts at IPL_HIGH are not allowed.
489	 */
490	li	v1, IPL_HIGH
491	sltu	t0, v0, v1
4922:	beqz	t0, 2b
493	 nop
494#endif /* PARANOIA */
495
496	INT_L	t1, CPU_INFO_IDEPTH(s2)		# we need to inc. intr depth
497	nop					# load delay
498	or	s0, t1				#   save old interrupt depth
499	INT_ADDU t1, 1
500	INT_S	t1, CPU_INFO_IDEPTH(s2)		#   store new interrupt depth
501
502	/*
503	 * Now that we're at splhigh so all interrupts are masked
504	 * individually and we won't get interrupted here, turn the
505	 * global interrupt enable bit on again. This will allow
506	 * high-priority interrupts to be delivered once a
507	 * low-priority interrupt handler lowers spl to execute.
508	 */
509	mfc0	v1, MIPS_COP_0_STATUS
510	nop
511	or	v0, v1, MIPS_SR_INT_IE
512	mtc0	v0, MIPS_COP_0_STATUS		# write new status
513
514	/*
515	 * Now hard interrupts can be processed.
516	 */
517	move	a1, ta0				# 2nd arg is exception PC
518	move	a2, s1				# 3rd arg is status
519	jal	_C_LABEL(cpu_intr)		# cpu_intr(ppl, pc, status)
520	 srl	a0, s0, 8			# 1st arg is previous pri level
521
522	and	t1, s0, 0xff			# get previous interrupt depth
523	INT_S	t1, CPU_INFO_IDEPTH(s2)		# to it previous value
524
525#ifdef PARANOIA
526	mfc0	t0, MIPS_COP_0_STATUS		# verify INT_IE is still set
527	nop
528	and	t0, MIPS_SR_INT_IE
5293:	beqz	t0, 3b
530	 nop
531#endif /* PARANOIA */
532
533#ifdef __HAVE_FAST_SOFTINTS
534	and	a0, s1, MIPS_SOFT_INT_MASK	# were softints enabled?
535	beqz	a0, 4f				#   nope
536	 nop
537	mfc0	v0, MIPS_COP_0_CAUSE		# grab the pending softints
538	nop
539	and	a0, v0				# are softints pending
540	beqz	a0, 4f				#   nope
541	 nop
542
543	jal	_C_LABEL(softint_process)	# softint_process(pending)
544	 nop
545
546#ifdef __HAVE_PREEMPTION
547	srl	v1, s0, 8			# get saved priority level
548	bnez	v1, 4f				# branch if not at IPL_NONE
549	 nop
550	INT_L	t0, CPU_INFO_SOFTINTS(s2)	# get pending softints
551	nop
552	and	v0, t0, 1 << SOFTINT_KPREEMPT	# do we need a kernel preempt?
553	beqz	v0, 4f				#   nope
554	 nop
555	xor	t0, v0				# clear preempt bit
556	INT_S	t0, CPU_INFO_SOFTINTS(s2)	# and save it.
557	jal	_C_LABEL(kpreempt)		# kpreempt(pc)
558	 PTR_L	a0, TF_BASE+TF_REG_EPC(sp)
559#endif /* __HAVE_PREEMPTION */
5604:
561#endif /* __HAVE_FAST_SOFTINTS */
562	/*
563	 * Interrupts handled, restore registers and return from the interrupt.
564	 * First, clear interrupt enable
565	 */
566	mtc0	s1, MIPS_COP_0_STATUS		# disable interrupts
567
568	srl	a0, s0, 8			# get previous priority level
569#ifdef PARANOIA
570	INT_L	t0, TF_BASE+TF_PPL(sp)		# get saved priority level
571	nop
5729:	bne	t0, a0, 9b			# should still match
573	 nop
574
575	li	t0, IPL_HIGH
576	sltu	v0, a0, t0
5778:	beqz	v0, 8b
578	 nop
579#endif /* PARANOIA */
580
581	/*
582	 * Restore IPL knowing interrupts are disabled
583	 */
584	jal	_C_LABEL(splx_noprof)		# splx(ppl)
585	 nop
586
587#ifdef PARANOIA
588	mfc0	v0, MIPS_COP_0_STATUS
589	nop
590	or	v0, MIPS_SR_INT_IE
5915:	bne	v0, s1, 5b
592	 nop
593#endif /* PARANOIA */
594
595	/*
596	 * Restore SR
597	 */
598	mtc0	s1, MIPS_COP_0_STATUS
599
600	/*
601	 * Restore s0-s2 and goto common kernel return code.
602	 */
603	REG_L	s0, TF_BASE+TF_REG_S0(sp)
604	REG_L	s1, TF_BASE+TF_REG_S1(sp)
605	b	MIPSX(kern_return)
606	 REG_L	s2, TF_BASE+TF_REG_S2(sp)
607	.set	at
608END(MIPSX(kern_intr))
609
610/*
611 * mipsN_user_gen_exception
612 *
613 * Handle an exception during user mode.
614 * Save user context atop the kernel stack, then call trap() to process
615 * the condition.  The context can be manipulated alternatively via
616 * curlwp->l_md.md_regs.
617 */
618NESTED_NOPROFILE(MIPSX(user_gen_exception), CALLFRAME_SIZ, ra)
619	.set	noat
620	.mask	0x80000000, -4
621	/*
622	 * Save all the registers except the kernel temporaries onto the stack.
623	 */
624	PTR_L	k1, CPUVAR(CURLWP)
625	nop
626	PTR_L	k0, L_PCB(k1)
627	nop
628	PTR_ADDU k0, USPACE - TF_SIZ - CALLFRAME_SIZ
629	REG_S	AT, CALLFRAME_SIZ+TF_REG_AST(k0)
630	REG_S	v0, CALLFRAME_SIZ+TF_REG_V0(k0)
631	REG_S	v1, CALLFRAME_SIZ+TF_REG_V1(k0)
632	mflo	v0
633	REG_S	a0, CALLFRAME_SIZ+TF_REG_A0(k0)
634	REG_S	a1, CALLFRAME_SIZ+TF_REG_A1(k0)
635	REG_S	a2, CALLFRAME_SIZ+TF_REG_A2(k0)
636	REG_S	a3, CALLFRAME_SIZ+TF_REG_A3(k0)
637	mfhi	v1
638	REG_S	t0, CALLFRAME_SIZ+TF_REG_T0(k0)
639	REG_S	t1, CALLFRAME_SIZ+TF_REG_T1(k0)
640	REG_S	t2, CALLFRAME_SIZ+TF_REG_T2(k0)
641	REG_S	t3, CALLFRAME_SIZ+TF_REG_T3(k0)
642	mfc0	a0, MIPS_COP_0_STATUS		# 1st arg is STATUS
643	REG_S	ta0, CALLFRAME_SIZ+TF_REG_TA0(k0)
644	REG_S	ta1, CALLFRAME_SIZ+TF_REG_TA1(k0)
645	REG_S	ta2, CALLFRAME_SIZ+TF_REG_TA2(k0)
646	REG_S	ta3, CALLFRAME_SIZ+TF_REG_TA3(k0)
647	mfc0	a1, MIPS_COP_0_CAUSE		# 2nd arg is CAUSE
648	REG_S	s0, CALLFRAME_SIZ+TF_REG_S0(k0)
649	REG_S	s1, CALLFRAME_SIZ+TF_REG_S1(k0)
650	REG_S	s2, CALLFRAME_SIZ+TF_REG_S2(k0)
651	REG_S	s3, CALLFRAME_SIZ+TF_REG_S3(k0)
652	_MFC0	a2, MIPS_COP_0_BAD_VADDR	# 3rd arg is fault address
653	REG_S	s4, CALLFRAME_SIZ+TF_REG_S4(k0)
654	REG_S	s5, CALLFRAME_SIZ+TF_REG_S5(k0)
655	REG_S	s6, CALLFRAME_SIZ+TF_REG_S6(k0)
656	REG_S	s7, CALLFRAME_SIZ+TF_REG_S7(k0)
657	_MFC0	a3, MIPS_COP_0_EXC_PC		# 4th arg is exception PC
658	REG_S	t8, CALLFRAME_SIZ+TF_REG_T8(k0)	# will be MIPS_CURLWP
659	REG_S	t9, CALLFRAME_SIZ+TF_REG_T9(k0)
660	REG_S	gp, CALLFRAME_SIZ+TF_REG_GP(k0)
661	REG_S	sp, CALLFRAME_SIZ+TF_REG_SP(k0)
662	REG_S	s8, CALLFRAME_SIZ+TF_REG_S8(k0)
663	REG_S	ra, CALLFRAME_SIZ+TF_REG_RA(k0)
664	REG_S	a0, CALLFRAME_SIZ+TF_REG_SR(k0)
665	REG_S	v0, CALLFRAME_SIZ+TF_REG_MULLO(k0)
666	REG_S	v1, CALLFRAME_SIZ+TF_REG_MULHI(k0)
667	REG_S	a3, CALLFRAME_SIZ+TF_REG_EPC(k0)
668#ifdef __GP_SUPPORT__
669	PTR_LA	gp, _C_LABEL(_gp)		# switch to kernel GP
670#endif
671	move	sp, k0				# switch to kernel SP
672	move	MIPS_CURLWP, k1
673#ifndef NOFPU
674	lui	t0, %hi(MIPS_SR_COP_1_BIT)
675	and	t0, a0
676	beqz	t0, 1f
677	 xor	t0, a0				# turn off the FPU
678	mtc0	t0, MIPS_COP_0_STATUS
679	 nop
6801:
681#endif
682/*
683 * Call the trap handler.
684 */
685	jal	_C_LABEL(trap)
686	 REG_S	a3, CALLFRAME_RA(sp)		# for debugging
687/*
688 * Check pending asynchronous traps.
689 */
690	INT_L	v0, L_MD_ASTPENDING(MIPS_CURLWP)# any pending ast?
691	nop
692	beqz	v0, MIPSX(user_return)		# if no, skip ast processing
693	 nop
694/*
695 * We have pending asynchronous traps; all the state is already saved.
696 */
697	lui	ra, %hi(MIPSX(user_return))	# return directly to user return
698	j	_C_LABEL(ast)
699	 PTR_ADDIU ra, %lo(MIPSX(user_return))	# return directly to user return
700	.set	at
701END(MIPSX(user_gen_exception))
702
703/*----------------------------------------------------------------------------
704 *
705 * mipsN_user_intr
706 *
707 *	Handle an interrupt from user mode.
708 *	We save partial state onto the kernel stack since we know there will
709 *	always a kernel stack and chances are we won't need the registers we
710 *	don't save.  If there is a pending asynchronous system trap, then save
711 *	the remaining state and call ast().
712 *
713 * Results:
714 * 	None.
715 *
716 * Side effects:
717 *	None.
718 *
719 *----------------------------------------------------------------------------
720 */
721NESTED_NOPROFILE(MIPSX(user_intr), CALLFRAME_SIZ, ra)
722	.set	noat
723	.mask	0x80000000, -4
724/*
725 * Save the relevant user registers onto the kernel stack.
726 * We don't need to save s0 - s8 because the compiler does it for us.
727 */
728	PTR_L	k1, CPUVAR(CURLWP)
729	nop
730	PTR_L	k0, L_PCB(k1)				# XXXuvm_lwp_getuarea
731	nop
732	PTR_ADDU k0, USPACE - TF_SIZ - CALLFRAME_SIZ
733	REG_S	AT, CALLFRAME_SIZ+TF_REG_AST(k0)	# $1
734	REG_S	v0, CALLFRAME_SIZ+TF_REG_V0(k0)		# $2
735	REG_S	v1, CALLFRAME_SIZ+TF_REG_V1(k0)		# $3
736	mflo	v0
737	REG_S	a0, CALLFRAME_SIZ+TF_REG_A0(k0)		# $4
738	REG_S	a1, CALLFRAME_SIZ+TF_REG_A1(k0)		# $5
739	REG_S	a2, CALLFRAME_SIZ+TF_REG_A2(k0)		# $6
740	REG_S	a3, CALLFRAME_SIZ+TF_REG_A3(k0)		# $7
741	mfhi	v1
742	REG_S	t0, CALLFRAME_SIZ+TF_REG_T0(k0)		# $8
743	REG_S	t1, CALLFRAME_SIZ+TF_REG_T1(k0)		# $9
744	REG_S	t2, CALLFRAME_SIZ+TF_REG_T2(k0)		# $10
745	REG_S	t3, CALLFRAME_SIZ+TF_REG_T3(k0)		# $11
746	mfc0	t0, MIPS_COP_0_CAUSE
747	REG_S	ta0, CALLFRAME_SIZ+TF_REG_TA0(k0)	# $12
748	REG_S	ta1, CALLFRAME_SIZ+TF_REG_TA1(k0)	# $13
749	REG_S	ta2, CALLFRAME_SIZ+TF_REG_TA2(k0)	# $14
750	REG_S	ta3, CALLFRAME_SIZ+TF_REG_TA3(k0)	# $15
751	REG_S	s0, CALLFRAME_SIZ+TF_REG_S0(k0)		# $16
752	REG_S	s1, CALLFRAME_SIZ+TF_REG_S1(k0)		# $17
753	mfc0	s1, MIPS_COP_0_STATUS
754	REG_S	t8, CALLFRAME_SIZ+TF_REG_T8(k0)		# $24 MIPS_CURLWP
755	REG_S	t9, CALLFRAME_SIZ+TF_REG_T9(k0)		# $25
756	REG_S	gp, CALLFRAME_SIZ+TF_REG_GP(k0)		# $28
757	REG_S	sp, CALLFRAME_SIZ+TF_REG_SP(k0)		# $29
758	REG_S	ra, CALLFRAME_SIZ+TF_REG_RA(k0)		# $31
759	REG_S	s1, CALLFRAME_SIZ+TF_REG_SR(k0)
760	_MFC0	ta0, MIPS_COP_0_EXC_PC
761	REG_S	v0, CALLFRAME_SIZ+TF_REG_MULLO(k0)
762	REG_S	v1, CALLFRAME_SIZ+TF_REG_MULHI(k0)
763	REG_S	ta0, CALLFRAME_SIZ+TF_REG_EPC(k0)
764	REG_S	t0, CALLFRAME_SIZ+TF_REG_CAUSE(k0)
765	move	sp, k0				# switch to kernel SP
766	move	MIPS_CURLWP, k1			# set curlwp reg (t8)
767#if defined(DDB) || defined(DEBUG) || defined(KGDB)
768	REG_S	ta0, CALLFRAME_RA(sp)		# for debugging
769#endif
770#ifdef __GP_SUPPORT__
771	PTR_LA	gp, _C_LABEL(_gp)		# switch to kernel GP
772#endif
773
774	/*
775	 * We first need to get to IPL_HIGH so that interrupts are masked.
776	 */
777	jal	_C_LABEL(splhigh_noprof)	# splhigh()
778	 nop
779	move	s0, v0				# remember previous priority
780
781	/*
782	 * Now that we're at splhigh so all interrupts are masked
783	 * individually and we won't get interrupted here, turn the
784	 * global interrupt enable bit on again. This will allow
785	 * high-priority interrupts to be delivered once a
786	 * low-priority interrupt handler lowers spl to execute.
787	 *
788	 * Also switch off the FPU.
789	 */
790	mfc0	v1, MIPS_COP_0_STATUS
791#ifndef NOFPU
792	lui	v0, %hi(MIPS_SR_COP_1_BIT)
793	and	v0, v1
794	or	v0, MIPS_SR_INT_IE		# make sure intrs are still on
795#else
796	li	v0, MIPS_SR_INT_IE		# reenable intrs
797#endif
798	xor	v0, v1
799	mtc0	v0, MIPS_COP_0_STATUS
800	nop
801
802	/*
803	 * Since we interrupted user mode, the new interrupt depth must be 1.
804	 */
805	PTR_L	t0, L_CPU(MIPS_CURLWP)
806	li	t1, 1
807	INT_S	t1, CPU_INFO_IDEPTH(t0)		# store new interrupt depth (1)
808
809	/*
810	 * Now hard interrupts can be processed.
811	 */
812	move	a1, ta0				# 2nd arg is exception pc
813	move	a2, s1				# 3rd arg is status
814	jal	_C_LABEL(cpu_intr)		# cpu_intr(ppl, pc, status)
815	 move	a0, s0				# 1st arg is previous pri level
816
817	/*
818	 * Interrupt depth is now back to 0.
819	 */
820	PTR_L	t0, L_CPU(MIPS_CURLWP)
821	nop
822	INT_S	zero, CPU_INFO_IDEPTH(t0)
823
824#ifdef __HAVE_FAST_SOFTINTS
825	/*
826	 * This an interrupt from user mode so both softints must be enabled.
827	 * No need to check (unless we're being paranoid).
828	 */
829#ifdef PARANOIA
830	and	a0, s1, MIPS_SOFT_INT_MASK	# get softints enabled bits
831	xor	a0, MIPS_SOFT_INT_MASK		# invert them.
8321:	bnez	a0, 1b				# loop forever if disabled
833	 nop
834#endif
835	mfc0	a0, MIPS_COP_0_CAUSE		# grab the pending softints
836	nop					# load delay
837	and	a0, MIPS_SOFT_INT_MASK		# are there softints pending
838	beqz	a0, 4f				#   nope
839	 nop
840	jal	_C_LABEL(softint_process)	# softint_process(pending)
841	 nop
8424:
843#endif
844	/*
845	 * Disable interrupts
846	 */
847	mfc0	v1, MIPS_COP_0_STATUS
848	nop					# delay slot
849	and	v0, v1, MIPS_SR_INT_IE		# clear interrupt enable
850	xor	v0, v1
851	mtc0	v0, MIPS_COP_0_STATUS		# interrupts are disabled
852
853	/*
854	 * Restore IPL knowing interrupts are off
855	 */
856	jal	_C_LABEL(splx_noprof)
857	 move	a0, s0				# fetch previous priority level
858
859	/*
860	 * Check pending asynchronous traps.
861	 */
862	REG_L	s0, CALLFRAME_SIZ+TF_REG_S0(sp)	# restore
863	REG_L	s1, CALLFRAME_SIZ+TF_REG_S1(sp)	# restore
864	INT_L	v0, L_MD_ASTPENDING(MIPS_CURLWP)# any pending ast?
865	nop
866	beqz	v0, MIPSX(user_intr_return)	# if no, skip ast processing
867	 nop
868
869	/*
870	 * We have a pending asynchronous trap; save remaining user state into
871	 * trapframe.
872	 */
873	#REG_S	s0, CALLFRAME_SIZ+TF_REG_S0(sp)	# $16 (saved above)
874	#REG_S	s1, CALLFRAME_SIZ+TF_REG_S1(sp)	# $17 (saved above)
875	REG_S	s2, CALLFRAME_SIZ+TF_REG_S2(sp)	# $18
876	REG_S	s3, CALLFRAME_SIZ+TF_REG_S3(sp)	# $19
877	REG_S	s4, CALLFRAME_SIZ+TF_REG_S4(sp)	# $20
878	REG_S	s5, CALLFRAME_SIZ+TF_REG_S5(sp)	# $21
879	REG_S	s6, CALLFRAME_SIZ+TF_REG_S6(sp)	# $22
880	REG_S	s7, CALLFRAME_SIZ+TF_REG_S7(sp)	# $23
881	REG_S	s8, CALLFRAME_SIZ+TF_REG_S8(sp)	# $30
882
883	mfc0	t0, MIPS_COP_0_STATUS
884	PTR_LA	ra, MIPSX(user_return)		# load delay
885	or	t0, MIPS_SR_INT_IE		# enable interrupts
886	j	_C_LABEL(ast)			# ast()
887	 mtc0	t0, MIPS_COP_0_STATUS		# enable interrupts (spl0)
888	.set	at
889END(MIPSX(user_intr))
890
891/*
892 * mipsN_systemcall
893 *
894 * Save user context atop of kernel stack, then call syscall() to process
895 * a system call.  The context can be manipulated alternatively via
896 * curlwp->l_md.md_utf->tf_regs.
897 */
898NESTED_NOPROFILE(MIPSX(systemcall), CALLFRAME_SIZ, ra)
899	.set	noat
900	.mask	0x80000000, -4
901	/*
902	 * Save all the registers but kernel temporaries onto the stack.
903	 */
904	PTR_L	k1, CPUVAR(CURLWP)
905	nop
906	PTR_L	k0, L_PCB(k1)
907	nop
908	PTR_ADDU k0, USPACE - TF_SIZ - CALLFRAME_SIZ
909	#REG_S	AT, CALLFRAME_SIZ+TF_REG_AST(k0)
910	#.set	at
911	REG_S	v0, CALLFRAME_SIZ+TF_REG_V0(k0)		# syscall #
912	REG_S	v1, CALLFRAME_SIZ+TF_REG_V1(k0)		# used by syscall()
913	mflo	v0
914	REG_S	a0, CALLFRAME_SIZ+TF_REG_A0(k0)
915	REG_S	a1, CALLFRAME_SIZ+TF_REG_A1(k0)
916	REG_S	a2, CALLFRAME_SIZ+TF_REG_A2(k0)
917	REG_S	a3, CALLFRAME_SIZ+TF_REG_A3(k0)
918	move	a0, k1					# 1st arg is curlwp
919	mfhi	v1
920	mfc0	a1, MIPS_COP_0_STATUS			# 2nd arg is STATUS
921	REG_S	s0, CALLFRAME_SIZ+TF_REG_S0(k0)
922	REG_S	s1, CALLFRAME_SIZ+TF_REG_S1(k0)
923	REG_S	s2, CALLFRAME_SIZ+TF_REG_S2(k0)
924	REG_S	s3, CALLFRAME_SIZ+TF_REG_S3(k0)
925	mfc0	a2, MIPS_COP_0_CAUSE			# 3rd arg is CAUSE
926	REG_S	s4, CALLFRAME_SIZ+TF_REG_S4(k0)
927	REG_S	s5, CALLFRAME_SIZ+TF_REG_S5(k0)
928	REG_S	s6, CALLFRAME_SIZ+TF_REG_S6(k0)
929	REG_S	s7, CALLFRAME_SIZ+TF_REG_S7(k0)
930	_MFC0	a3, MIPS_COP_0_EXC_PC			# 4th arg is PC
931	REG_S	t0, CALLFRAME_SIZ+TF_REG_T0(k0)
932	REG_S	t1, CALLFRAME_SIZ+TF_REG_T1(k0)
933	REG_S	t2, CALLFRAME_SIZ+TF_REG_T2(k0)
934	REG_S	t3, CALLFRAME_SIZ+TF_REG_T3(k0)		# syscall saved gp for fork
935	REG_S	ta0, CALLFRAME_SIZ+TF_REG_TA0(k0)
936	REG_S	ta1, CALLFRAME_SIZ+TF_REG_TA1(k0)
937	REG_S	ta2, CALLFRAME_SIZ+TF_REG_TA2(k0)
938	REG_S	ta3, CALLFRAME_SIZ+TF_REG_TA3(k0)
939	REG_S	t8, CALLFRAME_SIZ+TF_REG_T8(k0)		# will be MIPS_CURLWP
940	REG_S	t9, CALLFRAME_SIZ+TF_REG_T9(k0)
941	REG_S	gp, CALLFRAME_SIZ+TF_REG_GP(k0)
942	REG_S	sp, CALLFRAME_SIZ+TF_REG_SP(k0)
943	REG_S	s8, CALLFRAME_SIZ+TF_REG_S8(k0)
944	REG_S	ra, CALLFRAME_SIZ+TF_REG_RA(k0)
945	REG_S	a1, CALLFRAME_SIZ+TF_REG_SR(k0)
946	REG_S	v0, CALLFRAME_SIZ+TF_REG_MULLO(k0)
947	REG_S	v1, CALLFRAME_SIZ+TF_REG_MULHI(k0)
948	REG_S	a3, CALLFRAME_SIZ+TF_REG_EPC(k0)
949	PTR_L	t0, L_PROC(a0)			# curlwp->l_proc (used below)
950	move	sp, k0				# switch to kernel SP
951	move	MIPS_CURLWP, a0			# set curlwp reg
952#ifdef __GP_SUPPORT__
953	PTR_LA	gp, _C_LABEL(_gp)		# switch to kernel GP
954#endif
955#if defined(DDB) || defined(DEBUG) || defined(KGDB)
956	move	ra, a3
957	REG_S	ra, CALLFRAME_RA(sp)
958#endif
959	PTR_L	t9, P_MD_SYSCALL(t0)		# t9 = syscall
960	/*
961	 * Turn off FPU
962	 */
963#ifdef NOFPU
964	li	t0, MIPS_SR_INT_IE
965#else
966	lui	t0, %hi(MIPS_SR_COP_1_BIT)
967	and	t0, a1
968	ori	t0, MIPS_SR_INT_IE		# turn on IEc, enable intr.
969#endif
970	xor	t0, a1				# turns off the FPU & ints on
971	mtc0	t0, MIPS_COP_0_STATUS		# re-enable interrupts
972/*
973 * Call the system call handler.
974 */
975	jalr	t9
976	 nop
977/*
978 * Check pending asynchronous traps.
979 */
980	INT_L	v0, L_MD_ASTPENDING(MIPS_CURLWP)# any pending ast?
981	nop
982	beqz	v0, MIPSX(user_return)		# no, skip ast processing
983	 nop
984/*
985 * We have pending asynchronous traps; all the state is already saved.
986 */
987	lui	ra, %hi(MIPSX(user_return))	# return directly to user return
988	j	_C_LABEL(ast)
989	 PTR_ADDIU ra, %lo(MIPSX(user_return))	# return directly to user return
990	.set	at
991END(MIPSX(systemcall))
992
993/*----------------------------------------------------------------------------
994 *
995 *	R3000 TLB exception handlers
996 *
997 *----------------------------------------------------------------------------
998 */
999
1000/*----------------------------------------------------------------------------
1001 *
1002 * mipsN_kern_tlb_miss --
1003 *
1004 *	Handle a TLB miss exception from kernel mode in kernel space.
1005 *	The BaddVAddr, Context, and EntryHi registers contain the failed
1006 *	virtual address.
1007 *
1008 * Results:
1009 *	None.
1010 *
1011 * Side effects:
1012 *	None.
1013 *
1014 *----------------------------------------------------------------------------
1015 */
1016LEAF_NOPROFILE(MIPSX(kern_tlb_miss))
1017	.set	noat
1018	_MFC0	k0, MIPS_COP_0_BAD_VADDR	# get the fault address
1019	PTR_LA	k1, _C_LABEL(pmap_kern_segtab)	# get address of kernel segtab
1020	PTR_SRL	k0, SEGSHIFT - PTR_SCALESHIFT	# get segtab index (part1)
1021	and	k0, (NSEGPG-1) << PTR_SCALESHIFT # get segtab index (part2)
1022	PTR_ADDU k1, k0				# add index to segtab addr
1023	PTR_L	k1, 0(k1)			# load address of PTP
1024	_MFC0	k0, MIPS_COP_0_BAD_VADDR	# get the fault address
1025	/*
1026	 * If there isn't a PTP for this, let trap panic for us.
1027	 */
1028	beqz	k1, _C_LABEL(MIPSX(kern_gen_exception))	# full trap processing
1029	 PTR_SRL k0, PGSHIFT - PTPSHIFT		# - delay slot -
1030	and	k0, (NPTEPG-1) << PTPSHIFT	# get ptp index (part2)
1031	PTR_ADDU k1, k0				# add to PTP address
1032	INT_L	k0, 0(k1)			# get PTE entry
1033	_MFC0	k1, MIPS_COP_0_EXC_PC		# get return address
1034	mtc0	k0, MIPS_COP_0_TLB_LOW		# save PTE entry
1035	and	k0, MIPS1_PG_V			# check for valid PTE entry
1036	beqz	k0, _C_LABEL(MIPSX(kern_gen_exception)) # PTE invalid
1037	 nop
1038	tlbwr					# write random TLB
1039	j	k1
1040	 rfe
1041	.set	at
1042END(MIPSX(kern_tlb_miss))
1043
1044#if 0
1045/*----------------------------------------------------------------------------
1046 *
1047 * mipsN_tlb_invalid_exception --
1048 *
1049 *	Handle a TLB modified exception.
1050 *	The BaddVAddr, Context, and EntryHi registers contain the failed
1051 *	virtual address.
1052 *
1053 * Results:
1054 *	None.
1055 *
1056 * Side effects:
1057 *	None.
1058 *
1059 *----------------------------------------------------------------------------
1060 */
1061LEAF_NOPROFILE(MIPSX(tlb_mod_exception))
1062	.set	noat
1063	tlbp					# find the TLB entry
1064	mfc0	k0, MIPS_COP_0_TLB_LOW		# get the physical address
1065	mfc0	k1, MIPS_COP_0_TLB_INDEX	# check to be sure its valid
1066	or	k0, k0, MIPS1_TLB_DIRTY_BIT	# update TLB
1067	blt	k1, zero, 4f			# not found!!!
1068	mtc0	k0, MIPS_COP_0_TLB_LOW
1069	li	k1, MIPS_KSEG0_START
1070	PTR_SUBU k0, k1
1071	srl	k0, k0, MIPS1_TLB_PHYS_PAGE_SHIFT
1072	PTR_L	k1, pmap_attributes		# DANGER!  DANGER!
1073	PTR_ADDU k0, k1
1074	lbu	k1, 0(k0)			# fetch old value
1075	nop
1076	or	k1, k1, 1			# set modified bit
1077	sb	k1, 0(k0)			# save new value
1078	_MFC0	k0, MIPS_COP_0_EXC_PC		# get return address
1079	nop
1080	j	k0
1081	rfe
10824:
1083	break	0				# panic
1084	.set	at
1085END(MIPSX(tlb_mod_exception))
1086#endif
1087
1088/*
1089 * Mark where code entered from exception handler jumptable
1090 * ends, for stack traceback code.
1091 */
1092
1093	.globl	_C_LABEL(MIPSX(exceptionentry_end))
1094_C_LABEL(MIPSX(exceptionentry_end)):
1095
1096/*--------------------------------------------------------------------------
1097 *
1098 * mipsN_tlb_get_asid --
1099 *
1100 *	Return the pid from the TLB pid reg.
1101 *
1102 *	tlb_asid_t mipsN_tlb_get_asid(void)
1103 *
1104 * Results:
1105 *	The current ASID.
1106 *
1107 * Side effects:
1108 *	None.
1109 *
1110 *--------------------------------------------------------------------------
1111 */
1112LEAF(MIPSX(tlb_get_asid))
1113	mfc0	v0, MIPS_COP_0_TLB_HI		# Read the hi reg value
1114	nop
1115	and	v0, MIPS1_TLB_PID		# mask out only the PID
1116	j	ra
1117	 srl	v0, MIPS1_TLB_PID_SHIFT		# put PID in right spot
1118END(MIPSX(tlb_get_asid))
1119
1120/*--------------------------------------------------------------------------
1121 *
1122 * mipsN_tlb_set_asid --
1123 *
1124 *	Write the given pid into the TLB pid reg.
1125 *
1126 *	void mipsN_tlb_set_asid(tlb_asid_t pid)
1127 *
1128 * Results:
1129 *	None.
1130 *
1131 * Side effects:
1132 *	PID set in the entry hi register.
1133 *
1134 *--------------------------------------------------------------------------
1135 */
1136LEAF(MIPSX(tlb_set_asid))
1137	sll	a0, MIPS1_TLB_PID_SHIFT		# put PID in right spot
1138	and	a0, MIPS1_TLB_PID
1139	mtc0	a0, MIPS_COP_0_TLB_HI		# Write the hi reg value
1140	j	ra
1141	nop
1142END(MIPSX(tlb_set_asid))
1143
1144/*--------------------------------------------------------------------------
1145 *
1146 * mipsN_tlb_update_addr --
1147 *
1148 *	Update the TLB if highreg is found; otherwise, do_nothing
1149 *
1150 *	bool mipsN_tlb_update_addr(vaddr_t va, tlb_asid_t asid,
1151 *	    pt_entry_t pte, bool insert);
1152 *
1153 * Results:
1154 *	0 if skipped, 1 if updated
1155 *
1156 * Side effects:
1157 *	None.
1158 *
1159 *--------------------------------------------------------------------------
1160 */
1161LEAF(MIPSX(tlb_update_addr))
1162	mfc0	ta0, MIPS_COP_0_STATUS		# save the status register
1163	mtc0	zero, MIPS_COP_0_STATUS		# disable interrupts
1164	nop
1165	mfc0	ta1, MIPS_COP_0_TLB_HI		# save current PID
1166	nop
1167	sll	a1, MIPS1_TLB_PID_SHIFT
1168	or	a0, a1
1169	mtc0	a0, MIPS_COP_0_TLB_HI		# set entryhi
1170	nop
1171	tlbp					# probe the existence
1172	mfc0	v0, MIPS_COP_0_TLB_INDEX	# see what we got
1173	mtc0	a2, MIPS_COP_0_TLB_LOW		# set new entrylo
1174	bltz	v0, 2f				# index < 0 => !found
1175	 nop
1176	tlbwi					# update slot found
1177	b	3f				# return
1178	 li	v0, 1				#   and show success
11792:
1180	beqz	a2, 3f				# return
1181	 li	v0, 0				#   and show failure
1182	tlbwr					# put it in a new slot
1183	li	v0, 1				# show success
11843:
1185	mtc0	ta1, MIPS_COP_0_TLB_HI		# restore current PID
1186	j	ra
1187	 mtc0	ta0, MIPS_COP_0_STATUS		# restore interrupts
1188END(MIPSX(tlb_update_addr))
1189
1190/*--------------------------------------------------------------------------
1191 *
1192 * mipsN_tlb_read_entry --
1193 *
1194 *	Read the TLB entry.
1195 *
1196 *	void mipsN_tlb_read_entry(register_t entry, struct tlbmask *tlb)
1197 *
1198 * Results:
1199 *	tlb will contain the TLB entry found (tlb_lo1/tlb_mask will be 0).
1200 *
1201 *--------------------------------------------------------------------------
1202 */
1203LEAF(MIPSX(tlb_read_entry))
1204	mfc0	ta0, MIPS_COP_0_STATUS		# Save the status register.
1205	mtc0	zero, MIPS_COP_0_STATUS		# Disable interrupts
1206	mfc0	ta1, MIPS_COP_0_TLB_HI		# Get current PID
1207
1208	sll	a0, MIPS1_TLB_INDEX_SHIFT
1209	mtc0	a0, MIPS_COP_0_TLB_INDEX	# Set the index register
1210	nop
1211	tlbr					# Read from the TLB
1212	mfc0	t2, MIPS_COP_0_TLB_HI		# fetch the hi entry
1213	mfc0	t3, MIPS_COP_0_TLB_LOW		# fetch the low entry
1214
1215	mtc0	ta1, MIPS_COP_0_TLB_HI		# Restore proper PID
1216						# (before touching memory)
1217	mtc0	ta0, MIPS_COP_0_STATUS		# Restore the status register
1218
1219	PTR_S	t2, TLBMASK_HI(a1)
1220	REG_S	t3, TLBMASK_LO0(a1)
1221	REG_S	zero, TLBMASK_LO1(a1)
1222	j	ra
1223	 INT_S	zero, TLBMASK_MASK(a1)
1224END(MIPSX(tlb_read_entry))
1225
1226/*--------------------------------------------------------------------------
1227 *
1228 * mipsX_tlb_write_entry --
1229 *
1230 *	Write the TLB entry.
1231 *
1232 *	void mipsX_tlb_write_entry(size_t entry, struct tlbmask *tlb)
1233 *
1234 * Results:
1235 *	None.
1236 *
1237 *--------------------------------------------------------------------------
1238 */
1239LEAF(MIPSX(tlb_write_entry))
1240	PTR_L	t2, TLBMASK_HI(a1)		# fetch the hi entry
1241	INT_L	t3, TLBMASK_LO0(a1)		# fetch the low entry
1242	mfc0	ta0, MIPS_COP_0_STATUS		# Save the status register.
1243	mtc0	zero, MIPS_COP_0_STATUS		# Disable interrupts
1244	mfc0	ta1, MIPS_COP_0_TLB_HI		# Get current PID
1245
1246	sll	a0, MIPS1_TLB_INDEX_SHIFT
1247	mtc0	a0, MIPS_COP_0_TLB_INDEX	# Set the index register
1248	nop
1249	mtc0	t2, MIPS_COP_0_TLB_HI
1250	mtc0	t3, MIPS_COP_0_TLB_LOW
1251
1252	tlbwi					# Write to the TLB entry
1253
1254	mtc0	ta1, MIPS_COP_0_TLB_HI		# restore PID
1255	j	ra
1256	 mtc0	ta0, MIPS_COP_0_STATUS		# Restore the status register
1257END(MIPSX(tlb_write_entry))
1258
1259/*
1260 * void mipsN_tlb_invalidate_addr(vaddr_t va, tlb_asid_t asid)
1261 *
1262 * Invalidate a TLB entry for given virtual address if found in TLB.
1263 */
1264LEAF(MIPSX(tlb_invalidate_addr))
1265	mfc0	ta0, MIPS_COP_0_STATUS		# save status register
1266	mtc0	zero, MIPS_COP_0_STATUS		# disable interrupts
1267	mfc0	ta1, MIPS_COP_0_TLB_HI		# save current PID
1268	nop
1269
1270	sll	a1, MIPS1_TLB_PID_SHIFT		# move ASID into position
1271	and	a1, MIPS1_TLB_PID		# make it off
1272	or	a0, a1				# merge with addr
1273	mtc0	a0, MIPS_COP_0_TLB_HI		# look for addr & PID
1274	nop
1275	tlbp					# probe the entry in question
1276	mfc0	a0, MIPS_COP_0_TLB_INDEX	# see what we got
1277	li	t1, MIPS_KSEG0_START		# load invalid address
1278	bltz	a0, 1f				# index < 0 then skip
1279	 nop
1280	mtc0	t1, MIPS_COP_0_TLB_HI		# make entryHi invalid
1281	mtc0	zero, MIPS_COP_0_TLB_LOW	# zero out entryLo
1282	nop
1283	tlbwi
12841:
1285	mtc0	ta1, MIPS_COP_0_TLB_HI		# restore PID
1286	j	ra
1287	 mtc0	ta0, MIPS_COP_0_STATUS		# restore the status register
1288END(MIPSX(tlb_invalidate_addr))
1289
1290/*
1291 * void mipsN_tlb_invalidate_asids(uint32_t asid_lo, uint32_t asid_hi)
1292 *
1293 * Invalidate TLB entries belonging to asids (asid_lo,asid_hi]
1294 * leaving entries for kernel space marked global intact.
1295 */
1296LEAF(MIPSX(tlb_invalidate_asids))
1297	mfc0	ta1, MIPS_COP_0_TLB_HI		# save EntryHi
1298	mfc0	ta0, MIPS_COP_0_STATUS		# save status register
1299	mtc0	zero, MIPS_COP_0_STATUS		# disable interrupts
1300
1301	INT_L	t2, _C_LABEL(mips_options) + MO_NUM_TLB_ENTRIES
1302	li	t1, MIPS1_TLB_FIRST_RAND_ENTRY << MIPS1_TLB_INDEX_SHIFT
1303	li	v0, MIPS_KSEG0_START		# invalid address
1304	sll	t2, MIPS1_TLB_INDEX_SHIFT
1305
1306	# do {} while (t1 < t2)
13071:
1308	mtc0	t1, MIPS_COP_0_TLB_INDEX	# set index
1309	nop
1310	tlbr					# obtain an entry
1311	mfc0	t0, MIPS_COP_0_TLB_LOW
1312	nop
1313	and	t0, t0, MIPS1_PG_G		# check to see it has G bit
1314	bnez	t0, 2f
1315	 nop
1316
1317	mfc0	t0, MIPS_COP_0_TLB_HI		# get va and ASID
1318	nop
1319	and	t0, MIPS1_TLB_PID 		# mask off ASID
1320	srl	t0, MIPS1_TLB_PID_SHIFT
1321	sltu	v1, t0, a0			# < asid_lo
1322	bnez	v1, 2f				# yes, next tlb entry
1323	 nop
1324	sltu	v1, t0, a1			# < asid_hi
1325	beqz	v1, 2f				# no, next tlb entry
1326	 nop
1327
1328	mtc0	v0, MIPS_COP_0_TLB_HI		# make entryHi invalid
1329	mtc0	zero, MIPS_COP_0_TLB_LOW	# zero out entryLo
1330	nop
1331	tlbwi					# invalidate the TLB entry
13322:
1333	addu	t1, t1, 1 << MIPS1_TLB_INDEX_SHIFT	# increment index
1334	bne	t1, t2, 1b
1335	nop
1336
1337	mtc0	ta1, MIPS_COP_0_TLB_HI		# restore entryHi
1338
1339	j	ra				# new TLBpid will be set soon
1340	 mtc0	ta0, MIPS_COP_0_STATUS		# restore status register
1341END(MIPSX(tlb_invalidate_asids))
1342
1343/*
1344 * void mipsN_tlb_invalidate_all(void)
1345 *
1346 * Invalidate TLB entirely.
1347 */
1348LEAF(MIPSX(tlb_invalidate_all))
1349	INT_L	a0, _C_LABEL(mips_options) + MO_NUM_TLB_ENTRIES
1350
1351	mfc0	ta0, MIPS_COP_0_STATUS		# save the status register.
1352	mtc0	zero, MIPS_COP_0_STATUS		# disable interrupts
1353
1354	mfc0	ta1, MIPS_COP_0_TLB_HI		# save current PID
1355	li	t0, MIPS_KSEG0_START		# invalid address
1356	mtc0	t0, MIPS_COP_0_TLB_HI		# make entryHi invalid
1357	mtc0	zero, MIPS_COP_0_TLB_LOW	# zero out entryLo
1358
1359	move	t0, zero
1360	sll	a0, MIPS1_TLB_INDEX_SHIFT
1361
1362	# do {} while (t1 < a0)
13631:
1364	mtc0	t0, MIPS_COP_0_TLB_INDEX	# set TLBindex
1365	addu	t0, t0, 1 << MIPS1_TLB_INDEX_SHIFT	# increment index
1366	bne	t0, a0, 1b
1367	 tlbwi					# invalidate the entry
1368
1369	mtc0	ta1, MIPS_COP_0_TLB_HI		# restore PID
1370	j	ra
1371	 mtc0	ta0, MIPS_COP_0_STATUS		# restore status register
1372END(MIPSX(tlb_invalidate_all))
1373
1374/*
1375 * u_int mipsN_tlb_record_asids(u_long *bitmap, uint32_t asid_max)
1376 *
1377 * Scan the random part of the TLB looking at non-global entries and
1378 * record each ASID in use into the bitmap.  Additionally, return the
1379 * number of new unique ASIDs encountered.
1380 */
1381LEAF(MIPSX(tlb_record_asids))
1382	mfc0	ta1, MIPS_COP_0_TLB_HI		# save EntryHi
1383	li	v1, MIPS1_TLB_FIRST_RAND_ENTRY << MIPS1_TLB_INDEX_SHIFT
1384	INT_L	a3, _C_LABEL(mips_options) + MO_NUM_TLB_ENTRIES
1385	move	ta2, zero
1386	li	ta3, 1
1387	sll	a3, MIPS1_TLB_INDEX_SHIFT
1388
1389	mfc0	ta0, MIPS_COP_0_STATUS		# save status register
1390	mtc0	zero, MIPS_COP_0_STATUS		# disable interrupts
1391
1392	move	v0, zero			# start at zero ASIDs
1393
1394	# do {} while (v1 < ta1)
13951:
1396	mtc0	v1, MIPS_COP_0_TLB_INDEX	# set index
1397	nop
1398	tlbr					# obtain an entry
1399	mfc0	t0, MIPS_COP_0_TLB_LOW
1400	nop
1401	and	t0, MIPS1_PG_G			# check to see it has G bit
1402	bnez	t0, 4f
1403	 nop
1404
1405	mfc0	t0, MIPS_COP_0_TLB_HI		# get va and ASID
1406	nop
1407	and	t0, MIPS1_TLB_PID
1408	srl	t0, MIPS1_TLB_PID_SHIFT		# shift to low bits
1409	bgt	t0, a1, 4f			# > ASID max? skip
1410	 nop
1411
1412	srl	a2, t0, 3 + LONG_SCALESHIFT	# drop low 5 bits
1413	sll	a2, LONG_SCALESHIFT		# make an index for the bitmap
1414	sllv	t0, ta3, t0			# t0 is mask (ta3 == 1)
1415
1416	PTR_ADDU a2, a0				# index into the bitmap
1417	beq	a2, ta2, 3f			# is the desired cell loaded?
1418	 nop					#   yes, don't reload it
1419	beqz	ta2, 2f				# have we ever loaded it?
1420	 nop					#   nope, so don't save it
1421
1422	LONG_S	t2, 0(ta2)			# save the updated value.
14232:
1424	LONG_L	t2, 0(a2)			# and load it
1425	 move	ta2, a2				# remember the new cell's addr
14263:
1427	and	t1, t2, t0			# see if this asid was recorded
1428	sltu	t1, t1, ta3			# t1 = t1 < 1 (aka t1 == 0)
1429	addu	v0, t1				# v0 += t1
1430	or	t2, t0				# or in the new ASID bits
1431
14324:
1433	addu	v1, 1 << MIPS1_TLB_INDEX_SHIFT	# increment TLB entry #
1434	bne	v1, a3, 1b			# keep lookup if not limit
1435	 nop
1436
1437	beqz	ta2, 5f				# do we have a cell to write?
1438	 nop					#   nope, nothing.
1439
1440	LONG_S	t2, 0(ta2)			# save the updated value.
14415:
1442	mtc0	ta1, MIPS_COP_0_TLB_HI		# restore entryHi
1443
1444	j	ra				# new TLBpid will be set soon
1445	 mtc0	ta0, MIPS_COP_0_STATUS		# restore status register
1446END(MIPSX(tlb_record_asids))
1447
1448/*----------------------------------------------------------------------------
1449 *
1450 *	R3000 trampolines and context resume
1451 *
1452 *----------------------------------------------------------------------------
1453 */
1454
1455/*----------------------------------------------------------------------------
1456 *
1457 * mipsN_lwp_trampoline
1458 *
1459 * Special arrangement for a process about to go user mode right after
1460 * fork() system call.  When the first CPU tick is scheduled to run the
1461 * forked child, it starts running from here.  Then, a service function
1462 * is called with one argument supplied to complete final preparations,
1463 * and the process returns to user mode as if the fork() system call is
1464 * handled in a normal way.  No need to save any registers although this
1465 * calls another.
1466 *----------------------------------------------------------------------------
1467 */
1468LEAF(MIPSX(lwp_trampoline))
1469	PTR_ADDU sp, -CALLFRAME_SIZ
1470
1471	# Call lwp_startup(), with args from cpu_switchto()/cpu_lwp_fork()
1472	move	a0, v0
1473	jal	_C_LABEL(lwp_startup)
1474	 move	a1, MIPS_CURLWP
1475
1476	# Call the routine specified by cpu_lwp_fork()
1477	jalr	s0
1478	 move	a0, s1
1479
1480	# Return to user (won't happen if a kernel thread)
1481	.set	noat
1482MIPSX(user_return):
1483	REG_L	s0, CALLFRAME_SIZ+TF_REG_S0(sp)		# $16
1484	REG_L	s1, CALLFRAME_SIZ+TF_REG_S1(sp)		# $17
1485	REG_L	s2, CALLFRAME_SIZ+TF_REG_S2(sp)		# $18
1486	REG_L	s3, CALLFRAME_SIZ+TF_REG_S3(sp)		# $19
1487	REG_L	s4, CALLFRAME_SIZ+TF_REG_S4(sp)		# $20
1488	REG_L	s5, CALLFRAME_SIZ+TF_REG_S5(sp)		# $21
1489	REG_L	s6, CALLFRAME_SIZ+TF_REG_S6(sp)		# $22
1490	REG_L	s7, CALLFRAME_SIZ+TF_REG_S7(sp)		# $23
1491	REG_L	s8, CALLFRAME_SIZ+TF_REG_S8(sp)		# $30
1492MIPSX(user_intr_return):
1493	REG_L	a0, CALLFRAME_SIZ+TF_REG_SR(sp)
1494	REG_L	t0, CALLFRAME_SIZ+TF_REG_MULLO(sp)
1495	REG_L	t1, CALLFRAME_SIZ+TF_REG_MULHI(sp)
1496	mtc0	a0, MIPS_COP_0_STATUS	# this should disable interrupts
1497	mtlo	t0
1498	mthi	t1
1499	move	k1, sp
1500	REG_L	AT, TF_BASE+TF_REG_AST(sp)
1501	REG_L	k0, CALLFRAME_SIZ+TF_REG_EPC(k1)
1502	REG_L	AT, CALLFRAME_SIZ+TF_REG_AST(k1)
1503	REG_L	v0, CALLFRAME_SIZ+TF_REG_V0(k1)
1504	REG_L	v1, CALLFRAME_SIZ+TF_REG_V1(k1)
1505	REG_L	a0, CALLFRAME_SIZ+TF_REG_A0(k1)
1506	REG_L	a1, CALLFRAME_SIZ+TF_REG_A1(k1)
1507	REG_L	a2, CALLFRAME_SIZ+TF_REG_A2(k1)
1508	REG_L	a3, CALLFRAME_SIZ+TF_REG_A3(k1)
1509	REG_L	t0, CALLFRAME_SIZ+TF_REG_T0(k1)
1510	REG_L	t1, CALLFRAME_SIZ+TF_REG_T1(k1)
1511	REG_L	t2, CALLFRAME_SIZ+TF_REG_T2(k1)
1512	REG_L	t3, CALLFRAME_SIZ+TF_REG_T3(k1)
1513	REG_L	ta0, CALLFRAME_SIZ+TF_REG_TA0(k1)
1514	REG_L	ta1, CALLFRAME_SIZ+TF_REG_TA1(k1)
1515	REG_L	ta2, CALLFRAME_SIZ+TF_REG_TA2(k1)
1516	REG_L	ta3, CALLFRAME_SIZ+TF_REG_TA3(k1)
1517	REG_L	t8, CALLFRAME_SIZ+TF_REG_T8(k1)
1518	REG_L	t9, CALLFRAME_SIZ+TF_REG_T9(k1)
1519	REG_L	gp, CALLFRAME_SIZ+TF_REG_GP(k1)
1520	REG_L	ra, CALLFRAME_SIZ+TF_REG_RA(k1)
1521	REG_L	sp, CALLFRAME_SIZ+TF_REG_SP(k1)
1522	nop
1523	j	k0
1524	rfe
1525	.set	at
1526END(MIPSX(lwp_trampoline))
1527
1528/*
1529 * void mipsN_cpu_switch_resume(struct lwp *newlwp)
1530 *
1531 * Wiredown the USPACE of newproc with TLB entry#0 and #1.  Check
1532 * if target USPACE is already referred by any TLB entry before
1533 * doing that, and make sure TBIS(them) in the case.
1534 */
1535LEAF_NOPROFILE(MIPSX(cpu_switch_resume))
1536	INT_L	a1, L_MD_UPTE_0(a0)		# a1 = upte[0]
1537	INT_L	a2, L_MD_UPTE_1(a0)		# a2 = upte[1]
1538	PTR_L	s0, L_PCB(a0)			# va = l->l_addr
1539	li	s2, VM_MIN_KERNEL_ADDRESS
1540	blt	s0, s2, resume
1541	nop
1542
1543	mfc0	t3, MIPS_COP_0_TLB_HI		# save PID
1544	nop
1545	mtc0	s0, MIPS_COP_0_TLB_HI		# VPN = va
1546	nop
1547	tlbp					# probe 1st VPN
1548	mfc0	s1, MIPS_COP_0_TLB_INDEX
1549	nop
1550	bltz	s1, entry0set
1551	li	s1, MIPS_KSEG0_START		# found, then
1552	mtc0	s1, MIPS_COP_0_TLB_HI
1553	mtc0	zero, MIPS_COP_0_TLB_LOW
1554	nop
1555	tlbwi					# TBIS(va)
1556	nop
1557	mtc0	s0, MIPS_COP_0_TLB_HI		# set 1st VPN again
1558entry0set:
1559	mtc0	zero, MIPS_COP_0_TLB_INDEX	# TLB index #0
1560	ori	a1, a1, MIPS1_PG_G
1561	mtc0	a1, MIPS_COP_0_TLB_LOW		# 1st PFN w/ PG_G
1562	nop
1563	tlbwi					# set TLB entry #0
1564
1565	addu	s0, s0, PAGE_SIZE
1566	mtc0	s0, MIPS_COP_0_TLB_HI		# VPN = va+PAGE_SIZE
1567	nop
1568	tlbp					# probe 2nd VPN
1569	mfc0	s1, MIPS_COP_0_TLB_INDEX
1570	nop
1571	bltz	s1, entry1set
1572	li	s1, MIPS_KSEG0_START		# found, then
1573	mtc0	s1, MIPS_COP_0_TLB_HI
1574	mtc0	zero, MIPS_COP_0_TLB_LOW
1575	nop
1576	tlbwi					# TBIS(va+PAGE_SIZE)
1577	nop
1578	mtc0	s0, MIPS_COP_0_TLB_HI		# set 2nd VPN again
1579entry1set:
1580	li	s1, 1 << MIPS1_TLB_INDEX_SHIFT
1581	mtc0	s1, MIPS_COP_0_TLB_INDEX	# TLB index #1
1582	ori	a2, a2, MIPS1_PG_G
1583	mtc0	a2, MIPS_COP_0_TLB_LOW		# 2nd PFN w/ PG_G
1584	nop
1585	tlbwi					# set TLB entry #1
1586	nop
1587	mfc0	t3, MIPS_COP_0_TLB_HI		# restore PID
1588
1589resume:
1590	j	ra
1591	nop
1592END(MIPSX(cpu_switch_resume))
1593
1594/*----------------------------------------------------------------------------
1595 *
1596 *	R3000 cache sizing and flushing code.
1597 *
1598 *----------------------------------------------------------------------------
1599 */
1600#ifndef ENABLE_MIPS_TX3900
1601/*
1602 * void mipsN_wbflush(void)
1603 *
1604 * Drain processor's write buffer, normally used to ensure any I/O
1605 * register write operations are done before subsequent manipulations.
1606 *
1607 * Some hardware implementations have a WB chip independent from CPU
1608 * core, and CU0 (Coprocessor Usability #0) bit of CP0 status register
1609 * is wired to indicate writebuffer condition.  This code does busy-loop
1610 * while CU0 bit indicates false condition.
1611 *
1612 * For other hardware which have the writebuffer logic is implemented
1613 * in a system controller ASIC chip, wbflush operation would done
1614 * differently.
1615 */
1616LEAF(MIPSX(wbflush))
1617	nop
1618	nop
1619	nop
1620	nop
16211:	bc0f	1b
1622	nop
1623	j	ra
1624	nop
1625END(MIPSX(wbflush))
1626#else /* !ENABLE_MIPS_TX3900 */
1627/*
1628 *	The differences between R3900 and R3000.
1629 *	1. Cache system
1630 *		Physical-index physical-tag
1631 *		fixed line-size
1632 *		refil-size 4/8/16/32 words (set in config register)
1633 *		TX3912
1634 *		       Write-through
1635 *		       I-cache 4KB/16B direct mapped (256line)
1636 *		       D-cache 1KB/4B 2-way sa (128line)
1637 *		       Cache snoop
1638 *		TX3922
1639 *		       Write-through/write-back (set in config register)
1640 *		       I-cache 16KB/16B 2-way sa
1641 *		       D-cache 8KB/16B 2-way sa
1642 *		       Cache snoop
1643 *
1644 *	2. Coprocessor1
1645 *	2.1	cache operation.
1646 *		R3900 uses MIPSIII cache op like method.
1647 *	2.2	R3900 specific CP0 register.
1648 *		(mips/include/r3900regs.h overrides cpuregs.h)
1649 *	2.3	# of TLB entries
1650 *		TX3912 32 entries
1651 *		TX3922 64 entries
1652 *
1653 *	3. System address map
1654 *		kseg2 0xff000000-0xfffeffff is reserved.
1655 *		(mips/include/vmparam.h)
1656 *
1657 *  + If defined both MIPS1 and ENABLE_MIPS_TX3900, it generates kernel for
1658 * R3900. If defined MIPS1 only, No R3900 feature include.
1659 *  + R3920 core has write-back mode. but it is always disabled in NetBSD.
1660 */
1661
1662LEAF_NOPROFILE(tx3900_cp0_config_read)
1663	mfc0	v0, R3900_COP_0_CONFIG
1664	j	ra
1665	 nop
1666END(tx3900_cp0_config_read)
1667
1668LEAF(MIPSX(wbflush))
1669	.set push
1670	.set mips2
1671	sync
1672	.set pop
1673	j	ra
1674	nop
1675END(MIPSX(wbflush))
1676#endif /* !ENABLE_MIPS_TX3900 */
1677
1678	.rdata
1679
1680	.globl _C_LABEL(MIPSX(locore_vec))
1681_C_LABEL(MIPSX(locore_vec)):
1682	PTR_WORD _C_LABEL(MIPSX(cpu_switch_resume))
1683	PTR_WORD _C_LABEL(MIPSX(lwp_trampoline))
1684	PTR_WORD _C_LABEL(MIPSX(wbflush))		# wbflush
1685	PTR_WORD _C_LABEL(MIPSX(tlb_get_asid))
1686	PTR_WORD _C_LABEL(MIPSX(tlb_set_asid))
1687	PTR_WORD _C_LABEL(MIPSX(tlb_invalidate_asids))
1688	PTR_WORD _C_LABEL(MIPSX(tlb_invalidate_addr))
1689	PTR_WORD _C_LABEL(nullop)			# tlb_invalidate_globals
1690	PTR_WORD _C_LABEL(MIPSX(tlb_invalidate_all))
1691	PTR_WORD _C_LABEL(MIPSX(tlb_record_asids))
1692	PTR_WORD _C_LABEL(MIPSX(tlb_update_addr))
1693	PTR_WORD _C_LABEL(MIPSX(tlb_read_entry))
1694	PTR_WORD _C_LABEL(MIPSX(tlb_write_entry))
1695
1696	.globl _C_LABEL(MIPSX(locoresw))
1697_C_LABEL(MIPSX(locoresw)):
1698	PTR_WORD _C_LABEL(MIPSX(wbflush))		# lsw_wbflush
1699	PTR_WORD _C_LABEL(nullop)			# lsw_cpu_idle
1700	PTR_WORD _C_LABEL(nullop)			# lsw_send_ipi
1701	PTR_WORD _C_LABEL(nullop)			# lsw_cpu_offline_md
1702	PTR_WORD _C_LABEL(nullop)			# lsw_cpu_init
1703	PTR_WORD _C_LABEL(nullop)			# lsw_cpu_run
1704	PTR_WORD _C_LABEL(nullop)			# lsw_bus_error
1705
1706MIPSX(excpt_sw):
1707	####
1708	#### The kernel exception handlers.
1709	####
1710	PTR_WORD _C_LABEL(MIPSX(kern_intr))	# 0 external interrupt
1711	PTR_WORD _C_LABEL(MIPSX(kern_gen_exception))# 1 TLB modification
1712	PTR_WORD _C_LABEL(MIPSX(kern_tlb_miss))	# 2 TLB miss (LW/I-fetch)
1713	PTR_WORD _C_LABEL(MIPSX(kern_tlb_miss))	# 3 TLB miss (SW)
1714	PTR_WORD _C_LABEL(MIPSX(kern_gen_exception))# 4 address error (LW/I-fetch)
1715	PTR_WORD _C_LABEL(MIPSX(kern_gen_exception))# 5 address error (SW)
1716	PTR_WORD _C_LABEL(MIPSX(kern_gen_exception))# 6 bus error (I-fetch)
1717	PTR_WORD _C_LABEL(MIPSX(kern_gen_exception))# 7 bus error (load or store)
1718	PTR_WORD _C_LABEL(MIPSX(kern_gen_exception))# 8 system call
1719	PTR_WORD _C_LABEL(MIPSX(kern_gen_exception))# 9 breakpoint
1720	PTR_WORD _C_LABEL(MIPSX(kern_gen_exception))# 10 reserved instruction
1721	PTR_WORD _C_LABEL(MIPSX(kern_gen_exception))# 11 coprocessor unusable
1722	PTR_WORD _C_LABEL(MIPSX(kern_gen_exception))# 12 arithmetic overflow
1723	PTR_WORD _C_LABEL(MIPSX(kern_gen_exception))# 13 r3k reserved
1724	PTR_WORD _C_LABEL(MIPSX(kern_gen_exception))# 14 r3k reserved
1725	PTR_WORD _C_LABEL(MIPSX(kern_gen_exception))# 15 r3k reserved
1726	PTR_WORD _C_LABEL(MIPSX(kern_gen_exception))# 16 never happens w/ MIPS1
1727	PTR_WORD _C_LABEL(MIPSX(kern_gen_exception))# 17 never happens w/ MIPS1
1728	PTR_WORD _C_LABEL(MIPSX(kern_gen_exception))# 18 never happens w/ MIPS1
1729	PTR_WORD _C_LABEL(MIPSX(kern_gen_exception))# 19 never happens w/ MIPS1
1730	PTR_WORD _C_LABEL(MIPSX(kern_gen_exception))# 20 never happens w/ MIPS1
1731	PTR_WORD _C_LABEL(MIPSX(kern_gen_exception))# 21 never happens w/ MIPS1
1732	PTR_WORD _C_LABEL(MIPSX(kern_gen_exception))# 22 never happens w/ MIPS1
1733	PTR_WORD _C_LABEL(MIPSX(kern_gen_exception))# 23 never happens w/ MIPS1
1734	PTR_WORD _C_LABEL(MIPSX(kern_gen_exception))# 24 never happens w/ MIPS1
1735	PTR_WORD _C_LABEL(MIPSX(kern_gen_exception))# 25 never happens w/ MIPS1
1736	PTR_WORD _C_LABEL(MIPSX(kern_gen_exception))# 26 never happens w/ MIPS1
1737	PTR_WORD _C_LABEL(MIPSX(kern_gen_exception))# 27 never happens w/ MIPS1
1738	PTR_WORD _C_LABEL(MIPSX(kern_gen_exception))# 28 never happens w/ MIPS1
1739	PTR_WORD _C_LABEL(MIPSX(kern_gen_exception))# 29 never happens w/ MIPS1
1740	PTR_WORD _C_LABEL(MIPSX(kern_gen_exception))# 30 never happens w/ MIPS1
1741	PTR_WORD _C_LABEL(MIPSX(kern_gen_exception))# 31 never happens w/ MIPS1
1742	#####
1743	##### The user exception handlers.
1744	#####
1745	PTR_WORD _C_LABEL(MIPSX(user_intr))	#  0
1746	PTR_WORD _C_LABEL(MIPSX(user_gen_exception))#  1
1747	PTR_WORD _C_LABEL(MIPSX(user_gen_exception))#  2
1748	PTR_WORD _C_LABEL(MIPSX(user_gen_exception))#  3
1749	PTR_WORD _C_LABEL(MIPSX(user_gen_exception))#  4
1750	PTR_WORD _C_LABEL(MIPSX(user_gen_exception))#  5
1751	PTR_WORD _C_LABEL(MIPSX(user_gen_exception))#  6
1752	PTR_WORD _C_LABEL(MIPSX(user_gen_exception))#  7
1753	PTR_WORD _C_LABEL(MIPSX(systemcall))	#  8
1754	PTR_WORD _C_LABEL(MIPSX(user_gen_exception))#  9
1755	PTR_WORD _C_LABEL(MIPSX(user_gen_exception))# 10
1756	PTR_WORD _C_LABEL(MIPSX(user_gen_exception))# 11
1757	PTR_WORD _C_LABEL(MIPSX(user_gen_exception))# 12
1758	PTR_WORD _C_LABEL(MIPSX(user_gen_exception))# 13
1759	PTR_WORD _C_LABEL(MIPSX(user_gen_exception))# 14
1760	PTR_WORD _C_LABEL(MIPSX(user_gen_exception))# 15
1761	PTR_WORD _C_LABEL(MIPSX(user_gen_exception))# 16
1762	PTR_WORD _C_LABEL(MIPSX(user_gen_exception))# 17
1763	PTR_WORD _C_LABEL(MIPSX(user_gen_exception))# 18
1764	PTR_WORD _C_LABEL(MIPSX(user_gen_exception))# 19
1765	PTR_WORD _C_LABEL(MIPSX(user_gen_exception))# 20
1766	PTR_WORD _C_LABEL(MIPSX(user_gen_exception))# 21
1767	PTR_WORD _C_LABEL(MIPSX(user_gen_exception))# 22
1768	PTR_WORD _C_LABEL(MIPSX(user_gen_exception))# 23
1769	PTR_WORD _C_LABEL(MIPSX(user_gen_exception))# 24
1770	PTR_WORD _C_LABEL(MIPSX(user_gen_exception))# 25
1771	PTR_WORD _C_LABEL(MIPSX(user_gen_exception))# 26
1772	PTR_WORD _C_LABEL(MIPSX(user_gen_exception))# 27
1773	PTR_WORD _C_LABEL(MIPSX(user_gen_exception))# 28
1774	PTR_WORD _C_LABEL(MIPSX(user_gen_exception))# 29
1775	PTR_WORD _C_LABEL(MIPSX(user_gen_exception))# 20
1776	PTR_WORD _C_LABEL(MIPSX(user_gen_exception))# 31
1777