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