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