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