Home | History | Annotate | Line # | Download | only in mips
      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 
     60 RCSID("$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 
     85 EXPORT(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  */
     95 VECTOR(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
    117 1:
    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
    122 MIPSX(nopagetable):
    123 MIPSX(invalidpte):
    124 	j	MIPSX(slowfault)		#1a: handle the rest
    125 	 nop					#1b: branch delay
    126 	.set	at
    127 VECTOR_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
    138 VECTOR(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
    163 VECTOR_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  */
    178 MIPSX(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  */
    207 NESTED_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
    214 1:	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
    220 2:	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 	 */
    315 MIPSX(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
    328 11:	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
    348 1:
    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
    383 END(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  */
    393 NESTED_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
    400 1:	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
    406 2:	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
    413 3:	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
    479 1:	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
    492 2:	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
    529 3:	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 */
    560 4:
    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
    572 9:	bne	t0, a0, 9b			# should still match
    573 	 nop
    574 
    575 	li	t0, IPL_HIGH
    576 	sltu	v0, a0, t0
    577 8:	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
    591 5:	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
    608 END(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  */
    618 NESTED_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
    680 1:
    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
    701 END(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  */
    721 NESTED_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.
    832 1:	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
    842 4:
    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
    889 END(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  */
    898 NESTED_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
    991 END(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  */
   1016 LEAF_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
   1042 END(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  */
   1061 LEAF_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
   1082 4:
   1083 	break	0				# panic
   1084 	.set	at
   1085 END(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  */
   1112 LEAF(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
   1118 END(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  */
   1136 LEAF(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
   1142 END(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  */
   1161 LEAF(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
   1179 2:
   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
   1184 3:
   1185 	mtc0	ta1, MIPS_COP_0_TLB_HI		# restore current PID
   1186 	j	ra
   1187 	 mtc0	ta0, MIPS_COP_0_STATUS		# restore interrupts
   1188 END(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  */
   1203 LEAF(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)
   1224 END(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  */
   1239 LEAF(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
   1257 END(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  */
   1264 LEAF(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
   1284 1:
   1285 	mtc0	ta1, MIPS_COP_0_TLB_HI		# restore PID
   1286 	j	ra
   1287 	 mtc0	ta0, MIPS_COP_0_STATUS		# restore the status register
   1288 END(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  */
   1296 LEAF(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)
   1307 1:
   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
   1332 2:
   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
   1341 END(MIPSX(tlb_invalidate_asids))
   1342 
   1343 /*
   1344  * void mipsN_tlb_invalidate_all(void)
   1345  *
   1346  * Invalidate TLB entirely.
   1347  */
   1348 LEAF(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)
   1363 1:
   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
   1372 END(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  */
   1381 LEAF(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)
   1395 1:
   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.
   1423 2:
   1424 	LONG_L	t2, 0(a2)			# and load it
   1425 	 move	ta2, a2				# remember the new cell's addr
   1426 3:
   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 
   1432 4:
   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.
   1441 5:
   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
   1446 END(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  */
   1468 LEAF(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
   1482 MIPSX(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
   1492 MIPSX(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
   1526 END(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  */
   1535 LEAF_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
   1558 entry0set:
   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
   1579 entry1set:
   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 
   1589 resume:
   1590 	j	ra
   1591 	nop
   1592 END(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  */
   1616 LEAF(MIPSX(wbflush))
   1617 	nop
   1618 	nop
   1619 	nop
   1620 	nop
   1621 1:	bc0f	1b
   1622 	nop
   1623 	j	ra
   1624 	nop
   1625 END(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 
   1662 LEAF_NOPROFILE(tx3900_cp0_config_read)
   1663 	mfc0	v0, R3900_COP_0_CONFIG
   1664 	j	ra
   1665 	 nop
   1666 END(tx3900_cp0_config_read)
   1667 
   1668 LEAF(MIPSX(wbflush))
   1669 	.set push
   1670 	.set mips2
   1671 	sync
   1672 	.set pop
   1673 	j	ra
   1674 	nop
   1675 END(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 
   1706 MIPSX(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