xref: /original-bsd/sys/pmax/pmax/locore.s (revision 00a25f5a)
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.7 (Berkeley) 06/02/95
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	v1, MACH_COP_0_STATUS_REG	# save status register
1831	mtc0	zero, MACH_COP_0_STATUS_REG	# disable interrupts (2 cycles)
1832	nop
1833	nop
1834	mfc0	v0, MACH_COP_0_CAUSE_REG	# read cause register
1835	nop
1836	or	v0, v0, MACH_SOFT_INT_MASK_0	# set soft clock interrupt
1837	mtc0	v0, MACH_COP_0_CAUSE_REG	# save it
1838	mtc0	v1, MACH_COP_0_STATUS_REG
1839	j	ra
1840	nop
1841END(setsoftclock)
1842
1843LEAF(clearsoftclock)
1844	mfc0	v1, MACH_COP_0_STATUS_REG	# save status register
1845	mtc0	zero, MACH_COP_0_STATUS_REG	# disable interrupts (2 cycles)
1846	nop
1847	nop
1848	mfc0	v0, MACH_COP_0_CAUSE_REG	# read cause register
1849	nop
1850	and	v0, v0, ~MACH_SOFT_INT_MASK_0	# clear soft clock interrupt
1851	mtc0	v0, MACH_COP_0_CAUSE_REG	# save it
1852	mtc0	v1, MACH_COP_0_STATUS_REG
1853	j	ra
1854	nop
1855END(clearsoftclock)
1856
1857LEAF(setsoftnet)
1858	mfc0	v1, MACH_COP_0_STATUS_REG	# save status register
1859	mtc0	zero, MACH_COP_0_STATUS_REG	# disable interrupts (2 cycles)
1860	nop
1861	nop
1862	mfc0	v0, MACH_COP_0_CAUSE_REG	# read cause register
1863	nop
1864	or	v0, v0, MACH_SOFT_INT_MASK_1	# set soft net interrupt
1865	mtc0	v0, MACH_COP_0_CAUSE_REG	# save it
1866	mtc0	v1, MACH_COP_0_STATUS_REG
1867	j	ra
1868	nop
1869END(setsoftnet)
1870
1871LEAF(clearsoftnet)
1872	mfc0	v1, MACH_COP_0_STATUS_REG	# save status register
1873	mtc0	zero, MACH_COP_0_STATUS_REG	# disable interrupts (2 cycles)
1874	nop
1875	nop
1876	mfc0	v0, MACH_COP_0_CAUSE_REG	# read cause register
1877	nop
1878	and	v0, v0, ~MACH_SOFT_INT_MASK_1	# clear soft net interrupt
1879	mtc0	v0, MACH_COP_0_CAUSE_REG	# save it
1880	mtc0	v1, MACH_COP_0_STATUS_REG
1881	j	ra
1882	nop
1883END(clearsoftnet)
1884
1885/*
1886 * Set/change interrupt priority routines.
1887 */
1888
1889LEAF(MachEnableIntr)
1890	mfc0	v0, MACH_COP_0_STATUS_REG	# read status register
1891	nop
1892	or	v0, v0, MACH_SR_INT_ENA_CUR
1893	mtc0	v0, MACH_COP_0_STATUS_REG	# enable all interrupts
1894	j	ra
1895	nop
1896END(MachEnableIntr)
1897
1898LEAF(spl0)
1899	mfc0	v0, MACH_COP_0_STATUS_REG	# read status register
1900	nop
1901	or	t0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR)
1902	mtc0	t0, MACH_COP_0_STATUS_REG	# enable all interrupts
1903	j	ra
1904	and	v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR)
1905END(spl0)
1906
1907LEAF(splsoftclock)
1908	mfc0	v0, MACH_COP_0_STATUS_REG	# read status register
1909	li	t0, ~MACH_SOFT_INT_MASK_0	# disable soft clock
1910	and	t0, t0, v0
1911	mtc0	t0, MACH_COP_0_STATUS_REG	# save it
1912	j	ra
1913	and	v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR)
1914END(splsoftclock)
1915
1916LEAF(Mach_spl0)
1917	mfc0	v0, MACH_COP_0_STATUS_REG	# read status register
1918	li	t0, ~(MACH_INT_MASK_0|MACH_SOFT_INT_MASK_1|MACH_SOFT_INT_MASK_0)
1919	and	t0, t0, v0
1920	mtc0	t0, MACH_COP_0_STATUS_REG	# save it
1921	j	ra
1922	and	v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR)
1923END(Mach_spl0)
1924
1925LEAF(Mach_spl1)
1926	mfc0	v0, MACH_COP_0_STATUS_REG	# read status register
1927	li	t0, ~(MACH_INT_MASK_1|MACH_SOFT_INT_MASK_0|MACH_SOFT_INT_MASK_1)
1928	and	t0, t0, v0
1929	mtc0	t0, MACH_COP_0_STATUS_REG	# save it
1930	j	ra
1931	and	v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR)
1932END(Mach_spl1)
1933
1934LEAF(Mach_spl2)
1935	mfc0	v0, MACH_COP_0_STATUS_REG	# read status register
1936	li	t0, ~(MACH_INT_MASK_2|MACH_SOFT_INT_MASK_1|MACH_SOFT_INT_MASK_0)
1937	and	t0, t0, v0
1938	mtc0	t0, MACH_COP_0_STATUS_REG	# save it
1939	j	ra
1940	and	v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR)
1941END(Mach_spl2)
1942
1943LEAF(Mach_spl3)
1944	mfc0	v0, MACH_COP_0_STATUS_REG	# read status register
1945	li	t0, ~(MACH_INT_MASK_3|MACH_SOFT_INT_MASK_1|MACH_SOFT_INT_MASK_0)
1946	and	t0, t0, v0
1947	mtc0	t0, MACH_COP_0_STATUS_REG	# save it
1948	j	ra
1949	and	v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR)
1950END(Mach_spl3)
1951
1952/*
1953 * We define an alternate entry point after mcount is called so it
1954 * can be used in mcount without causeing a recursive loop.
1955 */
1956LEAF(splhigh)
1957ALEAF(_splhigh)
1958	mfc0	v0, MACH_COP_0_STATUS_REG	# read status register
1959	li	t0, ~MACH_SR_INT_ENA_CUR	# disable all interrupts
1960	and	t0, t0, v0
1961	mtc0	t0, MACH_COP_0_STATUS_REG	# save it
1962	j	ra
1963	and	v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR)
1964END(splhigh)
1965
1966/*
1967 * Restore saved interrupt mask.
1968 */
1969LEAF(splx)
1970ALEAF(_splx)
1971	mfc0	v0, MACH_COP_0_STATUS_REG
1972	li	t0, ~(MACH_INT_MASK | MACH_SR_INT_ENA_CUR)
1973	and	t0, t0, v0
1974	or	t0, t0, a0
1975	mtc0	t0, MACH_COP_0_STATUS_REG
1976	j	ra
1977	nop
1978END(splx)
1979
1980/*----------------------------------------------------------------------------
1981 *
1982 * MachEmptyWriteBuffer --
1983 *
1984 *	Return when the write buffer is empty.
1985 *
1986 *	MachEmptyWriteBuffer()
1987 *
1988 * Results:
1989 *	None.
1990 *
1991 * Side effects:
1992 *	None.
1993 *
1994 *----------------------------------------------------------------------------
1995 */
1996LEAF(MachEmptyWriteBuffer)
1997	nop
1998	nop
1999	nop
2000	nop
20011:	bc0f	1b
2002	nop
2003	j	ra
2004	nop
2005END(MachEmptyWriteBuffer)
2006
2007/*--------------------------------------------------------------------------
2008 *
2009 * MachTLBWriteIndexed --
2010 *
2011 *	Write the given entry into the TLB at the given index.
2012 *
2013 *	MachTLBWriteIndexed(index, highEntry, lowEntry)
2014 *		int index;
2015 *		int highEntry;
2016 *		int lowEntry;
2017 *
2018 * Results:
2019 *	None.
2020 *
2021 * Side effects:
2022 *	TLB entry set.
2023 *
2024 *--------------------------------------------------------------------------
2025 */
2026LEAF(MachTLBWriteIndexed)
2027	mfc0	v1, MACH_COP_0_STATUS_REG	# Save the status register.
2028	mtc0	zero, MACH_COP_0_STATUS_REG	# Disable interrupts
2029	mfc0	t0, MACH_COP_0_TLB_HI		# Save the current PID.
2030
2031	sll	a0, a0, VMMACH_TLB_INDEX_SHIFT
2032	mtc0	a0, MACH_COP_0_TLB_INDEX	# Set the index.
2033	mtc0	a1, MACH_COP_0_TLB_HI		# Set up entry high.
2034	mtc0	a2, MACH_COP_0_TLB_LOW		# Set up entry low.
2035	nop
2036	tlbwi					# Write the TLB
2037
2038	mtc0	t0, MACH_COP_0_TLB_HI		# Restore the PID.
2039	j	ra
2040	mtc0	v1, MACH_COP_0_STATUS_REG	# Restore the status register
2041END(MachTLBWriteIndexed)
2042
2043#if 0
2044/*--------------------------------------------------------------------------
2045 *
2046 * MachTLBWriteRandom --
2047 *
2048 *	Write the given entry into the TLB at a random location.
2049 *
2050 *	MachTLBWriteRandom(highEntry, lowEntry)
2051 *		unsigned highEntry;
2052 *		unsigned lowEntry;
2053 *
2054 * Results:
2055 *	None.
2056 *
2057 * Side effects:
2058 *	TLB entry set.
2059 *
2060 *--------------------------------------------------------------------------
2061 */
2062LEAF(MachTLBWriteRandom)
2063	mfc0	v1, MACH_COP_0_STATUS_REG	# Save the status register.
2064	mtc0	zero, MACH_COP_0_STATUS_REG	# Disable interrupts
2065	mfc0	v0, MACH_COP_0_TLB_HI		# Save the current PID.
2066	nop
2067
2068	mtc0	a0, MACH_COP_0_TLB_HI		# Set up entry high.
2069	mtc0	a1, MACH_COP_0_TLB_LOW		# Set up entry low.
2070	nop
2071	tlbwr					# Write the TLB
2072
2073	mtc0	v0, MACH_COP_0_TLB_HI		# Restore the PID.
2074	j	ra
2075	mtc0	v1, MACH_COP_0_STATUS_REG	# Restore the status register
2076END(MachTLBWriteRandom)
2077#endif
2078
2079/*--------------------------------------------------------------------------
2080 *
2081 * MachSetPID --
2082 *
2083 *	Write the given pid into the TLB pid reg.
2084 *
2085 *	MachSetPID(pid)
2086 *		int pid;
2087 *
2088 * Results:
2089 *	None.
2090 *
2091 * Side effects:
2092 *	PID set in the entry hi register.
2093 *
2094 *--------------------------------------------------------------------------
2095 */
2096LEAF(MachSetPID)
2097	sll	a0, a0, VMMACH_TLB_PID_SHIFT	# put PID in right spot
2098	mtc0	a0, MACH_COP_0_TLB_HI		# Write the hi reg value
2099	j	ra
2100	nop
2101END(MachSetPID)
2102
2103/*--------------------------------------------------------------------------
2104 *
2105 * MachTLBFlush --
2106 *
2107 *	Flush the "random" entries from the TLB.
2108 *
2109 *	MachTLBFlush()
2110 *
2111 * Results:
2112 *	None.
2113 *
2114 * Side effects:
2115 *	The TLB is flushed.
2116 *
2117 *--------------------------------------------------------------------------
2118 */
2119LEAF(MachTLBFlush)
2120	mfc0	v1, MACH_COP_0_STATUS_REG	# Save the status register.
2121	mtc0	zero, MACH_COP_0_STATUS_REG	# Disable interrupts
2122	mfc0	t0, MACH_COP_0_TLB_HI		# Save the PID
2123	li	t1, MACH_CACHED_MEMORY_ADDR	# invalid address
2124	mtc0	t1, MACH_COP_0_TLB_HI		# Mark entry high as invalid
2125	mtc0	zero, MACH_COP_0_TLB_LOW	# Zero out low entry.
2126/*
2127 * Align the starting value (t1) and the upper bound (t2).
2128 */
2129	li	t1, VMMACH_FIRST_RAND_ENTRY << VMMACH_TLB_INDEX_SHIFT
2130	li	t2, VMMACH_NUM_TLB_ENTRIES << VMMACH_TLB_INDEX_SHIFT
21311:
2132	mtc0	t1, MACH_COP_0_TLB_INDEX	# Set the index register.
2133	addu	t1, t1, 1 << VMMACH_TLB_INDEX_SHIFT	# Increment index.
2134	bne	t1, t2, 1b
2135	tlbwi					# Write the TLB entry.
2136
2137	mtc0	t0, MACH_COP_0_TLB_HI		# Restore the PID
2138	j	ra
2139	mtc0	v1, MACH_COP_0_STATUS_REG	# Restore the status register
2140END(MachTLBFlush)
2141
2142#if 0
2143/*--------------------------------------------------------------------------
2144 *
2145 * MachTLBFlushPID --
2146 *
2147 *	Flush all entries with the given PID from the TLB.
2148 *
2149 *	MachTLBFlushPID(pid)
2150 *		int pid;
2151 *
2152 * Results:
2153 *	None.
2154 *
2155 * Side effects:
2156 *	All entries corresponding to this PID are flushed.
2157 *
2158 *--------------------------------------------------------------------------
2159 */
2160LEAF(MachTLBFlushPID)
2161	mfc0	v1, MACH_COP_0_STATUS_REG	# Save the status register.
2162	mtc0	zero, MACH_COP_0_STATUS_REG	# Disable interrupts
2163	mfc0	t0, MACH_COP_0_TLB_HI		# Save the current PID
2164	sll	a0, a0, VMMACH_TLB_PID_SHIFT	# Align the pid to flush.
2165/*
2166 * Align the starting value (t1) and the upper bound (t2).
2167 */
2168	li	t1, VMMACH_FIRST_RAND_ENTRY << VMMACH_TLB_INDEX_SHIFT
2169	li	t2, VMMACH_NUM_TLB_ENTRIES << VMMACH_TLB_INDEX_SHIFT
2170	mtc0	t1, MACH_COP_0_TLB_INDEX	# Set the index register
21711:
2172	addu	t1, t1, 1 << VMMACH_TLB_INDEX_SHIFT	# Increment index.
2173	tlbr					# Read from the TLB
2174	mfc0	t4, MACH_COP_0_TLB_HI		# Fetch the hi register.
2175	nop
2176	and	t4, t4, VMMACH_TLB_PID		# compare PIDs
2177	bne	t4, a0, 2f
2178	li	v0, MACH_CACHED_MEMORY_ADDR	# invalid address
2179	mtc0	v0, MACH_COP_0_TLB_HI		# Mark entry high as invalid
2180	mtc0	zero, MACH_COP_0_TLB_LOW	# Zero out low entry.
2181	nop
2182	tlbwi					# Write the entry.
21832:
2184	bne	t1, t2, 1b
2185	mtc0	t1, MACH_COP_0_TLB_INDEX	# Set the index register
2186
2187	mtc0	t0, MACH_COP_0_TLB_HI		# restore PID
2188	j	ra
2189	mtc0	v1, MACH_COP_0_STATUS_REG	# Restore the status register
2190END(MachTLBFlushPID)
2191#endif
2192
2193/*--------------------------------------------------------------------------
2194 *
2195 * MachTLBFlushAddr --
2196 *
2197 *	Flush any TLB entries for the given address and TLB PID.
2198 *
2199 *	MachTLBFlushAddr(highreg)
2200 *		unsigned highreg;
2201 *
2202 * Results:
2203 *	None.
2204 *
2205 * Side effects:
2206 *	The process's page is flushed from the TLB.
2207 *
2208 *--------------------------------------------------------------------------
2209 */
2210LEAF(MachTLBFlushAddr)
2211	mfc0	v1, MACH_COP_0_STATUS_REG	# Save the status register.
2212	mtc0	zero, MACH_COP_0_STATUS_REG	# Disable interrupts
2213	mfc0	t0, MACH_COP_0_TLB_HI		# Get current PID
2214	nop
2215
2216	mtc0	a0, MACH_COP_0_TLB_HI		# look for addr & PID
2217	nop
2218	tlbp					# Probe for the entry.
2219	mfc0	v0, MACH_COP_0_TLB_INDEX	# See what we got
2220	li	t1, MACH_CACHED_MEMORY_ADDR	# Load invalid entry.
2221	bltz	v0, 1f				# index < 0 => !found
2222	mtc0	t1, MACH_COP_0_TLB_HI		# Mark entry high as invalid
2223	mtc0	zero, MACH_COP_0_TLB_LOW	# Zero out low entry.
2224	nop
2225	tlbwi
22261:
2227	mtc0	t0, MACH_COP_0_TLB_HI		# restore PID
2228	j	ra
2229	mtc0	v1, MACH_COP_0_STATUS_REG	# Restore the status register
2230END(MachTLBFlushAddr)
2231
2232/*--------------------------------------------------------------------------
2233 *
2234 * MachTLBUpdate --
2235 *
2236 *	Update the TLB if highreg is found; otherwise, enter the data.
2237 *
2238 *	MachTLBUpdate(highreg, lowreg)
2239 *		unsigned highreg, lowreg;
2240 *
2241 * Results:
2242 *	None.
2243 *
2244 * Side effects:
2245 *	None.
2246 *
2247 *--------------------------------------------------------------------------
2248 */
2249LEAF(MachTLBUpdate)
2250	mfc0	v1, MACH_COP_0_STATUS_REG	# Save the status register.
2251	mtc0	zero, MACH_COP_0_STATUS_REG	# Disable interrupts
2252	mfc0	t0, MACH_COP_0_TLB_HI		# Save current PID
2253	nop					# 2 cycles before intr disabled
2254	mtc0	a0, MACH_COP_0_TLB_HI		# init high reg.
2255	nop
2256	tlbp					# Probe for the entry.
2257	mfc0	v0, MACH_COP_0_TLB_INDEX	# See what we got
2258	mtc0	a1, MACH_COP_0_TLB_LOW		# init low reg.
2259	bltz	v0, 1f				# index < 0 => !found
2260	sra	v0, v0, VMMACH_TLB_INDEX_SHIFT	# convert index to regular num
2261	b	2f
2262	tlbwi					# update slot found
22631:
2264	mtc0	a0, MACH_COP_0_TLB_HI		# init high reg.
2265	nop
2266	tlbwr					# enter into a random slot
22672:
2268	mtc0	t0, MACH_COP_0_TLB_HI		# restore PID
2269	j	ra
2270	mtc0	v1, MACH_COP_0_STATUS_REG	# Restore the status register
2271END(MachTLBUpdate)
2272
2273#if defined(DEBUG)
2274/*--------------------------------------------------------------------------
2275 *
2276 * MachTLBFind --
2277 *
2278 *	Search the TLB for the given entry.
2279 *
2280 *	MachTLBFind(hi)
2281 *		unsigned hi;
2282 *
2283 * Results:
2284 *	Returns a value >= 0 if the entry was found (the index).
2285 *	Returns a value < 0 if the entry was not found.
2286 *
2287 * Side effects:
2288 *	tlbhi and tlblo will contain the TLB entry found.
2289 *
2290 *--------------------------------------------------------------------------
2291 */
2292	.comm	tlbhi, 4
2293	.comm	tlblo, 4
2294LEAF(MachTLBFind)
2295	mfc0	v1, MACH_COP_0_STATUS_REG	# Save the status register.
2296	mtc0	zero, MACH_COP_0_STATUS_REG	# Disable interrupts
2297	mfc0	t0, MACH_COP_0_TLB_HI		# Get current PID
2298	nop
2299	mtc0	a0, MACH_COP_0_TLB_HI		# Set up entry high.
2300	nop
2301	tlbp					# Probe for the entry.
2302	mfc0	v0, MACH_COP_0_TLB_INDEX	# See what we got
2303	nop
2304	bltz	v0, 1f				# not found
2305	nop
2306	tlbr					# read TLB
2307	mfc0	t1, MACH_COP_0_TLB_HI		# See what we got
2308	mfc0	t2, MACH_COP_0_TLB_LOW		# See what we got
2309	sw	t1, tlbhi
2310	sw	t2, tlblo
2311	srl	v0, v0, VMMACH_TLB_INDEX_SHIFT	# convert index to regular num
23121:
2313	mtc0	t0, MACH_COP_0_TLB_HI		# Restore current PID
2314	j	ra
2315	mtc0	v1, MACH_COP_0_STATUS_REG	# Restore the status register
2316END(MachTLBFind)
2317
2318/*--------------------------------------------------------------------------
2319 *
2320 * MachTLBRead --
2321 *
2322 *	Read the TLB entry.
2323 *
2324 *	MachTLBRead(entry)
2325 *		unsigned entry;
2326 *
2327 * Results:
2328 *	None.
2329 *
2330 * Side effects:
2331 *	tlbhi and tlblo will contain the TLB entry found.
2332 *
2333 *--------------------------------------------------------------------------
2334 */
2335LEAF(MachTLBRead)
2336	mfc0	v1, MACH_COP_0_STATUS_REG	# Save the status register.
2337	mtc0	zero, MACH_COP_0_STATUS_REG	# Disable interrupts
2338	mfc0	t0, MACH_COP_0_TLB_HI		# Get current PID
2339
2340	sll	a0, a0, VMMACH_TLB_INDEX_SHIFT
2341	mtc0	a0, MACH_COP_0_TLB_INDEX	# Set the index register
2342	nop
2343	tlbr					# Read from the TLB
2344	mfc0	t3, MACH_COP_0_TLB_HI		# fetch the hi entry
2345	mfc0	t4, MACH_COP_0_TLB_LOW		# fetch the low entry
2346	sw	t3, tlbhi
2347	sw	t4, tlblo
2348
2349	mtc0	t0, MACH_COP_0_TLB_HI		# restore PID
2350	j	ra
2351	mtc0	v1, MACH_COP_0_STATUS_REG	# Restore the status register
2352END(MachTLBRead)
2353
2354/*--------------------------------------------------------------------------
2355 *
2356 * MachTLBGetPID --
2357 *
2358 *	MachTLBGetPID()
2359 *
2360 * Results:
2361 *	Returns the current TLB pid reg.
2362 *
2363 * Side effects:
2364 *	None.
2365 *
2366 *--------------------------------------------------------------------------
2367 */
2368LEAF(MachTLBGetPID)
2369	mfc0	v0, MACH_COP_0_TLB_HI		# get PID
2370	nop
2371	and	v0, v0, VMMACH_TLB_PID		# mask off PID
2372	j	ra
2373	srl	v0, v0, VMMACH_TLB_PID_SHIFT	# put PID in right spot
2374END(MachTLBGetPID)
2375
2376/*
2377 * Return the current value of the cause register.
2378 */
2379LEAF(MachGetCauseReg)
2380	mfc0	v0, MACH_COP_0_CAUSE_REG
2381	j	ra
2382	nop
2383END(MachGetCauseReg)
2384#endif /* DEBUG */
2385
2386/*----------------------------------------------------------------------------
2387 *
2388 * MachSwitchFPState --
2389 *
2390 *	Save the current state into 'from' and restore it from 'to'.
2391 *
2392 *	MachSwitchFPState(from, to)
2393 *		struct proc *from;
2394 *		struct user *to;
2395 *
2396 * Results:
2397 *	None.
2398 *
2399 * Side effects:
2400 *	None.
2401 *
2402 *----------------------------------------------------------------------------
2403 */
2404LEAF(MachSwitchFPState)
2405	mfc0	t1, MACH_COP_0_STATUS_REG	# Save old SR
2406	li	t0, MACH_SR_COP_1_BIT		# enable the coprocessor
2407	mtc0	t0, MACH_COP_0_STATUS_REG
2408
2409	beq	a0, zero, 1f			# skip save if NULL pointer
2410	nop
2411/*
2412 * First read out the status register to make sure that all FP operations
2413 * have completed.
2414 */
2415	lw	a0, P_ADDR(a0)			# get pointer to pcb for proc
2416	cfc1	t0, MACH_FPC_CSR		# stall til FP done
2417	cfc1	t0, MACH_FPC_CSR		# now get status
2418	li	t3, ~MACH_SR_COP_1_BIT
2419	lw	t2, U_PCB_REGS+(PS * 4)(a0)	# get CPU status register
2420	sw	t0, U_PCB_FPREGS+(32 * 4)(a0)	# save FP status
2421	and	t2, t2, t3			# clear COP_1 enable bit
2422	sw	t2, U_PCB_REGS+(PS * 4)(a0)	# save new status register
2423/*
2424 * Save the floating point registers.
2425 */
2426	swc1	$f0, U_PCB_FPREGS+(0 * 4)(a0)
2427	swc1	$f1, U_PCB_FPREGS+(1 * 4)(a0)
2428	swc1	$f2, U_PCB_FPREGS+(2 * 4)(a0)
2429	swc1	$f3, U_PCB_FPREGS+(3 * 4)(a0)
2430	swc1	$f4, U_PCB_FPREGS+(4 * 4)(a0)
2431	swc1	$f5, U_PCB_FPREGS+(5 * 4)(a0)
2432	swc1	$f6, U_PCB_FPREGS+(6 * 4)(a0)
2433	swc1	$f7, U_PCB_FPREGS+(7 * 4)(a0)
2434	swc1	$f8, U_PCB_FPREGS+(8 * 4)(a0)
2435	swc1	$f9, U_PCB_FPREGS+(9 * 4)(a0)
2436	swc1	$f10, U_PCB_FPREGS+(10 * 4)(a0)
2437	swc1	$f11, U_PCB_FPREGS+(11 * 4)(a0)
2438	swc1	$f12, U_PCB_FPREGS+(12 * 4)(a0)
2439	swc1	$f13, U_PCB_FPREGS+(13 * 4)(a0)
2440	swc1	$f14, U_PCB_FPREGS+(14 * 4)(a0)
2441	swc1	$f15, U_PCB_FPREGS+(15 * 4)(a0)
2442	swc1	$f16, U_PCB_FPREGS+(16 * 4)(a0)
2443	swc1	$f17, U_PCB_FPREGS+(17 * 4)(a0)
2444	swc1	$f18, U_PCB_FPREGS+(18 * 4)(a0)
2445	swc1	$f19, U_PCB_FPREGS+(19 * 4)(a0)
2446	swc1	$f20, U_PCB_FPREGS+(20 * 4)(a0)
2447	swc1	$f21, U_PCB_FPREGS+(21 * 4)(a0)
2448	swc1	$f22, U_PCB_FPREGS+(22 * 4)(a0)
2449	swc1	$f23, U_PCB_FPREGS+(23 * 4)(a0)
2450	swc1	$f24, U_PCB_FPREGS+(24 * 4)(a0)
2451	swc1	$f25, U_PCB_FPREGS+(25 * 4)(a0)
2452	swc1	$f26, U_PCB_FPREGS+(26 * 4)(a0)
2453	swc1	$f27, U_PCB_FPREGS+(27 * 4)(a0)
2454	swc1	$f28, U_PCB_FPREGS+(28 * 4)(a0)
2455	swc1	$f29, U_PCB_FPREGS+(29 * 4)(a0)
2456	swc1	$f30, U_PCB_FPREGS+(30 * 4)(a0)
2457	swc1	$f31, U_PCB_FPREGS+(31 * 4)(a0)
2458
24591:
2460/*
2461 *  Restore the floating point registers.
2462 */
2463	lw	t0, U_PCB_FPREGS+(32 * 4)(a1)	# get status register
2464	lwc1	$f0, U_PCB_FPREGS+(0 * 4)(a1)
2465	lwc1	$f1, U_PCB_FPREGS+(1 * 4)(a1)
2466	lwc1	$f2, U_PCB_FPREGS+(2 * 4)(a1)
2467	lwc1	$f3, U_PCB_FPREGS+(3 * 4)(a1)
2468	lwc1	$f4, U_PCB_FPREGS+(4 * 4)(a1)
2469	lwc1	$f5, U_PCB_FPREGS+(5 * 4)(a1)
2470	lwc1	$f6, U_PCB_FPREGS+(6 * 4)(a1)
2471	lwc1	$f7, U_PCB_FPREGS+(7 * 4)(a1)
2472	lwc1	$f8, U_PCB_FPREGS+(8 * 4)(a1)
2473	lwc1	$f9, U_PCB_FPREGS+(9 * 4)(a1)
2474	lwc1	$f10, U_PCB_FPREGS+(10 * 4)(a1)
2475	lwc1	$f11, U_PCB_FPREGS+(11 * 4)(a1)
2476	lwc1	$f12, U_PCB_FPREGS+(12 * 4)(a1)
2477	lwc1	$f13, U_PCB_FPREGS+(13 * 4)(a1)
2478	lwc1	$f14, U_PCB_FPREGS+(14 * 4)(a1)
2479	lwc1	$f15, U_PCB_FPREGS+(15 * 4)(a1)
2480	lwc1	$f16, U_PCB_FPREGS+(16 * 4)(a1)
2481	lwc1	$f17, U_PCB_FPREGS+(17 * 4)(a1)
2482	lwc1	$f18, U_PCB_FPREGS+(18 * 4)(a1)
2483	lwc1	$f19, U_PCB_FPREGS+(19 * 4)(a1)
2484	lwc1	$f20, U_PCB_FPREGS+(20 * 4)(a1)
2485	lwc1	$f21, U_PCB_FPREGS+(21 * 4)(a1)
2486	lwc1	$f22, U_PCB_FPREGS+(22 * 4)(a1)
2487	lwc1	$f23, U_PCB_FPREGS+(23 * 4)(a1)
2488	lwc1	$f24, U_PCB_FPREGS+(24 * 4)(a1)
2489	lwc1	$f25, U_PCB_FPREGS+(25 * 4)(a1)
2490	lwc1	$f26, U_PCB_FPREGS+(26 * 4)(a1)
2491	lwc1	$f27, U_PCB_FPREGS+(27 * 4)(a1)
2492	lwc1	$f28, U_PCB_FPREGS+(28 * 4)(a1)
2493	lwc1	$f29, U_PCB_FPREGS+(29 * 4)(a1)
2494	lwc1	$f30, U_PCB_FPREGS+(30 * 4)(a1)
2495	lwc1	$f31, U_PCB_FPREGS+(31 * 4)(a1)
2496
2497	and	t0, t0, ~MACH_FPC_EXCEPTION_BITS
2498	ctc1	t0, MACH_FPC_CSR
2499	nop
2500
2501	mtc0	t1, MACH_COP_0_STATUS_REG	# Restore the status register.
2502	j	ra
2503	nop
2504END(MachSwitchFPState)
2505
2506/*----------------------------------------------------------------------------
2507 *
2508 * MachSaveCurFPState --
2509 *
2510 *	Save the current floating point coprocessor state.
2511 *
2512 *	MachSaveCurFPState(p)
2513 *		struct proc *p;
2514 *
2515 * Results:
2516 *	None.
2517 *
2518 * Side effects:
2519 *	machFPCurProcPtr is cleared.
2520 *
2521 *----------------------------------------------------------------------------
2522 */
2523LEAF(MachSaveCurFPState)
2524	lw	a0, P_ADDR(a0)			# get pointer to pcb for proc
2525	mfc0	t1, MACH_COP_0_STATUS_REG	# Disable interrupts and
2526	li	t0, MACH_SR_COP_1_BIT		#  enable the coprocessor
2527	mtc0	t0, MACH_COP_0_STATUS_REG
2528	sw	zero, machFPCurProcPtr		# indicate state has been saved
2529/*
2530 * First read out the status register to make sure that all FP operations
2531 * have completed.
2532 */
2533	lw	t2, U_PCB_REGS+(PS * 4)(a0)	# get CPU status register
2534	li	t3, ~MACH_SR_COP_1_BIT
2535	and	t2, t2, t3			# clear COP_1 enable bit
2536	cfc1	t0, MACH_FPC_CSR		# stall til FP done
2537	cfc1	t0, MACH_FPC_CSR		# now get status
2538	sw	t2, U_PCB_REGS+(PS * 4)(a0)	# save new status register
2539	sw	t0, U_PCB_FPREGS+(32 * 4)(a0)	# save FP status
2540/*
2541 * Save the floating point registers.
2542 */
2543	swc1	$f0, U_PCB_FPREGS+(0 * 4)(a0)
2544	swc1	$f1, U_PCB_FPREGS+(1 * 4)(a0)
2545	swc1	$f2, U_PCB_FPREGS+(2 * 4)(a0)
2546	swc1	$f3, U_PCB_FPREGS+(3 * 4)(a0)
2547	swc1	$f4, U_PCB_FPREGS+(4 * 4)(a0)
2548	swc1	$f5, U_PCB_FPREGS+(5 * 4)(a0)
2549	swc1	$f6, U_PCB_FPREGS+(6 * 4)(a0)
2550	swc1	$f7, U_PCB_FPREGS+(7 * 4)(a0)
2551	swc1	$f8, U_PCB_FPREGS+(8 * 4)(a0)
2552	swc1	$f9, U_PCB_FPREGS+(9 * 4)(a0)
2553	swc1	$f10, U_PCB_FPREGS+(10 * 4)(a0)
2554	swc1	$f11, U_PCB_FPREGS+(11 * 4)(a0)
2555	swc1	$f12, U_PCB_FPREGS+(12 * 4)(a0)
2556	swc1	$f13, U_PCB_FPREGS+(13 * 4)(a0)
2557	swc1	$f14, U_PCB_FPREGS+(14 * 4)(a0)
2558	swc1	$f15, U_PCB_FPREGS+(15 * 4)(a0)
2559	swc1	$f16, U_PCB_FPREGS+(16 * 4)(a0)
2560	swc1	$f17, U_PCB_FPREGS+(17 * 4)(a0)
2561	swc1	$f18, U_PCB_FPREGS+(18 * 4)(a0)
2562	swc1	$f19, U_PCB_FPREGS+(19 * 4)(a0)
2563	swc1	$f20, U_PCB_FPREGS+(20 * 4)(a0)
2564	swc1	$f21, U_PCB_FPREGS+(21 * 4)(a0)
2565	swc1	$f22, U_PCB_FPREGS+(22 * 4)(a0)
2566	swc1	$f23, U_PCB_FPREGS+(23 * 4)(a0)
2567	swc1	$f24, U_PCB_FPREGS+(24 * 4)(a0)
2568	swc1	$f25, U_PCB_FPREGS+(25 * 4)(a0)
2569	swc1	$f26, U_PCB_FPREGS+(26 * 4)(a0)
2570	swc1	$f27, U_PCB_FPREGS+(27 * 4)(a0)
2571	swc1	$f28, U_PCB_FPREGS+(28 * 4)(a0)
2572	swc1	$f29, U_PCB_FPREGS+(29 * 4)(a0)
2573	swc1	$f30, U_PCB_FPREGS+(30 * 4)(a0)
2574	swc1	$f31, U_PCB_FPREGS+(31 * 4)(a0)
2575
2576	mtc0	t1, MACH_COP_0_STATUS_REG	# Restore the status register.
2577	j	ra
2578	nop
2579END(MachSaveCurFPState)
2580
2581/*----------------------------------------------------------------------------
2582 *
2583 * MachFPInterrupt --
2584 *
2585 *	Handle a floating point interrupt.
2586 *
2587 *	MachFPInterrupt(statusReg, causeReg, pc)
2588 *		unsigned statusReg;
2589 *		unsigned causeReg;
2590 *		unsigned pc;
2591 *
2592 * Results:
2593 *	None.
2594 *
2595 * Side effects:
2596 *	None.
2597 *
2598 *----------------------------------------------------------------------------
2599 */
2600NON_LEAF(MachFPInterrupt, STAND_FRAME_SIZE, ra)
2601	subu	sp, sp, STAND_FRAME_SIZE
2602	mfc0	t0, MACH_COP_0_STATUS_REG
2603	sw	ra, STAND_RA_OFFSET(sp)
2604	.mask	0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
2605
2606	or	t1, t0, MACH_SR_COP_1_BIT
2607	mtc0	t1, MACH_COP_0_STATUS_REG
2608	nop
2609	nop
2610	cfc1	t1, MACH_FPC_CSR	# stall til FP done
2611	cfc1	t1, MACH_FPC_CSR	# now get status
2612	nop
2613	sll	t2, t1, (31 - 17)	# unimplemented operation?
2614	bgez	t2, 3f			# no, normal trap
2615	nop
2616/*
2617 * We got an unimplemented operation trap so
2618 * fetch the instruction, compute the next PC and emulate the instruction.
2619 */
2620	bgez	a1, 1f			# Check the branch delay bit.
2621	nop
2622/*
2623 * The instruction is in the branch delay slot so the branch will have to
2624 * be emulated to get the resulting PC.
2625 */
2626	sw	a2, STAND_FRAME_SIZE + 8(sp)
2627	li	a0, UADDR+U_PCB_REGS	# first arg is ptr to CPU registers
2628	move	a1, a2			# second arg is instruction PC
2629	move	a2, t1			# third arg is floating point CSR
2630	jal	MachEmulateBranch	# compute PC after branch
2631	move	a3, zero		# fourth arg is FALSE
2632/*
2633 * Now load the floating-point instruction in the branch delay slot
2634 * to be emulated.
2635 */
2636	lw	a2, STAND_FRAME_SIZE + 8(sp)	# restore EXC pc
2637	b	2f
2638	lw	a0, 4(a2)			# a0 = coproc instruction
2639/*
2640 * This is not in the branch delay slot so calculate the resulting
2641 * PC (epc + 4) into v0 and continue to MachEmulateFP().
2642 */
26431:
2644	lw	a0, 0(a2)			# a0 = coproc instruction
2645	addu	v0, a2, 4			# v0 = next pc
26462:
2647	sw	v0, UADDR+U_PCB_REGS+(PC * 4)	# save new pc
2648/*
2649 * Check to see if the instruction to be emulated is a floating-point
2650 * instruction.
2651 */
2652	srl	a3, a0, MACH_OPCODE_SHIFT
2653	beq	a3, MACH_OPCODE_C1, 4f		# this should never fail
2654/*
2655 * Send a floating point exception signal to the current process.
2656 */
26573:
2658	lw	a0, curproc			# get current process
2659	cfc1	a2, MACH_FPC_CSR		# code = FP execptions
2660	ctc1	zero, MACH_FPC_CSR		# Clear exceptions
2661	jal	trapsignal
2662	li	a1, SIGFPE
2663	b	FPReturn
2664	nop
2665
2666/*
2667 * Finally, we can call MachEmulateFP() where a0 is the instruction to emulate.
2668 */
26694:
2670	jal	MachEmulateFP
2671	nop
2672
2673/*
2674 * Turn off the floating point coprocessor and return.
2675 */
2676FPReturn:
2677	mfc0	t0, MACH_COP_0_STATUS_REG
2678	lw	ra, STAND_RA_OFFSET(sp)
2679	and	t0, t0, ~MACH_SR_COP_1_BIT
2680	mtc0	t0, MACH_COP_0_STATUS_REG
2681	j	ra
2682	addu	sp, sp, STAND_FRAME_SIZE
2683END(MachFPInterrupt)
2684
2685/*----------------------------------------------------------------------------
2686 *
2687 * MachConfigCache --
2688 *
2689 *	Size the caches.
2690 *	NOTE: should only be called from mach_init().
2691 *
2692 * Results:
2693 *     	None.
2694 *
2695 * Side effects:
2696 *	The size of the data cache is stored into machDataCacheSize and the
2697 *	size of instruction cache is stored into machInstCacheSize.
2698 *
2699 *----------------------------------------------------------------------------
2700 */
2701NON_LEAF(MachConfigCache, STAND_FRAME_SIZE, ra)
2702	subu	sp, sp, STAND_FRAME_SIZE
2703	sw	ra, STAND_RA_OFFSET(sp)		# Save return address.
2704	.mask	0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
2705	mtc0	zero, MACH_COP_0_STATUS_REG	# Disable interrupts.
2706	la	v0, 1f
2707	or	v0, MACH_UNCACHED_MEMORY_ADDR	# Run uncached.
2708	j	v0
2709	nop
27101:
2711/*
2712 * This works because jal doesn't change pc[31..28] and the
2713 * linker still thinks SizeCache is in the cached region so it computes
2714 * the correct address without complaining.
2715 */
2716	jal	SizeCache			# Get the size of the d-cache.
2717	nop
2718	sw	v0, machDataCacheSize
2719	nop					# Make sure sw out of pipe
2720	nop
2721	nop
2722	nop
2723	li	v0, MACH_SR_SWAP_CACHES		# Swap caches
2724	mtc0	v0, MACH_COP_0_STATUS_REG
2725	nop					# Insure caches stable
2726	nop
2727	nop
2728	nop
2729	jal	SizeCache			# Get the size of the i-cache.
2730	nop
2731	mtc0	zero, MACH_COP_0_STATUS_REG	# Swap back caches and enable.
2732	nop
2733	nop
2734	nop
2735	nop
2736	sw	v0, machInstCacheSize
2737	la	t0, 1f
2738	j	t0				# Back to cached mode
2739	nop
27401:
2741	lw	ra, STAND_RA_OFFSET(sp)		# Restore return addr
2742	addu	sp, sp, STAND_FRAME_SIZE	# Restore sp.
2743	j	ra
2744	nop
2745END(MachConfigCache)
2746
2747/*----------------------------------------------------------------------------
2748 *
2749 * SizeCache --
2750 *
2751 *	Get the size of the cache.
2752 *
2753 * Results:
2754 *	The size of the cache.
2755 *
2756 * Side effects:
2757 *	None.
2758 *
2759 *----------------------------------------------------------------------------
2760 */
2761LEAF(SizeCache)
2762	mfc0	t0, MACH_COP_0_STATUS_REG	# Save the current status reg.
2763	nop
2764	or	v0, t0, MACH_SR_ISOL_CACHES	# Isolate the caches.
2765	nop					# Make sure no stores in pipe
2766	mtc0	v0, MACH_COP_0_STATUS_REG
2767	nop					# Make sure isolated
2768	nop
2769	nop
2770/*
2771 * Clear cache size boundaries.
2772 */
2773	li	v0, MACH_MIN_CACHE_SIZE
2774	li	v1, MACH_CACHED_MEMORY_ADDR
2775	li	t2, MACH_MAX_CACHE_SIZE
27761:
2777	addu	t1, v0, v1			# Compute address to clear
2778	sw	zero, 0(t1)			# Clear cache memory
2779	bne	v0, t2, 1b
2780	sll	v0, v0, 1
2781
2782	li	v0, -1
2783	sw	v0, 0(v1)			# Store marker in cache
2784	li	v0, MACH_MIN_CACHE_SIZE
27852:
2786	addu	t1, v0, v1			# Compute address
2787	lw	t3, 0(t1)			# Look for marker
2788	nop
2789	bne	t3, zero, 3f			# Found marker.
2790	nop
2791	bne	v0, t2, 2b			# keep looking
2792	sll	v0, v0, 1			# cache size * 2
2793
2794	move	v0, zero			# must be no cache
27953:
2796	mtc0	t0, MACH_COP_0_STATUS_REG
2797	nop					# Make sure unisolated
2798	nop
2799	nop
2800	nop
2801	j	ra
2802	nop
2803END(SizeCache)
2804
2805/*----------------------------------------------------------------------------
2806 *
2807 * MachFlushCache --
2808 *
2809 *	Flush the caches.
2810 *
2811 * Results:
2812 *	None.
2813 *
2814 * Side effects:
2815 *	The contents of the caches is flushed.
2816 *
2817 *----------------------------------------------------------------------------
2818 */
2819LEAF(MachFlushCache)
2820	lw	t1, machInstCacheSize		# Must load before isolating
2821	lw	t2, machDataCacheSize		# Must load before isolating
2822	mfc0	t3, MACH_COP_0_STATUS_REG 	# Save the status register.
2823	mtc0	zero, MACH_COP_0_STATUS_REG	# Disable interrupts.
2824	la	v0, 1f
2825	or	v0, MACH_UNCACHED_MEMORY_ADDR	# Run uncached.
2826	j	v0
2827	nop
2828/*
2829 * Flush the instruction cache.
2830 */
28311:
2832	li	v0, MACH_SR_ISOL_CACHES | MACH_SR_SWAP_CACHES
2833	mtc0	v0, MACH_COP_0_STATUS_REG	# Isolate and swap caches.
2834	li	t0, MACH_UNCACHED_MEMORY_ADDR
2835	subu	t0, t0, t1
2836	li	t1, MACH_UNCACHED_MEMORY_ADDR
2837	la	v0, 1f				# Run cached
2838	j	v0
2839	nop
28401:
2841	addu	t0, t0, 4
2842	bne	t0, t1, 1b
2843	sb	zero, -4(t0)
2844
2845	la	v0, 1f
2846	or	v0, MACH_UNCACHED_MEMORY_ADDR
2847	j	v0				# Run uncached
2848	nop
2849/*
2850 * Flush the data cache.
2851 */
28521:
2853	li	v0, MACH_SR_ISOL_CACHES
2854	mtc0	v0, MACH_COP_0_STATUS_REG	# Isolate and swap back caches
2855	li	t0, MACH_UNCACHED_MEMORY_ADDR
2856	subu	t0, t0, t2
2857	la	v0, 1f
2858	j	v0				# Back to cached mode
2859	nop
28601:
2861	addu	t0, t0, 4
2862	bne	t0, t1, 1b
2863	sb	zero, -4(t0)
2864
2865	nop					# Insure isolated stores
2866	nop					#   out of pipe.
2867	nop
2868	nop
2869	mtc0	t3, MACH_COP_0_STATUS_REG	# Restore status reg.
2870	nop					# Insure cache unisolated.
2871	nop
2872	nop
2873	nop
2874	j	ra
2875	nop
2876END(MachFlushCache)
2877
2878/*----------------------------------------------------------------------------
2879 *
2880 * MachFlushICache --
2881 *
2882 *	void MachFlushICache(addr, len)
2883 *		vm_offset_t addr, len;
2884 *
2885 *	Flush instruction cache for range of addr to addr + len - 1.
2886 *	The address can be any valid address so long as no TLB misses occur.
2887 *
2888 * Results:
2889 *	None.
2890 *
2891 * Side effects:
2892 *	The contents of the cache is flushed.
2893 *
2894 *----------------------------------------------------------------------------
2895 */
2896LEAF(MachFlushICache)
2897	mfc0	t0, MACH_COP_0_STATUS_REG	# Save SR
2898	mtc0	zero, MACH_COP_0_STATUS_REG	# Disable interrupts.
2899
2900	la	v1, 1f
2901	or	v1, MACH_UNCACHED_MEMORY_ADDR	# Run uncached.
2902	j	v1
2903	nop
29041:
2905	bc0f	1b				# make sure stores are complete
2906	li	v1, MACH_SR_ISOL_CACHES | MACH_SR_SWAP_CACHES
2907	mtc0	v1, MACH_COP_0_STATUS_REG
2908	nop
2909	addu	a1, a1, a0			# compute ending address
29101:
2911	addu	a0, a0, 4
2912	bne	a0, a1, 1b
2913	sb	zero, -4(a0)
2914
2915	mtc0	t0, MACH_COP_0_STATUS_REG	# enable interrupts
2916	j	ra				# return and run cached
2917	nop
2918END(MachFlushICache)
2919
2920/*----------------------------------------------------------------------------
2921 *
2922 * MachFlushDCache --
2923 *
2924 *	void MachFlushDCache(addr, len)
2925 *		vm_offset_t addr, len;
2926 *
2927 *	Flush data cache for range of addr to addr + len - 1.
2928 *	The address can be any valid address so long as no TLB misses occur.
2929 *	(Be sure to use cached K0SEG kernel addresses)
2930 * Results:
2931 *	None.
2932 *
2933 * Side effects:
2934 *	The contents of the cache is flushed.
2935 *
2936 *----------------------------------------------------------------------------
2937 */
2938LEAF(MachFlushDCache)
2939	mfc0	t0, MACH_COP_0_STATUS_REG	# Save SR
2940	mtc0	zero, MACH_COP_0_STATUS_REG	# Disable interrupts.
2941
2942	la	v1, 1f
2943	or	v1, MACH_UNCACHED_MEMORY_ADDR	# Run uncached.
2944	j	v1
2945	nop
29461:
2947	bc0f	1b				# make sure stores are complete
2948	li	v1, MACH_SR_ISOL_CACHES
2949	mtc0	v1, MACH_COP_0_STATUS_REG
2950	nop
2951	addu	a1, a1, a0			# compute ending address
29521:
2953	addu	a0, a0, 4
2954	bne	a0, a1, 1b
2955	sb	zero, -4(a0)
2956
2957	mtc0	t0, MACH_COP_0_STATUS_REG	# enable interrupts
2958	j	ra				# return and run cached
2959	nop
2960END(MachFlushDCache)
2961
2962#ifdef KADB
2963/*
2964 * Read a long and return it.
2965 * Note: addresses can be unaligned!
2966 *
2967 * long
2968L* kdbpeek(addr)
2969L*	caddt_t addr;
2970L* {
2971L*	return (*(long *)addr);
2972L* }
2973 */
2974LEAF(kdbpeek)
2975	li	v0, KADBERR
2976	sw	v0, UADDR+U_PCB_ONFAULT
2977	and	v0, a0, 3		# unaligned address?
2978	bne	v0, zero, 1f
2979	nop
2980	b	2f
2981	lw	v0, (a0)		# aligned access
29821:
2983	lwr	v0, 0(a0)		# get next 4 bytes (unaligned)
2984	lwl	v0, 3(a0)
29852:
2986	j	ra			# made it w/o errors
2987	sw	zero, UADDR+U_PCB_ONFAULT
2988kadberr:
2989	li	v0, 1			# trap sends us here
2990	sw	v0, kdbmkfault
2991	j	ra
2992	nop
2993END(kdbpeek)
2994
2995/*
2996 * Write a long to 'addr'.
2997 * Note: addresses can be unaligned!
2998 *
2999L* void
3000L* kdbpoke(addr, value)
3001L*	caddt_t addr;
3002L*	long value;
3003L* {
3004L*	*(long *)addr = value;
3005L* }
3006 */
3007LEAF(kdbpoke)
3008	li	v0, KADBERR
3009	sw	v0, UADDR+U_PCB_ONFAULT
3010	and	v0, a0, 3		# unaligned address?
3011	bne	v0, zero, 1f
3012	nop
3013	b	2f
3014	sw	a1, (a0)		# aligned access
30151:
3016	swr	a1, 0(a0)		# store next 4 bytes (unaligned)
3017	swl	a1, 3(a0)
3018	and	a0, a0, ~3		# align address for cache flush
30192:
3020	sw	zero, UADDR+U_PCB_ONFAULT
3021	b	MachFlushICache		# flush instruction cache
3022	li	a1, 8
3023END(kdbpoke)
3024
3025/*
3026 * Save registers and state so we can do a 'kdbreset' (like longjmp) later.
3027 * Always returns zero.
3028 *
3029L* int kdb_savearea[11];
3030L*
3031L* int
3032L* kdbsetexit()
3033L* {
3034L*	kdb_savearea[0] = 0;
3035L*	return (0);
3036L* }
3037 */
3038	.comm	kdb_savearea, (11 * 4)
3039
3040LEAF(kdbsetexit)
3041	la	a0, kdb_savearea
3042	sw	s0, 0(a0)
3043	sw	s1, 4(a0)
3044	sw	s2, 8(a0)
3045	sw	s3, 12(a0)
3046	sw	s4, 16(a0)
3047	sw	s5, 20(a0)
3048	sw	s6, 24(a0)
3049	sw	s7, 28(a0)
3050	sw	sp, 32(a0)
3051	sw	s8, 36(a0)
3052	sw	ra, 40(a0)
3053	j	ra
3054	move	v0, zero
3055END(kdbsetexit)
3056
3057/*
3058 * Restore registers and state (like longjmp) and return x.
3059 *
3060L* int
3061L* kdbreset(x)
3062L* {
3063L*	return (x);
3064L* }
3065 */
3066LEAF(kdbreset)
3067	la	v0, kdb_savearea
3068	lw	ra, 40(v0)
3069	lw	s0, 0(v0)
3070	lw	s1, 4(v0)
3071	lw	s2, 8(v0)
3072	lw	s3, 12(v0)
3073	lw	s4, 16(v0)
3074	lw	s5, 20(v0)
3075	lw	s6, 24(v0)
3076	lw	s7, 28(v0)
3077	lw	sp, 32(v0)
3078	lw	s8, 36(v0)
3079	j	ra
3080	move	v0, a0
3081END(kdbreset)
3082
3083/*
3084 * Trap into the debugger.
3085 *
3086L* void
3087L* kdbpanic()
3088L* {
3089L* }
3090 */
3091LEAF(kdbpanic)
3092	break	MACH_BREAK_KDB_VAL
3093	j	ra
3094	nop
3095END(kdbpanic)
3096#endif /* KADB */
3097
3098#ifdef DEBUG
3099LEAF(cpu_getregs)
3100	sw	sp, 0(a0)
3101	sw	ra, 4(a0)
3102	j	ra
3103	sw	s8, 8(a0)
3104END(cpu_getregs)
3105#endif /* DEBUG */
3106
3107/*
3108 * Interrupt counters for vmstat.
3109 * XXX These aren't used yet.
3110 */
3111	.data
3112	.globl	intrcnt, eintrcnt, intrnames, eintrnames
3113intrnames:
3114	.asciiz	"softclock"
3115	.asciiz	"softnet"
3116	.asciiz	"dc"
3117	.asciiz	"ether"
3118	.asciiz	"disk"
3119	.asciiz	"memory"
3120	.asciiz	"clock"
3121	.asciiz	"fp"
3122eintrnames:
3123	.align	2
3124intrcnt:
3125	.word	0,0,0,0,0,0,0,0
3126eintrcnt:
3127	.word	0	# This shouldn't be needed but the eintrcnt label
3128			# ends up in a different section otherwise.
3129