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