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