xref: /original-bsd/sys/news3400/news3400/locore.s (revision 3c66dbce)
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.3 (Berkeley) 09/23/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_switch().
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_switch() 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 * The following primitives manipulate the run queues.  _whichqs tells which
776 * of the 32 queues _qs have processes in them.  Setrunqueue puts processes
777 * into queues, Remrq removes them from queues.  The running process is on
778 * no queue, other processes are on a queue related to p->p_priority, divided
779 * by 4 actually to shrink the 0-127 range of priorities into the 32 available
780 * queues.
781 */
782/*
783 * setrunqueue(p)
784 *	proc *p;
785 *
786 * Call should be made at splclock(), and p->p_stat should be SRUN.
787 */
788NON_LEAF(setrunqueue, STAND_FRAME_SIZE, ra)
789	subu	sp, sp, STAND_FRAME_SIZE
790	.mask	0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
791	lw	t0, P_BACK(a0)		## firewall: p->p_back must be 0
792	sw	ra, STAND_RA_OFFSET(sp)	##
793	beq	t0, zero, 1f		##
794	PANIC("setrunqueue")		##
7951:
796	lbu	t0, P_PRIORITY(a0)	# put on p->p_priority / 4 queue
797	srl	t0, t0, 2		# compute index into 'whichqs'
798	li	t1, 1			# compute corresponding bit
799	sll	t1, t1, t0
800	lw	t2, whichqs		# set corresponding bit
801	or	t2, t2, t1
802	sw	t2, whichqs
803	sll	t0, t0, 3		# compute index into 'qs'
804	la	t1, qs
805	addu	t0, t0, t1		# t0 = qp = &qs[pri >> 2]
806	lw	t1, P_BACK(t0)		# t1 = qp->ph_rlink
807	sw	t0, P_FORW(a0)		# p->p_forw = qp
808	sw	t1, P_BACK(a0)		# p->p_back = qp->ph_rlink
809	sw	a0, P_FORW(t1)		# p->p_back->p_forw = p;
810	sw	a0, P_BACK(t0)		# qp->ph_rlink = p
811	addu	sp, sp, STAND_FRAME_SIZE
812	j	ra
813END(setrunqueue)
814
815/*
816 * Remrq(p)
817 *
818 * Call should be made at splclock().
819 */
820NON_LEAF(remrq, STAND_FRAME_SIZE, ra)
821	subu	sp, sp, STAND_FRAME_SIZE
822	.mask	0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
823	lbu	t0, P_PRIORITY(a0)	# get from p->p_priority / 4 queue
824	srl	t0, t0, 2		# compute index into 'whichqs'
825	li	t1, 1			# compute corresponding bit
826	sll	t1, t1, t0
827	lw	t2, whichqs		# check corresponding bit
828	and	v0, t2, t1
829	sw	ra, STAND_RA_OFFSET(sp)	##
830	bne	v0, zero, 1f		##
831	PANIC("remrq")			## it wasn't recorded to be on its q
8321:
833	lw	v0, P_BACK(a0)		# v0 = p->p_back
834	lw	v1, P_FORW(a0)		# v1 = p->p_forw
835	sw	v1, P_FORW(v0)		# p->p_back->p_forw = p->p_forw;
836	sw	v0, P_BACK(v1)		# p->p_forw->p_back = p->r_rlink
837	sll	t0, t0, 3		# compute index into 'qs'
838	la	v0, qs
839	addu	t0, t0, v0		# t0 = qp = &qs[pri >> 2]
840	lw	v0, P_FORW(t0)		# check if queue empty
841	bne	v0, t0, 2f		# No. qp->ph_link != qp
842	xor	t2, t2, t1		# clear corresponding bit in 'whichqs'
843	sw	t2, whichqs
8442:
845	sw	zero, P_BACK(a0)	## for firewall checking
846	addu	sp, sp, STAND_FRAME_SIZE
847	j	ra
848END(remrq)
849
850/*
851 * switch_exit()
852 *
853 * At exit of a process, do a cpu_switch for the last time.  The mapping
854 * of the pcb at p->p_addr has already been deleted, and the memory for
855 * the pcb+stack has been freed.  All interrupts should be blocked at this
856 * point.
857 */
858LEAF(switch_exit)
859	.set	noreorder
860	la	v1, nullproc			# save state into garbage proc
861	lw	t0, P_UPTE+0(v1)		# t0 = first u. pte
862	lw	t1, P_UPTE+4(v1)		# t1 = 2nd u. pte
863	li	v0, UADDR			# v0 = first HI entry
864	mtc0	zero, MACH_COP_0_TLB_INDEX	# set the index register
865	mtc0	v0, MACH_COP_0_TLB_HI		# init high entry
866	mtc0	t0, MACH_COP_0_TLB_LOW		# init low entry
867	li	t0, 1 << VMMACH_TLB_INDEX_SHIFT
868	tlbwi					# Write the TLB entry.
869	addu	v0, v0, NBPG			# 2nd HI entry
870	mtc0	t0, MACH_COP_0_TLB_INDEX	# set the index register
871	mtc0	v0, MACH_COP_0_TLB_HI		# init high entry
872	mtc0	t1, MACH_COP_0_TLB_LOW		# init low entry
873	sw	zero, curproc
874	tlbwi					# Write the TLB entry.
875	.set	reorder
876	li	sp, KERNELSTACK - START_FRAME	# switch to standard stack
877	b	cpu_switch
878END(switch_exit)
879
880/*
881 * When no processes are on the runq, cpu_switch branches to idle to wait
882 * for something to come ready.  Note: this is really a part of cpu_switch()
883 * but defined here for kernel profiling.
884 */
885LEAF(idle)
886	.set	noreorder
887	li	t0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR)
888	mtc0	t0, MACH_COP_0_STATUS_REG	# enable all interrupts
889	sw	zero, curproc			# set curproc NULL for stats
8901:
891	lw	t0, whichqs			# look for non-empty queue
892	nop
893	beq	t0, zero, 1b
894	nop
895	b	sw1
896	mtc0	zero, MACH_COP_0_STATUS_REG	# Disable all interrupts
897	.set	reorder
898END(idle)
899
900/*
901 * cpu_switch()
902 * Find the highest priority process and resume it.
903 */
904NON_LEAF(cpu_switch, STAND_FRAME_SIZE, ra)
905	.set	noreorder
906	sw	sp, UADDR+U_PCB_CONTEXT+32	# save old sp
907	subu	sp, sp, STAND_FRAME_SIZE
908	sw	ra, STAND_RA_OFFSET(sp)
909	.mask	0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
910	lw	t2, cnt+V_SWTCH			# for statistics
911	lw	t1, whichqs			# look for non-empty queue
912	sw	s0, UADDR+U_PCB_CONTEXT+0	# do a 'savectx()'
913	sw	s1, UADDR+U_PCB_CONTEXT+4
914	sw	s2, UADDR+U_PCB_CONTEXT+8
915	sw	s3, UADDR+U_PCB_CONTEXT+12
916	mfc0	t0, MACH_COP_0_STATUS_REG	# t0 = saved status register
917	sw	s4, UADDR+U_PCB_CONTEXT+16
918	sw	s5, UADDR+U_PCB_CONTEXT+20
919	sw	s6, UADDR+U_PCB_CONTEXT+24
920	sw	s7, UADDR+U_PCB_CONTEXT+28
921	sw	s8, UADDR+U_PCB_CONTEXT+36
922	sw	ra, UADDR+U_PCB_CONTEXT+40	# save return address
923	sw	t0, UADDR+U_PCB_CONTEXT+44	# save status register
924	addu	t2, t2, 1
925	sw	t2, cnt+V_SWTCH
926	beq	t1, zero, idle			# if none, idle
927	mtc0	zero, MACH_COP_0_STATUS_REG	# Disable all interrupts
928sw1:
929	nop					# wait for intrs disabled
930	nop
931	lw	t0, whichqs			# look for non-empty queue
932	li	t2, -1				# t2 = lowest bit set
933	beq	t0, zero, idle			# if none, idle
934	move	t3, t0				# t3 = saved whichqs
9351:
936	add	t2, t2, 1
937	and	t1, t0, 1			# bit set?
938	beq	t1, zero, 1b
939	srl	t0, t0, 1			# try next bit
940/*
941 * Remove process from queue.
942 */
943	sll	t0, t2, 3
944	la	t1, qs
945	addu	t0, t0, t1			# t0 = qp = &qs[highbit]
946	lw	a0, P_FORW(t0)			# a0 = p = highest pri process
947	nop
948	lw	v0, P_FORW(a0)			# v0 = p->p_forw
949	bne	t0, a0, 2f			# make sure something in queue
950	sw	v0, P_FORW(t0)			# qp->ph_link = p->p_forw;
951	PANIC("cpu_switch")			# nothing in queue
9522:
953	sw	t0, P_BACK(v0)			# p->p_forw->p_back = qp
954	bne	v0, t0, 3f			# queue still not empty
955	sw	zero, P_BACK(a0)		## for firewall checking
956	li	v1, 1				# compute bit in 'whichqs'
957	sll	v1, v1, t2
958	xor	t3, t3, v1			# clear bit in 'whichqs'
959	sw	t3, whichqs
9603:
961/*
962 * Switch to new context.
963 */
964	sw	zero, want_resched
965	jal	pmap_alloc_tlbpid		# v0 = TLB PID
966	move	s0, a0				# save p
967	move	a0, s0				# restore p
968	sw	a0, curproc			# set curproc
969	sll	v0, v0, VMMACH_TLB_PID_SHIFT	# v0 = aligned PID
970	lw	t0, P_UPTE+0(a0)		# t0 = first u. pte
971	lw	t1, P_UPTE+4(a0)		# t1 = 2nd u. pte
972	or	v0, v0, UADDR			# v0 = first HI entry
973/*
974 * Resume process indicated by the pte's for its u struct
975 * NOTE: This is hard coded to UPAGES == 2.
976 * Also, there should be no TLB faults at this point.
977 */
978	mtc0	zero, MACH_COP_0_TLB_INDEX	# set the index register
979	mtc0	v0, MACH_COP_0_TLB_HI		# init high entry
980	mtc0	t0, MACH_COP_0_TLB_LOW		# init low entry
981	li	t0, 1 << VMMACH_TLB_INDEX_SHIFT
982	tlbwi					# Write the TLB entry.
983	addu	v0, v0, NBPG			# 2nd HI entry
984	mtc0	t0, MACH_COP_0_TLB_INDEX	# set the index register
985	mtc0	v0, MACH_COP_0_TLB_HI		# init high entry
986	mtc0	t1, MACH_COP_0_TLB_LOW		# init low entry
987	nop
988	tlbwi					# Write the TLB entry.
989/*
990 * Now running on new u struct.
991 * Restore registers and return.
992 */
993	lw	v0, UADDR+U_PCB_CONTEXT+44	# restore kernel context
994	lw	ra, UADDR+U_PCB_CONTEXT+40
995	lw	s0, UADDR+U_PCB_CONTEXT+0
996	lw	s1, UADDR+U_PCB_CONTEXT+4
997	lw	s2, UADDR+U_PCB_CONTEXT+8
998	lw	s3, UADDR+U_PCB_CONTEXT+12
999	lw	s4, UADDR+U_PCB_CONTEXT+16
1000	lw	s5, UADDR+U_PCB_CONTEXT+20
1001	lw	s6, UADDR+U_PCB_CONTEXT+24
1002	lw	s7, UADDR+U_PCB_CONTEXT+28
1003	lw	sp, UADDR+U_PCB_CONTEXT+32
1004	lw	s8, UADDR+U_PCB_CONTEXT+36
1005	mtc0	v0, MACH_COP_0_STATUS_REG
1006	j	ra
1007	li	v0, 1				# possible return to 'savectx()'
1008	.set	reorder
1009END(cpu_switch)
1010
1011/*
1012 * {fu,su},{ibyte,isword,iword}, fetch or store a byte, short or word to
1013 * user text space.
1014 * {fu,su},{byte,sword,word}, fetch or store a byte, short or word to
1015 * user data space.
1016 */
1017LEAF(fuword)
1018ALEAF(fuiword)
1019	li	v0, FSWBERR
1020	blt	a0, zero, fswberr	# make sure address is in user space
1021	sw	v0, UADDR+U_PCB_ONFAULT
1022	lw	v0, 0(a0)		# fetch word
1023	sw	zero, UADDR+U_PCB_ONFAULT
1024	j	ra
1025END(fuword)
1026
1027LEAF(fusword)
1028ALEAF(fuisword)
1029	li	v0, FSWBERR
1030	blt	a0, zero, fswberr	# make sure address is in user space
1031	sw	v0, UADDR+U_PCB_ONFAULT
1032	lhu	v0, 0(a0)		# fetch short
1033	sw	zero, UADDR+U_PCB_ONFAULT
1034	j	ra
1035END(fusword)
1036
1037LEAF(fubyte)
1038ALEAF(fuibyte)
1039	li	v0, FSWBERR
1040	blt	a0, zero, fswberr	# make sure address is in user space
1041	sw	v0, UADDR+U_PCB_ONFAULT
1042	lbu	v0, 0(a0)		# fetch byte
1043	sw	zero, UADDR+U_PCB_ONFAULT
1044	j	ra
1045END(fubyte)
1046
1047LEAF(suword)
1048	li	v0, FSWBERR
1049	blt	a0, zero, fswberr	# make sure address is in user space
1050	sw	v0, UADDR+U_PCB_ONFAULT
1051	sw	a1, 0(a0)		# store word
1052	sw	zero, UADDR+U_PCB_ONFAULT
1053	move	v0, zero
1054	j	ra
1055END(suword)
1056
1057/*
1058 * Have to flush instruction cache afterwards.
1059 */
1060LEAF(suiword)
1061	li	v0, FSWBERR
1062	blt	a0, zero, fswberr	# make sure address is in user space
1063	sw	v0, UADDR+U_PCB_ONFAULT
1064	sw	a1, 0(a0)		# store word
1065	sw	zero, UADDR+U_PCB_ONFAULT
1066	move	v0, zero
1067	li	a1, 4			# size of word
1068	b	MachFlushICache		# NOTE: this should not clobber v0!
1069END(suiword)
1070
1071/*
1072 * Will have to flush the instruction cache if byte merging is done in hardware.
1073 */
1074LEAF(susword)
1075ALEAF(suisword)
1076	li	v0, FSWBERR
1077	blt	a0, zero, fswberr	# make sure address is in user space
1078	sw	v0, UADDR+U_PCB_ONFAULT
1079	sh	a1, 0(a0)		# store short
1080	sw	zero, UADDR+U_PCB_ONFAULT
1081	move	v0, zero
1082	j	ra
1083END(susword)
1084
1085LEAF(subyte)
1086ALEAF(suibyte)
1087	li	v0, FSWBERR
1088	blt	a0, zero, fswberr	# make sure address is in user space
1089	sw	v0, UADDR+U_PCB_ONFAULT
1090	sb	a1, 0(a0)		# store byte
1091	sw	zero, UADDR+U_PCB_ONFAULT
1092	move	v0, zero
1093	j	ra
1094END(subyte)
1095
1096LEAF(fswberr)
1097	li	v0, -1
1098	j	ra
1099END(fswberr)
1100
1101/*
1102 * fuswintr and suswintr are just like fusword and susword except that if
1103 * the page is not in memory or would cause a trap, then we return an error.
1104 * The important thing is to prevent sleep() and switching.
1105 */
1106LEAF(fuswintr)
1107	li	v0, FSWINTRBERR
1108	blt	a0, zero, fswintrberr	# make sure address is in user space
1109	sw	v0, UADDR+U_PCB_ONFAULT
1110	lhu	v0, 0(a0)		# fetch short
1111	sw	zero, UADDR+U_PCB_ONFAULT
1112	j	ra
1113END(fuswintr)
1114
1115LEAF(suswintr)
1116	li	v0, FSWINTRBERR
1117	blt	a0, zero, fswintrberr	# make sure address is in user space
1118	sw	v0, UADDR+U_PCB_ONFAULT
1119	sh	a1, 0(a0)		# store short
1120	sw	zero, UADDR+U_PCB_ONFAULT
1121	move	v0, zero
1122	j	ra
1123END(suswintr)
1124
1125LEAF(fswintrberr)
1126	li	v0, -1
1127	j	ra
1128END(fswintrberr)
1129
1130/*
1131 * Insert 'p' after 'q'.
1132 *	_insque(p, q)
1133 *		caddr_t p, q;
1134 */
1135LEAF(_insque)
1136	lw	v0, 0(a1)		# v0 = q->next
1137	sw	a1, 4(a0)		# p->prev = q
1138	sw	v0, 0(a0)		# p->next = q->next
1139	sw	a0, 4(v0)		# q->next->prev = p
1140	sw	a0, 0(a1)		# q->next = p
1141	j	ra
1142END(_insque)
1143
1144/*
1145 * Remove item 'p' from queue.
1146 *	_remque(p)
1147 *		caddr_t p;
1148 */
1149LEAF(_remque)
1150	lw	v0, 0(a0)		# v0 = p->next
1151	lw	v1, 4(a0)		# v1 = p->prev
1152	sw	v0, 0(v1)		# p->prev->next = p->next
1153	sw	v1, 4(v0)		# p->next->prev = p->prev
1154	j	ra
1155END(_remque)
1156
1157/*
1158 * This code is copied to the UTLB exception vector address to
1159 * handle user level TLB translation misses.
1160 * NOTE: This code must be relocatable!!!
1161 */
1162	.globl	MachUTLBMiss
1163MachUTLBMiss:
1164	.set	noat
1165	.set	noreorder
1166	mfc0	k0, MACH_COP_0_BAD_VADDR	# get the virtual address
1167	lw	k1, UADDR+U_PCB_SEGTAB		# get the current segment table
1168	bltz	k0, 1f				# R3000 chip bug
1169	srl	k0, k0, SEGSHIFT		# compute segment table index
1170	sll	k0, k0, 2
1171	addu	k1, k1, k0
1172	mfc0	k0, MACH_COP_0_BAD_VADDR	# get the virtual address
1173	lw	k1, 0(k1)			# get pointer to segment map
1174	srl	k0, k0, PGSHIFT - 2		# compute segment map index
1175	andi	k0, k0, (NPTEPG - 1) << 2
1176	beq	k1, zero, 2f			# invalid segment map
1177	addu	k1, k1, k0			# index into segment map
1178	lw	k0, 0(k1)			# get page PTE
1179	nop
1180	beq	k0, zero, 2f			# dont load invalid entries
1181	mtc0	k0, MACH_COP_0_TLB_LOW
1182	mfc0	k1, MACH_COP_0_EXC_PC		# get return address
1183	tlbwr					# update TLB
1184	j	k1
1185	rfe
11861:
1187	mfc0	k1, MACH_COP_0_EXC_PC		# get return address
1188	nop
1189	j	k1
1190	rfe
11912:
1192	j	SlowFault			# handle the rest
1193	nop
1194	.set	reorder
1195	.set	at
1196	.globl	MachUTLBMissEnd
1197MachUTLBMissEnd:
1198
1199/*
1200 * This code is copied to the general exception vector address to
1201 * handle all execptions except RESET and UTLBMiss.
1202 * NOTE: This code must be relocatable!!!
1203 */
1204	.globl	MachException
1205MachException:
1206/*
1207 * Find out what mode we came from and jump to the proper handler.
1208 */
1209	.set	noat
1210	.set	noreorder
1211	mfc0	k0, MACH_COP_0_STATUS_REG	# Get the status register
1212	mfc0	k1, MACH_COP_0_CAUSE_REG	# Get the cause register value.
1213	and	k0, k0, MACH_SR_KU_PREV		# test for user mode
1214	sll	k0, k0, 3			# shift user bit for cause index
1215	and	k1, k1, MACH_CR_EXC_CODE	# Mask out the cause bits.
1216	or	k1, k1, k0			# change index to user table
12171:
1218	la	k0, machExceptionTable		# get base of the jump table
1219	addu	k0, k0, k1			# Get the address of the
1220						#  function entry.  Note that
1221						#  the cause is already
1222						#  shifted left by 2 bits so
1223						#  we don't have to shift.
1224	lw	k0, 0(k0)			# Get the function address
1225	nop
1226	j	k0				# Jump to the function.
1227	nop
1228	.set	reorder
1229	.set	at
1230	.globl	MachExceptionEnd
1231MachExceptionEnd:
1232
1233/*
1234 * We couldn't find a TLB entry.
1235 * Find out what mode we came from and call the appropriate handler.
1236 */
1237SlowFault:
1238	.set	noat
1239	.set	noreorder
1240	mfc0	k0, MACH_COP_0_STATUS_REG
1241	nop
1242	and	k0, k0, MACH_SR_KU_PREV
1243	bne	k0, zero, MachUserGenException
1244	nop
1245	.set	reorder
1246	.set	at
1247/*
1248 * Fall though ...
1249 */
1250
1251/*----------------------------------------------------------------------------
1252 *
1253 * MachKernGenException --
1254 *
1255 *	Handle an exception from kernel mode.
1256 *
1257 * Results:
1258 *	None.
1259 *
1260 * Side effects:
1261 *	None.
1262 *
1263 *----------------------------------------------------------------------------
1264 */
1265
1266/*
1267 * The kernel exception stack contains 18 saved general registers,
1268 * the status register and the multiply lo and high registers.
1269 * In addition, we set this up for linkage conventions.
1270 */
1271#define KERN_REG_SIZE		(18 * 4)
1272#define KERN_REG_OFFSET		(STAND_FRAME_SIZE)
1273#define KERN_SR_OFFSET		(STAND_FRAME_SIZE + KERN_REG_SIZE)
1274#define KERN_MULT_LO_OFFSET	(STAND_FRAME_SIZE + KERN_REG_SIZE + 4)
1275#define KERN_MULT_HI_OFFSET	(STAND_FRAME_SIZE + KERN_REG_SIZE + 8)
1276#define	KERN_EXC_FRAME_SIZE	(STAND_FRAME_SIZE + KERN_REG_SIZE + 12)
1277
1278NNON_LEAF(MachKernGenException, KERN_EXC_FRAME_SIZE, ra)
1279	.set	noreorder
1280	.set	noat
1281#ifdef KADB
1282	la	k0, kdbpcb			# save registers for kadb
1283	sw	s0, (S0 * 4)(k0)
1284	sw	s1, (S1 * 4)(k0)
1285	sw	s2, (S2 * 4)(k0)
1286	sw	s3, (S3 * 4)(k0)
1287	sw	s4, (S4 * 4)(k0)
1288	sw	s5, (S5 * 4)(k0)
1289	sw	s6, (S6 * 4)(k0)
1290	sw	s7, (S7 * 4)(k0)
1291	sw	s8, (S8 * 4)(k0)
1292	sw	gp, (GP * 4)(k0)
1293	sw	sp, (SP * 4)(k0)
1294#endif
1295	subu	sp, sp, KERN_EXC_FRAME_SIZE
1296	.mask	0x80000000, (STAND_RA_OFFSET - KERN_EXC_FRAME_SIZE)
1297/*
1298 * Save the relevant kernel registers onto the stack.
1299 * We don't need to save s0 - s8, sp and gp because
1300 * the compiler does it for us.
1301 */
1302	sw	AT, KERN_REG_OFFSET + 0(sp)
1303	sw	v0, KERN_REG_OFFSET + 4(sp)
1304	sw	v1, KERN_REG_OFFSET + 8(sp)
1305	sw	a0, KERN_REG_OFFSET + 12(sp)
1306	mflo	v0
1307	mfhi	v1
1308	sw	a1, KERN_REG_OFFSET + 16(sp)
1309	sw	a2, KERN_REG_OFFSET + 20(sp)
1310	sw	a3, KERN_REG_OFFSET + 24(sp)
1311	sw	t0, KERN_REG_OFFSET + 28(sp)
1312	mfc0	a0, MACH_COP_0_STATUS_REG	# First arg is the status reg.
1313	sw	t1, KERN_REG_OFFSET + 32(sp)
1314	sw	t2, KERN_REG_OFFSET + 36(sp)
1315	sw	t3, KERN_REG_OFFSET + 40(sp)
1316	sw	t4, KERN_REG_OFFSET + 44(sp)
1317	mfc0	a1, MACH_COP_0_CAUSE_REG	# Second arg is the cause reg.
1318	sw	t5, KERN_REG_OFFSET + 48(sp)
1319	sw	t6, KERN_REG_OFFSET + 52(sp)
1320	sw	t7, KERN_REG_OFFSET + 56(sp)
1321	sw	t8, KERN_REG_OFFSET + 60(sp)
1322	mfc0	a2, MACH_COP_0_BAD_VADDR	# Third arg is the fault addr.
1323	sw	t9, KERN_REG_OFFSET + 64(sp)
1324	sw	ra, KERN_REG_OFFSET + 68(sp)
1325	sw	v0, KERN_MULT_LO_OFFSET(sp)
1326	sw	v1, KERN_MULT_HI_OFFSET(sp)
1327	mfc0	a3, MACH_COP_0_EXC_PC		# Fourth arg is the pc.
1328	sw	a0, KERN_SR_OFFSET(sp)
1329/*
1330 * Call the exception handler.
1331 */
1332	jal	trap
1333	sw	a3, STAND_RA_OFFSET(sp)		# for debugging
1334/*
1335 * Restore registers and return from the exception.
1336 * v0 contains the return address.
1337 */
1338	lw	a0, KERN_SR_OFFSET(sp)
1339	lw	t0, KERN_MULT_LO_OFFSET(sp)
1340	lw	t1, KERN_MULT_HI_OFFSET(sp)
1341	mtc0	a0, MACH_COP_0_STATUS_REG	# Restore the SR, disable intrs
1342	mtlo	t0
1343	mthi	t1
1344	move	k0, v0
1345	lw	AT, KERN_REG_OFFSET + 0(sp)
1346	lw	v0, KERN_REG_OFFSET + 4(sp)
1347	lw	v1, KERN_REG_OFFSET + 8(sp)
1348	lw	a0, KERN_REG_OFFSET + 12(sp)
1349	lw	a1, KERN_REG_OFFSET + 16(sp)
1350	lw	a2, KERN_REG_OFFSET + 20(sp)
1351	lw	a3, KERN_REG_OFFSET + 24(sp)
1352	lw	t0, KERN_REG_OFFSET + 28(sp)
1353	lw	t1, KERN_REG_OFFSET + 32(sp)
1354	lw	t2, KERN_REG_OFFSET + 36(sp)
1355	lw	t3, KERN_REG_OFFSET + 40(sp)
1356	lw	t4, KERN_REG_OFFSET + 44(sp)
1357	lw	t5, KERN_REG_OFFSET + 48(sp)
1358	lw	t6, KERN_REG_OFFSET + 52(sp)
1359	lw	t7, KERN_REG_OFFSET + 56(sp)
1360	lw	t8, KERN_REG_OFFSET + 60(sp)
1361	lw	t9, KERN_REG_OFFSET + 64(sp)
1362	lw	ra, KERN_REG_OFFSET + 68(sp)
1363	addu	sp, sp, KERN_EXC_FRAME_SIZE
1364	j	k0				# Now return from the
1365	rfe					#  exception.
1366	.set	at
1367	.set	reorder
1368END(MachKernGenException)
1369	.globl	MachKernGenExceptionEnd
1370MachKernGenExceptionEnd:
1371
1372/*----------------------------------------------------------------------------
1373 *
1374 * MachUserGenException --
1375 *
1376 *	Handle an exception from user mode.
1377 *
1378 * Results:
1379 * 	None.
1380 *
1381 * Side effects:
1382 *	None.
1383 *
1384 *----------------------------------------------------------------------------
1385 */
1386NNON_LEAF(MachUserGenException, STAND_FRAME_SIZE, ra)
1387	.set	noreorder
1388	.set	noat
1389	.mask	0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
1390/*
1391 * Save all of the registers except for the kernel temporaries in u.u_pcb.
1392 */
1393	sw	AT, UADDR+U_PCB_REGS+(AST * 4)
1394	sw	v0, UADDR+U_PCB_REGS+(V0 * 4)
1395	sw	v1, UADDR+U_PCB_REGS+(V1 * 4)
1396	sw	a0, UADDR+U_PCB_REGS+(A0 * 4)
1397	mflo	v0
1398	sw	a1, UADDR+U_PCB_REGS+(A1 * 4)
1399	sw	a2, UADDR+U_PCB_REGS+(A2 * 4)
1400	sw	a3, UADDR+U_PCB_REGS+(A3 * 4)
1401	sw	t0, UADDR+U_PCB_REGS+(T0 * 4)
1402	mfhi	v1
1403	sw	t1, UADDR+U_PCB_REGS+(T1 * 4)
1404	sw	t2, UADDR+U_PCB_REGS+(T2 * 4)
1405	sw	t3, UADDR+U_PCB_REGS+(T3 * 4)
1406	sw	t4, UADDR+U_PCB_REGS+(T4 * 4)
1407	mfc0	a0, MACH_COP_0_STATUS_REG	# First arg is the status reg.
1408	sw	t5, UADDR+U_PCB_REGS+(T5 * 4)
1409	sw	t6, UADDR+U_PCB_REGS+(T6 * 4)
1410	sw	t7, UADDR+U_PCB_REGS+(T7 * 4)
1411	sw	s0, UADDR+U_PCB_REGS+(S0 * 4)
1412	mfc0	a1, MACH_COP_0_CAUSE_REG	# Second arg is the cause reg.
1413	sw	s1, UADDR+U_PCB_REGS+(S1 * 4)
1414	sw	s2, UADDR+U_PCB_REGS+(S2 * 4)
1415	sw	s3, UADDR+U_PCB_REGS+(S3 * 4)
1416	sw	s4, UADDR+U_PCB_REGS+(S4 * 4)
1417	mfc0	a2, MACH_COP_0_BAD_VADDR	# Third arg is the fault addr
1418	sw	s5, UADDR+U_PCB_REGS+(S5 * 4)
1419	sw	s6, UADDR+U_PCB_REGS+(S6 * 4)
1420	sw	s7, UADDR+U_PCB_REGS+(S7 * 4)
1421	sw	t8, UADDR+U_PCB_REGS+(T8 * 4)
1422	mfc0	a3, MACH_COP_0_EXC_PC		# Fourth arg is the pc.
1423	sw	t9, UADDR+U_PCB_REGS+(T9 * 4)
1424	sw	gp, UADDR+U_PCB_REGS+(GP * 4)
1425	sw	sp, UADDR+U_PCB_REGS+(SP * 4)
1426	sw	s8, UADDR+U_PCB_REGS+(S8 * 4)
1427	li	sp, KERNELSTACK - STAND_FRAME_SIZE	# switch to kernel SP
1428	sw	ra, UADDR+U_PCB_REGS+(RA * 4)
1429	sw	v0, UADDR+U_PCB_REGS+(MULLO * 4)
1430	sw	v1, UADDR+U_PCB_REGS+(MULHI * 4)
1431	sw	a0, UADDR+U_PCB_REGS+(SR * 4)
1432	la	gp, _gp				# switch to kernel GP
1433	sw	a3, UADDR+U_PCB_REGS+(PC * 4)
1434	sw	a3, STAND_RA_OFFSET(sp)		# for debugging
1435	and	t0, a0, ~MACH_SR_COP_1_BIT	# Turn off the FPU.
1436/*
1437 * Call the exception handler.
1438 */
1439	jal	trap
1440	mtc0	t0, MACH_COP_0_STATUS_REG
1441/*
1442 * Restore user registers and return. NOTE: interrupts are enabled.
1443 */
1444	lw	a0, UADDR+U_PCB_REGS+(SR * 4)
1445	lw	t0, UADDR+U_PCB_REGS+(MULLO * 4)
1446	lw	t1, UADDR+U_PCB_REGS+(MULHI * 4)
1447	mtc0	a0, MACH_COP_0_STATUS_REG	# this should disable interrupts
1448	mtlo	t0
1449	mthi	t1
1450	lw	k0, UADDR+U_PCB_REGS+(PC * 4)
1451	lw	AT, UADDR+U_PCB_REGS+(AST * 4)
1452	lw	v0, UADDR+U_PCB_REGS+(V0 * 4)
1453	lw	v1, UADDR+U_PCB_REGS+(V1 * 4)
1454	lw	a0, UADDR+U_PCB_REGS+(A0 * 4)
1455	lw	a1, UADDR+U_PCB_REGS+(A1 * 4)
1456	lw	a2, UADDR+U_PCB_REGS+(A2 * 4)
1457	lw	a3, UADDR+U_PCB_REGS+(A3 * 4)
1458	lw	t0, UADDR+U_PCB_REGS+(T0 * 4)
1459	lw	t1, UADDR+U_PCB_REGS+(T1 * 4)
1460	lw	t2, UADDR+U_PCB_REGS+(T2 * 4)
1461	lw	t3, UADDR+U_PCB_REGS+(T3 * 4)
1462	lw	t4, UADDR+U_PCB_REGS+(T4 * 4)
1463	lw	t5, UADDR+U_PCB_REGS+(T5 * 4)
1464	lw	t6, UADDR+U_PCB_REGS+(T6 * 4)
1465	lw	t7, UADDR+U_PCB_REGS+(T7 * 4)
1466	lw	s0, UADDR+U_PCB_REGS+(S0 * 4)
1467	lw	s1, UADDR+U_PCB_REGS+(S1 * 4)
1468	lw	s2, UADDR+U_PCB_REGS+(S2 * 4)
1469	lw	s3, UADDR+U_PCB_REGS+(S3 * 4)
1470	lw	s4, UADDR+U_PCB_REGS+(S4 * 4)
1471	lw	s5, UADDR+U_PCB_REGS+(S5 * 4)
1472	lw	s6, UADDR+U_PCB_REGS+(S6 * 4)
1473	lw	s7, UADDR+U_PCB_REGS+(S7 * 4)
1474	lw	t8, UADDR+U_PCB_REGS+(T8 * 4)
1475	lw	t9, UADDR+U_PCB_REGS+(T9 * 4)
1476	lw	gp, UADDR+U_PCB_REGS+(GP * 4)
1477	lw	sp, UADDR+U_PCB_REGS+(SP * 4)
1478	lw	s8, UADDR+U_PCB_REGS+(S8 * 4)
1479	lw	ra, UADDR+U_PCB_REGS+(RA * 4)
1480	j	k0
1481	rfe
1482	.set	at
1483	.set	reorder
1484END(MachUserGenException)
1485
1486/*----------------------------------------------------------------------------
1487 *
1488 * MachKernIntr --
1489 *
1490 *	Handle an interrupt from kernel mode.
1491 *	Interrupts use the standard kernel stack.
1492 *	switch_exit sets up a kernel stack after exit so interrupts won't fail.
1493 *
1494 * Results:
1495 *	None.
1496 *
1497 * Side effects:
1498 *	None.
1499 *
1500 *----------------------------------------------------------------------------
1501 */
1502#define KINTR_REG_OFFSET	(STAND_FRAME_SIZE)
1503#define KINTR_SR_OFFSET		(STAND_FRAME_SIZE + KERN_REG_SIZE)
1504#define KINTR_MULT_LO_OFFSET	(STAND_FRAME_SIZE + KERN_REG_SIZE + 4)
1505#define KINTR_MULT_HI_OFFSET	(STAND_FRAME_SIZE + KERN_REG_SIZE + 8)
1506#define	KINTR_FRAME_SIZE	(STAND_FRAME_SIZE + KERN_REG_SIZE + 12)
1507
1508NNON_LEAF(MachKernIntr, KINTR_FRAME_SIZE, ra)
1509	.set	noreorder
1510	.set	noat
1511	subu	sp, sp, KINTR_FRAME_SIZE	# allocate stack frame
1512	.mask	0x80000000, (STAND_RA_OFFSET - KINTR_FRAME_SIZE)
1513/*
1514 * Save the relevant kernel registers onto the stack.
1515 * We don't need to save s0 - s8, sp and gp because
1516 * the compiler does it for us.
1517 */
1518	sw	AT, KINTR_REG_OFFSET + 0(sp)
1519	sw	v0, KINTR_REG_OFFSET + 4(sp)
1520	sw	v1, KINTR_REG_OFFSET + 8(sp)
1521	sw	a0, KINTR_REG_OFFSET + 12(sp)
1522	mflo	v0
1523	mfhi	v1
1524	sw	a1, KINTR_REG_OFFSET + 16(sp)
1525	sw	a2, KINTR_REG_OFFSET + 20(sp)
1526	sw	a3, KINTR_REG_OFFSET + 24(sp)
1527	sw	t0, KINTR_REG_OFFSET + 28(sp)
1528	mfc0	a0, MACH_COP_0_STATUS_REG	# First arg is the status reg.
1529	sw	t1, KINTR_REG_OFFSET + 32(sp)
1530	sw	t2, KINTR_REG_OFFSET + 36(sp)
1531	sw	t3, KINTR_REG_OFFSET + 40(sp)
1532	sw	t4, KINTR_REG_OFFSET + 44(sp)
1533	mfc0	a1, MACH_COP_0_CAUSE_REG	# Second arg is the cause reg.
1534	sw	t5, KINTR_REG_OFFSET + 48(sp)
1535	sw	t6, KINTR_REG_OFFSET + 52(sp)
1536	sw	t7, KINTR_REG_OFFSET + 56(sp)
1537	sw	t8, KINTR_REG_OFFSET + 60(sp)
1538	mfc0	a2, MACH_COP_0_EXC_PC		# Third arg is the pc.
1539	sw	t9, KINTR_REG_OFFSET + 64(sp)
1540	sw	ra, KINTR_REG_OFFSET + 68(sp)
1541	sw	v0, KINTR_MULT_LO_OFFSET(sp)
1542	sw	v1, KINTR_MULT_HI_OFFSET(sp)
1543	sw	a0, KINTR_SR_OFFSET(sp)
1544/*
1545 * Call the interrupt handler.
1546 */
1547	jal	interrupt
1548	sw	a2, STAND_RA_OFFSET(sp)		# for debugging
1549/*
1550 * Restore registers and return from the interrupt.
1551 */
1552	lw	a0, KINTR_SR_OFFSET(sp)
1553	lw	t0, KINTR_MULT_LO_OFFSET(sp)
1554	lw	t1, KINTR_MULT_HI_OFFSET(sp)
1555	mtc0	a0, MACH_COP_0_STATUS_REG	# Restore the SR, disable intrs
1556	mtlo	t0
1557	mthi	t1
1558	lw	k0, STAND_RA_OFFSET(sp)
1559	lw	AT, KINTR_REG_OFFSET + 0(sp)
1560	lw	v0, KINTR_REG_OFFSET + 4(sp)
1561	lw	v1, KINTR_REG_OFFSET + 8(sp)
1562	lw	a0, KINTR_REG_OFFSET + 12(sp)
1563	lw	a1, KINTR_REG_OFFSET + 16(sp)
1564	lw	a2, KINTR_REG_OFFSET + 20(sp)
1565	lw	a3, KINTR_REG_OFFSET + 24(sp)
1566	lw	t0, KINTR_REG_OFFSET + 28(sp)
1567	lw	t1, KINTR_REG_OFFSET + 32(sp)
1568	lw	t2, KINTR_REG_OFFSET + 36(sp)
1569	lw	t3, KINTR_REG_OFFSET + 40(sp)
1570	lw	t4, KINTR_REG_OFFSET + 44(sp)
1571	lw	t5, KINTR_REG_OFFSET + 48(sp)
1572	lw	t6, KINTR_REG_OFFSET + 52(sp)
1573	lw	t7, KINTR_REG_OFFSET + 56(sp)
1574	lw	t8, KINTR_REG_OFFSET + 60(sp)
1575	lw	t9, KINTR_REG_OFFSET + 64(sp)
1576	lw	ra, KINTR_REG_OFFSET + 68(sp)
1577	addu	sp, sp, KINTR_FRAME_SIZE
1578	j	k0				# Now return from the
1579	rfe					#  interrupt.
1580	.set	at
1581	.set	reorder
1582END(MachKernIntr)
1583
1584/*----------------------------------------------------------------------------
1585 *
1586 * MachUserIntr --
1587 *
1588 *	Handle an interrupt from user mode.
1589 *	Note: we save minimal state in the u.u_pcb struct and use the standard
1590 *	kernel stack since there has to be a u page if we came from user mode.
1591 *	If there is a pending software interrupt, then save the remaining state
1592 *	and call softintr(). This is all because if we call mi_switch() inside
1593 *	interrupt(), not all the user registers have been saved in u.u_pcb.
1594 *
1595 * Results:
1596 * 	None.
1597 *
1598 * Side effects:
1599 *	None.
1600 *
1601 *----------------------------------------------------------------------------
1602 */
1603NNON_LEAF(MachUserIntr, STAND_FRAME_SIZE, ra)
1604	.set	noreorder
1605	.set	noat
1606	.mask	0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
1607/*
1608 * Save the relevant user registers into the u.u_pcb struct.
1609 * We don't need to save s0 - s8 because
1610 * the compiler does it for us.
1611 */
1612	sw	AT, UADDR+U_PCB_REGS+(AST * 4)
1613	sw	v0, UADDR+U_PCB_REGS+(V0 * 4)
1614	sw	v1, UADDR+U_PCB_REGS+(V1 * 4)
1615	sw	a0, UADDR+U_PCB_REGS+(A0 * 4)
1616	mflo	v0
1617	mfhi	v1
1618	sw	a1, UADDR+U_PCB_REGS+(A1 * 4)
1619	sw	a2, UADDR+U_PCB_REGS+(A2 * 4)
1620	sw	a3, UADDR+U_PCB_REGS+(A3 * 4)
1621	sw	t0, UADDR+U_PCB_REGS+(T0 * 4)
1622	mfc0	a0, MACH_COP_0_STATUS_REG	# First arg is the status reg.
1623	sw	t1, UADDR+U_PCB_REGS+(T1 * 4)
1624	sw	t2, UADDR+U_PCB_REGS+(T2 * 4)
1625	sw	t3, UADDR+U_PCB_REGS+(T3 * 4)
1626	sw	t4, UADDR+U_PCB_REGS+(T4 * 4)
1627	mfc0	a1, MACH_COP_0_CAUSE_REG	# Second arg is the cause reg.
1628	sw	t5, UADDR+U_PCB_REGS+(T5 * 4)
1629	sw	t6, UADDR+U_PCB_REGS+(T6 * 4)
1630	sw	t7, UADDR+U_PCB_REGS+(T7 * 4)
1631	sw	t8, UADDR+U_PCB_REGS+(T8 * 4)
1632	mfc0	a2, MACH_COP_0_EXC_PC		# Third arg is the pc.
1633	sw	t9, UADDR+U_PCB_REGS+(T9 * 4)
1634	sw	gp, UADDR+U_PCB_REGS+(GP * 4)
1635	sw	sp, UADDR+U_PCB_REGS+(SP * 4)
1636	sw	ra, UADDR+U_PCB_REGS+(RA * 4)
1637	li	sp, KERNELSTACK - STAND_FRAME_SIZE	# switch to kernel SP
1638	sw	v0, UADDR+U_PCB_REGS+(MULLO * 4)
1639	sw	v1, UADDR+U_PCB_REGS+(MULHI * 4)
1640	sw	a0, UADDR+U_PCB_REGS+(SR * 4)
1641	sw	a2, UADDR+U_PCB_REGS+(PC * 4)
1642	la	gp, _gp				# switch to kernel GP
1643	and	t0, a0, ~MACH_SR_COP_1_BIT	# Turn off the FPU.
1644	mtc0	t0, MACH_COP_0_STATUS_REG
1645/*
1646 * Call the interrupt handler.
1647 */
1648	jal	interrupt
1649	sw	a2, STAND_RA_OFFSET(sp)		# for debugging
1650/*
1651 * Restore registers and return from the interrupt.
1652 */
1653	lw	a0, UADDR+U_PCB_REGS+(SR * 4)
1654	lw	v0, astpending			# any pending interrupts?
1655	mtc0	a0, MACH_COP_0_STATUS_REG	# Restore the SR, disable intrs
1656	bne	v0, zero, 1f			# don't restore, call softintr
1657	lw	t0, UADDR+U_PCB_REGS+(MULLO * 4)
1658	lw	t1, UADDR+U_PCB_REGS+(MULHI * 4)
1659	lw	k0, UADDR+U_PCB_REGS+(PC * 4)
1660	lw	AT, UADDR+U_PCB_REGS+(AST * 4)
1661	lw	v0, UADDR+U_PCB_REGS+(V0 * 4)
1662	lw	v1, UADDR+U_PCB_REGS+(V1 * 4)
1663	lw	a0, UADDR+U_PCB_REGS+(A0 * 4)
1664	lw	a1, UADDR+U_PCB_REGS+(A1 * 4)
1665	lw	a2, UADDR+U_PCB_REGS+(A2 * 4)
1666	lw	a3, UADDR+U_PCB_REGS+(A3 * 4)
1667	mtlo	t0
1668	mthi	t1
1669	lw	t0, UADDR+U_PCB_REGS+(T0 * 4)
1670	lw	t1, UADDR+U_PCB_REGS+(T1 * 4)
1671	lw	t2, UADDR+U_PCB_REGS+(T2 * 4)
1672	lw	t3, UADDR+U_PCB_REGS+(T3 * 4)
1673	lw	t4, UADDR+U_PCB_REGS+(T4 * 4)
1674	lw	t5, UADDR+U_PCB_REGS+(T5 * 4)
1675	lw	t6, UADDR+U_PCB_REGS+(T6 * 4)
1676	lw	t7, UADDR+U_PCB_REGS+(T7 * 4)
1677	lw	t8, UADDR+U_PCB_REGS+(T8 * 4)
1678	lw	t9, UADDR+U_PCB_REGS+(T9 * 4)
1679	lw	gp, UADDR+U_PCB_REGS+(GP * 4)
1680	lw	sp, UADDR+U_PCB_REGS+(SP * 4)
1681	lw	ra, UADDR+U_PCB_REGS+(RA * 4)
1682	j	k0				# Now return from the
1683	rfe					#  interrupt.
1684
16851:
1686/*
1687 * We have pending software interrupts; save remaining user state in u.u_pcb.
1688 */
1689	sw	s0, UADDR+U_PCB_REGS+(S0 * 4)
1690	sw	s1, UADDR+U_PCB_REGS+(S1 * 4)
1691	sw	s2, UADDR+U_PCB_REGS+(S2 * 4)
1692	sw	s3, UADDR+U_PCB_REGS+(S3 * 4)
1693	sw	s4, UADDR+U_PCB_REGS+(S4 * 4)
1694	sw	s5, UADDR+U_PCB_REGS+(S5 * 4)
1695	sw	s6, UADDR+U_PCB_REGS+(S6 * 4)
1696	sw	s7, UADDR+U_PCB_REGS+(S7 * 4)
1697	sw	s8, UADDR+U_PCB_REGS+(S8 * 4)
1698	li	t0, MACH_HARD_INT_MASK | MACH_SR_INT_ENA_CUR
1699/*
1700 * Call the software interrupt handler.
1701 */
1702	jal	softintr
1703	mtc0	t0, MACH_COP_0_STATUS_REG	# enable interrupts (spl0)
1704/*
1705 * Restore user registers and return. NOTE: interrupts are enabled.
1706 */
1707	lw	a0, UADDR+U_PCB_REGS+(SR * 4)
1708	lw	t0, UADDR+U_PCB_REGS+(MULLO * 4)
1709	lw	t1, UADDR+U_PCB_REGS+(MULHI * 4)
1710	mtc0	a0, MACH_COP_0_STATUS_REG	# this should disable interrupts
1711	mtlo	t0
1712	mthi	t1
1713	lw	k0, UADDR+U_PCB_REGS+(PC * 4)
1714	lw	AT, UADDR+U_PCB_REGS+(AST * 4)
1715	lw	v0, UADDR+U_PCB_REGS+(V0 * 4)
1716	lw	v1, UADDR+U_PCB_REGS+(V1 * 4)
1717	lw	a0, UADDR+U_PCB_REGS+(A0 * 4)
1718	lw	a1, UADDR+U_PCB_REGS+(A1 * 4)
1719	lw	a2, UADDR+U_PCB_REGS+(A2 * 4)
1720	lw	a3, UADDR+U_PCB_REGS+(A3 * 4)
1721	lw	t0, UADDR+U_PCB_REGS+(T0 * 4)
1722	lw	t1, UADDR+U_PCB_REGS+(T1 * 4)
1723	lw	t2, UADDR+U_PCB_REGS+(T2 * 4)
1724	lw	t3, UADDR+U_PCB_REGS+(T3 * 4)
1725	lw	t4, UADDR+U_PCB_REGS+(T4 * 4)
1726	lw	t5, UADDR+U_PCB_REGS+(T5 * 4)
1727	lw	t6, UADDR+U_PCB_REGS+(T6 * 4)
1728	lw	t7, UADDR+U_PCB_REGS+(T7 * 4)
1729	lw	s0, UADDR+U_PCB_REGS+(S0 * 4)
1730	lw	s1, UADDR+U_PCB_REGS+(S1 * 4)
1731	lw	s2, UADDR+U_PCB_REGS+(S2 * 4)
1732	lw	s3, UADDR+U_PCB_REGS+(S3 * 4)
1733	lw	s4, UADDR+U_PCB_REGS+(S4 * 4)
1734	lw	s5, UADDR+U_PCB_REGS+(S5 * 4)
1735	lw	s6, UADDR+U_PCB_REGS+(S6 * 4)
1736	lw	s7, UADDR+U_PCB_REGS+(S7 * 4)
1737	lw	t8, UADDR+U_PCB_REGS+(T8 * 4)
1738	lw	t9, UADDR+U_PCB_REGS+(T9 * 4)
1739	lw	gp, UADDR+U_PCB_REGS+(GP * 4)
1740	lw	sp, UADDR+U_PCB_REGS+(SP * 4)
1741	lw	s8, UADDR+U_PCB_REGS+(S8 * 4)
1742	lw	ra, UADDR+U_PCB_REGS+(RA * 4)
1743	j	k0
1744	rfe
1745	.set	at
1746	.set	reorder
1747END(MachUserIntr)
1748
1749#if 0
1750/*----------------------------------------------------------------------------
1751 *
1752 * MachTLBModException --
1753 *
1754 *	Handle a TLB modified exception.
1755 *	The BaddVAddr, Context, and EntryHi registers contain the failed
1756 *	virtual address.
1757 *
1758 * Results:
1759 *	None.
1760 *
1761 * Side effects:
1762 *	None.
1763 *
1764 *----------------------------------------------------------------------------
1765 */
1766#ifdef NOTDEF
1767NLEAF(MachTLBModException)
1768	.set	noreorder
1769	.set	noat
1770	tlbp					# find the TLB entry
1771	mfc0	k0, MACH_COP_0_TLB_LOW		# get the physical address
1772	mfc0	k1, MACH_COP_0_TLB_INDEX	# check to be sure its valid
1773	or	k0, k0, VMMACH_TLB_MOD_BIT	# update TLB
1774	blt	k1, zero, 4f			# not found!!!
1775	mtc0	k0, MACH_COP_0_TLB_LOW
1776	li	k1, MACH_CACHED_MEMORY_ADDR
1777	subu	k0, k0, k1
1778	srl	k0, k0, VMMACH_TLB_PHYS_PAGE_SHIFT
1779	la	k1, pmap_attributes
1780	add	k0, k0, k1
1781	lbu	k1, 0(k0)			# fetch old value
1782	nop
1783	or	k1, k1, 1			# set modified bit
1784	sb	k1, 0(k0)			# save new value
1785	mfc0	k0, MACH_COP_0_EXC_PC		# get return address
1786	nop
1787	j	k0
1788	rfe
17894:
1790	break	0				# panic
1791	.set	reorder
1792	.set	at
1793END(MachTLBModException)
1794#endif /* NOTDEF */
1795#endif
1796
1797/*----------------------------------------------------------------------------
1798 *
1799 * MachTLBMissException --
1800 *
1801 *	Handle a TLB miss exception from kernel mode.
1802 *	The BaddVAddr, Context, and EntryHi registers contain the failed
1803 *	virtual address.
1804 *
1805 * Results:
1806 *	None.
1807 *
1808 * Side effects:
1809 *	None.
1810 *
1811 *----------------------------------------------------------------------------
1812 */
1813NLEAF(MachTLBMissException)
1814	.set	noreorder
1815	.set	noat
1816	mfc0	k0, MACH_COP_0_BAD_VADDR	# get the fault address
1817	li	k1, VM_MIN_KERNEL_ADDRESS	# compute index
1818	subu	k0, k0, k1
1819	lw	k1, Sysmapsize			# index within range?
1820	srl	k0, k0, PGSHIFT
1821	sltu	k1, k0, k1
1822	beq	k1, zero, 1f			# No. check for valid stack
1823	nop
1824	lw	k1, Sysmap
1825	sll	k0, k0, 2			# compute offset from index
1826	addu	k1, k1, k0
1827	lw	k0, 0(k1)			# get PTE entry
1828	mfc0	k1, MACH_COP_0_EXC_PC		# get return address
1829	mtc0	k0, MACH_COP_0_TLB_LOW		# save PTE entry
1830	and	k0, k0, PG_V			# check for valid entry
1831	beq	k0, zero, MachKernGenException	# PTE invalid
1832	nop
1833	tlbwr					# update TLB
1834	j	k1
1835	rfe
1836
18371:
1838	subu	k0, sp, UADDR + 0x200		# check to see if we have a
1839	sltiu	k0, UPAGES*NBPG - 0x200		#  valid kernel stack
1840	bne	k0, zero, MachKernGenException	# Go panic
1841	nop
1842
1843	la	a0, start - START_FRAME - 8	# set sp to a valid place
1844	sw	sp, 24(a0)
1845	move	sp, a0
1846	la	a0, 1f
1847	mfc0	a2, MACH_COP_0_STATUS_REG
1848	mfc0	a3, MACH_COP_0_CAUSE_REG
1849	mfc0	a1, MACH_COP_0_EXC_PC
1850	sw	a2, 16(sp)
1851	sw	a3, 20(sp)
1852	sw	sp, 24(sp)
1853	move	a2, ra
1854	jal	printf
1855	mfc0	a3, MACH_COP_0_BAD_VADDR
1856	.data
18571:
1858	.asciiz	"ktlbmiss: PC %x RA %x ADR %x\nSR %x CR %x SP %x\n"
1859	.text
1860
1861	la	sp, start - START_FRAME		# set sp to a valid place
1862	PANIC("kernel stack overflow")
1863	.set	reorder
1864	.set	at
1865END(MachTLBMissException)
1866
1867/*
1868 * Set/clear software interrupt routines.
1869 */
1870
1871LEAF(setsoftclock)
1872	.set	noreorder
1873	mfc0	v0, MACH_COP_0_CAUSE_REG	# read cause register
1874	nop
1875	or	v0, v0, MACH_SOFT_INT_MASK_0	# set soft clock interrupt
1876	mtc0	v0, MACH_COP_0_CAUSE_REG	# save it
1877	j	ra
1878	nop
1879	.set	reorder
1880END(setsoftclock)
1881
1882LEAF(clearsoftclock)
1883	.set	noreorder
1884	mfc0	v0, MACH_COP_0_CAUSE_REG	# read cause register
1885	nop
1886	and	v0, v0, ~MACH_SOFT_INT_MASK_0	# clear soft clock interrupt
1887	mtc0	v0, MACH_COP_0_CAUSE_REG	# save it
1888	j	ra
1889	nop
1890	.set	reorder
1891END(clearsoftclock)
1892
1893LEAF(setsoftnet)
1894	.set	noreorder
1895	mfc0	v0, MACH_COP_0_CAUSE_REG	# read cause register
1896	nop
1897	or	v0, v0, MACH_SOFT_INT_MASK_1	# set soft net interrupt
1898	mtc0	v0, MACH_COP_0_CAUSE_REG	# save it
1899	j	ra
1900	nop
1901	.set	reorder
1902END(setsoftnet)
1903
1904LEAF(clearsoftnet)
1905	.set	noreorder
1906	mfc0	v0, MACH_COP_0_CAUSE_REG	# read cause register
1907	nop
1908	and	v0, v0, ~MACH_SOFT_INT_MASK_1	# clear soft net interrupt
1909	mtc0	v0, MACH_COP_0_CAUSE_REG	# save it
1910	j	ra
1911	nop
1912	.set	reorder
1913END(clearsoftnet)
1914
1915/*
1916 * Set/change interrupt priority routines.
1917 */
1918#ifdef NOTDEF
1919LEAF(MachEnableIntr)
1920	.set	noreorder
1921	mfc0	v0, MACH_COP_0_STATUS_REG	# read status register
1922	nop
1923	or	v0, v0, MACH_SR_INT_ENA_CUR
1924	mtc0	v0, MACH_COP_0_STATUS_REG	# enable all interrupts
1925	j	ra
1926	nop
1927	.set	reorder
1928END(MachEnableIntr)
1929#endif /* NOTDEF */
1930
1931#include <sys/cdefs.h>
1932
1933#define	SPL(level) \
1934LEAF(__CONCAT(spl,level)); \
1935	.set	noreorder; \
1936	mfc0	v0, MACH_COP_0_STATUS_REG; \
1937	li	t0, __CONCAT(MACH_SPL_MASK_,level) | MACH_SR_INT_ENA_CUR; \
1938	and	t0, t0, v0; \
1939	j	ra; \
1940	mtc0	t0, MACH_COP_0_STATUS_REG; \
1941	.set	reorder; \
1942END(__CONCAT(spl,level)) \
1943
1944LEAF(spl0)
1945	.set	noreorder
1946	mfc0	v0, MACH_COP_0_STATUS_REG
1947	li	t0, MACH_SPL_MASK_0 | MACH_SR_INT_ENA_CUR
1948	j	ra
1949	mtc0	t0, MACH_COP_0_STATUS_REG
1950	.set	reorder
1951END(spl0)
1952
1953SPL(1); SPL(2); SPL(3); SPL(4); SPL(5); SPL(6); SPL(7)
1954
1955LEAF(spl8)
1956ALEAF(splhigh)
1957ALEAF(_splhigh)
1958	.set	noreorder
1959	mfc0	v0, MACH_COP_0_STATUS_REG
1960	li	t0, MACH_SPL_MASK_8 | MACH_SR_INT_ENA_CUR
1961	j	ra
1962	mtc0	t0, MACH_COP_0_STATUS_REG
1963	.set	reorder
1964END(spl8)
1965
1966/*
1967 * Restore saved interrupt mask.
1968 */
1969LEAF(splx)
1970ALEAF(_splx)
1971	.set	noreorder
1972	mfc0	v0, MACH_COP_0_STATUS_REG
1973	j	ra
1974	mtc0	a0, MACH_COP_0_STATUS_REG
1975	.set	reorder
1976END(splx)
1977
1978/*----------------------------------------------------------------------------
1979 *
1980 * MachEmptyWriteBuffer --
1981 *
1982 *	Return when the write buffer is empty.
1983 *
1984 *	MachEmptyWriteBuffer()
1985 *
1986 * Results:
1987 *	None.
1988 *
1989 * Side effects:
1990 *	None.
1991 *
1992 *----------------------------------------------------------------------------
1993 */
1994LEAF(MachEmptyWriteBuffer)
1995	.set	noreorder
1996	nop
1997	nop
1998	nop
1999	nop
20001:	bc0t	1b
2001	nop
2002	j	ra
2003	nop
2004	.set	reorder
2005END(MachEmptyWriteBuffer)
2006
2007/*--------------------------------------------------------------------------
2008 *
2009 * MachTLBWriteIndexed --
2010 *
2011 *	Write the given entry into the TLB at the given index.
2012 *
2013 *	MachTLBWriteIndexed(index, highEntry, lowEntry)
2014 *		int index;
2015 *		int highEntry;
2016 *		int lowEntry;
2017 *
2018 * Results:
2019 *	None.
2020 *
2021 * Side effects:
2022 *	TLB entry set.
2023 *
2024 *--------------------------------------------------------------------------
2025 */
2026LEAF(MachTLBWriteIndexed)
2027	.set	noreorder
2028	mfc0	v1, MACH_COP_0_STATUS_REG	# Save the status register.
2029	mtc0	zero, MACH_COP_0_STATUS_REG	# Disable interrupts
2030	mfc0	t0, MACH_COP_0_TLB_HI		# Save the current PID.
2031
2032	sll	a0, a0, VMMACH_TLB_INDEX_SHIFT
2033	mtc0	a0, MACH_COP_0_TLB_INDEX	# Set the index.
2034	mtc0	a1, MACH_COP_0_TLB_HI		# Set up entry high.
2035	mtc0	a2, MACH_COP_0_TLB_LOW		# Set up entry low.
2036	nop
2037	tlbwi					# Write the TLB
2038
2039	mtc0	t0, MACH_COP_0_TLB_HI		# Restore the PID.
2040	j	ra
2041	mtc0	v1, MACH_COP_0_STATUS_REG	# Restore the status register
2042	.set	reorder
2043END(MachTLBWriteIndexed)
2044
2045#if 0
2046/*--------------------------------------------------------------------------
2047 *
2048 * MachTLBWriteRandom --
2049 *
2050 *	Write the given entry into the TLB at a random location.
2051 *
2052 *	MachTLBWriteRandom(highEntry, lowEntry)
2053 *		unsigned highEntry;
2054 *		unsigned lowEntry;
2055 *
2056 * Results:
2057 *	None.
2058 *
2059 * Side effects:
2060 *	TLB entry set.
2061 *
2062 *--------------------------------------------------------------------------
2063 */
2064LEAF(MachTLBWriteRandom)
2065	.set	noreorder
2066	mfc0	v1, MACH_COP_0_STATUS_REG	# Save the status register.
2067	mtc0	zero, MACH_COP_0_STATUS_REG	# Disable interrupts
2068	mfc0	v0, MACH_COP_0_TLB_HI		# Save the current PID.
2069	nop
2070
2071	mtc0	a0, MACH_COP_0_TLB_HI		# Set up entry high.
2072	mtc0	a1, MACH_COP_0_TLB_LOW		# Set up entry low.
2073	nop
2074	tlbwr					# Write the TLB
2075
2076	mtc0	v0, MACH_COP_0_TLB_HI		# Restore the PID.
2077	j	ra
2078	mtc0	v1, MACH_COP_0_STATUS_REG	# Restore the status register
2079	.set	reorder
2080END(MachTLBWriteRandom)
2081#endif
2082
2083/*--------------------------------------------------------------------------
2084 *
2085 * MachSetPID --
2086 *
2087 *	Write the given pid into the TLB pid reg.
2088 *
2089 *	MachSetPID(pid)
2090 *		int pid;
2091 *
2092 * Results:
2093 *	None.
2094 *
2095 * Side effects:
2096 *	PID set in the entry hi register.
2097 *
2098 *--------------------------------------------------------------------------
2099 */
2100LEAF(MachSetPID)
2101	.set	noreorder
2102	sll	a0, a0, VMMACH_TLB_PID_SHIFT	# put PID in right spot
2103	mtc0	a0, MACH_COP_0_TLB_HI		# Write the hi reg value
2104	j	ra
2105	nop
2106	.set	reorder
2107END(MachSetPID)
2108
2109/*--------------------------------------------------------------------------
2110 *
2111 * MachTLBFlush --
2112 *
2113 *	Flush the "random" entries from the TLB.
2114 *
2115 *	MachTLBFlush()
2116 *
2117 * Results:
2118 *	None.
2119 *
2120 * Side effects:
2121 *	The TLB is flushed.
2122 *
2123 *--------------------------------------------------------------------------
2124 */
2125LEAF(MachTLBFlush)
2126	.set	noreorder
2127	mfc0	v1, MACH_COP_0_STATUS_REG	# Save the status register.
2128	mtc0	zero, MACH_COP_0_STATUS_REG	# Disable interrupts
2129	mfc0	t0, MACH_COP_0_TLB_HI		# Save the PID
2130	li	t1, MACH_CACHED_MEMORY_ADDR	# invalid address
2131	mtc0	t1, MACH_COP_0_TLB_HI		# Mark entry high as invalid
2132	mtc0	zero, MACH_COP_0_TLB_LOW	# Zero out low entry.
2133/*
2134 * Align the starting value (t1) and the upper bound (t2).
2135 */
2136	li	t1, VMMACH_FIRST_RAND_ENTRY << VMMACH_TLB_INDEX_SHIFT
2137	li	t2, VMMACH_NUM_TLB_ENTRIES << VMMACH_TLB_INDEX_SHIFT
21381:
2139	mtc0	t1, MACH_COP_0_TLB_INDEX	# Set the index register.
2140	addu	t1, t1, 1 << VMMACH_TLB_INDEX_SHIFT	# Increment index.
2141	bne	t1, t2, 1b
2142	tlbwi					# Write the TLB entry.
2143
2144	mtc0	t0, MACH_COP_0_TLB_HI		# Restore the PID
2145	j	ra
2146	mtc0	v1, MACH_COP_0_STATUS_REG	# Restore the status register
2147	.set	reorder
2148END(MachTLBFlush)
2149
2150#if 0
2151/*--------------------------------------------------------------------------
2152 *
2153 * MachTLBFlushPID --
2154 *
2155 *	Flush all entries with the given PID from the TLB.
2156 *
2157 *	MachTLBFlushPID(pid)
2158 *		int pid;
2159 *
2160 * Results:
2161 *	None.
2162 *
2163 * Side effects:
2164 *	All entries corresponding to this PID are flushed.
2165 *
2166 *--------------------------------------------------------------------------
2167 */
2168LEAF(MachTLBFlushPID)
2169	.set	noreorder
2170	mfc0	v1, MACH_COP_0_STATUS_REG	# Save the status register.
2171	mtc0	zero, MACH_COP_0_STATUS_REG	# Disable interrupts
2172	mfc0	t0, MACH_COP_0_TLB_HI		# Save the current PID
2173	sll	a0, a0, VMMACH_TLB_PID_SHIFT	# Align the pid to flush.
2174/*
2175 * Align the starting value (t1) and the upper bound (t2).
2176 */
2177	li	t1, VMMACH_FIRST_RAND_ENTRY << VMMACH_TLB_INDEX_SHIFT
2178	li	t2, VMMACH_NUM_TLB_ENTRIES << VMMACH_TLB_INDEX_SHIFT
2179	mtc0	t1, MACH_COP_0_TLB_INDEX	# Set the index register
21801:
2181	addu	t1, t1, 1 << VMMACH_TLB_INDEX_SHIFT	# Increment index.
2182	tlbr					# Read from the TLB
2183	mfc0	t4, MACH_COP_0_TLB_HI		# Fetch the hi register.
2184	nop
2185	and	t4, t4, VMMACH_TLB_PID		# compare PID's
2186	bne	t4, a0, 2f
2187	li	v0, MACH_CACHED_MEMORY_ADDR	# invalid address
2188	mtc0	v0, MACH_COP_0_TLB_HI		# Mark entry high as invalid
2189	mtc0	zero, MACH_COP_0_TLB_LOW	# Zero out low entry.
2190	nop
2191	tlbwi					# Write the entry.
21922:
2193	bne	t1, t2, 1b
2194	mtc0	t1, MACH_COP_0_TLB_INDEX	# Set the index register
2195
2196	mtc0	t0, MACH_COP_0_TLB_HI		# restore PID
2197	j	ra
2198	mtc0	v1, MACH_COP_0_STATUS_REG	# Restore the status register
2199	.set	reorder
2200END(MachTLBFlushPID)
2201#endif
2202
2203/*--------------------------------------------------------------------------
2204 *
2205 * MachTLBFlushAddr --
2206 *
2207 *	Flush any TLB entries for the given address and TLB PID.
2208 *
2209 *	MachTLBFlushAddr(highreg)
2210 *		unsigned highreg;
2211 *
2212 * Results:
2213 *	None.
2214 *
2215 * Side effects:
2216 *	The process's page is flushed from the TLB.
2217 *
2218 *--------------------------------------------------------------------------
2219 */
2220LEAF(MachTLBFlushAddr)
2221	.set	noreorder
2222	mfc0	v1, MACH_COP_0_STATUS_REG	# Save the status register.
2223	mtc0	zero, MACH_COP_0_STATUS_REG	# Disable interrupts
2224	mfc0	t0, MACH_COP_0_TLB_HI		# Get current PID
2225	nop
2226
2227	mtc0	a0, MACH_COP_0_TLB_HI		# look for addr & PID
2228	nop
2229	tlbp					# Probe for the entry.
2230	mfc0	v0, MACH_COP_0_TLB_INDEX	# See what we got
2231	li	t1, MACH_CACHED_MEMORY_ADDR	# Load invalid entry.
2232	bltz	v0, 1f				# index < 0 => !found
2233	mtc0	t1, MACH_COP_0_TLB_HI		# Mark entry high as invalid
2234	mtc0	zero, MACH_COP_0_TLB_LOW	# Zero out low entry.
2235	nop
2236	tlbwi
22371:
2238	mtc0	t0, MACH_COP_0_TLB_HI		# restore PID
2239	j	ra
2240	mtc0	v1, MACH_COP_0_STATUS_REG	# Restore the status register
2241	.set	reorder
2242END(MachTLBFlushAddr)
2243
2244/*--------------------------------------------------------------------------
2245 *
2246 * MachTLBUpdate --
2247 *
2248 *	Update the TLB if highreg is found; otherwise, enter the data.
2249 *
2250 *	MachTLBUpdate(highreg, lowreg)
2251 *		unsigned highreg, lowreg;
2252 *
2253 * Results:
2254 *	None.
2255 *
2256 * Side effects:
2257 *	None.
2258 *
2259 *--------------------------------------------------------------------------
2260 */
2261LEAF(MachTLBUpdate)
2262	.set	noreorder
2263	mfc0	v1, MACH_COP_0_STATUS_REG	# Save the status register.
2264	mtc0	zero, MACH_COP_0_STATUS_REG	# Disable interrupts
2265	mfc0	t0, MACH_COP_0_TLB_HI		# Save current PID
2266	nop					# 2 cycles before intr disabled
2267	mtc0	a0, MACH_COP_0_TLB_HI		# init high reg.
2268	nop
2269	tlbp					# Probe for the entry.
2270	mfc0	v0, MACH_COP_0_TLB_INDEX	# See what we got
2271	nop
2272	mtc0	a1, MACH_COP_0_TLB_LOW		# init low reg.
2273	nop
2274	bltz	v0, 1f				# index < 0 => !found
2275	sra	v0, v0, VMMACH_TLB_INDEX_SHIFT	# convert index to regular num
2276	b	2f
2277	tlbwi					# update slot found
22781:
2279	mtc0	a0, MACH_COP_0_TLB_HI		# init high reg.
2280	nop
2281	tlbwr					# enter into a random slot
22822:
2283	mtc0	t0, MACH_COP_0_TLB_HI		# restore PID
2284	j	ra
2285	mtc0	v1, MACH_COP_0_STATUS_REG	# Restore the status register
2286	.set	reorder
2287END(MachTLBUpdate)
2288
2289#if defined(DEBUG)
2290/*--------------------------------------------------------------------------
2291 *
2292 * MachTLBFind --
2293 *
2294 *	Search the TLB for the given entry.
2295 *
2296 *	MachTLBFind(hi)
2297 *		unsigned hi;
2298 *
2299 * Results:
2300 *	Returns a value >= 0 if the entry was found (the index).
2301 *	Returns a value < 0 if the entry was not found.
2302 *
2303 * Side effects:
2304 *	tlbhi and tlblo will contain the TLB entry found.
2305 *
2306 *--------------------------------------------------------------------------
2307 */
2308	.comm	tlbhi, 4
2309	.comm	tlblo, 4
2310LEAF(MachTLBFind)
2311	.set	noreorder
2312	mfc0	v1, MACH_COP_0_STATUS_REG	# Save the status register.
2313	mtc0	zero, MACH_COP_0_STATUS_REG	# Disable interrupts
2314	mfc0	t0, MACH_COP_0_TLB_HI		# Get current PID
2315	nop
2316	mtc0	a0, MACH_COP_0_TLB_HI		# Set up entry high.
2317	nop
2318	tlbp					# Probe for the entry.
2319	mfc0	v0, MACH_COP_0_TLB_INDEX	# See what we got
2320	nop
2321	bltz	v0, 1f				# not found
2322	nop
2323	tlbr					# read TLB
2324	mfc0	t1, MACH_COP_0_TLB_HI		# See what we got
2325	mfc0	t2, MACH_COP_0_TLB_LOW		# See what we got
2326	sw	t1, tlbhi
2327	sw	t2, tlblo
2328	srl	v0, v0, VMMACH_TLB_INDEX_SHIFT	# convert index to regular num
23291:
2330	mtc0	t0, MACH_COP_0_TLB_HI		# Restore current PID
2331	j	ra
2332	mtc0	v1, MACH_COP_0_STATUS_REG	# Restore the status register
2333	.set	reorder
2334END(MachTLBFind)
2335
2336/*--------------------------------------------------------------------------
2337 *
2338 * MachTLBRead --
2339 *
2340 *	Read the TLB entry.
2341 *
2342 *	MachTLBRead(entry)
2343 *		unsigned entry;
2344 *
2345 * Results:
2346 *	None.
2347 *
2348 * Side effects:
2349 *	tlbhi and tlblo will contain the TLB entry found.
2350 *
2351 *--------------------------------------------------------------------------
2352 */
2353LEAF(MachTLBRead)
2354	.set	noreorder
2355	mfc0	v1, MACH_COP_0_STATUS_REG	# Save the status register.
2356	mtc0	zero, MACH_COP_0_STATUS_REG	# Disable interrupts
2357	mfc0	t0, MACH_COP_0_TLB_HI		# Get current PID
2358
2359	sll	a0, a0, VMMACH_TLB_INDEX_SHIFT
2360	mtc0	a0, MACH_COP_0_TLB_INDEX	# Set the index register
2361	nop
2362	tlbr					# Read from the TLB
2363	mfc0	t3, MACH_COP_0_TLB_HI		# fetch the hi entry
2364	mfc0	t4, MACH_COP_0_TLB_LOW		# fetch the low entry
2365	sw	t3, tlbhi
2366	sw	t4, tlblo
2367
2368	mtc0	t0, MACH_COP_0_TLB_HI		# restore PID
2369	j	ra
2370	mtc0	v1, MACH_COP_0_STATUS_REG	# Restore the status register
2371	.set	reorder
2372END(MachTLBRead)
2373
2374/*--------------------------------------------------------------------------
2375 *
2376 * MachTLBGetPID --
2377 *
2378 *	MachTLBGetPID()
2379 *
2380 * Results:
2381 *	Returns the current TLB pid reg.
2382 *
2383 * Side effects:
2384 *	None.
2385 *
2386 *--------------------------------------------------------------------------
2387 */
2388#ifdef NOTDEF
2389LEAF(MachTLBGetPID)
2390	.set	noreorder
2391	mfc0	v0, MACH_COP_0_TLB_HI		# get PID
2392	nop
2393	and	v0, v0, VMMACH_TLB_PID		# mask off PID
2394	j	ra
2395	srl	v0, v0, VMMACH_TLB_PID_SHIFT	# put PID in right spot
2396	.set	reorder
2397END(MachTLBGetPID)
2398#endif /* NOTDEF */
2399
2400/*
2401 * Return the current value of the cause register.
2402 */
2403#ifdef NOTDEF
2404LEAF(MachGetCauseReg)
2405	.set	noreorder
2406	mfc0	v0, MACH_COP_0_CAUSE_REG
2407	j	ra
2408	nop
2409	.set	reorder
2410END(MachGetCauseReg)
2411#endif /* NOTDEF */
2412#endif /* DEBUG */
2413
2414/*----------------------------------------------------------------------------
2415 *
2416 * MachSwitchFPState --
2417 *
2418 *	Save the current state into 'from' and restore it from 'to'.
2419 *
2420 *	MachSwitchFPState(from, to)
2421 *		struct proc *from;
2422 *		struct user *to;
2423 *
2424 * Results:
2425 *	None.
2426 *
2427 * Side effects:
2428 *	None.
2429 *
2430 *----------------------------------------------------------------------------
2431 */
2432LEAF(MachSwitchFPState)
2433	.set	noreorder
2434	mfc0	t1, MACH_COP_0_STATUS_REG	# Save old SR
2435	li	t0, MACH_SR_COP_1_BIT		# enable the coprocessor
2436	mtc0	t0, MACH_COP_0_STATUS_REG
2437
2438	beq	a0, zero, 1f			# skip save if NULL pointer
2439	nop
2440/*
2441 * First read out the status register to make sure that all FP operations
2442 * have completed.
2443 */
2444	lw	a0, P_ADDR(a0)			# get pointer to pcb for proc
2445	cfc1	t0, MACH_FPC_CSR		# stall til FP done
2446	cfc1	t0, MACH_FPC_CSR		# now get status
2447	li	t3, ~MACH_SR_COP_1_BIT
2448	lw	t2, U_PCB_REGS+(PS * 4)(a0)	# get CPU status register
2449	sw	t0, U_PCB_FPREGS+(32 * 4)(a0)	# save FP status
2450	and	t2, t2, t3			# clear COP_1 enable bit
2451	sw	t2, U_PCB_REGS+(PS * 4)(a0)	# save new status register
2452/*
2453 * Save the floating point registers.
2454 */
2455	swc1	$f0, U_PCB_FPREGS+(0 * 4)(a0)
2456	swc1	$f1, U_PCB_FPREGS+(1 * 4)(a0)
2457	swc1	$f2, U_PCB_FPREGS+(2 * 4)(a0)
2458	swc1	$f3, U_PCB_FPREGS+(3 * 4)(a0)
2459	swc1	$f4, U_PCB_FPREGS+(4 * 4)(a0)
2460	swc1	$f5, U_PCB_FPREGS+(5 * 4)(a0)
2461	swc1	$f6, U_PCB_FPREGS+(6 * 4)(a0)
2462	swc1	$f7, U_PCB_FPREGS+(7 * 4)(a0)
2463	swc1	$f8, U_PCB_FPREGS+(8 * 4)(a0)
2464	swc1	$f9, U_PCB_FPREGS+(9 * 4)(a0)
2465	swc1	$f10, U_PCB_FPREGS+(10 * 4)(a0)
2466	swc1	$f11, U_PCB_FPREGS+(11 * 4)(a0)
2467	swc1	$f12, U_PCB_FPREGS+(12 * 4)(a0)
2468	swc1	$f13, U_PCB_FPREGS+(13 * 4)(a0)
2469	swc1	$f14, U_PCB_FPREGS+(14 * 4)(a0)
2470	swc1	$f15, U_PCB_FPREGS+(15 * 4)(a0)
2471	swc1	$f16, U_PCB_FPREGS+(16 * 4)(a0)
2472	swc1	$f17, U_PCB_FPREGS+(17 * 4)(a0)
2473	swc1	$f18, U_PCB_FPREGS+(18 * 4)(a0)
2474	swc1	$f19, U_PCB_FPREGS+(19 * 4)(a0)
2475	swc1	$f20, U_PCB_FPREGS+(20 * 4)(a0)
2476	swc1	$f21, U_PCB_FPREGS+(21 * 4)(a0)
2477	swc1	$f22, U_PCB_FPREGS+(22 * 4)(a0)
2478	swc1	$f23, U_PCB_FPREGS+(23 * 4)(a0)
2479	swc1	$f24, U_PCB_FPREGS+(24 * 4)(a0)
2480	swc1	$f25, U_PCB_FPREGS+(25 * 4)(a0)
2481	swc1	$f26, U_PCB_FPREGS+(26 * 4)(a0)
2482	swc1	$f27, U_PCB_FPREGS+(27 * 4)(a0)
2483	swc1	$f28, U_PCB_FPREGS+(28 * 4)(a0)
2484	swc1	$f29, U_PCB_FPREGS+(29 * 4)(a0)
2485	swc1	$f30, U_PCB_FPREGS+(30 * 4)(a0)
2486	swc1	$f31, U_PCB_FPREGS+(31 * 4)(a0)
2487
24881:
2489/*
2490 *  Restore the floating point registers.
2491 */
2492	lw	t0, U_PCB_FPREGS+(32 * 4)(a1)	# get status register
2493	lwc1	$f0, U_PCB_FPREGS+(0 * 4)(a1)
2494	lwc1	$f1, U_PCB_FPREGS+(1 * 4)(a1)
2495	lwc1	$f2, U_PCB_FPREGS+(2 * 4)(a1)
2496	lwc1	$f3, U_PCB_FPREGS+(3 * 4)(a1)
2497	lwc1	$f4, U_PCB_FPREGS+(4 * 4)(a1)
2498	lwc1	$f5, U_PCB_FPREGS+(5 * 4)(a1)
2499	lwc1	$f6, U_PCB_FPREGS+(6 * 4)(a1)
2500	lwc1	$f7, U_PCB_FPREGS+(7 * 4)(a1)
2501	lwc1	$f8, U_PCB_FPREGS+(8 * 4)(a1)
2502	lwc1	$f9, U_PCB_FPREGS+(9 * 4)(a1)
2503	lwc1	$f10, U_PCB_FPREGS+(10 * 4)(a1)
2504	lwc1	$f11, U_PCB_FPREGS+(11 * 4)(a1)
2505	lwc1	$f12, U_PCB_FPREGS+(12 * 4)(a1)
2506	lwc1	$f13, U_PCB_FPREGS+(13 * 4)(a1)
2507	lwc1	$f14, U_PCB_FPREGS+(14 * 4)(a1)
2508	lwc1	$f15, U_PCB_FPREGS+(15 * 4)(a1)
2509	lwc1	$f16, U_PCB_FPREGS+(16 * 4)(a1)
2510	lwc1	$f17, U_PCB_FPREGS+(17 * 4)(a1)
2511	lwc1	$f18, U_PCB_FPREGS+(18 * 4)(a1)
2512	lwc1	$f19, U_PCB_FPREGS+(19 * 4)(a1)
2513	lwc1	$f20, U_PCB_FPREGS+(20 * 4)(a1)
2514	lwc1	$f21, U_PCB_FPREGS+(21 * 4)(a1)
2515	lwc1	$f22, U_PCB_FPREGS+(22 * 4)(a1)
2516	lwc1	$f23, U_PCB_FPREGS+(23 * 4)(a1)
2517	lwc1	$f24, U_PCB_FPREGS+(24 * 4)(a1)
2518	lwc1	$f25, U_PCB_FPREGS+(25 * 4)(a1)
2519	lwc1	$f26, U_PCB_FPREGS+(26 * 4)(a1)
2520	lwc1	$f27, U_PCB_FPREGS+(27 * 4)(a1)
2521	lwc1	$f28, U_PCB_FPREGS+(28 * 4)(a1)
2522	lwc1	$f29, U_PCB_FPREGS+(29 * 4)(a1)
2523	lwc1	$f30, U_PCB_FPREGS+(30 * 4)(a1)
2524	lwc1	$f31, U_PCB_FPREGS+(31 * 4)(a1)
2525
2526	and	t0, t0, ~MACH_FPC_EXCEPTION_BITS
2527	ctc1	t0, MACH_FPC_CSR
2528	nop
2529
2530	mtc0	t1, MACH_COP_0_STATUS_REG	# Restore the status register.
2531	j	ra
2532	nop
2533	.set	reorder
2534END(MachSwitchFPState)
2535
2536/*----------------------------------------------------------------------------
2537 *
2538 * MachSaveCurFPState --
2539 *
2540 *	Save the current floating point coprocessor state.
2541 *
2542 *	MachSaveCurFPState(p)
2543 *		struct proc *p;
2544 *
2545 * Results:
2546 *	None.
2547 *
2548 * Side effects:
2549 *	machFPCurProcPtr is cleared.
2550 *
2551 *----------------------------------------------------------------------------
2552 */
2553LEAF(MachSaveCurFPState)
2554	.set	noreorder
2555	lw	a0, P_ADDR(a0)			# get pointer to pcb for proc
2556	mfc0	t1, MACH_COP_0_STATUS_REG	# Disable interrupts and
2557	li	t0, MACH_SR_COP_1_BIT		#  enable the coprocessor
2558	mtc0	t0, MACH_COP_0_STATUS_REG
2559	sw	zero, machFPCurProcPtr		# indicate state has been saved
2560/*
2561 * First read out the status register to make sure that all FP operations
2562 * have completed.
2563 */
2564	lw	t2, U_PCB_REGS+(PS * 4)(a0)	# get CPU status register
2565	li	t3, ~MACH_SR_COP_1_BIT
2566	and	t2, t2, t3			# clear COP_1 enable bit
2567	cfc1	t0, MACH_FPC_CSR		# stall til FP done
2568	cfc1	t0, MACH_FPC_CSR		# now get status
2569	sw	t2, U_PCB_REGS+(PS * 4)(a0)	# save new status register
2570	sw	t0, U_PCB_FPREGS+(32 * 4)(a0)	# save FP status
2571/*
2572 * Save the floating point registers.
2573 */
2574	swc1	$f0, U_PCB_FPREGS+(0 * 4)(a0)
2575	swc1	$f1, U_PCB_FPREGS+(1 * 4)(a0)
2576	swc1	$f2, U_PCB_FPREGS+(2 * 4)(a0)
2577	swc1	$f3, U_PCB_FPREGS+(3 * 4)(a0)
2578	swc1	$f4, U_PCB_FPREGS+(4 * 4)(a0)
2579	swc1	$f5, U_PCB_FPREGS+(5 * 4)(a0)
2580	swc1	$f6, U_PCB_FPREGS+(6 * 4)(a0)
2581	swc1	$f7, U_PCB_FPREGS+(7 * 4)(a0)
2582	swc1	$f8, U_PCB_FPREGS+(8 * 4)(a0)
2583	swc1	$f9, U_PCB_FPREGS+(9 * 4)(a0)
2584	swc1	$f10, U_PCB_FPREGS+(10 * 4)(a0)
2585	swc1	$f11, U_PCB_FPREGS+(11 * 4)(a0)
2586	swc1	$f12, U_PCB_FPREGS+(12 * 4)(a0)
2587	swc1	$f13, U_PCB_FPREGS+(13 * 4)(a0)
2588	swc1	$f14, U_PCB_FPREGS+(14 * 4)(a0)
2589	swc1	$f15, U_PCB_FPREGS+(15 * 4)(a0)
2590	swc1	$f16, U_PCB_FPREGS+(16 * 4)(a0)
2591	swc1	$f17, U_PCB_FPREGS+(17 * 4)(a0)
2592	swc1	$f18, U_PCB_FPREGS+(18 * 4)(a0)
2593	swc1	$f19, U_PCB_FPREGS+(19 * 4)(a0)
2594	swc1	$f20, U_PCB_FPREGS+(20 * 4)(a0)
2595	swc1	$f21, U_PCB_FPREGS+(21 * 4)(a0)
2596	swc1	$f22, U_PCB_FPREGS+(22 * 4)(a0)
2597	swc1	$f23, U_PCB_FPREGS+(23 * 4)(a0)
2598	swc1	$f24, U_PCB_FPREGS+(24 * 4)(a0)
2599	swc1	$f25, U_PCB_FPREGS+(25 * 4)(a0)
2600	swc1	$f26, U_PCB_FPREGS+(26 * 4)(a0)
2601	swc1	$f27, U_PCB_FPREGS+(27 * 4)(a0)
2602	swc1	$f28, U_PCB_FPREGS+(28 * 4)(a0)
2603	swc1	$f29, U_PCB_FPREGS+(29 * 4)(a0)
2604	swc1	$f30, U_PCB_FPREGS+(30 * 4)(a0)
2605	swc1	$f31, U_PCB_FPREGS+(31 * 4)(a0)
2606
2607	mtc0	t1, MACH_COP_0_STATUS_REG	# Restore the status register.
2608	j	ra
2609	nop
2610	.set	reorder
2611END(MachSaveCurFPState)
2612
2613/*----------------------------------------------------------------------------
2614 *
2615 * MachFPInterrupt --
2616 *
2617 *	Handle a floating point interrupt.
2618 *
2619 *	MachFPInterrupt(statusReg, causeReg, pc)
2620 *		unsigned statusReg;
2621 *		unsigned causeReg;
2622 *		unsigned pc;
2623 *
2624 * Results:
2625 *	None.
2626 *
2627 * Side effects:
2628 *	None.
2629 *
2630 *----------------------------------------------------------------------------
2631 */
2632NON_LEAF(MachFPInterrupt, STAND_FRAME_SIZE, ra)
2633	.set	noreorder
2634	subu	sp, sp, STAND_FRAME_SIZE
2635	mfc0	t0, MACH_COP_0_STATUS_REG
2636	sw	ra, STAND_RA_OFFSET(sp)
2637	.mask	0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
2638
2639	or	t1, t0, MACH_SR_COP_1_BIT
2640	mtc0	t1, MACH_COP_0_STATUS_REG
2641	nop
2642	nop
2643	cfc1	t1, MACH_FPC_CSR	# stall til FP done
2644	cfc1	t1, MACH_FPC_CSR	# now get status
2645	nop
2646	.set	reorder
2647	sll	t2, t1, (31 - 17)	# unimplemented operation?
2648	bgez	t2, 3f			# no, normal trap
2649/*
2650 * We got an unimplemented operation trap so
2651 * fetch the instruction, compute the next PC and emulate the instruction.
2652 */
2653	bgez	a1, 1f			# Check the branch delay bit.
2654/*
2655 * The instruction is in the branch delay slot so the branch will have to
2656 * be emulated to get the resulting PC.
2657 */
2658	sw	a2, STAND_FRAME_SIZE + 8(sp)
2659	li	a0, UADDR+U_PCB_REGS	# first arg is ptr to CPU registers
2660	move	a1, a2			# second arg is instruction PC
2661	move	a2, t1			# third arg is floating point CSR
2662	move	a3, zero		# fourth arg is FALSE
2663	jal	MachEmulateBranch	# compute PC after branch
2664/*
2665 * Now load the floating-point instruction in the branch delay slot
2666 * to be emulated.
2667 */
2668	lw	a2, STAND_FRAME_SIZE + 8(sp)	# restore EXC pc
2669	lw	a0, 4(a2)			# a0 = coproc instruction
2670	b	2f
2671/*
2672 * This is not in the branch delay slot so calculate the resulting
2673 * PC (epc + 4) into v0 and continue to MachEmulateFP().
2674 */
26751:
2676	lw	a0, 0(a2)			# a0 = coproc instruction
2677	addu	v0, a2, 4			# v0 = next pc
26782:
2679	sw	v0, UADDR+U_PCB_REGS+(PC * 4)	# save new pc
2680/*
2681 * Check to see if the instruction to be emulated is a floating-point
2682 * instruction.
2683 */
2684	srl	a3, a0, MACH_OPCODE_SHIFT
2685	beq	a3, MACH_OPCODE_C1, 4f		# this should never fail
2686/*
2687 * Send a floating point exception signal to the current process.
2688 */
26893:
2690	lw	a0, curproc			# get current process
2691	cfc1	a2, MACH_FPC_CSR		# code = FP execptions
2692	li	a1, SIGFPE
2693	ctc1	zero, MACH_FPC_CSR		# Clear exceptions
2694	jal	trapsignal
2695	b	FPReturn
2696
2697/*
2698 * Finally, we can call MachEmulateFP() where a0 is the instruction to emulate.
2699 */
27004:
2701	jal	MachEmulateFP
2702
2703/*
2704 * Turn off the floating point coprocessor and return.
2705 */
2706FPReturn:
2707	.set	noreorder
2708	mfc0	t0, MACH_COP_0_STATUS_REG
2709	lw	ra, STAND_RA_OFFSET(sp)
2710	and	t0, t0, ~MACH_SR_COP_1_BIT
2711	mtc0	t0, MACH_COP_0_STATUS_REG
2712	j	ra
2713	addu	sp, sp, STAND_FRAME_SIZE
2714	.set	reorder
2715END(MachFPInterrupt)
2716
2717/*----------------------------------------------------------------------------
2718 *
2719 * MachConfigCache --
2720 *
2721 *	Size the caches.
2722 *	NOTE: should only be called from mach_init().
2723 *
2724 * Results:
2725 *     	None.
2726 *
2727 * Side effects:
2728 *	The size of the data cache is stored into machDataCacheSize and the
2729 *	size of instruction cache is stored into machInstCacheSize.
2730 *
2731 *----------------------------------------------------------------------------
2732 */
2733NON_LEAF(MachConfigCache, STAND_FRAME_SIZE, ra)
2734	.set	noreorder
2735	subu	sp, sp, STAND_FRAME_SIZE
2736	sw	ra, STAND_RA_OFFSET(sp)		# Save return address.
2737	.mask	0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
2738	mtc0	zero, MACH_COP_0_STATUS_REG	# Disable interrupts.
2739	la	v0, 1f
2740	or	v0, MACH_UNCACHED_MEMORY_ADDR	# Run uncached.
2741	j	v0
2742	nop
27431:
2744/*
2745 * This works because jal doesn't change pc[31..28] and the
2746 * linker still thinks SizeCache is in the cached region so it computes
2747 * the correct address without complaining.
2748 */
2749	jal	SizeCache			# Get the size of the d-cache.
2750	nop
2751	sw	v0, machDataCacheSize
2752	nop					# Make sure sw out of pipe
2753	nop
2754	nop
2755	nop
2756	li	v0, MACH_SR_SWAP_CACHES		# Swap caches
2757	mtc0	v0, MACH_COP_0_STATUS_REG
2758	nop					# Insure caches stable
2759	nop
2760	nop
2761	nop
2762	jal	SizeCache			# Get the size of the i-cache.
2763	nop
2764	sw	v0, machInstCacheSize
2765	nop					# Make sure sw out of pipe
2766	nop
2767	nop
2768	nop
2769	mtc0	zero, MACH_COP_0_STATUS_REG	# Swap back caches.
2770	nop
2771	nop
2772	nop
2773	nop
2774	la	t0, 1f
2775	j	t0				# Back to cached mode
2776	nop
27771:
2778	lw	ra, STAND_RA_OFFSET(sp)		# Restore return addr
2779	addu	sp, sp, STAND_FRAME_SIZE	# Restore sp.
2780	j	ra
2781	nop
2782	.set	reorder
2783END(MachConfigCache)
2784
2785/*----------------------------------------------------------------------------
2786 *
2787 * SizeCache --
2788 *
2789 *	Get the size of the cache.
2790 *
2791 * Results:
2792 *	The size of the cache.
2793 *
2794 * Side effects:
2795 *	None.
2796 *
2797 *----------------------------------------------------------------------------
2798 */
2799LEAF(SizeCache)
2800	.set	noreorder
2801	mfc0	t0, MACH_COP_0_STATUS_REG	# Save the current status reg.
2802	nop
2803	or	v0, t0, MACH_SR_ISOL_CACHES	# Isolate the caches.
2804	nop					# Make sure no stores in pipe
2805	mtc0	v0, MACH_COP_0_STATUS_REG
2806	nop					# Make sure isolated
2807	nop
2808	nop
2809/*
2810 * Clear cache size boundaries.
2811 */
2812	li	v0, MACH_MIN_CACHE_SIZE
28131:
2814	sw	zero, MACH_CACHED_MEMORY_ADDR(v0)	# Clear cache memory
2815	sll	v0, v0, 1
2816	bleu	v0, +MACH_MAX_CACHE_SIZE, 1b
2817	nop
2818	li	v0, -1
2819	sw	v0, MACH_CACHED_MEMORY_ADDR(zero)	# Store marker in cache
2820	li	v0, MACH_MIN_CACHE_SIZE
28212:
2822	lw	v1, MACH_CACHED_MEMORY_ADDR(v0)		# Look for marker
2823	nop
2824	bne	v1, zero, 3f				# Found marker.
2825	nop
2826	sll	v0, v0, 1				# cache size * 2
2827	bleu	v0, +MACH_MAX_CACHE_SIZE, 2b		# keep looking
2828	nop
2829	move	v0, zero				# must be no cache
28303:
2831	mtc0	t0, MACH_COP_0_STATUS_REG
2832	nop						# Make sure unisolated
2833	nop
2834	nop
2835	nop
2836	j	ra
2837	nop
2838	.set	reorder
2839END(SizeCache)
2840
2841/*----------------------------------------------------------------------------
2842 *
2843 * MachFlushCache --
2844 *
2845 *	Flush the caches.
2846 *
2847 * Results:
2848 *	None.
2849 *
2850 * Side effects:
2851 *	The contents of the caches is flushed.
2852 *
2853 *----------------------------------------------------------------------------
2854 */
2855LEAF(MachFlushCache)
2856	.set	noreorder
2857	lw	t1, machInstCacheSize		# Must load before isolating
2858	lw	t2, machDataCacheSize		# Must load before isolating
2859	mfc0	t3, MACH_COP_0_STATUS_REG 	# Save the status register.
2860	mtc0	zero, MACH_COP_0_STATUS_REG	# Disable interrupts.
2861	la	v0, 1f
2862	or	v0, MACH_UNCACHED_MEMORY_ADDR	# Run uncached.
2863	j	v0
2864	nop
2865/*
2866 * Flush the instruction cache.
2867 */
28681:
2869	li	v0, MACH_SR_ISOL_CACHES | MACH_SR_SWAP_CACHES
2870	mtc0	v0, MACH_COP_0_STATUS_REG	# Isolate and swap caches.
2871	li	t0, MACH_UNCACHED_MEMORY_ADDR
2872	subu	t0, t0, t1
2873	li	t1, MACH_UNCACHED_MEMORY_ADDR
2874	la	v0, 1f				# Run cached
2875	j	v0
2876	nop
28771:
2878	addu	t0, t0, 4
2879	bne	t0, t1, 1b
2880	sb	zero, -4(t0)
2881
2882	la	v0, 1f
2883	or	v0, MACH_UNCACHED_MEMORY_ADDR
2884	j	v0				# Run uncached
2885	nop
2886/*
2887 * Flush the data cache.
2888 */
28891:
2890	li	v0, MACH_SR_ISOL_CACHES
2891	mtc0	v0, MACH_COP_0_STATUS_REG	# Isolate and swap back caches
2892	li	t0, MACH_UNCACHED_MEMORY_ADDR
2893	subu	t0, t0, t2
2894	la	v0, 1f
2895	j	v0				# Back to cached mode
2896	nop
28971:
2898	addu	t0, t0, 4
2899	bne	t0, t1, 1b
2900	sb	zero, -4(t0)
2901
2902	nop					# Insure isolated stores
2903	nop					#   out of pipe.
2904	nop
2905	nop
2906	mtc0	t3, MACH_COP_0_STATUS_REG	# Restore status reg.
2907	nop					# Insure cache unisolated.
2908	nop
2909	nop
2910	nop
2911	j	ra
2912	nop
2913	.set	reorder
2914END(MachFlushCache)
2915
2916/*----------------------------------------------------------------------------
2917 *
2918 * MachFlushICache --
2919 *
2920 *	void MachFlushICache(addr, len)
2921 *		vm_offset_t addr, len;
2922 *
2923 *	Flush instruction cache for range of addr to addr + len - 1.
2924 *	The address can be any valid address so long as no TLB misses occur.
2925 *
2926 * Results:
2927 *	None.
2928 *
2929 * Side effects:
2930 *	The contents of the cache is flushed.
2931 *
2932 *----------------------------------------------------------------------------
2933 */
2934LEAF(MachFlushICache)
2935	.set	noreorder
2936	mfc0	t0, MACH_COP_0_STATUS_REG	# Save SR
2937	mtc0	zero, MACH_COP_0_STATUS_REG	# Disable interrupts.
2938
2939	la	v1, 1f
2940	or	v1, MACH_UNCACHED_MEMORY_ADDR	# Run uncached.
2941	j	v1
2942	nop
29431:
2944	bc0t	1b				# make sure stores are complete
2945	li	v1, MACH_SR_ISOL_CACHES | MACH_SR_SWAP_CACHES
2946	mtc0	v1, MACH_COP_0_STATUS_REG
2947	nop
2948	addu	a1, a1, a0			# compute ending address
29491:
2950	addu	a0, a0, 4
2951	bne	a0, a1, 1b
2952	sb	zero, -4(a0)
2953
2954	mtc0	t0, MACH_COP_0_STATUS_REG	# enable interrupts
2955	j	ra				# return and run cached
2956	nop
2957	.set	reorder
2958END(MachFlushICache)
2959
2960#ifndef NOTDEF /* I don't know why Ralph's code doesn't work. KU:XXX */
2961/*----------------------------------------------------------------------------
2962 *
2963 * MachFlushDCache --
2964 *
2965 *	void MachFlushDCache(addr, len)
2966 *		vm_offset_t addr, len;
2967 *
2968 *	Flush data cache for range of addr to addr + len - 1.
2969 *	The address can be any valid address so long as no TLB misses occur.
2970 *
2971 * Results:
2972 *	None.
2973 *
2974 * Side effects:
2975 *	The contents of the cache is flushed.
2976 *
2977 *----------------------------------------------------------------------------
2978 */
2979LEAF(MachFlushDCache)
2980	.set	noreorder
2981	lw	t2, machDataCacheSize		# Must load before isolating
2982	mfc0	t0, MACH_COP_0_STATUS_REG	# Save SR
2983#ifdef notyet /* KU:??? why? */
2984	bltu    a1, t2, 1f			# if (length < cachesize)
2985#endif
2986	mtc0	zero, MACH_COP_0_STATUS_REG	# Disable interrupts.
2987	move    a1, t2				# length = cachesize
29881:
2989	li	v1, MACH_SR_ISOL_CACHES		# isolate dcache
2990	mtc0	v1, MACH_COP_0_STATUS_REG
2991	addu	a1, a1, a0			# compute ending address
2992	nop
29931:
2994	addu	a0, a0, 4
2995	bltu	a0, a1, 1b
2996	sb	zero, -4(a0)
2997
2998	nop					# Insure isolated stores
2999	nop					#   out of pipe.
3000	nop
3001	nop
3002	mtc0	t0, MACH_COP_0_STATUS_REG	# Restore status reg.
3003	nop					# Insure cache unisolated.
3004	nop
3005	nop
3006	nop
3007	j	ra				# return and run cached
3008	nop
3009	.set	reorder
3010END(MachFlushDCache)
3011#else
3012/*----------------------------------------------------------------------------
3013 *
3014 * MachFlushDCache --
3015 *
3016 *	void MachFlushDCache(addr, len)
3017 *		vm_offset_t addr, len;
3018 *
3019 *	Flush data cache for range of addr to addr + len - 1.
3020 *	The address can be any valid address so long as no TLB misses occur.
3021 *	(Be sure to use cached K0SEG kernel addresses)
3022 * Results:
3023 *	None.
3024 *
3025 * Side effects:
3026 *	The contents of the cache is flushed.
3027 *
3028 *----------------------------------------------------------------------------
3029 */
3030LEAF(MachFlushDCache)
3031	.set	noreorder
3032	mfc0	t0, MACH_COP_0_STATUS_REG	# Save SR
3033	mtc0	zero, MACH_COP_0_STATUS_REG	# Disable interrupts.
3034
3035	la	v1, 1f
3036	or	v1, MACH_UNCACHED_MEMORY_ADDR	# Run uncached.
3037	j	v1
3038	nop
30391:
3040	bc0t	1b				# make sure stores are complete
3041	li	v1, MACH_SR_ISOL_CACHES
3042	mtc0	v1, MACH_COP_0_STATUS_REG
3043	nop
3044	addu	a1, a1, a0			# compute ending address
30451:
3046	addu	a0, a0, 4
3047	bne	a0, a1, 1b
3048	sb	zero, -4(a0)
3049
3050	mtc0	t0, MACH_COP_0_STATUS_REG	# enable interrupts
3051	j	ra				# return and run cached
3052	nop
3053	.set	reorder
3054END(MachFlushDCache)
3055#endif /* NOTDEF */
3056
3057#ifdef KADB
3058/*
3059 * Read a long and return it.
3060 * Note: addresses can be unaligned!
3061 *
3062 * long
3063L* kdbpeek(addr)
3064L*	caddt_t addr;
3065L* {
3066L*	return (*(long *)addr);
3067L* }
3068 */
3069#ifdef NOTDEF
3070LEAF(kdbpeek)
3071	li	v0, KADBERR
3072	sw	v0, UADDR+U_PCB_ONFAULT
3073	and	v0, a0, 3		# unaligned address?
3074	bne	v0, zero, 1f
3075	lw	v0, (a0)		# aligned access
3076	b	2f
30771:
3078	LWHI	v0, 0(a0)		# get next 4 bytes (unaligned)
3079	LWLO	v0, 3(a0)
30802:
3081	sw	zero, UADDR+U_PCB_ONFAULT
3082	j	ra			# made it w/o errors
3083kadberr:
3084	li	v0, 1			# trap sends us here
3085	sw	v0, kdbmkfault
3086	j	ra
3087END(kdbpeek)
3088#endif /* NOTDEF */
3089
3090/*
3091 * Write a long to 'addr'.
3092 * Note: addresses can be unaligned!
3093 *
3094L* void
3095L* kdbpoke(addr, value)
3096L*	caddt_t addr;
3097L*	long value;
3098L* {
3099L*	*(long *)addr = value;
3100L* }
3101 */
3102#ifdef NOTDEF
3103LEAF(kdbpoke)
3104	li	v0, KADBERR
3105	sw	v0, UADDR+U_PCB_ONFAULT
3106	and	v0, a0, 3		# unaligned address?
3107	bne	v0, zero, 1f
3108	sw	a1, (a0)		# aligned access
3109	b	2f
31101:
3111	SWHI	a1, 0(a0)		# store next 4 bytes (unaligned)
3112	SWLO	a1, 3(a0)
3113	and	a0, a0, ~3		# align address for cache flush
31142:
3115	sw	zero, UADDR+U_PCB_ONFAULT
3116	li	a1, 8
3117	b	MachFlushICache		# flush instruction cache
3118END(kdbpoke)
3119#endif /* NOTDEF */
3120
3121/*
3122 * Save registers and state so we can do a 'kdbreset' (like longjmp) later.
3123 * Always returns zero.
3124 *
3125L* int kdb_savearea[11];
3126L*
3127L* int
3128L* kdbsetexit()
3129L* {
3130L*	kdb_savearea[0] = 0;
3131L*	return (0);
3132L* }
3133 */
3134	.comm	kdb_savearea, (11 * 4)
3135
3136#ifdef NOTDEF
3137LEAF(kdbsetexit)
3138	.set	noreorder
3139	la	a0, kdb_savearea
3140	sw	s0, 0(a0)
3141	sw	s1, 4(a0)
3142	sw	s2, 8(a0)
3143	sw	s3, 12(a0)
3144	sw	s4, 16(a0)
3145	sw	s5, 20(a0)
3146	sw	s6, 24(a0)
3147	sw	s7, 28(a0)
3148	sw	sp, 32(a0)
3149	sw	s8, 36(a0)
3150	sw	ra, 40(a0)
3151	j	ra
3152	move	v0, zero
3153	.set	reorder
3154END(kdbsetexit)
3155#endif /* NOTDEF */
3156
3157/*
3158 * Restore registers and state (like longjmp) and return x.
3159 *
3160L* int
3161L* kdbreset(x)
3162L* {
3163L*	return (x);
3164L* }
3165 */
3166#ifdef NOTDEF
3167LEAF(kdbreset)
3168	.set	noreorder
3169	la	v0, kdb_savearea
3170	lw	ra, 40(v0)
3171	lw	s0, 0(v0)
3172	lw	s1, 4(v0)
3173	lw	s2, 8(v0)
3174	lw	s3, 12(v0)
3175	lw	s4, 16(v0)
3176	lw	s5, 20(v0)
3177	lw	s6, 24(v0)
3178	lw	s7, 28(v0)
3179	lw	sp, 32(v0)
3180	lw	s8, 36(v0)
3181	j	ra
3182	move	v0, a0
3183	.set	reorder
3184END(kdbreset)
3185#endif /* NOTDEF */
3186
3187/*
3188 * Trap into the debugger.
3189 *
3190L* void
3191L* kdbpanic()
3192L* {
3193L* }
3194 */
3195#ifdef NOTDEF
3196LEAF(kdbpanic)
3197	break	MACH_BREAK_KDB_VAL
3198	j	ra
3199END(kdbpanic)
3200#endif /* NOTDEF */
3201#endif /* KADB */
3202
3203LEAF(to_monitor)
3204	.set	noreorder
3205#ifdef RB_PWOFF
3206	andi	a0, RB_PWOFF
3207	beq	a0, zero, 1f
3208	nop
32091:
3210#endif
3211	li	v0, MACH_SR_BOOT_EXC_VEC	# no interrupt and
3212	mtc0	v0, MACH_COP_0_STATUS_REG	# boot strap exception vector
3213	nop
3214	nop
3215	nop
3216	nop
3217	li	a1, MACH_MONARG_ADDR|MACH_UNCACHED_MEMORY_ADDR
3218	sw	a0, (a1)			# pass argument(howto)
3219	move	a0, zero			# syscall(#0)
3220	syscall
3221	nop
3222	.set	reorder
3223END(to_monitor)
3224
3225/*
3226 * getpcps(pc, sp)
3227 *      int *pc, *sp;
3228 * return value: sr
3229 */
3230LEAF(getpcsp)
3231	.set    noreorder
3232	mfc0    v0, MACH_COP_0_STATUS_REG
3233	sw      ra, (a0)
3234	.set    reorder
3235	sw      sp, (a1)
3236	j       ra
3237	.set	reorder
3238END(getpcps)
3239