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