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