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