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