xref: /original-bsd/sys/pmax/pmax/locore.s (revision 333da485)
1/*
2 * Copyright (c) 1992, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Digital Equipment Corporation and Ralph Campbell.
7 *
8 * %sccs.include.redist.c%
9 *
10 * Copyright (C) 1989 Digital Equipment Corporation.
11 * Permission to use, copy, modify, and distribute this software and
12 * its documentation for any purpose and without fee is hereby granted,
13 * provided that the above copyright notice appears in all copies.
14 * Digital Equipment Corporation makes no representations about the
15 * suitability of this software for any purpose.  It is provided "as is"
16 * without express or implied warranty.
17 *
18 * from: $Header: /sprite/src/kernel/mach/ds3100.md/RCS/loMem.s,
19 *	v 1.1 89/07/11 17:55:04 nelson Exp $ SPRITE (DECWRL)
20 * from: $Header: /sprite/src/kernel/mach/ds3100.md/RCS/machAsm.s,
21 *	v 9.2 90/01/29 18:00:39 shirriff Exp $ SPRITE (DECWRL)
22 * from: $Header: /sprite/src/kernel/vm/ds3100.md/vmPmaxAsm.s,
23 *	v 1.1 89/07/10 14:27:41 nelson Exp $ SPRITE (DECWRL)
24 *
25 *	@(#)locore.s	8.5 (Berkeley) 01/04/94
26 */
27
28/*
29 *	Contains code that is the first executed at boot time plus
30 *	assembly language support routines.
31 */
32
33#include <sys/errno.h>
34#include <sys/syscall.h>
35
36#include <machine/param.h>
37#include <machine/psl.h>
38#include <machine/reg.h>
39#include <machine/machAsmDefs.h>
40#include <machine/pte.h>
41
42#include "assym.h"
43
44	.set	noreorder
45
46/*
47 * Amount to take off of the stack for the benefit of the debugger.
48 */
49#define START_FRAME	((4 * 4) + 4 + 4)
50
51	.globl	start
52start:
53	mtc0	zero, MACH_COP_0_STATUS_REG	# Disable interrupts
54	li	t1, MACH_CACHED_MEMORY_ADDR	# invalid address
55	mtc0	t1, MACH_COP_0_TLB_HI		# Mark entry high as invalid
56	mtc0	zero, MACH_COP_0_TLB_LOW	# Zero out low entry.
57/*
58 * Clear the TLB (just to be safe).
59 * Align the starting value (t1), the increment (t2) and the upper bound (t3).
60 */
61	move	t1, zero
62	li	t2, 1 << VMMACH_TLB_INDEX_SHIFT
63	li	t3, VMMACH_NUM_TLB_ENTRIES << VMMACH_TLB_INDEX_SHIFT
641:
65	mtc0	t1, MACH_COP_0_TLB_INDEX	# Set the index register.
66	addu	t1, t1, t2			# Increment index.
67	bne	t1, t3, 1b			# NB: always executes next
68	tlbwi					# Write the TLB entry.
69
70	la	sp, start - START_FRAME
71 #	la	gp, _gp
72	sw	zero, START_FRAME - 4(sp)	# Zero out old ra for debugger
73	jal	mach_init			# mach_init(argc, argv, envp)
74	sw	zero, START_FRAME - 8(sp)	# Zero out old fp for debugger
75
76	li	t0, MACH_SR_COP_1_BIT		# Disable interrupts and
77	mtc0	t0, MACH_COP_0_STATUS_REG	#   enable the coprocessor
78	li	sp, KERNELSTACK - START_FRAME	# switch to standard stack
79	mfc0	t0, MACH_COP_0_PRID		# read processor ID register
80	cfc1	t1, MACH_FPC_ID			# read FPU ID register
81	sw	t0, cpu				# save PRID register
82	sw	t1, fpu				# save FPU ID register
83	jal	main				# main(regs)
84	move	a0, zero
85/*
86 * proc[1] == /etc/init now running here.
87 * Restore user registers and return.
88 */
89	.set	noat
90	li	v0, PSL_USERSET
91	mtc0	v0, MACH_COP_0_STATUS_REG	# switch to user mode
92	lw	a0, UADDR+U_PCB_REGS+(SR * 4)
93	lw	t0, UADDR+U_PCB_REGS+(MULLO * 4)
94	lw	t1, UADDR+U_PCB_REGS+(MULHI * 4)
95	mtlo	t0
96	mthi	t1
97	lw	k0, UADDR+U_PCB_REGS+(PC * 4)
98	lw	AT, UADDR+U_PCB_REGS+(AST * 4)
99	lw	v0, UADDR+U_PCB_REGS+(V0 * 4)
100	lw	v1, UADDR+U_PCB_REGS+(V1 * 4)
101	lw	a0, UADDR+U_PCB_REGS+(A0 * 4)
102	lw	a1, UADDR+U_PCB_REGS+(A1 * 4)
103	lw	a2, UADDR+U_PCB_REGS+(A2 * 4)
104	lw	a3, UADDR+U_PCB_REGS+(A3 * 4)
105	lw	t0, UADDR+U_PCB_REGS+(T0 * 4)
106	lw	t1, UADDR+U_PCB_REGS+(T1 * 4)
107	lw	t2, UADDR+U_PCB_REGS+(T2 * 4)
108	lw	t3, UADDR+U_PCB_REGS+(T3 * 4)
109	lw	t4, UADDR+U_PCB_REGS+(T4 * 4)
110	lw	t5, UADDR+U_PCB_REGS+(T5 * 4)
111	lw	t6, UADDR+U_PCB_REGS+(T6 * 4)
112	lw	t7, UADDR+U_PCB_REGS+(T7 * 4)
113	lw	s0, UADDR+U_PCB_REGS+(S0 * 4)
114	lw	s1, UADDR+U_PCB_REGS+(S1 * 4)
115	lw	s2, UADDR+U_PCB_REGS+(S2 * 4)
116	lw	s3, UADDR+U_PCB_REGS+(S3 * 4)
117	lw	s4, UADDR+U_PCB_REGS+(S4 * 4)
118	lw	s5, UADDR+U_PCB_REGS+(S5 * 4)
119	lw	s6, UADDR+U_PCB_REGS+(S6 * 4)
120	lw	s7, UADDR+U_PCB_REGS+(S7 * 4)
121	lw	t8, UADDR+U_PCB_REGS+(T8 * 4)
122	lw	t9, UADDR+U_PCB_REGS+(T9 * 4)
123	lw	gp, UADDR+U_PCB_REGS+(GP * 4)
124	lw	sp, UADDR+U_PCB_REGS+(SP * 4)
125	lw	s8, UADDR+U_PCB_REGS+(S8 * 4)
126	lw	ra, UADDR+U_PCB_REGS+(RA * 4)
127	j	k0
128	rfe
129	.set	at
130
131/*
132 * GCC2 seems to want to call __main in main() for some reason.
133 */
134LEAF(__main)
135	j	ra
136	nop
137END(__main)
138
139/*
140 * This code is copied the user's stack for returning from signal handlers
141 * (see sendsig() and sigreturn()). We have to compute the address
142 * of the sigcontext struct for the sigreturn call.
143 */
144	.globl	sigcode
145sigcode:
146	addu	a0, sp, 16		# address of sigcontext
147	li	v0, SYS_sigreturn	# sigreturn(scp)
148	syscall
149	break	0			# just in case sigreturn fails
150	.globl	esigcode
151esigcode:
152
153/*
154 * Primitives
155 */
156
157/*
158 * This table is indexed by u.u_pcb.pcb_onfault in trap().
159 * The reason for using this table rather than storing an address in
160 * u.u_pcb.pcb_onfault is simply to make the code faster.
161 */
162	.globl	onfault_table
163	.data
164	.align	2
165onfault_table:
166	.word	0		# invalid index number
167#define BADERR		1
168	.word	baderr
169#define COPYERR		2
170	.word	copyerr
171#define FSWBERR		3
172	.word	fswberr
173#define FSWINTRBERR	4
174	.word	fswintrberr
175#ifdef KADB
176#define KADBERR		5
177	.word	kadberr
178#endif
179	.text
180
181/*
182 * See if access to addr with a len type instruction causes a machine check.
183 * len is length of access (1=byte, 2=short, 4=long)
184 *
185 * badaddr(addr, len)
186 *	char *addr;
187 *	int len;
188 */
189LEAF(badaddr)
190	li	v0, BADERR
191	bne	a1, 1, 2f
192	sw	v0, UADDR+U_PCB_ONFAULT
193	b	5f
194	lbu	v0, (a0)
1952:
196	bne	a1, 2, 4f
197	nop
198	b	5f
199	lhu	v0, (a0)
2004:
201	lw	v0, (a0)
2025:
203	sw	zero, UADDR+U_PCB_ONFAULT
204	j	ra
205	move	v0, zero		# made it w/o errors
206baderr:
207	j	ra
208	li	v0, 1			# trap sends us here
209END(badaddr)
210
211/*
212 * netorder = htonl(hostorder)
213 * hostorder = ntohl(netorder)
214 */
215LEAF(htonl)				# a0 = 0x11223344, return 0x44332211
216ALEAF(ntohl)
217	srl	v1, a0, 24		# v1 = 0x00000011
218	sll	v0, a0, 24		# v0 = 0x44000000
219	or	v0, v0, v1
220	and	v1, a0, 0xff00
221	sll	v1, v1, 8		# v1 = 0x00330000
222	or	v0, v0, v1
223	srl	v1, a0, 8
224	and	v1, v1, 0xff00		# v1 = 0x00002200
225	j	ra
226	or	v0, v0, v1
227END(htonl)
228
229/*
230 * netorder = htons(hostorder)
231 * hostorder = ntohs(netorder)
232 */
233LEAF(htons)
234ALEAF(ntohs)
235	srl	v0, a0, 8
236	and	v0, v0, 0xff
237	sll	v1, a0, 8
238	and	v1, v1, 0xff00
239	j	ra
240	or	v0, v0, v1
241END(htons)
242
243/*
244 * bit = ffs(value)
245 */
246LEAF(ffs)
247	beq	a0, zero, 2f
248	move	v0, zero
2491:
250	and	v1, a0, 1		# bit set?
251	addu	v0, v0, 1
252	beq	v1, zero, 1b		# no, continue
253	srl	a0, a0, 1
2542:
255	j	ra
256	nop
257END(ffs)
258
259/*
260 * strlen(str)
261 */
262LEAF(strlen)
263	addu	v1, a0, 1
2641:
265	lb	v0, 0(a0)		# get byte from string
266	addu	a0, a0, 1		# increment pointer
267	bne	v0, zero, 1b		# continue if not end
268	nop
269	j	ra
270	subu	v0, a0, v1		# compute length - 1 for '\0' char
271END(strlen)
272
273/*
274 * NOTE: this version assumes unsigned chars in order to be "8 bit clean".
275 */
276LEAF(strcmp)
2771:
278	lbu	t0, 0(a0)		# get two bytes and compare them
279	lbu	t1, 0(a1)
280	beq	t0, zero, LessOrEq	# end of first string?
281	nop
282	bne	t0, t1, NotEq
283	nop
284	lbu	t0, 1(a0)		# unroll loop
285	lbu	t1, 1(a1)
286	beq	t0, zero, LessOrEq	# end of first string?
287	addu	a0, a0, 2
288	beq	t0, t1, 1b
289	addu	a1, a1, 2
290NotEq:
291	j	ra
292	subu	v0, t0, t1
293LessOrEq:
294	j	ra
295	subu	v0, zero, t1
296END(strcmp)
297
298/*
299 * bzero(s1, n)
300 */
301LEAF(bzero)
302ALEAF(blkclr)
303	blt	a1, 12, smallclr	# small amount to clear?
304	subu	a3, zero, a0		# compute # bytes to word align address
305	and	a3, a3, 3
306	beq	a3, zero, 1f		# skip if word aligned
307	subu	a1, a1, a3		# subtract from remaining count
308	swr	zero, 0(a0)		# clear 1, 2, or 3 bytes to align
309	addu	a0, a0, a3
3101:
311	and	v0, a1, 3		# compute number of words left
312	subu	a3, a1, v0
313	move	a1, v0
314	addu	a3, a3, a0		# compute ending address
3152:
316	addu	a0, a0, 4		# clear words
317	bne	a0, a3, 2b		#  unrolling loop does not help
318	sw	zero, -4(a0)		#  since we are limited by memory speed
319smallclr:
320	ble	a1, zero, 2f
321	addu	a3, a1, a0		# compute ending address
3221:
323	addu	a0, a0, 1		# clear bytes
324	bne	a0, a3, 1b
325	sb	zero, -1(a0)
3262:
327	j	ra
328	nop
329END(bzero)
330
331/*
332 * bcmp(s1, s2, n)
333 */
334LEAF(bcmp)
335	blt	a2, 16, smallcmp	# is it worth any trouble?
336	xor	v0, a0, a1		# compare low two bits of addresses
337	and	v0, v0, 3
338	subu	a3, zero, a1		# compute # bytes to word align address
339	bne	v0, zero, unalignedcmp	# not possible to align addresses
340	and	a3, a3, 3
341
342	beq	a3, zero, 1f
343	subu	a2, a2, a3		# subtract from remaining count
344	move	v0, v1			# init v0,v1 so unmodified bytes match
345	lwr	v0, 0(a0)		# read 1, 2, or 3 bytes
346	lwr	v1, 0(a1)
347	addu	a1, a1, a3
348	bne	v0, v1, nomatch
349	addu	a0, a0, a3
3501:
351	and	a3, a2, ~3		# compute number of whole words left
352	subu	a2, a2, a3		#   which has to be >= (16-3) & ~3
353	addu	a3, a3, a0		# compute ending address
3542:
355	lw	v0, 0(a0)		# compare words
356	lw	v1, 0(a1)
357	addu	a0, a0, 4
358	bne	v0, v1, nomatch
359	addu	a1, a1, 4
360	bne	a0, a3, 2b
361	nop
362	b	smallcmp		# finish remainder
363	nop
364unalignedcmp:
365	beq	a3, zero, 2f
366	subu	a2, a2, a3		# subtract from remaining count
367	addu	a3, a3, a0		# compute ending address
3681:
369	lbu	v0, 0(a0)		# compare bytes until a1 word aligned
370	lbu	v1, 0(a1)
371	addu	a0, a0, 1
372	bne	v0, v1, nomatch
373	addu	a1, a1, 1
374	bne	a0, a3, 1b
375	nop
3762:
377	and	a3, a2, ~3		# compute number of whole words left
378	subu	a2, a2, a3		#   which has to be >= (16-3) & ~3
379	addu	a3, a3, a0		# compute ending address
3803:
381	lwr	v0, 0(a0)		# compare words a0 unaligned, a1 aligned
382	lwl	v0, 3(a0)
383	lw	v1, 0(a1)
384	addu	a0, a0, 4
385	bne	v0, v1, nomatch
386	addu	a1, a1, 4
387	bne	a0, a3, 3b
388	nop
389smallcmp:
390	ble	a2, zero, match
391	addu	a3, a2, a0		# compute ending address
3921:
393	lbu	v0, 0(a0)
394	lbu	v1, 0(a1)
395	addu	a0, a0, 1
396	bne	v0, v1, nomatch
397	addu	a1, a1, 1
398	bne	a0, a3, 1b
399	nop
400match:
401	j	ra
402	move	v0, zero
403nomatch:
404	j	ra
405	li	v0, 1
406END(bcmp)
407
408/*
409 * memcpy(to, from, len)
410 * {ov}bcopy(from, to, len)
411 */
412LEAF(memcpy)
413	move	v0, a0			# swap from and to
414	move	a0, a1
415	move	a1, v0
416ALEAF(bcopy)
417ALEAF(ovbcopy)
418	addu	t0, a0, a2		# t0 = end of s1 region
419	sltu	t1, a1, t0
420	sltu	t2, a0, a1
421	and	t1, t1, t2		# t1 = true if from < to < (from+len)
422	beq	t1, zero, forward	# non overlapping, do forward copy
423	slt	t2, a2, 12		# check for small copy
424
425	ble	a2, zero, 2f
426	addu	t1, a1, a2		# t1 = end of to region
4271:
428	lb	v1, -1(t0)		# copy bytes backwards,
429	subu	t0, t0, 1		#   doesnt happen often so do slow way
430	subu	t1, t1, 1
431	bne	t0, a0, 1b
432	sb	v1, 0(t1)
4332:
434	j	ra
435	nop
436forward:
437	bne	t2, zero, smallcpy	# do a small bcopy
438	xor	v1, a0, a1		# compare low two bits of addresses
439	and	v1, v1, 3
440	subu	a3, zero, a1		# compute # bytes to word align address
441	beq	v1, zero, aligned	# addresses can be word aligned
442	and	a3, a3, 3
443
444	beq	a3, zero, 1f
445	subu	a2, a2, a3		# subtract from remaining count
446	lwr	v1, 0(a0)		# get next 4 bytes (unaligned)
447	lwl	v1, 3(a0)
448	addu	a0, a0, a3
449	swr	v1, 0(a1)		# store 1, 2, or 3 bytes to align a1
450	addu	a1, a1, a3
4511:
452	and	v1, a2, 3		# compute number of words left
453	subu	a3, a2, v1
454	move	a2, v1
455	addu	a3, a3, a0		# compute ending address
4562:
457	lwr	v1, 0(a0)		# copy words a0 unaligned, a1 aligned
458	lwl	v1, 3(a0)
459	addu	a0, a0, 4
460	addu	a1, a1, 4
461	bne	a0, a3, 2b
462	sw	v1, -4(a1)
463	b	smallcpy
464	nop
465aligned:
466	beq	a3, zero, 1f
467	subu	a2, a2, a3		# subtract from remaining count
468	lwr	v1, 0(a0)		# copy 1, 2, or 3 bytes to align
469	addu	a0, a0, a3
470	swr	v1, 0(a1)
471	addu	a1, a1, a3
4721:
473	and	v1, a2, 3		# compute number of whole words left
474	subu	a3, a2, v1
475	move	a2, v1
476	addu	a3, a3, a0		# compute ending address
4772:
478	lw	v1, 0(a0)		# copy words
479	addu	a0, a0, 4
480	addu	a1, a1, 4
481	bne	a0, a3, 2b
482	sw	v1, -4(a1)
483smallcpy:
484	ble	a2, zero, 2f
485	addu	a3, a2, a0		# compute ending address
4861:
487	lbu	v1, 0(a0)		# copy bytes
488	addu	a0, a0, 1
489	addu	a1, a1, 1
490	bne	a0, a3, 1b
491	sb	v1, -1(a1)
4922:
493	j	ra
494	nop
495END(memcpy)
496
497/*
498 * Copy a null terminated string within the kernel address space.
499 * Maxlength may be null if count not wanted.
500 *	copystr(fromaddr, toaddr, maxlength, &lencopied)
501 *		caddr_t fromaddr;
502 *		caddr_t toaddr;
503 *		u_int maxlength;
504 *		u_int *lencopied;
505 */
506LEAF(copystr)
507	move	t2, a2			# Save the number of bytes
5081:
509	lbu	t0, 0(a0)
510	subu	a2, a2, 1
511	beq	t0, zero, 2f
512	sb	t0, 0(a1)
513	addu	a0, a0, 1
514	bne	a2, zero, 1b
515	addu	a1, a1, 1
5162:
517	beq	a3, zero, 3f
518	subu	a2, t2, a2		# compute length copied
519	sw	a2, 0(a3)
5203:
521	j	ra
522	move	v0, zero
523END(copystr)
524
525/*
526 * Copy a null terminated string from the user address space into
527 * the kernel address space.
528 *
529 *	copyinstr(fromaddr, toaddr, maxlength, &lencopied)
530 *		caddr_t fromaddr;
531 *		caddr_t toaddr;
532 *		u_int maxlength;
533 *		u_int *lencopied;
534 */
535NON_LEAF(copyinstr, STAND_FRAME_SIZE, ra)
536	subu	sp, sp, STAND_FRAME_SIZE
537	.mask	0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
538	sw	ra, STAND_RA_OFFSET(sp)
539	blt	a0, zero, copyerr	# make sure address is in user space
540	li	v0, COPYERR
541	jal	copystr
542	sw	v0, UADDR+U_PCB_ONFAULT
543	lw	ra, STAND_RA_OFFSET(sp)
544	sw	zero, UADDR+U_PCB_ONFAULT
545	addu	sp, sp, STAND_FRAME_SIZE
546	j	ra
547	move	v0, zero
548END(copyinstr)
549
550/*
551 * Copy a null terminated string from the kernel address space into
552 * the user address space.
553 *
554 *	copyoutstr(fromaddr, toaddr, maxlength, &lencopied)
555 *		caddr_t fromaddr;
556 *		caddr_t toaddr;
557 *		u_int maxlength;
558 *		u_int *lencopied;
559 */
560NON_LEAF(copyoutstr, STAND_FRAME_SIZE, ra)
561	subu	sp, sp, STAND_FRAME_SIZE
562	.mask	0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
563	sw	ra, STAND_RA_OFFSET(sp)
564	blt	a1, zero, copyerr	# make sure address is in user space
565	li	v0, COPYERR
566	jal	copystr
567	sw	v0, UADDR+U_PCB_ONFAULT
568	lw	ra, STAND_RA_OFFSET(sp)
569	sw	zero, UADDR+U_PCB_ONFAULT
570	addu	sp, sp, STAND_FRAME_SIZE
571	j	ra
572	move	v0, zero
573END(copyoutstr)
574
575/*
576 * Copy specified amount of data from user space into the kernel
577 *	copyin(from, to, len)
578 *		caddr_t *from;	(user source address)
579 *		caddr_t *to;	(kernel destination address)
580 *		unsigned len;
581 */
582NON_LEAF(copyin, STAND_FRAME_SIZE, ra)
583	subu	sp, sp, STAND_FRAME_SIZE
584	.mask	0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
585	sw	ra, STAND_RA_OFFSET(sp)
586	blt	a0, zero, copyerr	# make sure address is in user space
587	li	v0, COPYERR
588	jal	bcopy
589	sw	v0, UADDR+U_PCB_ONFAULT
590	lw	ra, STAND_RA_OFFSET(sp)
591	sw	zero, UADDR+U_PCB_ONFAULT
592	addu	sp, sp, STAND_FRAME_SIZE
593	j	ra
594	move	v0, zero
595END(copyin)
596
597/*
598 * Copy specified amount of data from kernel to the user space
599 *	copyout(from, to, len)
600 *		caddr_t *from;	(kernel source address)
601 *		caddr_t *to;	(user destination address)
602 *		unsigned len;
603 */
604NON_LEAF(copyout, STAND_FRAME_SIZE, ra)
605	subu	sp, sp, STAND_FRAME_SIZE
606	.mask	0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
607	sw	ra, STAND_RA_OFFSET(sp)
608	blt	a1, zero, copyerr	# make sure address is in user space
609	li	v0, COPYERR
610	jal	bcopy
611	sw	v0, UADDR+U_PCB_ONFAULT
612	lw	ra, STAND_RA_OFFSET(sp)
613	sw	zero, UADDR+U_PCB_ONFAULT
614	addu	sp, sp, STAND_FRAME_SIZE
615	j	ra
616	move	v0, zero
617END(copyout)
618
619LEAF(copyerr)
620	lw	ra, STAND_RA_OFFSET(sp)
621	sw	zero, UADDR+U_PCB_ONFAULT
622	addu	sp, sp, STAND_FRAME_SIZE
623	j	ra
624	li	v0, EFAULT		# return error
625END(copyerr)
626
627/*
628 * Copy data to the DMA buffer.
629 * The DMA bufffer can only be written one short at a time
630 * (and takes ~14 cycles).
631 *
632 *	CopyToBuffer(src, dst, length)
633 *		u_short *src;	NOTE: must be short aligned
634 *		u_short *dst;
635 *		int length;
636 */
637LEAF(CopyToBuffer)
638	blez	a2, 2f
639	nop
6401:
641	lhu	t0, 0(a0)		# read 2 bytes of data
642	subu	a2, a2, 2
643	addu	a0, a0, 2
644	addu	a1, a1, 4
645	bgtz	a2, 1b
646	sh	t0, -4(a1)		# write 2 bytes of data to buffer
6472:
648	j	ra
649	nop
650END(CopyToBuffer)
651
652/*
653 * Copy data from the DMA buffer.
654 * The DMA bufffer can only be read one short at a time
655 * (and takes ~12 cycles).
656 *
657 *	CopyFromBuffer(src, dst, length)
658 *		u_short *src;
659 *		char *dst;
660 *		int length;
661 */
662LEAF(CopyFromBuffer)
663	and	t0, a1, 1		# test for aligned dst
664	beq	t0, zero, 3f
665	nop
666	blt	a2, 2, 7f		# at least 2 bytes to copy?
667	nop
6681:
669	lhu	t0, 0(a0)		# read 2 bytes of data from buffer
670	addu	a0, a0, 4		# keep buffer pointer word aligned
671	addu	a1, a1, 2
672	subu	a2, a2, 2
673	sb	t0, -2(a1)
674	srl	t0, t0, 8
675	bge	a2, 2, 1b
676	sb	t0, -1(a1)
6773:
678	blt	a2, 2, 7f		# at least 2 bytes to copy?
679	nop
6806:
681	lhu	t0, 0(a0)		# read 2 bytes of data from buffer
682	addu	a0, a0, 4		# keep buffer pointer word aligned
683	addu	a1, a1, 2
684	subu	a2, a2, 2
685	bge	a2, 2, 6b
686	sh	t0, -2(a1)
6877:
688	ble	a2, zero, 9f		# done?
689	nop
690	lhu	t0, 0(a0)		# copy one more byte
691	nop
692	sb	t0, 0(a1)
6939:
694	j	ra
695	nop
696END(CopyFromBuffer)
697
698/*
699 * Copy the kernel stack to the new process and save the current context so
700 * the new process will return nonzero when it is resumed by cpu_switch().
701 *
702 *	copykstack(up)
703 *		struct user *up;
704 */
705LEAF(copykstack)
706	subu	v0, sp, UADDR		# compute offset into stack
707	addu	v0, v0, a0		# v0 = new stack address
708	move	v1, sp			# v1 = old stack address
709	li	t1, KERNELSTACK
7101:
711	lw	t0, 0(v1)		# copy stack data
712	addu	v1, v1, 4
713	sw	t0, 0(v0)
714	bne	v1, t1, 1b
715	addu	v0, v0, 4
716	/* FALLTHROUGH */
717/*
718 * Save registers and state so we can do a longjmp later.
719 * Note: this only works if p != curproc since
720 * cpu_switch() will copy over pcb_context.
721 *
722 *	savectx(up)
723 *		struct user *up;
724 */
725ALEAF(savectx)
726	sw	s0, U_PCB_CONTEXT+0(a0)
727	sw	s1, U_PCB_CONTEXT+4(a0)
728	sw	s2, U_PCB_CONTEXT+8(a0)
729	sw	s3, U_PCB_CONTEXT+12(a0)
730	mfc0	v0, MACH_COP_0_STATUS_REG
731	sw	s4, U_PCB_CONTEXT+16(a0)
732	sw	s5, U_PCB_CONTEXT+20(a0)
733	sw	s6, U_PCB_CONTEXT+24(a0)
734	sw	s7, U_PCB_CONTEXT+28(a0)
735	sw	sp, U_PCB_CONTEXT+32(a0)
736	sw	s8, U_PCB_CONTEXT+36(a0)
737	sw	ra, U_PCB_CONTEXT+40(a0)
738	sw	v0, U_PCB_CONTEXT+44(a0)
739	j	ra
740	move	v0, zero
741END(copykstack)
742
743/*
744 * The following primitives manipulate the run queues.  _whichqs tells which
745 * of the 32 queues _qs have processes in them.  Setrunqueue puts processes
746 * into queues, Remrq removes them from queues.  The running process is on
747 * no queue, other processes are on a queue related to p->p_priority, divided
748 * by 4 actually to shrink the 0-127 range of priorities into the 32 available
749 * queues.
750 */
751/*
752 * setrunqueue(p)
753 *	proc *p;
754 *
755 * Call should be made at splclock(), and p->p_stat should be SRUN.
756 */
757NON_LEAF(setrunqueue, STAND_FRAME_SIZE, ra)
758	subu	sp, sp, STAND_FRAME_SIZE
759	.mask	0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
760	lw	t0, P_BACK(a0)		## firewall: p->p_back must be 0
761	sw	ra, STAND_RA_OFFSET(sp)	##
762	beq	t0, zero, 1f		##
763	lbu	t0, P_PRIORITY(a0)	# put on p->p_priority / 4 queue
764	PANIC("setrunqueue")		##
7651:
766	li	t1, 1			# compute corresponding bit
767	srl	t0, t0, 2		# compute index into 'whichqs'
768	sll	t1, t1, t0
769	lw	t2, whichqs		# set corresponding bit
770	nop
771	or	t2, t2, t1
772	sw	t2, whichqs
773	sll	t0, t0, 3		# compute index into 'qs'
774	la	t1, qs
775	addu	t0, t0, t1		# t0 = qp = &qs[pri >> 2]
776	lw	t1, P_BACK(t0)		# t1 = qp->ph_rlink
777	sw	t0, P_FORW(a0)		# p->p_forw = qp
778	sw	t1, P_BACK(a0)		# p->p_back = qp->ph_rlink
779	sw	a0, P_FORW(t1)		# p->p_back->p_forw = p;
780	sw	a0, P_BACK(t0)		# qp->ph_rlink = p
781	j	ra
782	addu	sp, sp, STAND_FRAME_SIZE
783END(setrunqueue)
784
785/*
786 * Remrq(p)
787 *
788 * Call should be made at splclock().
789 */
790NON_LEAF(remrq, STAND_FRAME_SIZE, ra)
791	subu	sp, sp, STAND_FRAME_SIZE
792	.mask	0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
793	lbu	t0, P_PRIORITY(a0)	# get from p->p_priority / 4 queue
794	li	t1, 1			# compute corresponding bit
795	srl	t0, t0, 2		# compute index into 'whichqs'
796	lw	t2, whichqs		# check corresponding bit
797	sll	t1, t1, t0
798	and	v0, t2, t1
799	sw	ra, STAND_RA_OFFSET(sp)	##
800	bne	v0, zero, 1f		##
801	lw	v0, P_BACK(a0)		# v0 = p->p_back
802	PANIC("remrq")			## it wasnt recorded to be on its q
8031:
804	lw	v1, P_FORW(a0)		# v1 = p->p_forw
805	nop
806	sw	v1, P_FORW(v0)		# p->p_back->p_forw = p->p_forw;
807	sw	v0, P_BACK(v1)		# p->p_forw->p_back = p->r_rlink
808	sll	t0, t0, 3		# compute index into 'qs'
809	la	v0, qs
810	addu	t0, t0, v0		# t0 = qp = &qs[pri >> 2]
811	lw	v0, P_FORW(t0)		# check if queue empty
812	nop
813	bne	v0, t0, 2f		# No. qp->ph_link != qp
814	nop
815	xor	t2, t2, t1		# clear corresponding bit in 'whichqs'
816	sw	t2, whichqs
8172:
818	sw	zero, P_BACK(a0)	## for firewall checking
819	j	ra
820	addu	sp, sp, STAND_FRAME_SIZE
821END(remrq)
822
823/*
824 * switch_exit()
825 *
826 * At exit of a process, do a cpu_switch for the last time.
827 * The mapping of the pcb at p->p_addr has already been deleted,
828 * and the memory for the pcb+stack has been freed.
829 * All interrupts should be blocked at this point.
830 */
831LEAF(switch_exit)
832	la	v1, nullproc			# save state into garbage proc
833	lw	t0, P_UPTE+0(v1)		# t0 = first u. pte
834	lw	t1, P_UPTE+4(v1)		# t1 = 2nd u. pte
835	li	v0, UADDR			# v0 = first HI entry
836	mtc0	zero, MACH_COP_0_TLB_INDEX	# set the index register
837	mtc0	v0, MACH_COP_0_TLB_HI		# init high entry
838	mtc0	t0, MACH_COP_0_TLB_LOW		# init low entry
839	li	t0, 1 << VMMACH_TLB_INDEX_SHIFT
840	tlbwi					# Write the TLB entry.
841	addu	v0, v0, NBPG			# 2nd HI entry
842	mtc0	t0, MACH_COP_0_TLB_INDEX	# set the index register
843	mtc0	v0, MACH_COP_0_TLB_HI		# init high entry
844	mtc0	t1, MACH_COP_0_TLB_LOW		# init low entry
845	sw	zero, curproc
846	tlbwi					# Write the TLB entry.
847	b	cpu_switch
848	li	sp, KERNELSTACK - START_FRAME	# switch to standard stack
849END(switch_exit)
850
851/*
852 * When no processes are on the runq, cpu_switch branches to idle
853 * to wait for something to come ready.
854 * Note: this is really a part of cpu_switch() but defined here for kernel
855 * profiling.
856 */
857LEAF(idle)
858	li	t0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR)
859	mtc0	t0, MACH_COP_0_STATUS_REG	# enable all interrupts
860	sw	zero, curproc			# set curproc NULL for stats
8611:
862	lw	t0, whichqs			# look for non-empty queue
863	nop
864	beq	t0, zero, 1b
865	nop
866	b	sw1
867	mtc0	zero, MACH_COP_0_STATUS_REG	# Disable all interrupts
868END(idle)
869
870/*
871 * cpu_switch()
872 * Find the highest priority process and resume it.
873 */
874NON_LEAF(cpu_switch, STAND_FRAME_SIZE, ra)
875	sw	sp, UADDR+U_PCB_CONTEXT+32	# save old sp
876	subu	sp, sp, STAND_FRAME_SIZE
877	sw	ra, STAND_RA_OFFSET(sp)
878	.mask	0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
879	lw	t2, cnt+V_SWTCH			# for statistics
880	lw	t1, whichqs			# look for non-empty queue
881	sw	s0, UADDR+U_PCB_CONTEXT+0	# do a 'savectx()'
882	sw	s1, UADDR+U_PCB_CONTEXT+4
883	sw	s2, UADDR+U_PCB_CONTEXT+8
884	sw	s3, UADDR+U_PCB_CONTEXT+12
885	mfc0	t0, MACH_COP_0_STATUS_REG	# t0 = saved status register
886	sw	s4, UADDR+U_PCB_CONTEXT+16
887	sw	s5, UADDR+U_PCB_CONTEXT+20
888	sw	s6, UADDR+U_PCB_CONTEXT+24
889	sw	s7, UADDR+U_PCB_CONTEXT+28
890	sw	s8, UADDR+U_PCB_CONTEXT+36
891	sw	ra, UADDR+U_PCB_CONTEXT+40	# save return address
892	sw	t0, UADDR+U_PCB_CONTEXT+44	# save status register
893	addu	t2, t2, 1
894	sw	t2, cnt+V_SWTCH
895	beq	t1, zero, idle			# if none, idle
896	mtc0	zero, MACH_COP_0_STATUS_REG	# Disable all interrupts
897sw1:
898	nop					# wait for intrs disabled
899	nop
900	lw	t0, whichqs			# look for non-empty queue
901	li	t2, -1				# t2 = lowest bit set
902	beq	t0, zero, idle			# if none, idle
903	move	t3, t0				# t3 = saved whichqs
9041:
905	addu	t2, t2, 1
906	and	t1, t0, 1			# bit set?
907	beq	t1, zero, 1b
908	srl	t0, t0, 1			# try next bit
909/*
910 * Remove process from queue.
911 */
912	sll	t0, t2, 3
913	la	t1, qs
914	addu	t0, t0, t1			# t0 = qp = &qs[highbit]
915	lw	a0, P_FORW(t0)			# a0 = p = highest pri process
916	nop
917	lw	v0, P_FORW(a0)			# v0 = p->p_forw
918	bne	t0, a0, 2f			# make sure something in queue
919	sw	v0, P_FORW(t0)			# qp->ph_link = p->p_forw;
920	PANIC("cpu_switch")			# nothing in queue
9212:
922	sw	t0, P_BACK(v0)			# p->p_forw->p_back = qp
923	bne	v0, t0, 3f			# queue still not empty
924	sw	zero, P_BACK(a0)		## for firewall checking
925	li	v1, 1				# compute bit in 'whichqs'
926	sll	v1, v1, t2
927	xor	t3, t3, v1			# clear bit in 'whichqs'
928	sw	t3, whichqs
9293:
930/*
931 * Switch to new context.
932 */
933	sw	zero, want_resched
934	jal	pmap_alloc_tlbpid		# v0 = TLB PID
935	move	s0, a0				# BDSLOT: save p
936	sw	s0, curproc			# set curproc
937	sll	v0, v0, VMMACH_TLB_PID_SHIFT	# v0 = aligned PID
938	lw	t0, P_UPTE+0(s0)		# t0 = first u. pte
939	lw	t1, P_UPTE+4(s0)		# t1 = 2nd u. pte
940	or	v0, v0, UADDR			# v0 = first HI entry
941/*
942 * Resume process indicated by the pte's for its u struct
943 * NOTE: This is hard coded to UPAGES == 2.
944 * Also, there should be no TLB faults at this point.
945 */
946	mtc0	zero, MACH_COP_0_TLB_INDEX	# set the index register
947	mtc0	v0, MACH_COP_0_TLB_HI		# init high entry
948	mtc0	t0, MACH_COP_0_TLB_LOW		# init low entry
949	li	t0, 1 << VMMACH_TLB_INDEX_SHIFT
950	tlbwi					# Write the TLB entry.
951	addu	v0, v0, NBPG			# 2nd HI entry
952	mtc0	t0, MACH_COP_0_TLB_INDEX	# set the index register
953	mtc0	v0, MACH_COP_0_TLB_HI		# init high entry
954	mtc0	t1, MACH_COP_0_TLB_LOW		# init low entry
955	nop
956	tlbwi					# Write the TLB entry.
957/*
958 * Now running on new u struct.
959 * Restore registers and return.
960 */
961	lw	v0, UADDR+U_PCB_CONTEXT+44	# restore kernel context
962	lw	ra, UADDR+U_PCB_CONTEXT+40
963	lw	s0, UADDR+U_PCB_CONTEXT+0
964	lw	s1, UADDR+U_PCB_CONTEXT+4
965	lw	s2, UADDR+U_PCB_CONTEXT+8
966	lw	s3, UADDR+U_PCB_CONTEXT+12
967	lw	s4, UADDR+U_PCB_CONTEXT+16
968	lw	s5, UADDR+U_PCB_CONTEXT+20
969	lw	s6, UADDR+U_PCB_CONTEXT+24
970	lw	s7, UADDR+U_PCB_CONTEXT+28
971	lw	sp, UADDR+U_PCB_CONTEXT+32
972	lw	s8, UADDR+U_PCB_CONTEXT+36
973	mtc0	v0, MACH_COP_0_STATUS_REG
974	j	ra
975	li	v0, 1				# possible return to 'savectx()'
976END(cpu_switch)
977
978/*
979 * {fu,su},{ibyte,isword,iword}, fetch or store a byte, short or word to
980 * user text space.
981 * {fu,su},{byte,sword,word}, fetch or store a byte, short or word to
982 * user data space.
983 */
984LEAF(fuword)
985ALEAF(fuiword)
986	blt	a0, zero, fswberr	# make sure address is in user space
987	li	v0, FSWBERR
988	sw	v0, UADDR+U_PCB_ONFAULT
989	lw	v0, 0(a0)		# fetch word
990	j	ra
991	sw	zero, UADDR+U_PCB_ONFAULT
992END(fuword)
993
994LEAF(fusword)
995ALEAF(fuisword)
996	blt	a0, zero, fswberr	# make sure address is in user space
997	li	v0, FSWBERR
998	sw	v0, UADDR+U_PCB_ONFAULT
999	lhu	v0, 0(a0)		# fetch short
1000	j	ra
1001	sw	zero, UADDR+U_PCB_ONFAULT
1002END(fusword)
1003
1004LEAF(fubyte)
1005ALEAF(fuibyte)
1006	blt	a0, zero, fswberr	# make sure address is in user space
1007	li	v0, FSWBERR
1008	sw	v0, UADDR+U_PCB_ONFAULT
1009	lbu	v0, 0(a0)		# fetch byte
1010	j	ra
1011	sw	zero, UADDR+U_PCB_ONFAULT
1012END(fubyte)
1013
1014LEAF(suword)
1015	blt	a0, zero, fswberr	# make sure address is in user space
1016	li	v0, FSWBERR
1017	sw	v0, UADDR+U_PCB_ONFAULT
1018	sw	a1, 0(a0)		# store word
1019	sw	zero, UADDR+U_PCB_ONFAULT
1020	j	ra
1021	move	v0, zero
1022END(suword)
1023
1024/*
1025 * Have to flush instruction cache afterwards.
1026 */
1027LEAF(suiword)
1028	blt	a0, zero, fswberr	# make sure address is in user space
1029	li	v0, FSWBERR
1030	sw	v0, UADDR+U_PCB_ONFAULT
1031	sw	a1, 0(a0)		# store word
1032	sw	zero, UADDR+U_PCB_ONFAULT
1033	move	v0, zero
1034	b	MachFlushICache		# NOTE: this should not clobber v0!
1035	li	a1, 4			# size of word
1036END(suiword)
1037
1038/*
1039 * Will have to flush the instruction cache if byte merging is done in hardware.
1040 */
1041LEAF(susword)
1042ALEAF(suisword)
1043	blt	a0, zero, fswberr	# make sure address is in user space
1044	li	v0, FSWBERR
1045	sw	v0, UADDR+U_PCB_ONFAULT
1046	sh	a1, 0(a0)		# store short
1047	sw	zero, UADDR+U_PCB_ONFAULT
1048	j	ra
1049	move	v0, zero
1050END(susword)
1051
1052LEAF(subyte)
1053ALEAF(suibyte)
1054	blt	a0, zero, fswberr	# make sure address is in user space
1055	li	v0, FSWBERR
1056	sw	v0, UADDR+U_PCB_ONFAULT
1057	sb	a1, 0(a0)		# store byte
1058	sw	zero, UADDR+U_PCB_ONFAULT
1059	j	ra
1060	move	v0, zero
1061END(subyte)
1062
1063LEAF(fswberr)
1064	j	ra
1065	li	v0, -1
1066END(fswberr)
1067
1068/*
1069 * fuswintr and suswintr are just like fusword and susword except that if
1070 * the page is not in memory or would cause a trap, then we return an error.
1071 * The important thing is to prevent sleep() and switch().
1072 */
1073LEAF(fuswintr)
1074	blt	a0, zero, fswintrberr	# make sure address is in user space
1075	li	v0, FSWINTRBERR
1076	sw	v0, UADDR+U_PCB_ONFAULT
1077	lhu	v0, 0(a0)		# fetch short
1078	j	ra
1079	sw	zero, UADDR+U_PCB_ONFAULT
1080END(fuswintr)
1081
1082LEAF(suswintr)
1083	blt	a0, zero, fswintrberr	# make sure address is in user space
1084	li	v0, FSWINTRBERR
1085	sw	v0, UADDR+U_PCB_ONFAULT
1086	sh	a1, 0(a0)		# store short
1087	sw	zero, UADDR+U_PCB_ONFAULT
1088	j	ra
1089	move	v0, zero
1090END(suswintr)
1091
1092LEAF(fswintrberr)
1093	j	ra
1094	li	v0, -1
1095END(fswintrberr)
1096
1097/*
1098 * Insert 'p' after 'q'.
1099 *	_insque(p, q)
1100 *		caddr_t p, q;
1101 */
1102LEAF(_insque)
1103	lw	v0, 0(a1)		# v0 = q->next
1104	sw	a1, 4(a0)		# p->prev = q
1105	sw	v0, 0(a0)		# p->next = q->next
1106	sw	a0, 4(v0)		# q->next->prev = p
1107	j	ra
1108	sw	a0, 0(a1)		# q->next = p
1109END(_insque)
1110
1111/*
1112 * Remove item 'p' from queue.
1113 *	_remque(p)
1114 *		caddr_t p;
1115 */
1116LEAF(_remque)
1117	lw	v0, 0(a0)		# v0 = p->next
1118	lw	v1, 4(a0)		# v1 = p->prev
1119	nop
1120	sw	v0, 0(v1)		# p->prev->next = p->next
1121	j	ra
1122	sw	v1, 4(v0)		# p->next->prev = p->prev
1123END(_remque)
1124
1125/*
1126 * This code is copied to the UTLB exception vector address to
1127 * handle user level TLB translation misses.
1128 * NOTE: This code must be relocatable!!!
1129 */
1130	.globl	MachUTLBMiss
1131MachUTLBMiss:
1132	.set	noat
1133	mfc0	k0, MACH_COP_0_BAD_VADDR	# get the virtual address
1134	lw	k1, UADDR+U_PCB_SEGTAB		# get the current segment table
1135	bltz	k0, 1f				# R3000 chip bug
1136	srl	k0, k0, SEGSHIFT		# compute segment table index
1137	sll	k0, k0, 2
1138	addu	k1, k1, k0
1139	mfc0	k0, MACH_COP_0_BAD_VADDR	# get the virtual address
1140	lw	k1, 0(k1)			# get pointer to segment map
1141	srl	k0, k0, PGSHIFT - 2		# compute segment map index
1142	andi	k0, k0, (NPTEPG - 1) << 2
1143	beq	k1, zero, 2f			# invalid segment map
1144	addu	k1, k1, k0			# index into segment map
1145	lw	k0, 0(k1)			# get page PTE
1146	nop
1147	beq	k0, zero, 2f			# dont load invalid entries
1148	mtc0	k0, MACH_COP_0_TLB_LOW
1149	mfc0	k1, MACH_COP_0_EXC_PC		# get return address
1150	tlbwr					# update TLB
1151	j	k1
1152	rfe
11531:
1154	mfc0	k1, MACH_COP_0_EXC_PC		# get return address
1155	nop
1156	j	k1
1157	rfe
11582:
1159	j	SlowFault			# handle the rest
1160	nop
1161	.set	at
1162	.globl	MachUTLBMissEnd
1163MachUTLBMissEnd:
1164
1165/*
1166 * This code is copied to the general exception vector address to
1167 * handle all execptions except RESET and UTLBMiss.
1168 * NOTE: This code must be relocatable!!!
1169 */
1170	.globl	MachException
1171MachException:
1172/*
1173 * Find out what mode we came from and jump to the proper handler.
1174 */
1175	.set	noat
1176	mfc0	k0, MACH_COP_0_STATUS_REG	# Get the status register
1177	mfc0	k1, MACH_COP_0_CAUSE_REG	# Get the cause register value.
1178	and	k0, k0, MACH_SR_KU_PREV		# test for user mode
1179	sll	k0, k0, 3			# shift user bit for cause index
1180	and	k1, k1, MACH_CR_EXC_CODE	# Mask out the cause bits.
1181	or	k1, k1, k0			# change index to user table
11821:
1183	la	k0, machExceptionTable		# get base of the jump table
1184	addu	k0, k0, k1			# Get the address of the
1185						#  function entry.  Note that
1186						#  the cause is already
1187						#  shifted left by 2 bits so
1188						#  we dont have to shift.
1189	lw	k0, 0(k0)			# Get the function address
1190	nop
1191	j	k0				# Jump to the function.
1192	nop
1193	.set	at
1194	.globl	MachExceptionEnd
1195MachExceptionEnd:
1196
1197/*
1198 * We couldn't find a TLB entry.
1199 * Find out what mode we came from and call the appropriate handler.
1200 */
1201SlowFault:
1202	.set	noat
1203	mfc0	k0, MACH_COP_0_STATUS_REG
1204	nop
1205	and	k0, k0, MACH_SR_KU_PREV
1206	bne	k0, zero, MachUserGenException
1207	nop
1208	.set	at
1209/*
1210 * Fall though ...
1211 */
1212
1213/*----------------------------------------------------------------------------
1214 *
1215 * MachKernGenException --
1216 *
1217 *	Handle an exception from kernel mode.
1218 *
1219 * Results:
1220 *	None.
1221 *
1222 * Side effects:
1223 *	None.
1224 *
1225 *----------------------------------------------------------------------------
1226 */
1227
1228/*
1229 * The kernel exception stack contains 18 saved general registers,
1230 * the status register and the multiply lo and high registers.
1231 * In addition, we set this up for linkage conventions.
1232 */
1233#define KERN_REG_SIZE		(18 * 4)
1234#define KERN_REG_OFFSET		(STAND_FRAME_SIZE)
1235#define KERN_SR_OFFSET		(STAND_FRAME_SIZE + KERN_REG_SIZE)
1236#define KERN_MULT_LO_OFFSET	(STAND_FRAME_SIZE + KERN_REG_SIZE + 4)
1237#define KERN_MULT_HI_OFFSET	(STAND_FRAME_SIZE + KERN_REG_SIZE + 8)
1238#define	KERN_EXC_FRAME_SIZE	(STAND_FRAME_SIZE + KERN_REG_SIZE + 12)
1239
1240NNON_LEAF(MachKernGenException, KERN_EXC_FRAME_SIZE, ra)
1241	.set	noat
1242#ifdef KADB
1243	la	k0, kdbpcb			# save registers for kadb
1244	sw	s0, (S0 * 4)(k0)
1245	sw	s1, (S1 * 4)(k0)
1246	sw	s2, (S2 * 4)(k0)
1247	sw	s3, (S3 * 4)(k0)
1248	sw	s4, (S4 * 4)(k0)
1249	sw	s5, (S5 * 4)(k0)
1250	sw	s6, (S6 * 4)(k0)
1251	sw	s7, (S7 * 4)(k0)
1252	sw	s8, (S8 * 4)(k0)
1253	sw	gp, (GP * 4)(k0)
1254	sw	sp, (SP * 4)(k0)
1255#endif
1256	subu	sp, sp, KERN_EXC_FRAME_SIZE
1257	.mask	0x80000000, (STAND_RA_OFFSET - KERN_EXC_FRAME_SIZE)
1258/*
1259 * Save the relevant kernel registers onto the stack.
1260 * We don't need to save s0 - s8, sp and gp because
1261 * the compiler does it for us.
1262 */
1263	sw	AT, KERN_REG_OFFSET + 0(sp)
1264	sw	v0, KERN_REG_OFFSET + 4(sp)
1265	sw	v1, KERN_REG_OFFSET + 8(sp)
1266	sw	a0, KERN_REG_OFFSET + 12(sp)
1267	mflo	v0
1268	mfhi	v1
1269	sw	a1, KERN_REG_OFFSET + 16(sp)
1270	sw	a2, KERN_REG_OFFSET + 20(sp)
1271	sw	a3, KERN_REG_OFFSET + 24(sp)
1272	sw	t0, KERN_REG_OFFSET + 28(sp)
1273	mfc0	a0, MACH_COP_0_STATUS_REG	# First arg is the status reg.
1274	sw	t1, KERN_REG_OFFSET + 32(sp)
1275	sw	t2, KERN_REG_OFFSET + 36(sp)
1276	sw	t3, KERN_REG_OFFSET + 40(sp)
1277	sw	t4, KERN_REG_OFFSET + 44(sp)
1278	mfc0	a1, MACH_COP_0_CAUSE_REG	# Second arg is the cause reg.
1279	sw	t5, KERN_REG_OFFSET + 48(sp)
1280	sw	t6, KERN_REG_OFFSET + 52(sp)
1281	sw	t7, KERN_REG_OFFSET + 56(sp)
1282	sw	t8, KERN_REG_OFFSET + 60(sp)
1283	mfc0	a2, MACH_COP_0_BAD_VADDR	# Third arg is the fault addr.
1284	sw	t9, KERN_REG_OFFSET + 64(sp)
1285	sw	ra, KERN_REG_OFFSET + 68(sp)
1286	sw	v0, KERN_MULT_LO_OFFSET(sp)
1287	sw	v1, KERN_MULT_HI_OFFSET(sp)
1288	mfc0	a3, MACH_COP_0_EXC_PC		# Fourth arg is the pc.
1289	sw	a0, KERN_SR_OFFSET(sp)
1290/*
1291 * Call the exception handler.
1292 */
1293	jal	trap
1294	sw	a3, STAND_RA_OFFSET(sp)		# for debugging
1295/*
1296 * Restore registers and return from the exception.
1297 * v0 contains the return address.
1298 */
1299	lw	a0, KERN_SR_OFFSET(sp)
1300	lw	t0, KERN_MULT_LO_OFFSET(sp)
1301	lw	t1, KERN_MULT_HI_OFFSET(sp)
1302	mtc0	a0, MACH_COP_0_STATUS_REG	# Restore the SR, disable intrs
1303	mtlo	t0
1304	mthi	t1
1305	move	k0, v0
1306	lw	AT, KERN_REG_OFFSET + 0(sp)
1307	lw	v0, KERN_REG_OFFSET + 4(sp)
1308	lw	v1, KERN_REG_OFFSET + 8(sp)
1309	lw	a0, KERN_REG_OFFSET + 12(sp)
1310	lw	a1, KERN_REG_OFFSET + 16(sp)
1311	lw	a2, KERN_REG_OFFSET + 20(sp)
1312	lw	a3, KERN_REG_OFFSET + 24(sp)
1313	lw	t0, KERN_REG_OFFSET + 28(sp)
1314	lw	t1, KERN_REG_OFFSET + 32(sp)
1315	lw	t2, KERN_REG_OFFSET + 36(sp)
1316	lw	t3, KERN_REG_OFFSET + 40(sp)
1317	lw	t4, KERN_REG_OFFSET + 44(sp)
1318	lw	t5, KERN_REG_OFFSET + 48(sp)
1319	lw	t6, KERN_REG_OFFSET + 52(sp)
1320	lw	t7, KERN_REG_OFFSET + 56(sp)
1321	lw	t8, KERN_REG_OFFSET + 60(sp)
1322	lw	t9, KERN_REG_OFFSET + 64(sp)
1323	lw	ra, KERN_REG_OFFSET + 68(sp)
1324	addu	sp, sp, KERN_EXC_FRAME_SIZE
1325	j	k0				# Now return from the
1326	rfe					#  exception.
1327	.set	at
1328END(MachKernGenException)
1329
1330/*----------------------------------------------------------------------------
1331 *
1332 * MachUserGenException --
1333 *
1334 *	Handle an exception from user mode.
1335 *
1336 * Results:
1337 * 	None.
1338 *
1339 * Side effects:
1340 *	None.
1341 *
1342 *----------------------------------------------------------------------------
1343 */
1344NNON_LEAF(MachUserGenException, STAND_FRAME_SIZE, ra)
1345	.set	noat
1346	.mask	0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
1347/*
1348 * Save all of the registers except for the kernel temporaries in u.u_pcb.
1349 */
1350	sw	AT, UADDR+U_PCB_REGS+(AST * 4)
1351	sw	v0, UADDR+U_PCB_REGS+(V0 * 4)
1352	sw	v1, UADDR+U_PCB_REGS+(V1 * 4)
1353	sw	a0, UADDR+U_PCB_REGS+(A0 * 4)
1354	mflo	v0
1355	sw	a1, UADDR+U_PCB_REGS+(A1 * 4)
1356	sw	a2, UADDR+U_PCB_REGS+(A2 * 4)
1357	sw	a3, UADDR+U_PCB_REGS+(A3 * 4)
1358	sw	t0, UADDR+U_PCB_REGS+(T0 * 4)
1359	mfhi	v1
1360	sw	t1, UADDR+U_PCB_REGS+(T1 * 4)
1361	sw	t2, UADDR+U_PCB_REGS+(T2 * 4)
1362	sw	t3, UADDR+U_PCB_REGS+(T3 * 4)
1363	sw	t4, UADDR+U_PCB_REGS+(T4 * 4)
1364	mfc0	a0, MACH_COP_0_STATUS_REG	# First arg is the status reg.
1365	sw	t5, UADDR+U_PCB_REGS+(T5 * 4)
1366	sw	t6, UADDR+U_PCB_REGS+(T6 * 4)
1367	sw	t7, UADDR+U_PCB_REGS+(T7 * 4)
1368	sw	s0, UADDR+U_PCB_REGS+(S0 * 4)
1369	mfc0	a1, MACH_COP_0_CAUSE_REG	# Second arg is the cause reg.
1370	sw	s1, UADDR+U_PCB_REGS+(S1 * 4)
1371	sw	s2, UADDR+U_PCB_REGS+(S2 * 4)
1372	sw	s3, UADDR+U_PCB_REGS+(S3 * 4)
1373	sw	s4, UADDR+U_PCB_REGS+(S4 * 4)
1374	mfc0	a2, MACH_COP_0_BAD_VADDR	# Third arg is the fault addr
1375	sw	s5, UADDR+U_PCB_REGS+(S5 * 4)
1376	sw	s6, UADDR+U_PCB_REGS+(S6 * 4)
1377	sw	s7, UADDR+U_PCB_REGS+(S7 * 4)
1378	sw	t8, UADDR+U_PCB_REGS+(T8 * 4)
1379	mfc0	a3, MACH_COP_0_EXC_PC		# Fourth arg is the pc.
1380	sw	t9, UADDR+U_PCB_REGS+(T9 * 4)
1381	sw	gp, UADDR+U_PCB_REGS+(GP * 4)
1382	sw	sp, UADDR+U_PCB_REGS+(SP * 4)
1383	sw	s8, UADDR+U_PCB_REGS+(S8 * 4)
1384	li	sp, KERNELSTACK - STAND_FRAME_SIZE	# switch to kernel SP
1385	sw	ra, UADDR+U_PCB_REGS+(RA * 4)
1386	sw	v0, UADDR+U_PCB_REGS+(MULLO * 4)
1387	sw	v1, UADDR+U_PCB_REGS+(MULHI * 4)
1388	sw	a0, UADDR+U_PCB_REGS+(SR * 4)
1389 #	la	gp, _gp				# switch to kernel GP
1390	sw	a3, UADDR+U_PCB_REGS+(PC * 4)
1391	sw	a3, STAND_RA_OFFSET(sp)		# for debugging
1392	.set	at
1393	and	t0, a0, ~MACH_SR_COP_1_BIT	# Turn off the FPU.
1394	.set	noat
1395/*
1396 * Call the exception handler.
1397 */
1398	jal	trap
1399	mtc0	t0, MACH_COP_0_STATUS_REG
1400/*
1401 * Restore user registers and return. NOTE: interrupts are enabled.
1402 */
1403	lw	a0, UADDR+U_PCB_REGS+(SR * 4)
1404	lw	t0, UADDR+U_PCB_REGS+(MULLO * 4)
1405	lw	t1, UADDR+U_PCB_REGS+(MULHI * 4)
1406	mtc0	a0, MACH_COP_0_STATUS_REG	# this should disable interrupts
1407	mtlo	t0
1408	mthi	t1
1409	lw	k0, UADDR+U_PCB_REGS+(PC * 4)
1410	lw	AT, UADDR+U_PCB_REGS+(AST * 4)
1411	lw	v0, UADDR+U_PCB_REGS+(V0 * 4)
1412	lw	v1, UADDR+U_PCB_REGS+(V1 * 4)
1413	lw	a0, UADDR+U_PCB_REGS+(A0 * 4)
1414	lw	a1, UADDR+U_PCB_REGS+(A1 * 4)
1415	lw	a2, UADDR+U_PCB_REGS+(A2 * 4)
1416	lw	a3, UADDR+U_PCB_REGS+(A3 * 4)
1417	lw	t0, UADDR+U_PCB_REGS+(T0 * 4)
1418	lw	t1, UADDR+U_PCB_REGS+(T1 * 4)
1419	lw	t2, UADDR+U_PCB_REGS+(T2 * 4)
1420	lw	t3, UADDR+U_PCB_REGS+(T3 * 4)
1421	lw	t4, UADDR+U_PCB_REGS+(T4 * 4)
1422	lw	t5, UADDR+U_PCB_REGS+(T5 * 4)
1423	lw	t6, UADDR+U_PCB_REGS+(T6 * 4)
1424	lw	t7, UADDR+U_PCB_REGS+(T7 * 4)
1425	lw	s0, UADDR+U_PCB_REGS+(S0 * 4)
1426	lw	s1, UADDR+U_PCB_REGS+(S1 * 4)
1427	lw	s2, UADDR+U_PCB_REGS+(S2 * 4)
1428	lw	s3, UADDR+U_PCB_REGS+(S3 * 4)
1429	lw	s4, UADDR+U_PCB_REGS+(S4 * 4)
1430	lw	s5, UADDR+U_PCB_REGS+(S5 * 4)
1431	lw	s6, UADDR+U_PCB_REGS+(S6 * 4)
1432	lw	s7, UADDR+U_PCB_REGS+(S7 * 4)
1433	lw	t8, UADDR+U_PCB_REGS+(T8 * 4)
1434	lw	t9, UADDR+U_PCB_REGS+(T9 * 4)
1435	lw	gp, UADDR+U_PCB_REGS+(GP * 4)
1436	lw	sp, UADDR+U_PCB_REGS+(SP * 4)
1437	lw	s8, UADDR+U_PCB_REGS+(S8 * 4)
1438	lw	ra, UADDR+U_PCB_REGS+(RA * 4)
1439	j	k0
1440	rfe
1441	.set	at
1442END(MachUserGenException)
1443
1444/*----------------------------------------------------------------------------
1445 *
1446 * MachKernIntr --
1447 *
1448 *	Handle an interrupt from kernel mode.
1449 *	Interrupts use the standard kernel stack.
1450 *	switch_exit sets up a kernel stack after exit so interrupts won't fail.
1451 *
1452 * Results:
1453 *	None.
1454 *
1455 * Side effects:
1456 *	None.
1457 *
1458 *----------------------------------------------------------------------------
1459 */
1460#define KINTR_REG_OFFSET	(STAND_FRAME_SIZE)
1461#define KINTR_SR_OFFSET		(STAND_FRAME_SIZE + KERN_REG_SIZE)
1462#define KINTR_MULT_LO_OFFSET	(STAND_FRAME_SIZE + KERN_REG_SIZE + 4)
1463#define KINTR_MULT_HI_OFFSET	(STAND_FRAME_SIZE + KERN_REG_SIZE + 8)
1464#define	KINTR_FRAME_SIZE	(STAND_FRAME_SIZE + KERN_REG_SIZE + 12)
1465
1466NNON_LEAF(MachKernIntr, KINTR_FRAME_SIZE, ra)
1467	.set	noat
1468	subu	sp, sp, KINTR_FRAME_SIZE	# allocate stack frame
1469	.mask	0x80000000, (STAND_RA_OFFSET - KINTR_FRAME_SIZE)
1470/*
1471 * Save the relevant kernel registers onto the stack.
1472 * We don't need to save s0 - s8, sp and gp because
1473 * the compiler does it for us.
1474 */
1475	sw	AT, KINTR_REG_OFFSET + 0(sp)
1476	sw	v0, KINTR_REG_OFFSET + 4(sp)
1477	sw	v1, KINTR_REG_OFFSET + 8(sp)
1478	sw	a0, KINTR_REG_OFFSET + 12(sp)
1479	mflo	v0
1480	mfhi	v1
1481	sw	a1, KINTR_REG_OFFSET + 16(sp)
1482	sw	a2, KINTR_REG_OFFSET + 20(sp)
1483	sw	a3, KINTR_REG_OFFSET + 24(sp)
1484	sw	t0, KINTR_REG_OFFSET + 28(sp)
1485	mfc0	a0, MACH_COP_0_STATUS_REG	# First arg is the status reg.
1486	sw	t1, KINTR_REG_OFFSET + 32(sp)
1487	sw	t2, KINTR_REG_OFFSET + 36(sp)
1488	sw	t3, KINTR_REG_OFFSET + 40(sp)
1489	sw	t4, KINTR_REG_OFFSET + 44(sp)
1490	mfc0	a1, MACH_COP_0_CAUSE_REG	# Second arg is the cause reg.
1491	sw	t5, KINTR_REG_OFFSET + 48(sp)
1492	sw	t6, KINTR_REG_OFFSET + 52(sp)
1493	sw	t7, KINTR_REG_OFFSET + 56(sp)
1494	sw	t8, KINTR_REG_OFFSET + 60(sp)
1495	mfc0	a2, MACH_COP_0_EXC_PC		# Third arg is the pc.
1496	sw	t9, KINTR_REG_OFFSET + 64(sp)
1497	sw	ra, KINTR_REG_OFFSET + 68(sp)
1498	sw	v0, KINTR_MULT_LO_OFFSET(sp)
1499	sw	v1, KINTR_MULT_HI_OFFSET(sp)
1500	sw	a0, KINTR_SR_OFFSET(sp)
1501/*
1502 * Call the interrupt handler.
1503 */
1504	jal	interrupt
1505	sw	a2, STAND_RA_OFFSET(sp)		# for debugging
1506/*
1507 * Restore registers and return from the interrupt.
1508 */
1509	lw	a0, KINTR_SR_OFFSET(sp)
1510	lw	t0, KINTR_MULT_LO_OFFSET(sp)
1511	lw	t1, KINTR_MULT_HI_OFFSET(sp)
1512	mtc0	a0, MACH_COP_0_STATUS_REG	# Restore the SR, disable intrs
1513	mtlo	t0
1514	mthi	t1
1515	lw	k0, STAND_RA_OFFSET(sp)
1516	lw	AT, KINTR_REG_OFFSET + 0(sp)
1517	lw	v0, KINTR_REG_OFFSET + 4(sp)
1518	lw	v1, KINTR_REG_OFFSET + 8(sp)
1519	lw	a0, KINTR_REG_OFFSET + 12(sp)
1520	lw	a1, KINTR_REG_OFFSET + 16(sp)
1521	lw	a2, KINTR_REG_OFFSET + 20(sp)
1522	lw	a3, KINTR_REG_OFFSET + 24(sp)
1523	lw	t0, KINTR_REG_OFFSET + 28(sp)
1524	lw	t1, KINTR_REG_OFFSET + 32(sp)
1525	lw	t2, KINTR_REG_OFFSET + 36(sp)
1526	lw	t3, KINTR_REG_OFFSET + 40(sp)
1527	lw	t4, KINTR_REG_OFFSET + 44(sp)
1528	lw	t5, KINTR_REG_OFFSET + 48(sp)
1529	lw	t6, KINTR_REG_OFFSET + 52(sp)
1530	lw	t7, KINTR_REG_OFFSET + 56(sp)
1531	lw	t8, KINTR_REG_OFFSET + 60(sp)
1532	lw	t9, KINTR_REG_OFFSET + 64(sp)
1533	lw	ra, KINTR_REG_OFFSET + 68(sp)
1534	addu	sp, sp, KINTR_FRAME_SIZE
1535	j	k0				# Now return from the
1536	rfe					#  interrupt.
1537	.set	at
1538END(MachKernIntr)
1539
1540/*----------------------------------------------------------------------------
1541 *
1542 * MachUserIntr --
1543 *
1544 *	Handle an interrupt from user mode.
1545 *	Note: we save minimal state in the u.u_pcb struct and use the standard
1546 *	kernel stack since there has to be a u page if we came from user mode.
1547 *	If there is a pending software interrupt, then save the remaining state
1548 *	and call softintr(). This is all because if we call switch() inside
1549 *	interrupt(), not all the user registers have been saved in u.u_pcb.
1550 *
1551 * Results:
1552 * 	None.
1553 *
1554 * Side effects:
1555 *	None.
1556 *
1557 *----------------------------------------------------------------------------
1558 */
1559NNON_LEAF(MachUserIntr, STAND_FRAME_SIZE, ra)
1560	.set	noat
1561	.mask	0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
1562/*
1563 * Save the relevant user registers into the u.u_pcb struct.
1564 * We don't need to save s0 - s8 because
1565 * the compiler does it for us.
1566 */
1567	sw	AT, UADDR+U_PCB_REGS+(AST * 4)
1568	sw	v0, UADDR+U_PCB_REGS+(V0 * 4)
1569	sw	v1, UADDR+U_PCB_REGS+(V1 * 4)
1570	sw	a0, UADDR+U_PCB_REGS+(A0 * 4)
1571	mflo	v0
1572	mfhi	v1
1573	sw	a1, UADDR+U_PCB_REGS+(A1 * 4)
1574	sw	a2, UADDR+U_PCB_REGS+(A2 * 4)
1575	sw	a3, UADDR+U_PCB_REGS+(A3 * 4)
1576	sw	t0, UADDR+U_PCB_REGS+(T0 * 4)
1577	mfc0	a0, MACH_COP_0_STATUS_REG	# First arg is the status reg.
1578	sw	t1, UADDR+U_PCB_REGS+(T1 * 4)
1579	sw	t2, UADDR+U_PCB_REGS+(T2 * 4)
1580	sw	t3, UADDR+U_PCB_REGS+(T3 * 4)
1581	sw	t4, UADDR+U_PCB_REGS+(T4 * 4)
1582	mfc0	a1, MACH_COP_0_CAUSE_REG	# Second arg is the cause reg.
1583	sw	t5, UADDR+U_PCB_REGS+(T5 * 4)
1584	sw	t6, UADDR+U_PCB_REGS+(T6 * 4)
1585	sw	t7, UADDR+U_PCB_REGS+(T7 * 4)
1586	sw	t8, UADDR+U_PCB_REGS+(T8 * 4)
1587	mfc0	a2, MACH_COP_0_EXC_PC		# Third arg is the pc.
1588	sw	t9, UADDR+U_PCB_REGS+(T9 * 4)
1589	sw	gp, UADDR+U_PCB_REGS+(GP * 4)
1590	sw	sp, UADDR+U_PCB_REGS+(SP * 4)
1591	sw	ra, UADDR+U_PCB_REGS+(RA * 4)
1592	li	sp, KERNELSTACK - STAND_FRAME_SIZE	# switch to kernel SP
1593	sw	v0, UADDR+U_PCB_REGS+(MULLO * 4)
1594	sw	v1, UADDR+U_PCB_REGS+(MULHI * 4)
1595	sw	a0, UADDR+U_PCB_REGS+(SR * 4)
1596	sw	a2, UADDR+U_PCB_REGS+(PC * 4)
1597 #	la	gp, _gp				# switch to kernel GP
1598	.set	at
1599	and	t0, a0, ~MACH_SR_COP_1_BIT	# Turn off the FPU.
1600	.set	noat
1601	mtc0	t0, MACH_COP_0_STATUS_REG
1602/*
1603 * Call the interrupt handler.
1604 */
1605	jal	interrupt
1606	sw	a2, STAND_RA_OFFSET(sp)		# for debugging
1607/*
1608 * Restore registers and return from the interrupt.
1609 */
1610	lw	a0, UADDR+U_PCB_REGS+(SR * 4)
1611	lw	v0, astpending			# any pending interrupts?
1612	mtc0	a0, MACH_COP_0_STATUS_REG	# Restore the SR, disable intrs
1613	bne	v0, zero, 1f			# dont restore, call softintr
1614	lw	t0, UADDR+U_PCB_REGS+(MULLO * 4)
1615	lw	t1, UADDR+U_PCB_REGS+(MULHI * 4)
1616	lw	k0, UADDR+U_PCB_REGS+(PC * 4)
1617	lw	AT, UADDR+U_PCB_REGS+(AST * 4)
1618	lw	v0, UADDR+U_PCB_REGS+(V0 * 4)
1619	lw	v1, UADDR+U_PCB_REGS+(V1 * 4)
1620	lw	a0, UADDR+U_PCB_REGS+(A0 * 4)
1621	lw	a1, UADDR+U_PCB_REGS+(A1 * 4)
1622	lw	a2, UADDR+U_PCB_REGS+(A2 * 4)
1623	lw	a3, UADDR+U_PCB_REGS+(A3 * 4)
1624	mtlo	t0
1625	mthi	t1
1626	lw	t0, UADDR+U_PCB_REGS+(T0 * 4)
1627	lw	t1, UADDR+U_PCB_REGS+(T1 * 4)
1628	lw	t2, UADDR+U_PCB_REGS+(T2 * 4)
1629	lw	t3, UADDR+U_PCB_REGS+(T3 * 4)
1630	lw	t4, UADDR+U_PCB_REGS+(T4 * 4)
1631	lw	t5, UADDR+U_PCB_REGS+(T5 * 4)
1632	lw	t6, UADDR+U_PCB_REGS+(T6 * 4)
1633	lw	t7, UADDR+U_PCB_REGS+(T7 * 4)
1634	lw	t8, UADDR+U_PCB_REGS+(T8 * 4)
1635	lw	t9, UADDR+U_PCB_REGS+(T9 * 4)
1636	lw	gp, UADDR+U_PCB_REGS+(GP * 4)
1637	lw	sp, UADDR+U_PCB_REGS+(SP * 4)
1638	lw	ra, UADDR+U_PCB_REGS+(RA * 4)
1639	j	k0				# Now return from the
1640	rfe					#  interrupt.
1641
16421:
1643/*
1644 * We have pending software interrupts; save remaining user state in u.u_pcb.
1645 */
1646	sw	s0, UADDR+U_PCB_REGS+(S0 * 4)
1647	sw	s1, UADDR+U_PCB_REGS+(S1 * 4)
1648	sw	s2, UADDR+U_PCB_REGS+(S2 * 4)
1649	sw	s3, UADDR+U_PCB_REGS+(S3 * 4)
1650	sw	s4, UADDR+U_PCB_REGS+(S4 * 4)
1651	sw	s5, UADDR+U_PCB_REGS+(S5 * 4)
1652	sw	s6, UADDR+U_PCB_REGS+(S6 * 4)
1653	sw	s7, UADDR+U_PCB_REGS+(S7 * 4)
1654	sw	s8, UADDR+U_PCB_REGS+(S8 * 4)
1655	li	t0, MACH_HARD_INT_MASK | MACH_SR_INT_ENA_CUR
1656/*
1657 * Call the software interrupt handler.
1658 */
1659	jal	softintr
1660	mtc0	t0, MACH_COP_0_STATUS_REG	# enable interrupts (spl0)
1661/*
1662 * Restore user registers and return. NOTE: interrupts are enabled.
1663 */
1664	lw	a0, UADDR+U_PCB_REGS+(SR * 4)
1665	lw	t0, UADDR+U_PCB_REGS+(MULLO * 4)
1666	lw	t1, UADDR+U_PCB_REGS+(MULHI * 4)
1667	mtc0	a0, MACH_COP_0_STATUS_REG	# this should disable interrupts
1668	mtlo	t0
1669	mthi	t1
1670	lw	k0, UADDR+U_PCB_REGS+(PC * 4)
1671	lw	AT, UADDR+U_PCB_REGS+(AST * 4)
1672	lw	v0, UADDR+U_PCB_REGS+(V0 * 4)
1673	lw	v1, UADDR+U_PCB_REGS+(V1 * 4)
1674	lw	a0, UADDR+U_PCB_REGS+(A0 * 4)
1675	lw	a1, UADDR+U_PCB_REGS+(A1 * 4)
1676	lw	a2, UADDR+U_PCB_REGS+(A2 * 4)
1677	lw	a3, UADDR+U_PCB_REGS+(A3 * 4)
1678	lw	t0, UADDR+U_PCB_REGS+(T0 * 4)
1679	lw	t1, UADDR+U_PCB_REGS+(T1 * 4)
1680	lw	t2, UADDR+U_PCB_REGS+(T2 * 4)
1681	lw	t3, UADDR+U_PCB_REGS+(T3 * 4)
1682	lw	t4, UADDR+U_PCB_REGS+(T4 * 4)
1683	lw	t5, UADDR+U_PCB_REGS+(T5 * 4)
1684	lw	t6, UADDR+U_PCB_REGS+(T6 * 4)
1685	lw	t7, UADDR+U_PCB_REGS+(T7 * 4)
1686	lw	s0, UADDR+U_PCB_REGS+(S0 * 4)
1687	lw	s1, UADDR+U_PCB_REGS+(S1 * 4)
1688	lw	s2, UADDR+U_PCB_REGS+(S2 * 4)
1689	lw	s3, UADDR+U_PCB_REGS+(S3 * 4)
1690	lw	s4, UADDR+U_PCB_REGS+(S4 * 4)
1691	lw	s5, UADDR+U_PCB_REGS+(S5 * 4)
1692	lw	s6, UADDR+U_PCB_REGS+(S6 * 4)
1693	lw	s7, UADDR+U_PCB_REGS+(S7 * 4)
1694	lw	t8, UADDR+U_PCB_REGS+(T8 * 4)
1695	lw	t9, UADDR+U_PCB_REGS+(T9 * 4)
1696	lw	gp, UADDR+U_PCB_REGS+(GP * 4)
1697	lw	sp, UADDR+U_PCB_REGS+(SP * 4)
1698	lw	s8, UADDR+U_PCB_REGS+(S8 * 4)
1699	lw	ra, UADDR+U_PCB_REGS+(RA * 4)
1700	j	k0
1701	rfe
1702	.set	at
1703END(MachUserIntr)
1704
1705#if 0
1706/*----------------------------------------------------------------------------
1707 *
1708 * MachTLBModException --
1709 *
1710 *	Handle a TLB modified exception.
1711 *	The BaddVAddr, Context, and EntryHi registers contain the failed
1712 *	virtual address.
1713 *
1714 * Results:
1715 *	None.
1716 *
1717 * Side effects:
1718 *	None.
1719 *
1720 *----------------------------------------------------------------------------
1721 */
1722NLEAF(MachTLBModException)
1723	.set	noat
1724	tlbp					# find the TLB entry
1725	mfc0	k0, MACH_COP_0_TLB_LOW		# get the physical address
1726	mfc0	k1, MACH_COP_0_TLB_INDEX	# check to be sure its valid
1727	or	k0, k0, VMMACH_TLB_MOD_BIT	# update TLB
1728	blt	k1, zero, 4f			# not found!!!
1729	mtc0	k0, MACH_COP_0_TLB_LOW
1730	li	k1, MACH_CACHED_MEMORY_ADDR
1731	subu	k0, k0, k1
1732	srl	k0, k0, VMMACH_TLB_PHYS_PAGE_SHIFT
1733	la	k1, pmap_attributes
1734	addu	k0, k0, k1
1735	lbu	k1, 0(k0)			# fetch old value
1736	nop
1737	or	k1, k1, 1			# set modified bit
1738	sb	k1, 0(k0)			# save new value
1739	mfc0	k0, MACH_COP_0_EXC_PC		# get return address
1740	nop
1741	j	k0
1742	rfe
17434:
1744	break	0				# panic
1745	.set	at
1746END(MachTLBModException)
1747#endif
1748
1749/*----------------------------------------------------------------------------
1750 *
1751 * MachTLBMissException --
1752 *
1753 *	Handle a TLB miss exception from kernel mode.
1754 *	The BaddVAddr, Context, and EntryHi registers contain the failed
1755 *	virtual address.
1756 *
1757 * Results:
1758 *	None.
1759 *
1760 * Side effects:
1761 *	None.
1762 *
1763 *----------------------------------------------------------------------------
1764 */
1765NLEAF(MachTLBMissException)
1766	.set	noat
1767	mfc0	k0, MACH_COP_0_BAD_VADDR	# get the fault address
1768	li	k1, VM_MIN_KERNEL_ADDRESS	# compute index
1769	subu	k0, k0, k1
1770	lw	k1, Sysmapsize			# index within range?
1771	srl	k0, k0, PGSHIFT
1772	sltu	k1, k0, k1
1773	beq	k1, zero, 1f			# No. check for valid stack
1774	nop
1775	lw	k1, Sysmap
1776	sll	k0, k0, 2			# compute offset from index
1777	addu	k1, k1, k0
1778	lw	k0, 0(k1)			# get PTE entry
1779	mfc0	k1, MACH_COP_0_EXC_PC		# get return address
1780	mtc0	k0, MACH_COP_0_TLB_LOW		# save PTE entry
1781	and	k0, k0, PG_V			# check for valid entry
1782	beq	k0, zero, MachKernGenException	# PTE invalid
1783	nop
1784	tlbwr					# update TLB
1785	j	k1
1786	rfe
1787
17881:
1789	subu	k0, sp, UADDR + 0x200		# check to see if we have a
1790	sltiu	k0, UPAGES*NBPG - 0x200		#  valid kernel stack
1791	bne	k0, zero, MachKernGenException	# Go panic
1792	nop
1793
1794	la	a0, start - START_FRAME - 8	# set sp to a valid place
1795	sw	sp, 24(a0)
1796	move	sp, a0
1797	la	a0, 1f
1798	mfc0	a2, MACH_COP_0_STATUS_REG
1799	mfc0	a3, MACH_COP_0_CAUSE_REG
1800	mfc0	a1, MACH_COP_0_EXC_PC
1801	sw	a2, 16(sp)
1802	sw	a3, 20(sp)
1803	sw	sp, 24(sp)
1804	move	a2, ra
1805	jal	printf
1806	mfc0	a3, MACH_COP_0_BAD_VADDR
1807	.data
18081:
1809	.asciiz	"ktlbmiss: PC %x RA %x ADR %x\nSR %x CR %x SP %x\n"
1810	.text
1811
1812	la	sp, start - START_FRAME		# set sp to a valid place
1813	PANIC("kernel stack overflow")
1814	.set	at
1815END(MachTLBMissException)
1816
1817/*
1818 * Set/clear software interrupt routines.
1819 */
1820
1821LEAF(setsoftclock)
1822	mfc0	v0, MACH_COP_0_CAUSE_REG	# read cause register
1823	nop
1824	or	v0, v0, MACH_SOFT_INT_MASK_0	# set soft clock interrupt
1825	mtc0	v0, MACH_COP_0_CAUSE_REG	# save it
1826	j	ra
1827	nop
1828END(setsoftclock)
1829
1830LEAF(clearsoftclock)
1831	mfc0	v0, MACH_COP_0_CAUSE_REG	# read cause register
1832	nop
1833	and	v0, v0, ~MACH_SOFT_INT_MASK_0	# clear soft clock interrupt
1834	mtc0	v0, MACH_COP_0_CAUSE_REG	# save it
1835	j	ra
1836	nop
1837END(clearsoftclock)
1838
1839LEAF(setsoftnet)
1840	mfc0	v0, MACH_COP_0_CAUSE_REG	# read cause register
1841	nop
1842	or	v0, v0, MACH_SOFT_INT_MASK_1	# set soft net interrupt
1843	mtc0	v0, MACH_COP_0_CAUSE_REG	# save it
1844	j	ra
1845	nop
1846END(setsoftnet)
1847
1848LEAF(clearsoftnet)
1849	mfc0	v0, MACH_COP_0_CAUSE_REG	# read cause register
1850	nop
1851	and	v0, v0, ~MACH_SOFT_INT_MASK_1	# clear soft net interrupt
1852	mtc0	v0, MACH_COP_0_CAUSE_REG	# save it
1853	j	ra
1854	nop
1855END(clearsoftnet)
1856
1857/*
1858 * Set/change interrupt priority routines.
1859 */
1860
1861LEAF(MachEnableIntr)
1862	mfc0	v0, MACH_COP_0_STATUS_REG	# read status register
1863	nop
1864	or	v0, v0, MACH_SR_INT_ENA_CUR
1865	mtc0	v0, MACH_COP_0_STATUS_REG	# enable all interrupts
1866	j	ra
1867	nop
1868END(MachEnableIntr)
1869
1870LEAF(spl0)
1871	mfc0	v0, MACH_COP_0_STATUS_REG	# read status register
1872	nop
1873	or	t0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR)
1874	mtc0	t0, MACH_COP_0_STATUS_REG	# enable all interrupts
1875	j	ra
1876	and	v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR)
1877END(spl0)
1878
1879LEAF(splsoftclock)
1880	mfc0	v0, MACH_COP_0_STATUS_REG	# read status register
1881	li	t0, ~MACH_SOFT_INT_MASK_0	# disable soft clock
1882	and	t0, t0, v0
1883	mtc0	t0, MACH_COP_0_STATUS_REG	# save it
1884	j	ra
1885	and	v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR)
1886END(splsoftclock)
1887
1888LEAF(Mach_spl0)
1889	mfc0	v0, MACH_COP_0_STATUS_REG	# read status register
1890	li	t0, ~(MACH_INT_MASK_0|MACH_SOFT_INT_MASK_1|MACH_SOFT_INT_MASK_0)
1891	and	t0, t0, v0
1892	mtc0	t0, MACH_COP_0_STATUS_REG	# save it
1893	j	ra
1894	and	v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR)
1895END(Mach_spl0)
1896
1897LEAF(Mach_spl1)
1898	mfc0	v0, MACH_COP_0_STATUS_REG	# read status register
1899	li	t0, ~(MACH_INT_MASK_1|MACH_SOFT_INT_MASK_0|MACH_SOFT_INT_MASK_1)
1900	and	t0, t0, v0
1901	mtc0	t0, MACH_COP_0_STATUS_REG	# save it
1902	j	ra
1903	and	v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR)
1904END(Mach_spl1)
1905
1906LEAF(Mach_spl2)
1907	mfc0	v0, MACH_COP_0_STATUS_REG	# read status register
1908	li	t0, ~(MACH_INT_MASK_2|MACH_SOFT_INT_MASK_1|MACH_SOFT_INT_MASK_0)
1909	and	t0, t0, v0
1910	mtc0	t0, MACH_COP_0_STATUS_REG	# save it
1911	j	ra
1912	and	v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR)
1913END(Mach_spl2)
1914
1915LEAF(Mach_spl3)
1916	mfc0	v0, MACH_COP_0_STATUS_REG	# read status register
1917	li	t0, ~(MACH_INT_MASK_3|MACH_SOFT_INT_MASK_1|MACH_SOFT_INT_MASK_0)
1918	and	t0, t0, v0
1919	mtc0	t0, MACH_COP_0_STATUS_REG	# save it
1920	j	ra
1921	and	v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR)
1922END(Mach_spl3)
1923
1924/*
1925 * We define an alternate entry point after mcount is called so it
1926 * can be used in mcount without causeing a recursive loop.
1927 */
1928LEAF(splhigh)
1929ALEAF(_splhigh)
1930	mfc0	v0, MACH_COP_0_STATUS_REG	# read status register
1931	li	t0, ~MACH_SR_INT_ENA_CUR	# disable all interrupts
1932	and	t0, t0, v0
1933	mtc0	t0, MACH_COP_0_STATUS_REG	# save it
1934	j	ra
1935	and	v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR)
1936END(splhigh)
1937
1938/*
1939 * Restore saved interrupt mask.
1940 */
1941LEAF(splx)
1942ALEAF(_splx)
1943	mfc0	v0, MACH_COP_0_STATUS_REG
1944	li	t0, ~(MACH_INT_MASK | MACH_SR_INT_ENA_CUR)
1945	and	t0, t0, v0
1946	or	t0, t0, a0
1947	mtc0	t0, MACH_COP_0_STATUS_REG
1948	j	ra
1949	nop
1950END(splx)
1951
1952/*----------------------------------------------------------------------------
1953 *
1954 * MachEmptyWriteBuffer --
1955 *
1956 *	Return when the write buffer is empty.
1957 *
1958 *	MachEmptyWriteBuffer()
1959 *
1960 * Results:
1961 *	None.
1962 *
1963 * Side effects:
1964 *	None.
1965 *
1966 *----------------------------------------------------------------------------
1967 */
1968LEAF(MachEmptyWriteBuffer)
1969	nop
1970	nop
1971	nop
1972	nop
19731:	bc0f	1b
1974	nop
1975	j	ra
1976	nop
1977END(MachEmptyWriteBuffer)
1978
1979/*--------------------------------------------------------------------------
1980 *
1981 * MachTLBWriteIndexed --
1982 *
1983 *	Write the given entry into the TLB at the given index.
1984 *
1985 *	MachTLBWriteIndexed(index, highEntry, lowEntry)
1986 *		int index;
1987 *		int highEntry;
1988 *		int lowEntry;
1989 *
1990 * Results:
1991 *	None.
1992 *
1993 * Side effects:
1994 *	TLB entry set.
1995 *
1996 *--------------------------------------------------------------------------
1997 */
1998LEAF(MachTLBWriteIndexed)
1999	mfc0	v1, MACH_COP_0_STATUS_REG	# Save the status register.
2000	mtc0	zero, MACH_COP_0_STATUS_REG	# Disable interrupts
2001	mfc0	t0, MACH_COP_0_TLB_HI		# Save the current PID.
2002
2003	sll	a0, a0, VMMACH_TLB_INDEX_SHIFT
2004	mtc0	a0, MACH_COP_0_TLB_INDEX	# Set the index.
2005	mtc0	a1, MACH_COP_0_TLB_HI		# Set up entry high.
2006	mtc0	a2, MACH_COP_0_TLB_LOW		# Set up entry low.
2007	nop
2008	tlbwi					# Write the TLB
2009
2010	mtc0	t0, MACH_COP_0_TLB_HI		# Restore the PID.
2011	j	ra
2012	mtc0	v1, MACH_COP_0_STATUS_REG	# Restore the status register
2013END(MachTLBWriteIndexed)
2014
2015#if 0
2016/*--------------------------------------------------------------------------
2017 *
2018 * MachTLBWriteRandom --
2019 *
2020 *	Write the given entry into the TLB at a random location.
2021 *
2022 *	MachTLBWriteRandom(highEntry, lowEntry)
2023 *		unsigned highEntry;
2024 *		unsigned lowEntry;
2025 *
2026 * Results:
2027 *	None.
2028 *
2029 * Side effects:
2030 *	TLB entry set.
2031 *
2032 *--------------------------------------------------------------------------
2033 */
2034LEAF(MachTLBWriteRandom)
2035	mfc0	v1, MACH_COP_0_STATUS_REG	# Save the status register.
2036	mtc0	zero, MACH_COP_0_STATUS_REG	# Disable interrupts
2037	mfc0	v0, MACH_COP_0_TLB_HI		# Save the current PID.
2038	nop
2039
2040	mtc0	a0, MACH_COP_0_TLB_HI		# Set up entry high.
2041	mtc0	a1, MACH_COP_0_TLB_LOW		# Set up entry low.
2042	nop
2043	tlbwr					# Write the TLB
2044
2045	mtc0	v0, MACH_COP_0_TLB_HI		# Restore the PID.
2046	j	ra
2047	mtc0	v1, MACH_COP_0_STATUS_REG	# Restore the status register
2048END(MachTLBWriteRandom)
2049#endif
2050
2051/*--------------------------------------------------------------------------
2052 *
2053 * MachSetPID --
2054 *
2055 *	Write the given pid into the TLB pid reg.
2056 *
2057 *	MachSetPID(pid)
2058 *		int pid;
2059 *
2060 * Results:
2061 *	None.
2062 *
2063 * Side effects:
2064 *	PID set in the entry hi register.
2065 *
2066 *--------------------------------------------------------------------------
2067 */
2068LEAF(MachSetPID)
2069	sll	a0, a0, VMMACH_TLB_PID_SHIFT	# put PID in right spot
2070	mtc0	a0, MACH_COP_0_TLB_HI		# Write the hi reg value
2071	j	ra
2072	nop
2073END(MachSetPID)
2074
2075/*--------------------------------------------------------------------------
2076 *
2077 * MachTLBFlush --
2078 *
2079 *	Flush the "random" entries from the TLB.
2080 *
2081 *	MachTLBFlush()
2082 *
2083 * Results:
2084 *	None.
2085 *
2086 * Side effects:
2087 *	The TLB is flushed.
2088 *
2089 *--------------------------------------------------------------------------
2090 */
2091LEAF(MachTLBFlush)
2092	mfc0	v1, MACH_COP_0_STATUS_REG	# Save the status register.
2093	mtc0	zero, MACH_COP_0_STATUS_REG	# Disable interrupts
2094	mfc0	t0, MACH_COP_0_TLB_HI		# Save the PID
2095	li	t1, MACH_CACHED_MEMORY_ADDR	# invalid address
2096	mtc0	t1, MACH_COP_0_TLB_HI		# Mark entry high as invalid
2097	mtc0	zero, MACH_COP_0_TLB_LOW	# Zero out low entry.
2098/*
2099 * Align the starting value (t1) and the upper bound (t2).
2100 */
2101	li	t1, VMMACH_FIRST_RAND_ENTRY << VMMACH_TLB_INDEX_SHIFT
2102	li	t2, VMMACH_NUM_TLB_ENTRIES << VMMACH_TLB_INDEX_SHIFT
21031:
2104	mtc0	t1, MACH_COP_0_TLB_INDEX	# Set the index register.
2105	addu	t1, t1, 1 << VMMACH_TLB_INDEX_SHIFT	# Increment index.
2106	bne	t1, t2, 1b
2107	tlbwi					# Write the TLB entry.
2108
2109	mtc0	t0, MACH_COP_0_TLB_HI		# Restore the PID
2110	j	ra
2111	mtc0	v1, MACH_COP_0_STATUS_REG	# Restore the status register
2112END(MachTLBFlush)
2113
2114#if 0
2115/*--------------------------------------------------------------------------
2116 *
2117 * MachTLBFlushPID --
2118 *
2119 *	Flush all entries with the given PID from the TLB.
2120 *
2121 *	MachTLBFlushPID(pid)
2122 *		int pid;
2123 *
2124 * Results:
2125 *	None.
2126 *
2127 * Side effects:
2128 *	All entries corresponding to this PID are flushed.
2129 *
2130 *--------------------------------------------------------------------------
2131 */
2132LEAF(MachTLBFlushPID)
2133	mfc0	v1, MACH_COP_0_STATUS_REG	# Save the status register.
2134	mtc0	zero, MACH_COP_0_STATUS_REG	# Disable interrupts
2135	mfc0	t0, MACH_COP_0_TLB_HI		# Save the current PID
2136	sll	a0, a0, VMMACH_TLB_PID_SHIFT	# Align the pid to flush.
2137/*
2138 * Align the starting value (t1) and the upper bound (t2).
2139 */
2140	li	t1, VMMACH_FIRST_RAND_ENTRY << VMMACH_TLB_INDEX_SHIFT
2141	li	t2, VMMACH_NUM_TLB_ENTRIES << VMMACH_TLB_INDEX_SHIFT
2142	mtc0	t1, MACH_COP_0_TLB_INDEX	# Set the index register
21431:
2144	addu	t1, t1, 1 << VMMACH_TLB_INDEX_SHIFT	# Increment index.
2145	tlbr					# Read from the TLB
2146	mfc0	t4, MACH_COP_0_TLB_HI		# Fetch the hi register.
2147	nop
2148	and	t4, t4, VMMACH_TLB_PID		# compare PIDs
2149	bne	t4, a0, 2f
2150	li	v0, MACH_CACHED_MEMORY_ADDR	# invalid address
2151	mtc0	v0, MACH_COP_0_TLB_HI		# Mark entry high as invalid
2152	mtc0	zero, MACH_COP_0_TLB_LOW	# Zero out low entry.
2153	nop
2154	tlbwi					# Write the entry.
21552:
2156	bne	t1, t2, 1b
2157	mtc0	t1, MACH_COP_0_TLB_INDEX	# Set the index register
2158
2159	mtc0	t0, MACH_COP_0_TLB_HI		# restore PID
2160	j	ra
2161	mtc0	v1, MACH_COP_0_STATUS_REG	# Restore the status register
2162END(MachTLBFlushPID)
2163#endif
2164
2165/*--------------------------------------------------------------------------
2166 *
2167 * MachTLBFlushAddr --
2168 *
2169 *	Flush any TLB entries for the given address and TLB PID.
2170 *
2171 *	MachTLBFlushAddr(highreg)
2172 *		unsigned highreg;
2173 *
2174 * Results:
2175 *	None.
2176 *
2177 * Side effects:
2178 *	The process's page is flushed from the TLB.
2179 *
2180 *--------------------------------------------------------------------------
2181 */
2182LEAF(MachTLBFlushAddr)
2183	mfc0	v1, MACH_COP_0_STATUS_REG	# Save the status register.
2184	mtc0	zero, MACH_COP_0_STATUS_REG	# Disable interrupts
2185	mfc0	t0, MACH_COP_0_TLB_HI		# Get current PID
2186	nop
2187
2188	mtc0	a0, MACH_COP_0_TLB_HI		# look for addr & PID
2189	nop
2190	tlbp					# Probe for the entry.
2191	mfc0	v0, MACH_COP_0_TLB_INDEX	# See what we got
2192	li	t1, MACH_CACHED_MEMORY_ADDR	# Load invalid entry.
2193	bltz	v0, 1f				# index < 0 => !found
2194	mtc0	t1, MACH_COP_0_TLB_HI		# Mark entry high as invalid
2195	mtc0	zero, MACH_COP_0_TLB_LOW	# Zero out low entry.
2196	nop
2197	tlbwi
21981:
2199	mtc0	t0, MACH_COP_0_TLB_HI		# restore PID
2200	j	ra
2201	mtc0	v1, MACH_COP_0_STATUS_REG	# Restore the status register
2202END(MachTLBFlushAddr)
2203
2204/*--------------------------------------------------------------------------
2205 *
2206 * MachTLBUpdate --
2207 *
2208 *	Update the TLB if highreg is found; otherwise, enter the data.
2209 *
2210 *	MachTLBUpdate(highreg, lowreg)
2211 *		unsigned highreg, lowreg;
2212 *
2213 * Results:
2214 *	None.
2215 *
2216 * Side effects:
2217 *	None.
2218 *
2219 *--------------------------------------------------------------------------
2220 */
2221LEAF(MachTLBUpdate)
2222	mfc0	v1, MACH_COP_0_STATUS_REG	# Save the status register.
2223	mtc0	zero, MACH_COP_0_STATUS_REG	# Disable interrupts
2224	mfc0	t0, MACH_COP_0_TLB_HI		# Save current PID
2225	nop					# 2 cycles before intr disabled
2226	mtc0	a0, MACH_COP_0_TLB_HI		# init high reg.
2227	nop
2228	tlbp					# Probe for the entry.
2229	mfc0	v0, MACH_COP_0_TLB_INDEX	# See what we got
2230	mtc0	a1, MACH_COP_0_TLB_LOW		# init low reg.
2231	bltz	v0, 1f				# index < 0 => !found
2232	sra	v0, v0, VMMACH_TLB_INDEX_SHIFT	# convert index to regular num
2233	b	2f
2234	tlbwi					# update slot found
22351:
2236	mtc0	a0, MACH_COP_0_TLB_HI		# init high reg.
2237	nop
2238	tlbwr					# enter into a random slot
22392:
2240	mtc0	t0, MACH_COP_0_TLB_HI		# restore PID
2241	j	ra
2242	mtc0	v1, MACH_COP_0_STATUS_REG	# Restore the status register
2243END(MachTLBUpdate)
2244
2245#if defined(DEBUG)
2246/*--------------------------------------------------------------------------
2247 *
2248 * MachTLBFind --
2249 *
2250 *	Search the TLB for the given entry.
2251 *
2252 *	MachTLBFind(hi)
2253 *		unsigned hi;
2254 *
2255 * Results:
2256 *	Returns a value >= 0 if the entry was found (the index).
2257 *	Returns a value < 0 if the entry was not found.
2258 *
2259 * Side effects:
2260 *	tlbhi and tlblo will contain the TLB entry found.
2261 *
2262 *--------------------------------------------------------------------------
2263 */
2264	.comm	tlbhi, 4
2265	.comm	tlblo, 4
2266LEAF(MachTLBFind)
2267	mfc0	v1, MACH_COP_0_STATUS_REG	# Save the status register.
2268	mtc0	zero, MACH_COP_0_STATUS_REG	# Disable interrupts
2269	mfc0	t0, MACH_COP_0_TLB_HI		# Get current PID
2270	nop
2271	mtc0	a0, MACH_COP_0_TLB_HI		# Set up entry high.
2272	nop
2273	tlbp					# Probe for the entry.
2274	mfc0	v0, MACH_COP_0_TLB_INDEX	# See what we got
2275	nop
2276	bltz	v0, 1f				# not found
2277	nop
2278	tlbr					# read TLB
2279	mfc0	t1, MACH_COP_0_TLB_HI		# See what we got
2280	mfc0	t2, MACH_COP_0_TLB_LOW		# See what we got
2281	sw	t1, tlbhi
2282	sw	t2, tlblo
2283	srl	v0, v0, VMMACH_TLB_INDEX_SHIFT	# convert index to regular num
22841:
2285	mtc0	t0, MACH_COP_0_TLB_HI		# Restore current PID
2286	j	ra
2287	mtc0	v1, MACH_COP_0_STATUS_REG	# Restore the status register
2288END(MachTLBFind)
2289
2290/*--------------------------------------------------------------------------
2291 *
2292 * MachTLBRead --
2293 *
2294 *	Read the TLB entry.
2295 *
2296 *	MachTLBRead(entry)
2297 *		unsigned entry;
2298 *
2299 * Results:
2300 *	None.
2301 *
2302 * Side effects:
2303 *	tlbhi and tlblo will contain the TLB entry found.
2304 *
2305 *--------------------------------------------------------------------------
2306 */
2307LEAF(MachTLBRead)
2308	mfc0	v1, MACH_COP_0_STATUS_REG	# Save the status register.
2309	mtc0	zero, MACH_COP_0_STATUS_REG	# Disable interrupts
2310	mfc0	t0, MACH_COP_0_TLB_HI		# Get current PID
2311
2312	sll	a0, a0, VMMACH_TLB_INDEX_SHIFT
2313	mtc0	a0, MACH_COP_0_TLB_INDEX	# Set the index register
2314	nop
2315	tlbr					# Read from the TLB
2316	mfc0	t3, MACH_COP_0_TLB_HI		# fetch the hi entry
2317	mfc0	t4, MACH_COP_0_TLB_LOW		# fetch the low entry
2318	sw	t3, tlbhi
2319	sw	t4, tlblo
2320
2321	mtc0	t0, MACH_COP_0_TLB_HI		# restore PID
2322	j	ra
2323	mtc0	v1, MACH_COP_0_STATUS_REG	# Restore the status register
2324END(MachTLBRead)
2325
2326/*--------------------------------------------------------------------------
2327 *
2328 * MachTLBGetPID --
2329 *
2330 *	MachTLBGetPID()
2331 *
2332 * Results:
2333 *	Returns the current TLB pid reg.
2334 *
2335 * Side effects:
2336 *	None.
2337 *
2338 *--------------------------------------------------------------------------
2339 */
2340LEAF(MachTLBGetPID)
2341	mfc0	v0, MACH_COP_0_TLB_HI		# get PID
2342	nop
2343	and	v0, v0, VMMACH_TLB_PID		# mask off PID
2344	j	ra
2345	srl	v0, v0, VMMACH_TLB_PID_SHIFT	# put PID in right spot
2346END(MachTLBGetPID)
2347
2348/*
2349 * Return the current value of the cause register.
2350 */
2351LEAF(MachGetCauseReg)
2352	mfc0	v0, MACH_COP_0_CAUSE_REG
2353	j	ra
2354	nop
2355END(MachGetCauseReg)
2356#endif /* DEBUG */
2357
2358/*----------------------------------------------------------------------------
2359 *
2360 * MachSwitchFPState --
2361 *
2362 *	Save the current state into 'from' and restore it from 'to'.
2363 *
2364 *	MachSwitchFPState(from, to)
2365 *		struct proc *from;
2366 *		struct user *to;
2367 *
2368 * Results:
2369 *	None.
2370 *
2371 * Side effects:
2372 *	None.
2373 *
2374 *----------------------------------------------------------------------------
2375 */
2376LEAF(MachSwitchFPState)
2377	mfc0	t1, MACH_COP_0_STATUS_REG	# Save old SR
2378	li	t0, MACH_SR_COP_1_BIT		# enable the coprocessor
2379	mtc0	t0, MACH_COP_0_STATUS_REG
2380
2381	beq	a0, zero, 1f			# skip save if NULL pointer
2382	nop
2383/*
2384 * First read out the status register to make sure that all FP operations
2385 * have completed.
2386 */
2387	lw	a0, P_ADDR(a0)			# get pointer to pcb for proc
2388	cfc1	t0, MACH_FPC_CSR		# stall til FP done
2389	cfc1	t0, MACH_FPC_CSR		# now get status
2390	li	t3, ~MACH_SR_COP_1_BIT
2391	lw	t2, U_PCB_REGS+(PS * 4)(a0)	# get CPU status register
2392	sw	t0, U_PCB_FPREGS+(32 * 4)(a0)	# save FP status
2393	and	t2, t2, t3			# clear COP_1 enable bit
2394	sw	t2, U_PCB_REGS+(PS * 4)(a0)	# save new status register
2395/*
2396 * Save the floating point registers.
2397 */
2398	swc1	$f0, U_PCB_FPREGS+(0 * 4)(a0)
2399	swc1	$f1, U_PCB_FPREGS+(1 * 4)(a0)
2400	swc1	$f2, U_PCB_FPREGS+(2 * 4)(a0)
2401	swc1	$f3, U_PCB_FPREGS+(3 * 4)(a0)
2402	swc1	$f4, U_PCB_FPREGS+(4 * 4)(a0)
2403	swc1	$f5, U_PCB_FPREGS+(5 * 4)(a0)
2404	swc1	$f6, U_PCB_FPREGS+(6 * 4)(a0)
2405	swc1	$f7, U_PCB_FPREGS+(7 * 4)(a0)
2406	swc1	$f8, U_PCB_FPREGS+(8 * 4)(a0)
2407	swc1	$f9, U_PCB_FPREGS+(9 * 4)(a0)
2408	swc1	$f10, U_PCB_FPREGS+(10 * 4)(a0)
2409	swc1	$f11, U_PCB_FPREGS+(11 * 4)(a0)
2410	swc1	$f12, U_PCB_FPREGS+(12 * 4)(a0)
2411	swc1	$f13, U_PCB_FPREGS+(13 * 4)(a0)
2412	swc1	$f14, U_PCB_FPREGS+(14 * 4)(a0)
2413	swc1	$f15, U_PCB_FPREGS+(15 * 4)(a0)
2414	swc1	$f16, U_PCB_FPREGS+(16 * 4)(a0)
2415	swc1	$f17, U_PCB_FPREGS+(17 * 4)(a0)
2416	swc1	$f18, U_PCB_FPREGS+(18 * 4)(a0)
2417	swc1	$f19, U_PCB_FPREGS+(19 * 4)(a0)
2418	swc1	$f20, U_PCB_FPREGS+(20 * 4)(a0)
2419	swc1	$f21, U_PCB_FPREGS+(21 * 4)(a0)
2420	swc1	$f22, U_PCB_FPREGS+(22 * 4)(a0)
2421	swc1	$f23, U_PCB_FPREGS+(23 * 4)(a0)
2422	swc1	$f24, U_PCB_FPREGS+(24 * 4)(a0)
2423	swc1	$f25, U_PCB_FPREGS+(25 * 4)(a0)
2424	swc1	$f26, U_PCB_FPREGS+(26 * 4)(a0)
2425	swc1	$f27, U_PCB_FPREGS+(27 * 4)(a0)
2426	swc1	$f28, U_PCB_FPREGS+(28 * 4)(a0)
2427	swc1	$f29, U_PCB_FPREGS+(29 * 4)(a0)
2428	swc1	$f30, U_PCB_FPREGS+(30 * 4)(a0)
2429	swc1	$f31, U_PCB_FPREGS+(31 * 4)(a0)
2430
24311:
2432/*
2433 *  Restore the floating point registers.
2434 */
2435	lw	t0, U_PCB_FPREGS+(32 * 4)(a1)	# get status register
2436	lwc1	$f0, U_PCB_FPREGS+(0 * 4)(a1)
2437	lwc1	$f1, U_PCB_FPREGS+(1 * 4)(a1)
2438	lwc1	$f2, U_PCB_FPREGS+(2 * 4)(a1)
2439	lwc1	$f3, U_PCB_FPREGS+(3 * 4)(a1)
2440	lwc1	$f4, U_PCB_FPREGS+(4 * 4)(a1)
2441	lwc1	$f5, U_PCB_FPREGS+(5 * 4)(a1)
2442	lwc1	$f6, U_PCB_FPREGS+(6 * 4)(a1)
2443	lwc1	$f7, U_PCB_FPREGS+(7 * 4)(a1)
2444	lwc1	$f8, U_PCB_FPREGS+(8 * 4)(a1)
2445	lwc1	$f9, U_PCB_FPREGS+(9 * 4)(a1)
2446	lwc1	$f10, U_PCB_FPREGS+(10 * 4)(a1)
2447	lwc1	$f11, U_PCB_FPREGS+(11 * 4)(a1)
2448	lwc1	$f12, U_PCB_FPREGS+(12 * 4)(a1)
2449	lwc1	$f13, U_PCB_FPREGS+(13 * 4)(a1)
2450	lwc1	$f14, U_PCB_FPREGS+(14 * 4)(a1)
2451	lwc1	$f15, U_PCB_FPREGS+(15 * 4)(a1)
2452	lwc1	$f16, U_PCB_FPREGS+(16 * 4)(a1)
2453	lwc1	$f17, U_PCB_FPREGS+(17 * 4)(a1)
2454	lwc1	$f18, U_PCB_FPREGS+(18 * 4)(a1)
2455	lwc1	$f19, U_PCB_FPREGS+(19 * 4)(a1)
2456	lwc1	$f20, U_PCB_FPREGS+(20 * 4)(a1)
2457	lwc1	$f21, U_PCB_FPREGS+(21 * 4)(a1)
2458	lwc1	$f22, U_PCB_FPREGS+(22 * 4)(a1)
2459	lwc1	$f23, U_PCB_FPREGS+(23 * 4)(a1)
2460	lwc1	$f24, U_PCB_FPREGS+(24 * 4)(a1)
2461	lwc1	$f25, U_PCB_FPREGS+(25 * 4)(a1)
2462	lwc1	$f26, U_PCB_FPREGS+(26 * 4)(a1)
2463	lwc1	$f27, U_PCB_FPREGS+(27 * 4)(a1)
2464	lwc1	$f28, U_PCB_FPREGS+(28 * 4)(a1)
2465	lwc1	$f29, U_PCB_FPREGS+(29 * 4)(a1)
2466	lwc1	$f30, U_PCB_FPREGS+(30 * 4)(a1)
2467	lwc1	$f31, U_PCB_FPREGS+(31 * 4)(a1)
2468
2469	and	t0, t0, ~MACH_FPC_EXCEPTION_BITS
2470	ctc1	t0, MACH_FPC_CSR
2471	nop
2472
2473	mtc0	t1, MACH_COP_0_STATUS_REG	# Restore the status register.
2474	j	ra
2475	nop
2476END(MachSwitchFPState)
2477
2478/*----------------------------------------------------------------------------
2479 *
2480 * MachSaveCurFPState --
2481 *
2482 *	Save the current floating point coprocessor state.
2483 *
2484 *	MachSaveCurFPState(p)
2485 *		struct proc *p;
2486 *
2487 * Results:
2488 *	None.
2489 *
2490 * Side effects:
2491 *	machFPCurProcPtr is cleared.
2492 *
2493 *----------------------------------------------------------------------------
2494 */
2495LEAF(MachSaveCurFPState)
2496	lw	a0, P_ADDR(a0)			# get pointer to pcb for proc
2497	mfc0	t1, MACH_COP_0_STATUS_REG	# Disable interrupts and
2498	li	t0, MACH_SR_COP_1_BIT		#  enable the coprocessor
2499	mtc0	t0, MACH_COP_0_STATUS_REG
2500	sw	zero, machFPCurProcPtr		# indicate state has been saved
2501/*
2502 * First read out the status register to make sure that all FP operations
2503 * have completed.
2504 */
2505	lw	t2, U_PCB_REGS+(PS * 4)(a0)	# get CPU status register
2506	li	t3, ~MACH_SR_COP_1_BIT
2507	and	t2, t2, t3			# clear COP_1 enable bit
2508	cfc1	t0, MACH_FPC_CSR		# stall til FP done
2509	cfc1	t0, MACH_FPC_CSR		# now get status
2510	sw	t2, U_PCB_REGS+(PS * 4)(a0)	# save new status register
2511	sw	t0, U_PCB_FPREGS+(32 * 4)(a0)	# save FP status
2512/*
2513 * Save the floating point registers.
2514 */
2515	swc1	$f0, U_PCB_FPREGS+(0 * 4)(a0)
2516	swc1	$f1, U_PCB_FPREGS+(1 * 4)(a0)
2517	swc1	$f2, U_PCB_FPREGS+(2 * 4)(a0)
2518	swc1	$f3, U_PCB_FPREGS+(3 * 4)(a0)
2519	swc1	$f4, U_PCB_FPREGS+(4 * 4)(a0)
2520	swc1	$f5, U_PCB_FPREGS+(5 * 4)(a0)
2521	swc1	$f6, U_PCB_FPREGS+(6 * 4)(a0)
2522	swc1	$f7, U_PCB_FPREGS+(7 * 4)(a0)
2523	swc1	$f8, U_PCB_FPREGS+(8 * 4)(a0)
2524	swc1	$f9, U_PCB_FPREGS+(9 * 4)(a0)
2525	swc1	$f10, U_PCB_FPREGS+(10 * 4)(a0)
2526	swc1	$f11, U_PCB_FPREGS+(11 * 4)(a0)
2527	swc1	$f12, U_PCB_FPREGS+(12 * 4)(a0)
2528	swc1	$f13, U_PCB_FPREGS+(13 * 4)(a0)
2529	swc1	$f14, U_PCB_FPREGS+(14 * 4)(a0)
2530	swc1	$f15, U_PCB_FPREGS+(15 * 4)(a0)
2531	swc1	$f16, U_PCB_FPREGS+(16 * 4)(a0)
2532	swc1	$f17, U_PCB_FPREGS+(17 * 4)(a0)
2533	swc1	$f18, U_PCB_FPREGS+(18 * 4)(a0)
2534	swc1	$f19, U_PCB_FPREGS+(19 * 4)(a0)
2535	swc1	$f20, U_PCB_FPREGS+(20 * 4)(a0)
2536	swc1	$f21, U_PCB_FPREGS+(21 * 4)(a0)
2537	swc1	$f22, U_PCB_FPREGS+(22 * 4)(a0)
2538	swc1	$f23, U_PCB_FPREGS+(23 * 4)(a0)
2539	swc1	$f24, U_PCB_FPREGS+(24 * 4)(a0)
2540	swc1	$f25, U_PCB_FPREGS+(25 * 4)(a0)
2541	swc1	$f26, U_PCB_FPREGS+(26 * 4)(a0)
2542	swc1	$f27, U_PCB_FPREGS+(27 * 4)(a0)
2543	swc1	$f28, U_PCB_FPREGS+(28 * 4)(a0)
2544	swc1	$f29, U_PCB_FPREGS+(29 * 4)(a0)
2545	swc1	$f30, U_PCB_FPREGS+(30 * 4)(a0)
2546	swc1	$f31, U_PCB_FPREGS+(31 * 4)(a0)
2547
2548	mtc0	t1, MACH_COP_0_STATUS_REG	# Restore the status register.
2549	j	ra
2550	nop
2551END(MachSaveCurFPState)
2552
2553/*----------------------------------------------------------------------------
2554 *
2555 * MachFPInterrupt --
2556 *
2557 *	Handle a floating point interrupt.
2558 *
2559 *	MachFPInterrupt(statusReg, causeReg, pc)
2560 *		unsigned statusReg;
2561 *		unsigned causeReg;
2562 *		unsigned pc;
2563 *
2564 * Results:
2565 *	None.
2566 *
2567 * Side effects:
2568 *	None.
2569 *
2570 *----------------------------------------------------------------------------
2571 */
2572NON_LEAF(MachFPInterrupt, STAND_FRAME_SIZE, ra)
2573	subu	sp, sp, STAND_FRAME_SIZE
2574	mfc0	t0, MACH_COP_0_STATUS_REG
2575	sw	ra, STAND_RA_OFFSET(sp)
2576	.mask	0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
2577
2578	or	t1, t0, MACH_SR_COP_1_BIT
2579	mtc0	t1, MACH_COP_0_STATUS_REG
2580	nop
2581	nop
2582	cfc1	t1, MACH_FPC_CSR	# stall til FP done
2583	cfc1	t1, MACH_FPC_CSR	# now get status
2584	nop
2585	sll	t2, t1, (31 - 17)	# unimplemented operation?
2586	bgez	t2, 3f			# no, normal trap
2587	nop
2588/*
2589 * We got an unimplemented operation trap so
2590 * fetch the instruction, compute the next PC and emulate the instruction.
2591 */
2592	bgez	a1, 1f			# Check the branch delay bit.
2593	nop
2594/*
2595 * The instruction is in the branch delay slot so the branch will have to
2596 * be emulated to get the resulting PC.
2597 */
2598	sw	a2, STAND_FRAME_SIZE + 8(sp)
2599	li	a0, UADDR+U_PCB_REGS	# first arg is ptr to CPU registers
2600	move	a1, a2			# second arg is instruction PC
2601	move	a2, t1			# third arg is floating point CSR
2602	jal	MachEmulateBranch	# compute PC after branch
2603	move	a3, zero		# fourth arg is FALSE
2604/*
2605 * Now load the floating-point instruction in the branch delay slot
2606 * to be emulated.
2607 */
2608	lw	a2, STAND_FRAME_SIZE + 8(sp)	# restore EXC pc
2609	b	2f
2610	lw	a0, 4(a2)			# a0 = coproc instruction
2611/*
2612 * This is not in the branch delay slot so calculate the resulting
2613 * PC (epc + 4) into v0 and continue to MachEmulateFP().
2614 */
26151:
2616	lw	a0, 0(a2)			# a0 = coproc instruction
2617	addu	v0, a2, 4			# v0 = next pc
26182:
2619	sw	v0, UADDR+U_PCB_REGS+(PC * 4)	# save new pc
2620/*
2621 * Check to see if the instruction to be emulated is a floating-point
2622 * instruction.
2623 */
2624	srl	a3, a0, MACH_OPCODE_SHIFT
2625	beq	a3, MACH_OPCODE_C1, 4f		# this should never fail
2626/*
2627 * Send a floating point exception signal to the current process.
2628 */
26293:
2630	lw	a0, curproc			# get current process
2631	cfc1	a2, MACH_FPC_CSR		# code = FP execptions
2632	ctc1	zero, MACH_FPC_CSR		# Clear exceptions
2633	jal	trapsignal
2634	li	a1, SIGFPE
2635	b	FPReturn
2636	nop
2637
2638/*
2639 * Finally, we can call MachEmulateFP() where a0 is the instruction to emulate.
2640 */
26414:
2642	jal	MachEmulateFP
2643	nop
2644
2645/*
2646 * Turn off the floating point coprocessor and return.
2647 */
2648FPReturn:
2649	mfc0	t0, MACH_COP_0_STATUS_REG
2650	lw	ra, STAND_RA_OFFSET(sp)
2651	and	t0, t0, ~MACH_SR_COP_1_BIT
2652	mtc0	t0, MACH_COP_0_STATUS_REG
2653	j	ra
2654	addu	sp, sp, STAND_FRAME_SIZE
2655END(MachFPInterrupt)
2656
2657/*----------------------------------------------------------------------------
2658 *
2659 * MachConfigCache --
2660 *
2661 *	Size the caches.
2662 *	NOTE: should only be called from mach_init().
2663 *
2664 * Results:
2665 *     	None.
2666 *
2667 * Side effects:
2668 *	The size of the data cache is stored into machDataCacheSize and the
2669 *	size of instruction cache is stored into machInstCacheSize.
2670 *
2671 *----------------------------------------------------------------------------
2672 */
2673NON_LEAF(MachConfigCache, STAND_FRAME_SIZE, ra)
2674	subu	sp, sp, STAND_FRAME_SIZE
2675	sw	ra, STAND_RA_OFFSET(sp)		# Save return address.
2676	.mask	0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
2677	mtc0	zero, MACH_COP_0_STATUS_REG	# Disable interrupts.
2678	la	v0, 1f
2679	or	v0, MACH_UNCACHED_MEMORY_ADDR	# Run uncached.
2680	j	v0
2681	nop
26821:
2683/*
2684 * This works because jal doesn't change pc[31..28] and the
2685 * linker still thinks SizeCache is in the cached region so it computes
2686 * the correct address without complaining.
2687 */
2688	jal	SizeCache			# Get the size of the d-cache.
2689	nop
2690	sw	v0, machDataCacheSize
2691	nop					# Make sure sw out of pipe
2692	nop
2693	nop
2694	nop
2695	li	v0, MACH_SR_SWAP_CACHES		# Swap caches
2696	mtc0	v0, MACH_COP_0_STATUS_REG
2697	nop					# Insure caches stable
2698	nop
2699	nop
2700	nop
2701	jal	SizeCache			# Get the size of the i-cache.
2702	nop
2703	mtc0	zero, MACH_COP_0_STATUS_REG	# Swap back caches and enable.
2704	nop
2705	nop
2706	nop
2707	nop
2708	sw	v0, machInstCacheSize
2709	la	t0, 1f
2710	j	t0				# Back to cached mode
2711	nop
27121:
2713	lw	ra, STAND_RA_OFFSET(sp)		# Restore return addr
2714	addu	sp, sp, STAND_FRAME_SIZE	# Restore sp.
2715	j	ra
2716	nop
2717END(MachConfigCache)
2718
2719/*----------------------------------------------------------------------------
2720 *
2721 * SizeCache --
2722 *
2723 *	Get the size of the cache.
2724 *
2725 * Results:
2726 *	The size of the cache.
2727 *
2728 * Side effects:
2729 *	None.
2730 *
2731 *----------------------------------------------------------------------------
2732 */
2733LEAF(SizeCache)
2734	mfc0	t0, MACH_COP_0_STATUS_REG	# Save the current status reg.
2735	nop
2736	or	v0, t0, MACH_SR_ISOL_CACHES	# Isolate the caches.
2737	nop					# Make sure no stores in pipe
2738	mtc0	v0, MACH_COP_0_STATUS_REG
2739	nop					# Make sure isolated
2740	nop
2741	nop
2742/*
2743 * Clear cache size boundaries.
2744 */
2745	li	v0, MACH_MIN_CACHE_SIZE
2746	li	v1, MACH_CACHED_MEMORY_ADDR
2747	li	t2, MACH_MAX_CACHE_SIZE
27481:
2749	addu	t1, v0, v1			# Compute address to clear
2750	sw	zero, 0(t1)			# Clear cache memory
2751	bne	v0, t2, 1b
2752	sll	v0, v0, 1
2753
2754	li	v0, -1
2755	sw	v0, 0(v1)			# Store marker in cache
2756	li	v0, MACH_MIN_CACHE_SIZE
27572:
2758	addu	t1, v0, v1			# Compute address
2759	lw	t3, 0(t1)			# Look for marker
2760	nop
2761	bne	t3, zero, 3f			# Found marker.
2762	nop
2763	bne	v0, t2, 2b			# keep looking
2764	sll	v0, v0, 1			# cache size * 2
2765
2766	move	v0, zero			# must be no cache
27673:
2768	mtc0	t0, MACH_COP_0_STATUS_REG
2769	nop					# Make sure unisolated
2770	nop
2771	nop
2772	nop
2773	j	ra
2774	nop
2775END(SizeCache)
2776
2777/*----------------------------------------------------------------------------
2778 *
2779 * MachFlushCache --
2780 *
2781 *	Flush the caches.
2782 *
2783 * Results:
2784 *	None.
2785 *
2786 * Side effects:
2787 *	The contents of the caches is flushed.
2788 *
2789 *----------------------------------------------------------------------------
2790 */
2791LEAF(MachFlushCache)
2792	lw	t1, machInstCacheSize		# Must load before isolating
2793	lw	t2, machDataCacheSize		# Must load before isolating
2794	mfc0	t3, MACH_COP_0_STATUS_REG 	# Save the status register.
2795	mtc0	zero, MACH_COP_0_STATUS_REG	# Disable interrupts.
2796	la	v0, 1f
2797	or	v0, MACH_UNCACHED_MEMORY_ADDR	# Run uncached.
2798	j	v0
2799	nop
2800/*
2801 * Flush the instruction cache.
2802 */
28031:
2804	li	v0, MACH_SR_ISOL_CACHES | MACH_SR_SWAP_CACHES
2805	mtc0	v0, MACH_COP_0_STATUS_REG	# Isolate and swap caches.
2806	li	t0, MACH_UNCACHED_MEMORY_ADDR
2807	subu	t0, t0, t1
2808	li	t1, MACH_UNCACHED_MEMORY_ADDR
2809	la	v0, 1f				# Run cached
2810	j	v0
2811	nop
28121:
2813	addu	t0, t0, 4
2814	bne	t0, t1, 1b
2815	sb	zero, -4(t0)
2816
2817	la	v0, 1f
2818	or	v0, MACH_UNCACHED_MEMORY_ADDR
2819	j	v0				# Run uncached
2820	nop
2821/*
2822 * Flush the data cache.
2823 */
28241:
2825	li	v0, MACH_SR_ISOL_CACHES
2826	mtc0	v0, MACH_COP_0_STATUS_REG	# Isolate and swap back caches
2827	li	t0, MACH_UNCACHED_MEMORY_ADDR
2828	subu	t0, t0, t2
2829	la	v0, 1f
2830	j	v0				# Back to cached mode
2831	nop
28321:
2833	addu	t0, t0, 4
2834	bne	t0, t1, 1b
2835	sb	zero, -4(t0)
2836
2837	nop					# Insure isolated stores
2838	nop					#   out of pipe.
2839	nop
2840	nop
2841	mtc0	t3, MACH_COP_0_STATUS_REG	# Restore status reg.
2842	nop					# Insure cache unisolated.
2843	nop
2844	nop
2845	nop
2846	j	ra
2847	nop
2848END(MachFlushCache)
2849
2850/*----------------------------------------------------------------------------
2851 *
2852 * MachFlushICache --
2853 *
2854 *	void MachFlushICache(addr, len)
2855 *		vm_offset_t addr, len;
2856 *
2857 *	Flush instruction cache for range of addr to addr + len - 1.
2858 *	The address can be any valid address so long as no TLB misses occur.
2859 *
2860 * Results:
2861 *	None.
2862 *
2863 * Side effects:
2864 *	The contents of the cache is flushed.
2865 *
2866 *----------------------------------------------------------------------------
2867 */
2868LEAF(MachFlushICache)
2869	mfc0	t0, MACH_COP_0_STATUS_REG	# Save SR
2870	mtc0	zero, MACH_COP_0_STATUS_REG	# Disable interrupts.
2871
2872	la	v1, 1f
2873	or	v1, MACH_UNCACHED_MEMORY_ADDR	# Run uncached.
2874	j	v1
2875	nop
28761:
2877	bc0f	1b				# make sure stores are complete
2878	li	v1, MACH_SR_ISOL_CACHES | MACH_SR_SWAP_CACHES
2879	mtc0	v1, MACH_COP_0_STATUS_REG
2880	nop
2881	addu	a1, a1, a0			# compute ending address
28821:
2883	addu	a0, a0, 4
2884	bne	a0, a1, 1b
2885	sb	zero, -4(a0)
2886
2887	mtc0	t0, MACH_COP_0_STATUS_REG	# enable interrupts
2888	j	ra				# return and run cached
2889	nop
2890END(MachFlushICache)
2891
2892/*----------------------------------------------------------------------------
2893 *
2894 * MachFlushDCache --
2895 *
2896 *	void MachFlushDCache(addr, len)
2897 *		vm_offset_t addr, len;
2898 *
2899 *	Flush data cache for range of addr to addr + len - 1.
2900 *	The address can be any valid address so long as no TLB misses occur.
2901 *	(Be sure to use cached K0SEG kernel addresses)
2902 * Results:
2903 *	None.
2904 *
2905 * Side effects:
2906 *	The contents of the cache is flushed.
2907 *
2908 *----------------------------------------------------------------------------
2909 */
2910LEAF(MachFlushDCache)
2911	mfc0	t0, MACH_COP_0_STATUS_REG	# Save SR
2912	mtc0	zero, MACH_COP_0_STATUS_REG	# Disable interrupts.
2913
2914	la	v1, 1f
2915	or	v1, MACH_UNCACHED_MEMORY_ADDR	# Run uncached.
2916	j	v1
2917	nop
29181:
2919	bc0f	1b				# make sure stores are complete
2920	li	v1, MACH_SR_ISOL_CACHES
2921	mtc0	v1, MACH_COP_0_STATUS_REG
2922	nop
2923	addu	a1, a1, a0			# compute ending address
29241:
2925	addu	a0, a0, 4
2926	bne	a0, a1, 1b
2927	sb	zero, -4(a0)
2928
2929	mtc0	t0, MACH_COP_0_STATUS_REG	# enable interrupts
2930	j	ra				# return and run cached
2931	nop
2932END(MachFlushDCache)
2933
2934#ifdef KADB
2935/*
2936 * Read a long and return it.
2937 * Note: addresses can be unaligned!
2938 *
2939 * long
2940L* kdbpeek(addr)
2941L*	caddt_t addr;
2942L* {
2943L*	return (*(long *)addr);
2944L* }
2945 */
2946LEAF(kdbpeek)
2947	li	v0, KADBERR
2948	sw	v0, UADDR+U_PCB_ONFAULT
2949	and	v0, a0, 3		# unaligned address?
2950	bne	v0, zero, 1f
2951	nop
2952	b	2f
2953	lw	v0, (a0)		# aligned access
29541:
2955	lwr	v0, 0(a0)		# get next 4 bytes (unaligned)
2956	lwl	v0, 3(a0)
29572:
2958	j	ra			# made it w/o errors
2959	sw	zero, UADDR+U_PCB_ONFAULT
2960kadberr:
2961	li	v0, 1			# trap sends us here
2962	sw	v0, kdbmkfault
2963	j	ra
2964	nop
2965END(kdbpeek)
2966
2967/*
2968 * Write a long to 'addr'.
2969 * Note: addresses can be unaligned!
2970 *
2971L* void
2972L* kdbpoke(addr, value)
2973L*	caddt_t addr;
2974L*	long value;
2975L* {
2976L*	*(long *)addr = value;
2977L* }
2978 */
2979LEAF(kdbpoke)
2980	li	v0, KADBERR
2981	sw	v0, UADDR+U_PCB_ONFAULT
2982	and	v0, a0, 3		# unaligned address?
2983	bne	v0, zero, 1f
2984	nop
2985	b	2f
2986	sw	a1, (a0)		# aligned access
29871:
2988	swr	a1, 0(a0)		# store next 4 bytes (unaligned)
2989	swl	a1, 3(a0)
2990	and	a0, a0, ~3		# align address for cache flush
29912:
2992	sw	zero, UADDR+U_PCB_ONFAULT
2993	b	MachFlushICache		# flush instruction cache
2994	li	a1, 8
2995END(kdbpoke)
2996
2997/*
2998 * Save registers and state so we can do a 'kdbreset' (like longjmp) later.
2999 * Always returns zero.
3000 *
3001L* int kdb_savearea[11];
3002L*
3003L* int
3004L* kdbsetexit()
3005L* {
3006L*	kdb_savearea[0] = 0;
3007L*	return (0);
3008L* }
3009 */
3010	.comm	kdb_savearea, (11 * 4)
3011
3012LEAF(kdbsetexit)
3013	la	a0, kdb_savearea
3014	sw	s0, 0(a0)
3015	sw	s1, 4(a0)
3016	sw	s2, 8(a0)
3017	sw	s3, 12(a0)
3018	sw	s4, 16(a0)
3019	sw	s5, 20(a0)
3020	sw	s6, 24(a0)
3021	sw	s7, 28(a0)
3022	sw	sp, 32(a0)
3023	sw	s8, 36(a0)
3024	sw	ra, 40(a0)
3025	j	ra
3026	move	v0, zero
3027END(kdbsetexit)
3028
3029/*
3030 * Restore registers and state (like longjmp) and return x.
3031 *
3032L* int
3033L* kdbreset(x)
3034L* {
3035L*	return (x);
3036L* }
3037 */
3038LEAF(kdbreset)
3039	la	v0, kdb_savearea
3040	lw	ra, 40(v0)
3041	lw	s0, 0(v0)
3042	lw	s1, 4(v0)
3043	lw	s2, 8(v0)
3044	lw	s3, 12(v0)
3045	lw	s4, 16(v0)
3046	lw	s5, 20(v0)
3047	lw	s6, 24(v0)
3048	lw	s7, 28(v0)
3049	lw	sp, 32(v0)
3050	lw	s8, 36(v0)
3051	j	ra
3052	move	v0, a0
3053END(kdbreset)
3054
3055/*
3056 * Trap into the debugger.
3057 *
3058L* void
3059L* kdbpanic()
3060L* {
3061L* }
3062 */
3063LEAF(kdbpanic)
3064	break	MACH_BREAK_KDB_VAL
3065	j	ra
3066	nop
3067END(kdbpanic)
3068#endif /* KADB */
3069
3070#ifdef DEBUG
3071LEAF(cpu_getregs)
3072	sw	sp, 0(a0)
3073	sw	ra, 4(a0)
3074	j	ra
3075	sw	s8, 8(a0)
3076END(cpu_getregs)
3077#endif /* DEBUG */
3078
3079/*
3080 * Interrupt counters for vmstat.
3081 * XXX These aren't used yet.
3082 */
3083	.data
3084	.globl	intrcnt, eintrcnt, intrnames, eintrnames
3085intrnames:
3086	.asciiz	"spur"
3087	.asciiz	"hil"
3088	.asciiz	"lev2"
3089	.asciiz	"lev3"
3090	.asciiz	"lev4"
3091	.asciiz	"lev5"
3092	.asciiz	"dma"
3093	.asciiz	"clock"
3094	.asciiz	"statclock"
3095	.asciiz	"nmi"
3096eintrnames:
3097	.align	2
3098intrcnt:
3099	.word	0,0,0,0,0,0,0,0,0,0
3100eintrcnt:
3101