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