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