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