xref: /netbsd/sys/arch/sparc/sparc/locore.s (revision bf9ec67e)
1/*	$NetBSD: locore.s,v 1.153 2002/02/04 08:36:36 pk Exp $	*/
2
3/*
4 * Copyright (c) 1996 Paul Kranenburg
5 * Copyright (c) 1996
6 * 	The President and Fellows of Harvard College. All rights reserved.
7 * Copyright (c) 1992, 1993
8 *	The Regents of the University of California.  All rights reserved.
9 *
10 * This software was developed by the Computer Systems Engineering group
11 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
12 * contributed to Berkeley.
13 *
14 * All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 *	This product includes software developed by the University of
17 *	California, Lawrence Berkeley Laboratory.
18 *	This product includes software developed by Harvard University.
19 *
20 * Redistribution and use in source and binary forms, with or without
21 * modification, are permitted provided that the following conditions
22 * are met:
23 * 1. Redistributions of source code must retain the above copyright
24 *    notice, this list of conditions and the following disclaimer.
25 * 2. Redistributions in binary form must reproduce the above copyright
26 *    notice, this list of conditions and the following disclaimer in the
27 *    documentation and/or other materials provided with the distribution.
28 * 3. All advertising materials mentioning features or use of this software
29 *    must display the following acknowledgement:
30 *	This product includes software developed by the University of
31 *	California, Berkeley and its contributors.
32 *	This product includes software developed by Harvard University.
33 *	This product includes software developed by Paul Kranenburg.
34 * 4. Neither the name of the University nor the names of its contributors
35 *    may be used to endorse or promote products derived from this software
36 *    without specific prior written permission.
37 *
38 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
39 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
40 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
41 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
42 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
43 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
44 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
45 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
46 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
47 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48 * SUCH DAMAGE.
49 *
50 *	@(#)locore.s	8.4 (Berkeley) 12/10/93
51 */
52
53#include "opt_ddb.h"
54#include "opt_kgdb.h"
55#include "opt_compat_svr4.h"
56#include "opt_compat_sunos.h"
57#include "opt_multiprocessor.h"
58#include "opt_lockdebug.h"
59
60#include "assym.h"
61#include <machine/param.h>
62#include <machine/asm.h>
63#include <sparc/sparc/intreg.h>
64#include <sparc/sparc/timerreg.h>
65#include <sparc/sparc/vaddrs.h>
66#ifdef notyet
67#include <sparc/dev/zsreg.h>
68#endif
69#include <machine/ctlreg.h>
70#include <machine/psl.h>
71#include <machine/signal.h>
72#include <machine/trap.h>
73#include <sys/syscall.h>
74
75/*
76 * GNU assembler does not understand `.empty' directive; Sun assembler
77 * gripes about labels without it.  To allow cross-compilation using
78 * the Sun assembler, and because .empty directives are useful documentation,
79 * we use this trick.
80 */
81#ifdef SUN_AS
82#define	EMPTY	.empty
83#else
84#define	EMPTY	/* .empty */
85#endif
86
87/* use as needed to align things on longword boundaries */
88#define	_ALIGN	.align 4
89
90/*
91 * CCFSZ (C Compiler Frame SiZe) is the size of a stack frame required if
92 * a function is to call C code.  It should be just 64, but Sun defined
93 * their frame with space to hold arguments 0 through 5 (plus some junk),
94 * and varargs routines (such as printf) demand this, and gcc uses this
95 * area at times anyway.
96 */
97#define	CCFSZ	96
98
99/*
100 * A handy macro for maintaining instrumentation counters.
101 * Note that this clobbers %o0 and %o1.  Normal usage is
102 * something like:
103 *	foointr:
104 *		TRAP_SETUP(...)		! makes %o registers safe
105 *		INCR(cnt+V_FOO)	! count a foo
106 */
107#define INCR(what) \
108	sethi	%hi(what), %o0; \
109	ld	[%o0 + %lo(what)], %o1; \
110	inc	%o1; \
111	st	%o1, [%o0 + %lo(what)]
112
113/*
114 * Another handy macro: load one register window, given `base' address.
115 * This can be either a simple register (e.g., %sp) or include an initial
116 * offset (e.g., %g6 + PCB_RW).
117 */
118#define	LOADWIN(addr) \
119	ldd	[addr], %l0; \
120	ldd	[addr + 8], %l2; \
121	ldd	[addr + 16], %l4; \
122	ldd	[addr + 24], %l6; \
123	ldd	[addr + 32], %i0; \
124	ldd	[addr + 40], %i2; \
125	ldd	[addr + 48], %i4; \
126	ldd	[addr + 56], %i6
127
128/*
129 * To return from trap we need the two-instruction sequence
130 * `jmp %l1; rett %l2', which is defined here for convenience.
131 */
132#define	RETT	jmp %l1; rett %l2
133
134	.data
135/*
136 * The interrupt stack.
137 *
138 * This is the very first thing in the data segment, and therefore has
139 * the lowest kernel stack address.  We count on this in the interrupt
140 * trap-frame setup code, since we may need to switch from the kernel
141 * stack to the interrupt stack (iff we are not already on the interrupt
142 * stack).  One sethi+cmp is all we need since this is so carefully
143 * arranged.
144 *
145 * In SMP kernels, each CPU has its own interrupt stack and the computation
146 * to determine whether we're already on the interrupt stack is slightly
147 * more time consuming (see INTR_SETUP() below).
148 */
149	.globl	_C_LABEL(intstack)
150	.globl	_C_LABEL(eintstack)
151_C_LABEL(intstack):
152	.skip	INT_STACK_SIZE		! 16k = 128 128-byte stack frames
153_C_LABEL(eintstack):
154
155_EINTSTACKP = CPUINFO_VA + CPUINFO_EINTSTACK
156
157/*
158 * CPUINFO_VA is a CPU-local virtual address; cpi->ci_self is a global
159 * virtual address for the same structure.  It must be stored in p->p_cpu
160 * upon context switch.
161 */
162_CISELFP = CPUINFO_VA + CPUINFO_SELF
163_CIFLAGS = CPUINFO_VA + CPUINFO_FLAGS
164
165/*
166 * When a process exits and its u. area goes away, we set cpcb to point
167 * to this `u.', leaving us with something to use for an interrupt stack,
168 * and letting all the register save code have a pcb_uw to examine.
169 * This is also carefully arranged (to come just before u0, so that
170 * process 0's kernel stack can quietly overrun into it during bootup, if
171 * we feel like doing that).
172 */
173	.globl	_C_LABEL(idle_u)
174_C_LABEL(idle_u):
175	.skip	USPACE
176/*
177 * On SMP kernels, there's an idle u-area for each CPU and we must
178 * read its location from cpuinfo.
179 */
180IDLE_UP = CPUINFO_VA + CPUINFO_IDLE_U
181
182/*
183 * Process 0's u.
184 *
185 * This must be aligned on an 8 byte boundary.
186 */
187	.globl	_C_LABEL(u0)
188_C_LABEL(u0):	.skip	USPACE
189estack0:
190
191#ifdef KGDB
192/*
193 * Another item that must be aligned, easiest to put it here.
194 */
195KGDB_STACK_SIZE = 2048
196	.globl	_C_LABEL(kgdb_stack)
197_C_LABEL(kgdb_stack):
198	.skip	KGDB_STACK_SIZE		! hope this is enough
199#endif
200
201/*
202 * cpcb points to the current pcb (and hence u. area).
203 * Initially this is the special one.
204 */
205cpcb = CPUINFO_VA + CPUINFO_CURPCB
206
207/* curproc points to the current process that has the CPU */
208curproc = CPUINFO_VA + CPUINFO_CURPROC
209
210/*
211 * cputyp is the current cpu type, used to distinguish between
212 * the many variations of different sun4* machines. It contains
213 * the value CPU_SUN4, CPU_SUN4C, or CPU_SUN4M.
214 */
215	.globl	_C_LABEL(cputyp)
216_C_LABEL(cputyp):
217	.word	1
218
219#if defined(SUN4C) || defined(SUN4M)
220cputypval:
221	.asciz	"sun4c"
222	.ascii	"     "
223cputypvar:
224	.asciz	"compatible"
225	_ALIGN
226#endif
227
228/*
229 * There variables are pointed to by the cpp symbols PGSHIFT, NBPG,
230 * and PGOFSET.
231 */
232	.globl	_C_LABEL(pgshift), _C_LABEL(nbpg), _C_LABEL(pgofset)
233_C_LABEL(pgshift):
234	.word	0
235_C_LABEL(nbpg):
236	.word	0
237_C_LABEL(pgofset):
238	.word	0
239
240	.globl	_C_LABEL(trapbase)
241_C_LABEL(trapbase):
242	.word	0
243
244#if 0
245#if defined(SUN4M)
246_mapme:
247	.asciz "0 0 f8000000 15c6a0 map-pages"
248#endif
249#endif
250
251#if !defined(SUN4M)
252sun4m_notsup:
253	.asciz	"cr .( NetBSD/sparc: this kernel does not support the sun4m) cr"
254#endif
255#if !defined(SUN4C)
256sun4c_notsup:
257	.asciz	"cr .( NetBSD/sparc: this kernel does not support the sun4c) cr"
258#endif
259#if !defined(SUN4)
260sun4_notsup:
261	! the extra characters at the end are to ensure the zs fifo drains
262	! before we halt. Sick, eh?
263	.asciz	"NetBSD/sparc: this kernel does not support the sun4\n\r \b"
264#endif
265	_ALIGN
266
267	.text
268
269/*
270 * The first thing in the real text segment is the trap vector table,
271 * which must be aligned on a 4096 byte boundary.  The text segment
272 * starts beyond page 0 of KERNBASE so that there is a red zone
273 * between user and kernel space.  Since the boot ROM loads us at
274 * PROM_LOADADDR, it is far easier to start at KERNBASE+PROM_LOADADDR than to
275 * buck the trend.  This is two or four pages in (depending on if
276 * pagesize is 8192 or 4096).    We place two items in this area:
277 * the message buffer (phys addr 0) and the cpu_softc structure for
278 * the first processor in the system (phys addr 0x2000).
279 * Because the message buffer is in our "red zone" between user and
280 * kernel space we remap it in configure() to another location and
281 * invalidate the mapping at KERNBASE.
282 */
283
284/*
285 * Each trap has room for four instructions, of which one perforce must
286 * be a branch.  On entry the hardware has copied pc and npc to %l1 and
287 * %l2 respectively.  We use two more to read the psr into %l0, and to
288 * put the trap type value into %l3 (with a few exceptions below).
289 * We could read the trap type field of %tbr later in the code instead,
290 * but there is no need, and that would require more instructions
291 * (read+mask, vs 1 `mov' here).
292 *
293 * I used to generate these numbers by address arithmetic, but gas's
294 * expression evaluator has about as much sense as your average slug
295 * (oddly enough, the code looks about as slimy too).  Thus, all the
296 * trap numbers are given as arguments to the trap macros.  This means
297 * there is one line per trap.  Sigh.
298 *
299 * Note that only the local registers may be used, since the trap
300 * window is potentially the last window.  Its `in' registers are
301 * the previous window's outs (as usual), but more important, its
302 * `out' registers may be in use as the `topmost' window's `in' registers.
303 * The global registers are of course verboten (well, until we save
304 * them away).
305 *
306 * Hardware interrupt vectors can be `linked'---the linkage is to regular
307 * C code---or rewired to fast in-window handlers.  The latter are good
308 * for unbuffered hardware like the Zilog serial chip and the AMD audio
309 * chip, where many interrupts can be handled trivially with pseudo-DMA or
310 * similar.  Only one `fast' interrupt can be used per level, however, and
311 * direct and `fast' interrupts are incompatible.  Routines in intr.c
312 * handle setting these, with optional paranoia.
313 */
314
315	/* regular vectored traps */
316#define	VTRAP(type, label) \
317	mov (type), %l3; b label; mov %psr, %l0; nop
318
319	/* hardware interrupts (can be linked or made `fast') */
320#define	HARDINT44C(lev) \
321	mov (lev), %l3; b _C_LABEL(sparc_interrupt44c); mov %psr, %l0; nop
322
323	/* hardware interrupts (can be linked or made `fast') */
324#define	HARDINT4M(lev) \
325	mov (lev), %l3; b _C_LABEL(sparc_interrupt4m); mov %psr, %l0; nop
326
327	/* software interrupts (may not be made direct, sorry---but you
328	   should not be using them trivially anyway) */
329#define	SOFTINT44C(lev, bit) \
330	mov (lev), %l3; mov (bit), %l4; b softintr_sun44c; mov %psr, %l0
331
332	/* There's no SOFTINT4M(): both hard and soft vector the same way */
333
334	/* traps that just call trap() */
335#define	TRAP(type)	VTRAP(type, slowtrap)
336
337	/* architecturally undefined traps (cause panic) */
338#define	UTRAP(type)	VTRAP(type, slowtrap)
339
340	/* software undefined traps (may be replaced) */
341#define	STRAP(type)	VTRAP(type, slowtrap)
342
343/* breakpoint acts differently under kgdb */
344#ifdef KGDB
345#define	BPT		VTRAP(T_BREAKPOINT, bpt)
346#define	BPT_KGDB_EXEC	VTRAP(T_KGDB_EXEC, bpt)
347#else
348#define	BPT		TRAP(T_BREAKPOINT)
349#define	BPT_KGDB_EXEC	TRAP(T_KGDB_EXEC)
350#endif
351
352/* special high-speed 1-instruction-shaved-off traps (get nothing in %l3) */
353#define	SYSCALL		b _C_LABEL(_syscall); mov %psr, %l0; nop; nop
354#define	WINDOW_OF	b window_of; mov %psr, %l0; nop; nop
355#define	WINDOW_UF	b window_uf; mov %psr, %l0; nop; nop
356#ifdef notyet
357#define	ZS_INTERRUPT	b zshard; mov %psr, %l0; nop; nop
358#else
359#define	ZS_INTERRUPT44C	HARDINT44C(12)
360#define	ZS_INTERRUPT4M	HARDINT4M(12)
361#endif
362
363	.globl	_ASM_LABEL(start), _C_LABEL(kernel_text)
364	_C_LABEL(kernel_text) = start		! for kvm_mkdb(8)
365_ASM_LABEL(start):
366/*
367 * Put sun4 traptable first, since it needs the most stringent aligment (8192)
368 */
369#if defined(SUN4)
370trapbase_sun4:
371	/* trap 0 is special since we cannot receive it */
372	b dostart; nop; nop; nop	! 00 = reset (fake)
373	VTRAP(T_TEXTFAULT, memfault_sun4)	! 01 = instr. fetch fault
374	TRAP(T_ILLINST)			! 02 = illegal instruction
375	TRAP(T_PRIVINST)		! 03 = privileged instruction
376	TRAP(T_FPDISABLED)		! 04 = fp instr, but EF bit off in psr
377	WINDOW_OF			! 05 = window overflow
378	WINDOW_UF			! 06 = window underflow
379	TRAP(T_ALIGN)			! 07 = address alignment error
380	VTRAP(T_FPE, fp_exception)	! 08 = fp exception
381	VTRAP(T_DATAFAULT, memfault_sun4)	! 09 = data fetch fault
382	TRAP(T_TAGOF)			! 0a = tag overflow
383	UTRAP(0x0b)
384	UTRAP(0x0c)
385	UTRAP(0x0d)
386	UTRAP(0x0e)
387	UTRAP(0x0f)
388	UTRAP(0x10)
389	SOFTINT44C(1, IE_L1)		! 11 = level 1 interrupt
390	HARDINT44C(2)			! 12 = level 2 interrupt
391	HARDINT44C(3)			! 13 = level 3 interrupt
392	SOFTINT44C(4, IE_L4)		! 14 = level 4 interrupt
393	HARDINT44C(5)			! 15 = level 5 interrupt
394	SOFTINT44C(6, IE_L6)		! 16 = level 6 interrupt
395	HARDINT44C(7)			! 17 = level 7 interrupt
396	HARDINT44C(8)			! 18 = level 8 interrupt
397	HARDINT44C(9)			! 19 = level 9 interrupt
398	HARDINT44C(10)			! 1a = level 10 interrupt
399	HARDINT44C(11)			! 1b = level 11 interrupt
400	ZS_INTERRUPT44C			! 1c = level 12 (zs) interrupt
401	HARDINT44C(13)			! 1d = level 13 interrupt
402	HARDINT44C(14)			! 1e = level 14 interrupt
403	VTRAP(15, nmi_sun4)		! 1f = nonmaskable interrupt
404	UTRAP(0x20)
405	UTRAP(0x21)
406	UTRAP(0x22)
407	UTRAP(0x23)
408	TRAP(T_CPDISABLED)	! 24 = coprocessor instr, EC bit off in psr
409	UTRAP(0x25)
410	UTRAP(0x26)
411	UTRAP(0x27)
412	TRAP(T_CPEXCEPTION)	! 28 = coprocessor exception
413	UTRAP(0x29)
414	UTRAP(0x2a)
415	UTRAP(0x2b)
416	UTRAP(0x2c)
417	UTRAP(0x2d)
418	UTRAP(0x2e)
419	UTRAP(0x2f)
420	UTRAP(0x30)
421	UTRAP(0x31)
422	UTRAP(0x32)
423	UTRAP(0x33)
424	UTRAP(0x34)
425	UTRAP(0x35)
426	UTRAP(0x36)
427	UTRAP(0x37)
428	UTRAP(0x38)
429	UTRAP(0x39)
430	UTRAP(0x3a)
431	UTRAP(0x3b)
432	UTRAP(0x3c)
433	UTRAP(0x3d)
434	UTRAP(0x3e)
435	UTRAP(0x3f)
436	UTRAP(0x40)
437	UTRAP(0x41)
438	UTRAP(0x42)
439	UTRAP(0x43)
440	UTRAP(0x44)
441	UTRAP(0x45)
442	UTRAP(0x46)
443	UTRAP(0x47)
444	UTRAP(0x48)
445	UTRAP(0x49)
446	UTRAP(0x4a)
447	UTRAP(0x4b)
448	UTRAP(0x4c)
449	UTRAP(0x4d)
450	UTRAP(0x4e)
451	UTRAP(0x4f)
452	UTRAP(0x50)
453	UTRAP(0x51)
454	UTRAP(0x52)
455	UTRAP(0x53)
456	UTRAP(0x54)
457	UTRAP(0x55)
458	UTRAP(0x56)
459	UTRAP(0x57)
460	UTRAP(0x58)
461	UTRAP(0x59)
462	UTRAP(0x5a)
463	UTRAP(0x5b)
464	UTRAP(0x5c)
465	UTRAP(0x5d)
466	UTRAP(0x5e)
467	UTRAP(0x5f)
468	UTRAP(0x60)
469	UTRAP(0x61)
470	UTRAP(0x62)
471	UTRAP(0x63)
472	UTRAP(0x64)
473	UTRAP(0x65)
474	UTRAP(0x66)
475	UTRAP(0x67)
476	UTRAP(0x68)
477	UTRAP(0x69)
478	UTRAP(0x6a)
479	UTRAP(0x6b)
480	UTRAP(0x6c)
481	UTRAP(0x6d)
482	UTRAP(0x6e)
483	UTRAP(0x6f)
484	UTRAP(0x70)
485	UTRAP(0x71)
486	UTRAP(0x72)
487	UTRAP(0x73)
488	UTRAP(0x74)
489	UTRAP(0x75)
490	UTRAP(0x76)
491	UTRAP(0x77)
492	UTRAP(0x78)
493	UTRAP(0x79)
494	UTRAP(0x7a)
495	UTRAP(0x7b)
496	UTRAP(0x7c)
497	UTRAP(0x7d)
498	UTRAP(0x7e)
499	UTRAP(0x7f)
500	SYSCALL			! 80 = sun syscall
501	BPT			! 81 = pseudo breakpoint instruction
502	TRAP(T_DIV0)		! 82 = divide by zero
503	TRAP(T_FLUSHWIN)	! 83 = flush windows
504	TRAP(T_CLEANWIN)	! 84 = provide clean windows
505	TRAP(T_RANGECHECK)	! 85 = ???
506	TRAP(T_FIXALIGN)	! 86 = fix up unaligned accesses
507	TRAP(T_INTOF)		! 87 = integer overflow
508	SYSCALL			! 88 = svr4 syscall
509	SYSCALL			! 89 = bsd syscall
510	BPT_KGDB_EXEC		! 8a = enter kernel gdb on kernel startup
511	STRAP(0x8b)
512	STRAP(0x8c)
513	STRAP(0x8d)
514	STRAP(0x8e)
515	STRAP(0x8f)
516	STRAP(0x90)
517	STRAP(0x91)
518	STRAP(0x92)
519	STRAP(0x93)
520	STRAP(0x94)
521	STRAP(0x95)
522	STRAP(0x96)
523	STRAP(0x97)
524	STRAP(0x98)
525	STRAP(0x99)
526	STRAP(0x9a)
527	STRAP(0x9b)
528	STRAP(0x9c)
529	STRAP(0x9d)
530	STRAP(0x9e)
531	STRAP(0x9f)
532	STRAP(0xa0)
533	STRAP(0xa1)
534	STRAP(0xa2)
535	STRAP(0xa3)
536	STRAP(0xa4)
537	STRAP(0xa5)
538	STRAP(0xa6)
539	STRAP(0xa7)
540	STRAP(0xa8)
541	STRAP(0xa9)
542	STRAP(0xaa)
543	STRAP(0xab)
544	STRAP(0xac)
545	STRAP(0xad)
546	STRAP(0xae)
547	STRAP(0xaf)
548	STRAP(0xb0)
549	STRAP(0xb1)
550	STRAP(0xb2)
551	STRAP(0xb3)
552	STRAP(0xb4)
553	STRAP(0xb5)
554	STRAP(0xb6)
555	STRAP(0xb7)
556	STRAP(0xb8)
557	STRAP(0xb9)
558	STRAP(0xba)
559	STRAP(0xbb)
560	STRAP(0xbc)
561	STRAP(0xbd)
562	STRAP(0xbe)
563	STRAP(0xbf)
564	STRAP(0xc0)
565	STRAP(0xc1)
566	STRAP(0xc2)
567	STRAP(0xc3)
568	STRAP(0xc4)
569	STRAP(0xc5)
570	STRAP(0xc6)
571	STRAP(0xc7)
572	STRAP(0xc8)
573	STRAP(0xc9)
574	STRAP(0xca)
575	STRAP(0xcb)
576	STRAP(0xcc)
577	STRAP(0xcd)
578	STRAP(0xce)
579	STRAP(0xcf)
580	STRAP(0xd0)
581	STRAP(0xd1)
582	STRAP(0xd2)
583	STRAP(0xd3)
584	STRAP(0xd4)
585	STRAP(0xd5)
586	STRAP(0xd6)
587	STRAP(0xd7)
588	STRAP(0xd8)
589	STRAP(0xd9)
590	STRAP(0xda)
591	STRAP(0xdb)
592	STRAP(0xdc)
593	STRAP(0xdd)
594	STRAP(0xde)
595	STRAP(0xdf)
596	STRAP(0xe0)
597	STRAP(0xe1)
598	STRAP(0xe2)
599	STRAP(0xe3)
600	STRAP(0xe4)
601	STRAP(0xe5)
602	STRAP(0xe6)
603	STRAP(0xe7)
604	STRAP(0xe8)
605	STRAP(0xe9)
606	STRAP(0xea)
607	STRAP(0xeb)
608	STRAP(0xec)
609	STRAP(0xed)
610	STRAP(0xee)
611	STRAP(0xef)
612	STRAP(0xf0)
613	STRAP(0xf1)
614	STRAP(0xf2)
615	STRAP(0xf3)
616	STRAP(0xf4)
617	STRAP(0xf5)
618	STRAP(0xf6)
619	STRAP(0xf7)
620	STRAP(0xf8)
621	STRAP(0xf9)
622	STRAP(0xfa)
623	STRAP(0xfb)
624	STRAP(0xfc)
625	STRAP(0xfd)
626	STRAP(0xfe)
627	STRAP(0xff)
628#endif
629
630#if defined(SUN4C)
631trapbase_sun4c:
632/* trap 0 is special since we cannot receive it */
633	b dostart; nop; nop; nop	! 00 = reset (fake)
634	VTRAP(T_TEXTFAULT, memfault_sun4c)	! 01 = instr. fetch fault
635	TRAP(T_ILLINST)			! 02 = illegal instruction
636	TRAP(T_PRIVINST)		! 03 = privileged instruction
637	TRAP(T_FPDISABLED)		! 04 = fp instr, but EF bit off in psr
638	WINDOW_OF			! 05 = window overflow
639	WINDOW_UF			! 06 = window underflow
640	TRAP(T_ALIGN)			! 07 = address alignment error
641	VTRAP(T_FPE, fp_exception)	! 08 = fp exception
642	VTRAP(T_DATAFAULT, memfault_sun4c)	! 09 = data fetch fault
643	TRAP(T_TAGOF)			! 0a = tag overflow
644	UTRAP(0x0b)
645	UTRAP(0x0c)
646	UTRAP(0x0d)
647	UTRAP(0x0e)
648	UTRAP(0x0f)
649	UTRAP(0x10)
650	SOFTINT44C(1, IE_L1)		! 11 = level 1 interrupt
651	HARDINT44C(2)			! 12 = level 2 interrupt
652	HARDINT44C(3)			! 13 = level 3 interrupt
653	SOFTINT44C(4, IE_L4)		! 14 = level 4 interrupt
654	HARDINT44C(5)			! 15 = level 5 interrupt
655	SOFTINT44C(6, IE_L6)		! 16 = level 6 interrupt
656	HARDINT44C(7)			! 17 = level 7 interrupt
657	HARDINT44C(8)			! 18 = level 8 interrupt
658	HARDINT44C(9)			! 19 = level 9 interrupt
659	HARDINT44C(10)			! 1a = level 10 interrupt
660	HARDINT44C(11)			! 1b = level 11 interrupt
661	ZS_INTERRUPT44C			! 1c = level 12 (zs) interrupt
662	HARDINT44C(13)			! 1d = level 13 interrupt
663	HARDINT44C(14)			! 1e = level 14 interrupt
664	VTRAP(15, nmi_sun4c)		! 1f = nonmaskable interrupt
665	UTRAP(0x20)
666	UTRAP(0x21)
667	UTRAP(0x22)
668	UTRAP(0x23)
669	TRAP(T_CPDISABLED)	! 24 = coprocessor instr, EC bit off in psr
670	UTRAP(0x25)
671	UTRAP(0x26)
672	UTRAP(0x27)
673	TRAP(T_CPEXCEPTION)	! 28 = coprocessor exception
674	UTRAP(0x29)
675	UTRAP(0x2a)
676	UTRAP(0x2b)
677	UTRAP(0x2c)
678	UTRAP(0x2d)
679	UTRAP(0x2e)
680	UTRAP(0x2f)
681	UTRAP(0x30)
682	UTRAP(0x31)
683	UTRAP(0x32)
684	UTRAP(0x33)
685	UTRAP(0x34)
686	UTRAP(0x35)
687	UTRAP(0x36)
688	UTRAP(0x37)
689	UTRAP(0x38)
690	UTRAP(0x39)
691	UTRAP(0x3a)
692	UTRAP(0x3b)
693	UTRAP(0x3c)
694	UTRAP(0x3d)
695	UTRAP(0x3e)
696	UTRAP(0x3f)
697	UTRAP(0x40)
698	UTRAP(0x41)
699	UTRAP(0x42)
700	UTRAP(0x43)
701	UTRAP(0x44)
702	UTRAP(0x45)
703	UTRAP(0x46)
704	UTRAP(0x47)
705	UTRAP(0x48)
706	UTRAP(0x49)
707	UTRAP(0x4a)
708	UTRAP(0x4b)
709	UTRAP(0x4c)
710	UTRAP(0x4d)
711	UTRAP(0x4e)
712	UTRAP(0x4f)
713	UTRAP(0x50)
714	UTRAP(0x51)
715	UTRAP(0x52)
716	UTRAP(0x53)
717	UTRAP(0x54)
718	UTRAP(0x55)
719	UTRAP(0x56)
720	UTRAP(0x57)
721	UTRAP(0x58)
722	UTRAP(0x59)
723	UTRAP(0x5a)
724	UTRAP(0x5b)
725	UTRAP(0x5c)
726	UTRAP(0x5d)
727	UTRAP(0x5e)
728	UTRAP(0x5f)
729	UTRAP(0x60)
730	UTRAP(0x61)
731	UTRAP(0x62)
732	UTRAP(0x63)
733	UTRAP(0x64)
734	UTRAP(0x65)
735	UTRAP(0x66)
736	UTRAP(0x67)
737	UTRAP(0x68)
738	UTRAP(0x69)
739	UTRAP(0x6a)
740	UTRAP(0x6b)
741	UTRAP(0x6c)
742	UTRAP(0x6d)
743	UTRAP(0x6e)
744	UTRAP(0x6f)
745	UTRAP(0x70)
746	UTRAP(0x71)
747	UTRAP(0x72)
748	UTRAP(0x73)
749	UTRAP(0x74)
750	UTRAP(0x75)
751	UTRAP(0x76)
752	UTRAP(0x77)
753	UTRAP(0x78)
754	UTRAP(0x79)
755	UTRAP(0x7a)
756	UTRAP(0x7b)
757	UTRAP(0x7c)
758	UTRAP(0x7d)
759	UTRAP(0x7e)
760	UTRAP(0x7f)
761	SYSCALL			! 80 = sun syscall
762	BPT			! 81 = pseudo breakpoint instruction
763	TRAP(T_DIV0)		! 82 = divide by zero
764	TRAP(T_FLUSHWIN)	! 83 = flush windows
765	TRAP(T_CLEANWIN)	! 84 = provide clean windows
766	TRAP(T_RANGECHECK)	! 85 = ???
767	TRAP(T_FIXALIGN)	! 86 = fix up unaligned accesses
768	TRAP(T_INTOF)		! 87 = integer overflow
769	SYSCALL			! 88 = svr4 syscall
770	SYSCALL			! 89 = bsd syscall
771	BPT_KGDB_EXEC		! 8a = enter kernel gdb on kernel startup
772	STRAP(0x8b)
773	STRAP(0x8c)
774	STRAP(0x8d)
775	STRAP(0x8e)
776	STRAP(0x8f)
777	STRAP(0x90)
778	STRAP(0x91)
779	STRAP(0x92)
780	STRAP(0x93)
781	STRAP(0x94)
782	STRAP(0x95)
783	STRAP(0x96)
784	STRAP(0x97)
785	STRAP(0x98)
786	STRAP(0x99)
787	STRAP(0x9a)
788	STRAP(0x9b)
789	STRAP(0x9c)
790	STRAP(0x9d)
791	STRAP(0x9e)
792	STRAP(0x9f)
793	STRAP(0xa0)
794	STRAP(0xa1)
795	STRAP(0xa2)
796	STRAP(0xa3)
797	STRAP(0xa4)
798	STRAP(0xa5)
799	STRAP(0xa6)
800	STRAP(0xa7)
801	STRAP(0xa8)
802	STRAP(0xa9)
803	STRAP(0xaa)
804	STRAP(0xab)
805	STRAP(0xac)
806	STRAP(0xad)
807	STRAP(0xae)
808	STRAP(0xaf)
809	STRAP(0xb0)
810	STRAP(0xb1)
811	STRAP(0xb2)
812	STRAP(0xb3)
813	STRAP(0xb4)
814	STRAP(0xb5)
815	STRAP(0xb6)
816	STRAP(0xb7)
817	STRAP(0xb8)
818	STRAP(0xb9)
819	STRAP(0xba)
820	STRAP(0xbb)
821	STRAP(0xbc)
822	STRAP(0xbd)
823	STRAP(0xbe)
824	STRAP(0xbf)
825	STRAP(0xc0)
826	STRAP(0xc1)
827	STRAP(0xc2)
828	STRAP(0xc3)
829	STRAP(0xc4)
830	STRAP(0xc5)
831	STRAP(0xc6)
832	STRAP(0xc7)
833	STRAP(0xc8)
834	STRAP(0xc9)
835	STRAP(0xca)
836	STRAP(0xcb)
837	STRAP(0xcc)
838	STRAP(0xcd)
839	STRAP(0xce)
840	STRAP(0xcf)
841	STRAP(0xd0)
842	STRAP(0xd1)
843	STRAP(0xd2)
844	STRAP(0xd3)
845	STRAP(0xd4)
846	STRAP(0xd5)
847	STRAP(0xd6)
848	STRAP(0xd7)
849	STRAP(0xd8)
850	STRAP(0xd9)
851	STRAP(0xda)
852	STRAP(0xdb)
853	STRAP(0xdc)
854	STRAP(0xdd)
855	STRAP(0xde)
856	STRAP(0xdf)
857	STRAP(0xe0)
858	STRAP(0xe1)
859	STRAP(0xe2)
860	STRAP(0xe3)
861	STRAP(0xe4)
862	STRAP(0xe5)
863	STRAP(0xe6)
864	STRAP(0xe7)
865	STRAP(0xe8)
866	STRAP(0xe9)
867	STRAP(0xea)
868	STRAP(0xeb)
869	STRAP(0xec)
870	STRAP(0xed)
871	STRAP(0xee)
872	STRAP(0xef)
873	STRAP(0xf0)
874	STRAP(0xf1)
875	STRAP(0xf2)
876	STRAP(0xf3)
877	STRAP(0xf4)
878	STRAP(0xf5)
879	STRAP(0xf6)
880	STRAP(0xf7)
881	STRAP(0xf8)
882	STRAP(0xf9)
883	STRAP(0xfa)
884	STRAP(0xfb)
885	STRAP(0xfc)
886	STRAP(0xfd)
887	STRAP(0xfe)
888	STRAP(0xff)
889#endif
890
891#if defined(SUN4M)
892trapbase_sun4m:
893/* trap 0 is special since we cannot receive it */
894	b dostart; nop; nop; nop	! 00 = reset (fake)
895	VTRAP(T_TEXTFAULT, memfault_sun4m)	! 01 = instr. fetch fault
896	TRAP(T_ILLINST)			! 02 = illegal instruction
897	TRAP(T_PRIVINST)		! 03 = privileged instruction
898	TRAP(T_FPDISABLED)		! 04 = fp instr, but EF bit off in psr
899	WINDOW_OF			! 05 = window overflow
900	WINDOW_UF			! 06 = window underflow
901	TRAP(T_ALIGN)			! 07 = address alignment error
902	VTRAP(T_FPE, fp_exception)	! 08 = fp exception
903	VTRAP(T_DATAFAULT, memfault_sun4m)	! 09 = data fetch fault
904	TRAP(T_TAGOF)			! 0a = tag overflow
905	UTRAP(0x0b)
906	UTRAP(0x0c)
907	UTRAP(0x0d)
908	UTRAP(0x0e)
909	UTRAP(0x0f)
910	UTRAP(0x10)
911	HARDINT4M(1)			! 11 = level 1 interrupt
912	HARDINT4M(2)			! 12 = level 2 interrupt
913	HARDINT4M(3)			! 13 = level 3 interrupt
914	HARDINT4M(4)			! 14 = level 4 interrupt
915	HARDINT4M(5)			! 15 = level 5 interrupt
916	HARDINT4M(6)			! 16 = level 6 interrupt
917	HARDINT4M(7)			! 17 = level 7 interrupt
918	HARDINT4M(8)			! 18 = level 8 interrupt
919	HARDINT4M(9)			! 19 = level 9 interrupt
920	HARDINT4M(10)			! 1a = level 10 interrupt
921	HARDINT4M(11)			! 1b = level 11 interrupt
922	ZS_INTERRUPT4M			! 1c = level 12 (zs) interrupt
923	HARDINT4M(13)			! 1d = level 13 interrupt
924	HARDINT4M(14)			! 1e = level 14 interrupt
925	VTRAP(15, nmi_sun4m)		! 1f = nonmaskable interrupt
926	UTRAP(0x20)
927	UTRAP(0x21)
928	UTRAP(0x22)
929	UTRAP(0x23)
930	TRAP(T_CPDISABLED)	! 24 = coprocessor instr, EC bit off in psr
931	UTRAP(0x25)
932	UTRAP(0x26)
933	UTRAP(0x27)
934	TRAP(T_CPEXCEPTION)	! 28 = coprocessor exception
935	UTRAP(0x29)
936	UTRAP(0x2a)
937	VTRAP(T_STOREBUFFAULT, memfault_sun4m) ! 2b = SuperSPARC store buffer fault
938	UTRAP(0x2c)
939	UTRAP(0x2d)
940	UTRAP(0x2e)
941	UTRAP(0x2f)
942	UTRAP(0x30)
943	UTRAP(0x31)
944	UTRAP(0x32)
945	UTRAP(0x33)
946	UTRAP(0x34)
947	UTRAP(0x35)
948	UTRAP(0x36)
949	UTRAP(0x37)
950	UTRAP(0x38)
951	UTRAP(0x39)
952	UTRAP(0x3a)
953	UTRAP(0x3b)
954	UTRAP(0x3c)
955	UTRAP(0x3d)
956	UTRAP(0x3e)
957	UTRAP(0x3f)
958	UTRAP(0x40)
959	UTRAP(0x41)
960	UTRAP(0x42)
961	UTRAP(0x43)
962	UTRAP(0x44)
963	UTRAP(0x45)
964	UTRAP(0x46)
965	UTRAP(0x47)
966	UTRAP(0x48)
967	UTRAP(0x49)
968	UTRAP(0x4a)
969	UTRAP(0x4b)
970	UTRAP(0x4c)
971	UTRAP(0x4d)
972	UTRAP(0x4e)
973	UTRAP(0x4f)
974	UTRAP(0x50)
975	UTRAP(0x51)
976	UTRAP(0x52)
977	UTRAP(0x53)
978	UTRAP(0x54)
979	UTRAP(0x55)
980	UTRAP(0x56)
981	UTRAP(0x57)
982	UTRAP(0x58)
983	UTRAP(0x59)
984	UTRAP(0x5a)
985	UTRAP(0x5b)
986	UTRAP(0x5c)
987	UTRAP(0x5d)
988	UTRAP(0x5e)
989	UTRAP(0x5f)
990	UTRAP(0x60)
991	UTRAP(0x61)
992	UTRAP(0x62)
993	UTRAP(0x63)
994	UTRAP(0x64)
995	UTRAP(0x65)
996	UTRAP(0x66)
997	UTRAP(0x67)
998	UTRAP(0x68)
999	UTRAP(0x69)
1000	UTRAP(0x6a)
1001	UTRAP(0x6b)
1002	UTRAP(0x6c)
1003	UTRAP(0x6d)
1004	UTRAP(0x6e)
1005	UTRAP(0x6f)
1006	UTRAP(0x70)
1007	UTRAP(0x71)
1008	UTRAP(0x72)
1009	UTRAP(0x73)
1010	UTRAP(0x74)
1011	UTRAP(0x75)
1012	UTRAP(0x76)
1013	UTRAP(0x77)
1014	UTRAP(0x78)
1015	UTRAP(0x79)
1016	UTRAP(0x7a)
1017	UTRAP(0x7b)
1018	UTRAP(0x7c)
1019	UTRAP(0x7d)
1020	UTRAP(0x7e)
1021	UTRAP(0x7f)
1022	SYSCALL			! 80 = sun syscall
1023	BPT			! 81 = pseudo breakpoint instruction
1024	TRAP(T_DIV0)		! 82 = divide by zero
1025	TRAP(T_FLUSHWIN)	! 83 = flush windows
1026	TRAP(T_CLEANWIN)	! 84 = provide clean windows
1027	TRAP(T_RANGECHECK)	! 85 = ???
1028	TRAP(T_FIXALIGN)	! 86 = fix up unaligned accesses
1029	TRAP(T_INTOF)		! 87 = integer overflow
1030	SYSCALL			! 88 = svr4 syscall
1031	SYSCALL			! 89 = bsd syscall
1032	BPT_KGDB_EXEC		! 8a = enter kernel gdb on kernel startup
1033	STRAP(0x8b)
1034	STRAP(0x8c)
1035	STRAP(0x8d)
1036	STRAP(0x8e)
1037	STRAP(0x8f)
1038	STRAP(0x90)
1039	STRAP(0x91)
1040	STRAP(0x92)
1041	STRAP(0x93)
1042	STRAP(0x94)
1043	STRAP(0x95)
1044	STRAP(0x96)
1045	STRAP(0x97)
1046	STRAP(0x98)
1047	STRAP(0x99)
1048	STRAP(0x9a)
1049	STRAP(0x9b)
1050	STRAP(0x9c)
1051	STRAP(0x9d)
1052	STRAP(0x9e)
1053	STRAP(0x9f)
1054	STRAP(0xa0)
1055	STRAP(0xa1)
1056	STRAP(0xa2)
1057	STRAP(0xa3)
1058	STRAP(0xa4)
1059	STRAP(0xa5)
1060	STRAP(0xa6)
1061	STRAP(0xa7)
1062	STRAP(0xa8)
1063	STRAP(0xa9)
1064	STRAP(0xaa)
1065	STRAP(0xab)
1066	STRAP(0xac)
1067	STRAP(0xad)
1068	STRAP(0xae)
1069	STRAP(0xaf)
1070	STRAP(0xb0)
1071	STRAP(0xb1)
1072	STRAP(0xb2)
1073	STRAP(0xb3)
1074	STRAP(0xb4)
1075	STRAP(0xb5)
1076	STRAP(0xb6)
1077	STRAP(0xb7)
1078	STRAP(0xb8)
1079	STRAP(0xb9)
1080	STRAP(0xba)
1081	STRAP(0xbb)
1082	STRAP(0xbc)
1083	STRAP(0xbd)
1084	STRAP(0xbe)
1085	STRAP(0xbf)
1086	STRAP(0xc0)
1087	STRAP(0xc1)
1088	STRAP(0xc2)
1089	STRAP(0xc3)
1090	STRAP(0xc4)
1091	STRAP(0xc5)
1092	STRAP(0xc6)
1093	STRAP(0xc7)
1094	STRAP(0xc8)
1095	STRAP(0xc9)
1096	STRAP(0xca)
1097	STRAP(0xcb)
1098	STRAP(0xcc)
1099	STRAP(0xcd)
1100	STRAP(0xce)
1101	STRAP(0xcf)
1102	STRAP(0xd0)
1103	STRAP(0xd1)
1104	STRAP(0xd2)
1105	STRAP(0xd3)
1106	STRAP(0xd4)
1107	STRAP(0xd5)
1108	STRAP(0xd6)
1109	STRAP(0xd7)
1110	STRAP(0xd8)
1111	STRAP(0xd9)
1112	STRAP(0xda)
1113	STRAP(0xdb)
1114	STRAP(0xdc)
1115	STRAP(0xdd)
1116	STRAP(0xde)
1117	STRAP(0xdf)
1118	STRAP(0xe0)
1119	STRAP(0xe1)
1120	STRAP(0xe2)
1121	STRAP(0xe3)
1122	STRAP(0xe4)
1123	STRAP(0xe5)
1124	STRAP(0xe6)
1125	STRAP(0xe7)
1126	STRAP(0xe8)
1127	STRAP(0xe9)
1128	STRAP(0xea)
1129	STRAP(0xeb)
1130	STRAP(0xec)
1131	STRAP(0xed)
1132	STRAP(0xee)
1133	STRAP(0xef)
1134	STRAP(0xf0)
1135	STRAP(0xf1)
1136	STRAP(0xf2)
1137	STRAP(0xf3)
1138	STRAP(0xf4)
1139	STRAP(0xf5)
1140	STRAP(0xf6)
1141	STRAP(0xf7)
1142	STRAP(0xf8)
1143	STRAP(0xf9)
1144	STRAP(0xfa)
1145	STRAP(0xfb)
1146	STRAP(0xfc)
1147	STRAP(0xfd)
1148	STRAP(0xfe)
1149	STRAP(0xff)
1150#endif
1151
1152/*
1153 * Pad the trap table to max page size.
1154 * Trap table size is 0x100 * 4instr * 4byte/instr = 4096 bytes;
1155 * need to .skip 4096 to pad to page size iff. the number of trap tables
1156 * defined above is odd.
1157 */
1158#if (defined(SUN4) + defined(SUN4C) + defined(SUN4M)) % 2 == 1
1159	.skip	4096
1160#endif
1161
1162#ifdef DEBUG
1163/*
1164 * A hardware red zone is impossible.  We simulate one in software by
1165 * keeping a `red zone' pointer; if %sp becomes less than this, we panic.
1166 * This is expensive and is only enabled when debugging.
1167 */
1168
1169/* `redzone' is located in the per-CPU information structure */
1170_redzone = CPUINFO_VA + CPUINFO_REDZONE
1171	.data
1172#define	REDSTACK 2048		/* size of `panic: stack overflow' region */
1173_redstack:
1174	.skip	REDSTACK
1175	.text
1176Lpanic_red:
1177	.asciz	"stack overflow"
1178	_ALIGN
1179
1180	/* set stack pointer redzone to base+minstack; alters base */
1181#define	SET_SP_REDZONE(base, tmp) \
1182	add	base, REDSIZE, base; \
1183	sethi	%hi(_redzone), tmp; \
1184	st	base, [tmp + %lo(_redzone)]
1185
1186	/* variant with a constant */
1187#define	SET_SP_REDZONE_CONST(const, tmp1, tmp2) \
1188	set	(const) + REDSIZE, tmp1; \
1189	sethi	%hi(_redzone), tmp2; \
1190	st	tmp1, [tmp2 + %lo(_redzone)]
1191
1192	/* variant with a variable & offset */
1193#define	SET_SP_REDZONE_VAR(var, offset, tmp1, tmp2) \
1194	sethi	%hi(var), tmp1; \
1195	ld	[tmp1 + %lo(var)], tmp1; \
1196	sethi	%hi(offset), tmp2; \
1197	add	tmp1, tmp2, tmp1; \
1198	SET_SP_REDZONE(tmp1, tmp2)
1199
1200	/* check stack pointer against redzone (uses two temps) */
1201#define	CHECK_SP_REDZONE(t1, t2) \
1202	sethi	%hi(_redzone), t1; \
1203	ld	[t1 + %lo(_redzone)], t2; \
1204	cmp	%sp, t2;	/* if sp >= t2, not in red zone */ \
1205	bgeu	7f; nop;	/* and can continue normally */ \
1206	/* move to panic stack */ \
1207	st	%g0, [t1 + %lo(_redzone)]; \
1208	set	_redstack + REDSTACK - 96, %sp; \
1209	/* prevent panic() from lowering ipl */ \
1210	sethi	%hi(_C_LABEL(panicstr)), t2; \
1211	set	Lpanic_red, t2; \
1212	st	t2, [t1 + %lo(_C_LABEL(panicstr))]; \
1213	rd	%psr, t1;		/* t1 = splhigh() */ \
1214	or	t1, PSR_PIL, t2; \
1215	wr	t2, 0, %psr; \
1216	wr	t2, PSR_ET, %psr;	/* turn on traps */ \
1217	nop; nop; nop; \
1218	save	%sp, -CCFSZ, %sp;	/* preserve current window */ \
1219	sethi	%hi(Lpanic_red), %o0; \
1220	call	_C_LABEL(panic); or %o0, %lo(Lpanic_red), %o0; \
12217:
1222
1223#else
1224
1225#define	SET_SP_REDZONE(base, tmp)
1226#define	SET_SP_REDZONE_CONST(const, t1, t2)
1227#define	SET_SP_REDZONE_VAR(var, offset, t1, t2)
1228#define	CHECK_SP_REDZONE(t1, t2)
1229#endif /* DEBUG */
1230
1231/*
1232 * The window code must verify user stack addresses before using them.
1233 * A user stack pointer is invalid if:
1234 *	- it is not on an 8 byte boundary;
1235 *	- its pages (a register window, being 64 bytes, can occupy
1236 *	  two pages) are not readable or writable.
1237 * We define three separate macros here for testing user stack addresses.
1238 *
1239 * PTE_OF_ADDR locates a PTE, branching to a `bad address'
1240 *	handler if the stack pointer points into the hole in the
1241 *	address space (i.e., top 3 bits are not either all 1 or all 0);
1242 * CMP_PTE_USER_READ compares the located PTE against `user read' mode;
1243 * CMP_PTE_USER_WRITE compares the located PTE against `user write' mode.
1244 * The compares give `equal' if read or write is OK.
1245 *
1246 * Note that the user stack pointer usually points into high addresses
1247 * (top 3 bits all 1), so that is what we check first.
1248 *
1249 * The code below also assumes that PTE_OF_ADDR is safe in a delay
1250 * slot; it is, at it merely sets its `pte' register to a temporary value.
1251 */
1252#if defined(SUN4) || defined(SUN4C)
1253	/* input: addr, output: pte; aux: bad address label */
1254#define	PTE_OF_ADDR4_4C(addr, pte, bad, page_offset) \
1255	sra	addr, PG_VSHIFT, pte; \
1256	cmp	pte, -1; \
1257	be,a	1f; andn addr, page_offset, pte; \
1258	tst	pte; \
1259	bne	bad; EMPTY; \
1260	andn	addr, page_offset, pte; \
12611:
1262
1263	/* input: pte; output: condition codes */
1264#define	CMP_PTE_USER_READ4_4C(pte) \
1265	lda	[pte] ASI_PTE, pte; \
1266	srl	pte, PG_PROTSHIFT, pte; \
1267	andn	pte, (PG_W >> PG_PROTSHIFT), pte; \
1268	cmp	pte, PG_PROTUREAD
1269
1270	/* input: pte; output: condition codes */
1271#define	CMP_PTE_USER_WRITE4_4C(pte) \
1272	lda	[pte] ASI_PTE, pte; \
1273	srl	pte, PG_PROTSHIFT, pte; \
1274	cmp	pte, PG_PROTUWRITE
1275#endif
1276
1277/*
1278 * The Sun4M does not have the memory hole that the 4C does. Thus all
1279 * we need to do here is clear the page offset from addr.
1280 */
1281#if defined(SUN4M)
1282#define	PTE_OF_ADDR4M(addr, pte, bad, page_offset) \
1283	andn	addr, page_offset, pte
1284
1285/*
1286 * After obtaining the PTE through ASI_SRMMUFP, we read the Sync Fault
1287 * Status register. This is necessary on Hypersparcs which stores and
1288 * locks the fault address and status registers if the translation
1289 * fails (thanks to Chris Torek for finding this quirk).
1290 */
1291/* note: pmap currently does not use the PPROT_R_R and PPROT_RW_RW cases */
1292#define CMP_PTE_USER_READ4M(pte, tmp) \
1293	or	pte, ASI_SRMMUFP_L3, pte; \
1294	lda	[pte] ASI_SRMMUFP, pte; \
1295	set	SRMMU_SFSR, tmp; \
1296	and	pte, (SRMMU_TETYPE | SRMMU_PROT_MASK), pte; \
1297	cmp	pte, (SRMMU_TEPTE | PPROT_RWX_RWX); \
1298	be	8f; \
1299	 lda	[tmp] ASI_SRMMU, %g0; \
1300	cmp	pte, (SRMMU_TEPTE | PPROT_RX_RX); \
13018:
1302
1303
1304/* note: PTE bit 4 set implies no user writes */
1305#define CMP_PTE_USER_WRITE4M(pte, tmp) \
1306	or	pte, ASI_SRMMUFP_L3, pte; \
1307	lda	[pte] ASI_SRMMUFP, pte; \
1308	set	SRMMU_SFSR, tmp; \
1309	lda	[tmp] ASI_SRMMU, %g0; \
1310	and	pte, (SRMMU_TETYPE | 0x14), pte; \
1311	cmp	pte, (SRMMU_TEPTE | PPROT_WRITE)
1312#endif /* 4m */
1313
1314#if defined(SUN4M) && !(defined(SUN4C) || defined(SUN4))
1315
1316#define PTE_OF_ADDR(addr, pte, bad, page_offset, label) \
1317	PTE_OF_ADDR4M(addr, pte, bad, page_offset)
1318#define CMP_PTE_USER_WRITE(pte, tmp, label)	CMP_PTE_USER_WRITE4M(pte,tmp)
1319#define CMP_PTE_USER_READ(pte, tmp, label)	CMP_PTE_USER_READ4M(pte,tmp)
1320
1321#elif (defined(SUN4C) || defined(SUN4)) && !defined(SUN4M)
1322
1323#define PTE_OF_ADDR(addr, pte, bad, page_offset,label) \
1324	PTE_OF_ADDR4_4C(addr, pte, bad, page_offset)
1325#define CMP_PTE_USER_WRITE(pte, tmp, label)	CMP_PTE_USER_WRITE4_4C(pte)
1326#define CMP_PTE_USER_READ(pte, tmp, label)	CMP_PTE_USER_READ4_4C(pte)
1327
1328#else /* both defined, ugh */
1329
1330#define	PTE_OF_ADDR(addr, pte, bad, page_offset, label) \
1331label:	b,a	2f; \
1332	PTE_OF_ADDR4M(addr, pte, bad, page_offset); \
1333	b,a	3f; \
13342: \
1335	PTE_OF_ADDR4_4C(addr, pte, bad, page_offset); \
13363:
1337
1338#define CMP_PTE_USER_READ(pte, tmp, label) \
1339label:	b,a	1f; \
1340	CMP_PTE_USER_READ4M(pte,tmp); \
1341	b,a	2f; \
13421: \
1343	CMP_PTE_USER_READ4_4C(pte); \
13442:
1345
1346#define CMP_PTE_USER_WRITE(pte, tmp, label) \
1347label:	b,a	1f; \
1348	CMP_PTE_USER_WRITE4M(pte,tmp); \
1349	b,a	2f; \
13501: \
1351	CMP_PTE_USER_WRITE4_4C(pte); \
13522:
1353#endif
1354
1355
1356/*
1357 * The calculations in PTE_OF_ADDR and CMP_PTE_USER_* are rather slow:
1358 * in particular, according to Gordon Irlam of the University of Adelaide
1359 * in Australia, these consume at least 18 cycles on an SS1 and 37 on an
1360 * SS2.  Hence, we try to avoid them in the common case.
1361 *
1362 * A chunk of 64 bytes is on a single page if and only if:
1363 *
1364 *	((base + 64 - 1) & ~(NBPG-1)) == (base & ~(NBPG-1))
1365 *
1366 * Equivalently (and faster to test), the low order bits (base & 4095) must
1367 * be small enough so that the sum (base + 63) does not carry out into the
1368 * upper page-address bits, i.e.,
1369 *
1370 *	(base & (NBPG-1)) < (NBPG - 63)
1371 *
1372 * so we allow testing that here.  This macro is also assumed to be safe
1373 * in a delay slot (modulo overwriting its temporary).
1374 */
1375#define	SLT_IF_1PAGE_RW(addr, tmp, page_offset) \
1376	and	addr, page_offset, tmp; \
1377	sub	page_offset, 62, page_offset; \
1378	cmp	tmp, page_offset
1379
1380/*
1381 * Every trap that enables traps must set up stack space.
1382 * If the trap is from user mode, this involves switching to the kernel
1383 * stack for the current process, and we must also set cpcb->pcb_uw
1384 * so that the window overflow handler can tell user windows from kernel
1385 * windows.
1386 *
1387 * The number of user windows is:
1388 *
1389 *	cpcb->pcb_uw = (cpcb->pcb_wim - 1 - CWP) % nwindows
1390 *
1391 * (where pcb_wim = log2(current %wim) and CWP = low 5 bits of %psr).
1392 * We compute this expression by table lookup in uwtab[CWP - pcb_wim],
1393 * which has been set up as:
1394 *
1395 *	for i in [-nwin+1 .. nwin-1]
1396 *		uwtab[i] = (nwin - 1 - i) % nwin;
1397 *
1398 * (If you do not believe this works, try it for yourself.)
1399 *
1400 * We also keep one or two more tables:
1401 *
1402 *	for i in 0..nwin-1
1403 *		wmask[i] = 1 << ((i + 1) % nwindows);
1404 *
1405 * wmask[CWP] tells whether a `rett' would return into the invalid window.
1406 */
1407	.data
1408	.skip	32			! alignment byte & negative indicies
1409uwtab:	.skip	32			! u_char uwtab[-31..31];
1410wmask:	.skip	32			! u_char wmask[0..31];
1411
1412	.text
1413/*
1414 * Things begin to grow uglier....
1415 *
1416 * Each trap handler may (always) be running in the trap window.
1417 * If this is the case, it cannot enable further traps until it writes
1418 * the register windows into the stack (or, if the stack is no good,
1419 * the current pcb).
1420 *
1421 * ASSUMPTIONS: TRAP_SETUP() is called with:
1422 *	%l0 = %psr
1423 *	%l1 = return pc
1424 *	%l2 = return npc
1425 *	%l3 = (some value that must not be altered)
1426 * which means we have 4 registers to work with.
1427 *
1428 * The `stackspace' argument is the number of stack bytes to allocate
1429 * for register-saving, and must be at least -64 (and typically more,
1430 * for global registers and %y).
1431 *
1432 * Trapframes should use -CCFSZ-80.  (80 = sizeof(struct trapframe);
1433 * see trap.h.  This basically means EVERYONE.  Interrupt frames could
1434 * get away with less, but currently do not.)
1435 *
1436 * The basic outline here is:
1437 *
1438 *	if (trap came from kernel mode) {
1439 *		if (we are in the trap window)
1440 *			save it away;
1441 *		%sp = %fp - stackspace;
1442 *	} else {
1443 *		compute the number of user windows;
1444 *		if (we are in the trap window)
1445 *			save it away;
1446 *		%sp = (top of kernel stack) - stackspace;
1447 *	}
1448 *
1449 * Again, the number of user windows is:
1450 *
1451 *	cpcb->pcb_uw = (cpcb->pcb_wim - 1 - CWP) % nwindows
1452 *
1453 * (where pcb_wim = log2(current %wim) and CWP is the low 5 bits of %psr),
1454 * and this is computed as `uwtab[CWP - pcb_wim]'.
1455 *
1456 * NOTE: if you change this code, you will have to look carefully
1457 * at the window overflow and underflow handlers and make sure they
1458 * have similar changes made as needed.
1459 */
1460#define	CALL_CLEAN_TRAP_WINDOW \
1461	sethi	%hi(clean_trap_window), %l7; \
1462	jmpl	%l7 + %lo(clean_trap_window), %l4; \
1463	 mov	%g7, %l7	/* save %g7 in %l7 for clean_trap_window */
1464
1465#define	TRAP_SETUP(stackspace) \
1466	rd	%wim, %l4; \
1467	mov	1, %l5; \
1468	sll	%l5, %l0, %l5; \
1469	btst	PSR_PS, %l0; \
1470	bz	1f; \
1471	 btst	%l5, %l4; \
1472	/* came from kernel mode; cond codes indicate trap window */ \
1473	bz,a	3f; \
1474	 add	%fp, stackspace, %sp;	/* want to just set %sp */ \
1475	CALL_CLEAN_TRAP_WINDOW;		/* but maybe need to clean first */ \
1476	b	3f; \
1477	 add	%fp, stackspace, %sp; \
14781: \
1479	/* came from user mode: compute pcb_nw */ \
1480	sethi	%hi(cpcb), %l6; \
1481	ld	[%l6 + %lo(cpcb)], %l6; \
1482	ld	[%l6 + PCB_WIM], %l5; \
1483	and	%l0, 31, %l4; \
1484	sub	%l4, %l5, %l5; \
1485	set	uwtab, %l4; \
1486	ldub	[%l4 + %l5], %l5; \
1487	st	%l5, [%l6 + PCB_UW]; \
1488	/* cond codes still indicate whether in trap window */ \
1489	bz,a	2f; \
1490	 sethi	%hi(USPACE+(stackspace)), %l5; \
1491	/* yes, in trap window; must clean it */ \
1492	CALL_CLEAN_TRAP_WINDOW; \
1493	sethi	%hi(cpcb), %l6; \
1494	ld	[%l6 + %lo(cpcb)], %l6; \
1495	sethi	%hi(USPACE+(stackspace)), %l5; \
14962: \
1497	/* trap window is (now) clean: set %sp */ \
1498	or	%l5, %lo(USPACE+(stackspace)), %l5; \
1499	add	%l6, %l5, %sp; \
1500	SET_SP_REDZONE(%l6, %l5); \
15013: \
1502	CHECK_SP_REDZONE(%l6, %l5)
1503
1504/*
1505 * Interrupt setup is almost exactly like trap setup, but we need to
1506 * go to the interrupt stack if (a) we came from user mode or (b) we
1507 * came from kernel mode on the kernel stack.
1508 */
1509#if defined(MULTIPROCESSOR)
1510/*
1511 * SMP kernels: read `eintstack' from cpuinfo structure. Since the
1512 * location of the interrupt stack is not known in advance, we need
1513 * to check the current %fp against both ends of the stack space.
1514 */
1515#define	INTR_SETUP(stackspace) \
1516	rd	%wim, %l4; \
1517	mov	1, %l5; \
1518	sll	%l5, %l0, %l5; \
1519	btst	PSR_PS, %l0; \
1520	bz	1f; \
1521	 btst	%l5, %l4; \
1522	/* came from kernel mode; cond codes still indicate trap window */ \
1523	bz,a	0f; \
1524	 sethi	%hi(_EINTSTACKP), %l7; \
1525	CALL_CLEAN_TRAP_WINDOW; \
1526	sethi	%hi(_EINTSTACKP), %l7; \
15270:	/* now if not intstack > %fp >= eintstack, we were on the kernel stack */ \
1528	ld	[%l7 + %lo(_EINTSTACKP)], %l7; \
1529	cmp	%fp, %l7; \
1530	bge,a	3f;			/* %fp >= eintstack */ \
1531	 add	%l7, stackspace, %sp;	/* so switch to intstack */ \
1532	sethi	%hi(INT_STACK_SIZE), %l6; \
1533	sub	%l7, %l6, %l6; \
1534	cmp	%fp, %l6; \
1535	blu,a	3f;			/* %fp < intstack */ \
1536	 add	%l7, stackspace, %sp;	/* so switch to intstack */ \
1537	b	4f; \
1538	 add	%fp, stackspace, %sp;	/* else stay on intstack */ \
15391: \
1540	/* came from user mode: compute pcb_nw */ \
1541	sethi	%hi(cpcb), %l6; \
1542	ld	[%l6 + %lo(cpcb)], %l6; \
1543	ld	[%l6 + PCB_WIM], %l5; \
1544	and	%l0, 31, %l4; \
1545	sub	%l4, %l5, %l5; \
1546	set	uwtab, %l4; \
1547	ldub	[%l4 + %l5], %l5; \
1548	st	%l5, [%l6 + PCB_UW]; \
1549	/* cond codes still indicate whether in trap window */ \
1550	bz,a	2f; \
1551	 sethi	%hi(_EINTSTACKP), %l7; \
1552	/* yes, in trap window; must save regs */ \
1553	CALL_CLEAN_TRAP_WINDOW; \
1554	sethi	%hi(_EINTSTACKP), %l7; \
15552: \
1556	ld	[%l7 + %lo(_EINTSTACKP)], %l7; \
1557	add	%l7, stackspace, %sp; \
15583: \
1559	SET_SP_REDZONE_VAR(_EINTSTACKP, -INT_STACK_SIZE, %l6, %l5); \
15604: \
1561	CHECK_SP_REDZONE(%l6, %l5)
1562
1563#else /* MULTIPROCESSOR */
1564
1565#define	INTR_SETUP(stackspace) \
1566	rd	%wim, %l4; \
1567	mov	1, %l5; \
1568	sll	%l5, %l0, %l5; \
1569	btst	PSR_PS, %l0; \
1570	bz	1f; \
1571	 btst	%l5, %l4; \
1572	/* came from kernel mode; cond codes still indicate trap window */ \
1573	bz,a	0f; \
1574	 sethi	%hi(_C_LABEL(eintstack)), %l7; \
1575	CALL_CLEAN_TRAP_WINDOW; \
1576	sethi	%hi(_C_LABEL(eintstack)), %l7; \
15770:	/* now if %fp >= eintstack, we were on the kernel stack */ \
1578	cmp	%fp, %l7; \
1579	bge,a	3f; \
1580	 add	%l7, stackspace, %sp;	/* so switch to intstack */ \
1581	b	4f; \
1582	 add	%fp, stackspace, %sp;	/* else stay on intstack */ \
15831: \
1584	/* came from user mode: compute pcb_nw */ \
1585	sethi	%hi(cpcb), %l6; \
1586	ld	[%l6 + %lo(cpcb)], %l6; \
1587	ld	[%l6 + PCB_WIM], %l5; \
1588	and	%l0, 31, %l4; \
1589	sub	%l4, %l5, %l5; \
1590	set	uwtab, %l4; \
1591	ldub	[%l4 + %l5], %l5; \
1592	st	%l5, [%l6 + PCB_UW]; \
1593	/* cond codes still indicate whether in trap window */ \
1594	bz,a	2f; \
1595	 sethi	%hi(_C_LABEL(eintstack)), %l7; \
1596	/* yes, in trap window; must save regs */ \
1597	CALL_CLEAN_TRAP_WINDOW; \
1598	sethi	%hi(_C_LABEL(eintstack)), %l7; \
15992: \
1600	add	%l7, stackspace, %sp; \
16013: \
1602	SET_SP_REDZONE_CONST(_C_LABEL(intstack), %l6, %l5); \
16034: \
1604	CHECK_SP_REDZONE(%l6, %l5)
1605#endif /* MULTIPROCESSOR */
1606
1607/*
1608 * Handler for making the trap window shiny clean.
1609 *
1610 * On entry:
1611 *	cpcb->pcb_nw = number of user windows
1612 *	%l0 = %psr
1613 *	%l1 must not be clobbered
1614 *	%l2 must not be clobbered
1615 *	%l3 must not be clobbered
1616 *	%l4 = address for `return'
1617 *	%l7 = saved %g7 (we put this in a delay slot above, to save work)
1618 *
1619 * On return:
1620 *	%wim has changed, along with cpcb->pcb_wim
1621 *	%g7 has been restored
1622 *
1623 * Normally, we push only one window.
1624 */
1625clean_trap_window:
1626	mov	%g5, %l5		! save %g5
1627	mov	%g6, %l6		! ... and %g6
1628/*	mov	%g7, %l7		! ... and %g7 (already done for us) */
1629	sethi	%hi(cpcb), %g6		! get current pcb
1630	ld	[%g6 + %lo(cpcb)], %g6
1631
1632	/* Figure out whether it is a user window (cpcb->pcb_uw > 0). */
1633	ld	[%g6 + PCB_UW], %g7
1634	deccc	%g7
1635	bge	ctw_user
1636	 save	%g0, %g0, %g0		! in any case, enter window to save
1637
1638	/* The window to be pushed is a kernel window. */
1639	std	%l0, [%sp + (0*8)]
1640ctw_merge:
1641	std	%l2, [%sp + (1*8)]
1642	std	%l4, [%sp + (2*8)]
1643	std	%l6, [%sp + (3*8)]
1644	std	%i0, [%sp + (4*8)]
1645	std	%i2, [%sp + (5*8)]
1646	std	%i4, [%sp + (6*8)]
1647	std	%i6, [%sp + (7*8)]
1648
1649	/* Set up new window invalid mask, and update cpcb->pcb_wim. */
1650	rd	%psr, %g7		! g7 = (junk << 5) + new_cwp
1651	mov	1, %g5			! g5 = 1 << new_cwp;
1652	sll	%g5, %g7, %g5
1653	wr	%g5, 0, %wim		! setwim(g5);
1654	and	%g7, 31, %g7		! cpcb->pcb_wim = g7 & 31;
1655	sethi	%hi(cpcb), %g6		! re-get current pcb
1656	ld	[%g6 + %lo(cpcb)], %g6
1657	st	%g7, [%g6 + PCB_WIM]
1658	nop
1659	restore				! back to trap window
1660
1661	mov	%l5, %g5		! restore g5
1662	mov	%l6, %g6		! ... and g6
1663	jmp	%l4 + 8			! return to caller
1664	 mov	%l7, %g7		! ... and g7
1665	/* NOTREACHED */
1666
1667ctw_user:
1668	/*
1669	 * The window to be pushed is a user window.
1670	 * We must verify the stack pointer (alignment & permissions).
1671	 * See comments above definition of PTE_OF_ADDR.
1672	 */
1673	st	%g7, [%g6 + PCB_UW]	! cpcb->pcb_uw--;
1674	btst	7, %sp			! if not aligned,
1675	bne	ctw_invalid		! choke on it
1676	 EMPTY
1677
1678	sethi	%hi(_C_LABEL(pgofset)), %g6	! trash %g6=curpcb
1679	ld	[%g6 + %lo(_C_LABEL(pgofset))], %g6
1680	PTE_OF_ADDR(%sp, %g7, ctw_invalid, %g6, NOP_ON_4M_1)
1681	CMP_PTE_USER_WRITE(%g7, %g5, NOP_ON_4M_2) ! likewise if not writable
1682	bne	ctw_invalid
1683	 EMPTY
1684	/* Note side-effect of SLT_IF_1PAGE_RW: decrements %g6 by 62 */
1685	SLT_IF_1PAGE_RW(%sp, %g7, %g6)
1686	bl,a	ctw_merge		! all ok if only 1
1687	 std	%l0, [%sp]
1688	add	%sp, 7*8, %g5		! check last addr too
1689	add	%g6, 62, %g6		! restore %g6 to `pgofset'
1690	PTE_OF_ADDR(%g5, %g7, ctw_invalid, %g6, NOP_ON_4M_3)
1691	CMP_PTE_USER_WRITE(%g7, %g6, NOP_ON_4M_4)
1692	be,a	ctw_merge		! all ok: store <l0,l1> and merge
1693	 std	%l0, [%sp]
1694
1695	/*
1696	 * The window we wanted to push could not be pushed.
1697	 * Instead, save ALL user windows into the pcb.
1698	 * We will notice later that we did this, when we
1699	 * get ready to return from our trap or syscall.
1700	 *
1701	 * The code here is run rarely and need not be optimal.
1702	 */
1703ctw_invalid:
1704	/*
1705	 * Reread cpcb->pcb_uw.  We decremented this earlier,
1706	 * so it is off by one.
1707	 */
1708	sethi	%hi(cpcb), %g6		! re-get current pcb
1709	ld	[%g6 + %lo(cpcb)], %g6
1710
1711	ld	[%g6 + PCB_UW], %g7	! (number of user windows) - 1
1712	add	%g6, PCB_RW, %g5
1713
1714	/* save g7+1 windows, starting with the current one */
17151:					! do {
1716	std	%l0, [%g5 + (0*8)]	!	rw->rw_local[0] = l0;
1717	std	%l2, [%g5 + (1*8)]	!	...
1718	std	%l4, [%g5 + (2*8)]
1719	std	%l6, [%g5 + (3*8)]
1720	std	%i0, [%g5 + (4*8)]
1721	std	%i2, [%g5 + (5*8)]
1722	std	%i4, [%g5 + (6*8)]
1723	std	%i6, [%g5 + (7*8)]
1724	deccc	%g7			!	if (n > 0) save(), rw++;
1725	bge,a	1b			! } while (--n >= 0);
1726	 save	%g5, 64, %g5
1727
1728	/* stash sp for bottommost window */
1729	st	%sp, [%g5 + 64 + (7*8)]
1730
1731	/* set up new wim */
1732	rd	%psr, %g7		! g7 = (junk << 5) + new_cwp;
1733	mov	1, %g5			! g5 = 1 << new_cwp;
1734	sll	%g5, %g7, %g5
1735	wr	%g5, 0, %wim		! wim = g5;
1736	and	%g7, 31, %g7
1737	st	%g7, [%g6 + PCB_WIM]	! cpcb->pcb_wim = new_cwp;
1738
1739	/* fix up pcb fields */
1740	ld	[%g6 + PCB_UW], %g7	! n = cpcb->pcb_uw;
1741	add	%g7, 1, %g5
1742	st	%g5, [%g6 + PCB_NSAVED]	! cpcb->pcb_nsaved = n + 1;
1743	st	%g0, [%g6 + PCB_UW]	! cpcb->pcb_uw = 0;
1744
1745	/* return to trap window */
17461:	deccc	%g7			! do {
1747	bge	1b			!	restore();
1748	 restore			! } while (--n >= 0);
1749
1750	mov	%l5, %g5		! restore g5, g6, & g7, and return
1751	mov	%l6, %g6
1752	jmp	%l4 + 8
1753	 mov	%l7, %g7
1754	/* NOTREACHED */
1755
1756
1757/*
1758 * Each memory access (text or data) fault, from user or kernel mode,
1759 * comes here.  We read the error register and figure out what has
1760 * happened.
1761 *
1762 * This cannot be done from C code since we must not enable traps (and
1763 * hence may not use the `save' instruction) until we have decided that
1764 * the error is or is not an asynchronous one that showed up after a
1765 * synchronous error, but which must be handled before the sync err.
1766 *
1767 * Most memory faults are user mode text or data faults, which can cause
1768 * signal delivery or ptracing, for which we must build a full trapframe.
1769 * It does not seem worthwhile to work to avoid this in the other cases,
1770 * so we store all the %g registers on the stack immediately.
1771 *
1772 * On entry:
1773 *	%l0 = %psr
1774 *	%l1 = return pc
1775 *	%l2 = return npc
1776 *	%l3 = T_TEXTFAULT or T_DATAFAULT
1777 *
1778 * Internal:
1779 *	%l4 = %y, until we call mem_access_fault (then onto trapframe)
1780 *	%l5 = IE_reg_addr, if async mem error
1781 *
1782 */
1783
1784#if defined(SUN4)
1785memfault_sun4:
1786	TRAP_SETUP(-CCFSZ-80)
1787	INCR(_C_LABEL(uvmexp)+V_FAULTS)	! cnt.v_faults++ (clobbers %o0,%o1)
1788
1789	st	%g1, [%sp + CCFSZ + 20]	! save g1
1790	rd	%y, %l4			! save y
1791
1792	/*
1793	 * registers:
1794	 * memerr.ctrl	= memory error control reg., error if 0x80 set
1795	 * memerr.vaddr	= address of memory error
1796	 * buserr	= basically just like sun4c sync error reg but
1797	 *		  no SER_WRITE bit (have to figure out from code).
1798	 */
1799	set	_C_LABEL(par_err_reg), %o0 ! memerr ctrl addr -- XXX mapped?
1800	ld	[%o0], %o0		! get it
1801	std	%g2, [%sp + CCFSZ + 24]	! save g2, g3
1802	ld	[%o0], %o1		! memerr ctrl register
1803	inc	4, %o0			! now VA of memerr vaddr register
1804	std	%g4, [%sp + CCFSZ + 32]	! (sneak g4,g5 in here)
1805	ld	[%o0], %o2		! memerr virt addr
1806	st	%g0, [%o0]		! NOTE: this clears latching!!!
1807	btst	ME_REG_IERR, %o1	! memory error?
1808					! XXX this value may not be correct
1809					! as I got some parity errors and the
1810					! correct bits were not on?
1811	std	%g6, [%sp + CCFSZ + 40]
1812	bz,a	0f			! no, just a regular fault
1813	 wr	%l0, PSR_ET, %psr	! (and reenable traps)
1814
1815	/* memory error = death for now XXX */
1816	clr	%o3
1817	clr	%o4
1818	call	_C_LABEL(memerr4_4c)	! memerr(0, ser, sva, 0, 0)
1819	 clr	%o0
1820	call	_C_LABEL(prom_halt)
1821	 nop
1822
18230:
1824	/*
1825	 * have to make SUN4 emulate SUN4C.   4C code expects
1826	 * SER in %o1 and the offending VA in %o2, everything else is ok.
1827	 * (must figure out if SER_WRITE should be set)
1828	 */
1829	set	AC_BUS_ERR, %o0		! bus error register
1830	cmp	%l3, T_TEXTFAULT	! text fault always on PC
1831	be	normal_mem_fault	! go
1832	 lduba	[%o0] ASI_CONTROL, %o1	! get its value
1833
1834#define STORE_BIT 21 /* bit that indicates a store instruction for sparc */
1835	ld	[%l1], %o3		! offending instruction in %o3 [l1=pc]
1836	srl	%o3, STORE_BIT, %o3	! get load/store bit (wont fit simm13)
1837	btst	1, %o3			! test for store operation
1838
1839	bz	normal_mem_fault	! if (z) is a load (so branch)
1840	 sethi	%hi(SER_WRITE), %o5     ! damn SER_WRITE wont fit simm13
1841!	or	%lo(SER_WRITE), %o5, %o5! not necessary since %lo is zero
1842	or	%o5, %o1, %o1		! set SER_WRITE
1843#if defined(SUN4C) || defined(SUN4M)
1844	ba,a	normal_mem_fault
1845	 !!nop				! XXX make efficient later
1846#endif /* SUN4C || SUN4M */
1847#endif /* SUN4 */
1848
1849memfault_sun4c:
1850#if defined(SUN4C)
1851	TRAP_SETUP(-CCFSZ-80)
1852	INCR(_C_LABEL(uvmexp)+V_FAULTS)	! cnt.v_faults++ (clobbers %o0,%o1)
1853
1854	st	%g1, [%sp + CCFSZ + 20]	! save g1
1855	rd	%y, %l4			! save y
1856
1857	/*
1858	 * We know about the layout of the error registers here.
1859	 *	addr	reg
1860	 *	----	---
1861	 *	a	AC_SYNC_ERR
1862	 *	a+4	AC_SYNC_VA
1863	 *	a+8	AC_ASYNC_ERR
1864	 *	a+12	AC_ASYNC_VA
1865	 */
1866
1867#if AC_SYNC_ERR + 4 != AC_SYNC_VA || \
1868    AC_SYNC_ERR + 8 != AC_ASYNC_ERR || AC_SYNC_ERR + 12 != AC_ASYNC_VA
1869	help help help		! I, I, I wanna be a lifeguard
1870#endif
1871	set	AC_SYNC_ERR, %o0
1872	std	%g2, [%sp + CCFSZ + 24]	! save g2, g3
1873	lda	[%o0] ASI_CONTROL, %o1	! sync err reg
1874	inc	4, %o0
1875	std	%g4, [%sp + CCFSZ + 32]	! (sneak g4,g5 in here)
1876	lda	[%o0] ASI_CONTROL, %o2	! sync virt addr
1877	btst	SER_MEMERR, %o1		! memory error?
1878	std	%g6, [%sp + CCFSZ + 40]
1879	bz,a	normal_mem_fault	! no, just a regular fault
1880 	 wr	%l0, PSR_ET, %psr	! (and reenable traps)
1881
1882	/*
1883	 * We got a synchronous memory error.  It could be one that
1884	 * happened because there were two stores in a row, and the
1885	 * first went into the write buffer, and the second caused this
1886	 * synchronous trap; so there could now be a pending async error.
1887	 * This is in fact the case iff the two va's differ.
1888	 */
1889	inc	4, %o0
1890	lda	[%o0] ASI_CONTROL, %o3	! async err reg
1891	inc	4, %o0
1892	lda	[%o0] ASI_CONTROL, %o4	! async virt addr
1893	cmp	%o2, %o4
1894	be,a	1f			! no, not an async err
1895	 wr	%l0, PSR_ET, %psr	! (and reenable traps)
1896
1897	/*
1898	 * Handle the async error; ignore the sync error for now
1899	 * (we may end up getting it again, but so what?).
1900	 * This code is essentially the same as that at `nmi' below,
1901	 * but the register usage is different and we cannot merge.
1902	 */
1903	sethi	%hi(INTRREG_VA), %l5	! ienab_bic(IE_ALLIE);
1904	ldub	[%l5 + %lo(INTRREG_VA)], %o0
1905	andn	%o0, IE_ALLIE, %o0
1906	stb	%o0, [%l5 + %lo(INTRREG_VA)]
1907
1908	/*
1909	 * Now reenable traps and call C code.
1910	 * %o1 through %o4 still hold the error reg contents.
1911	 * If memerr() returns, return from the trap.
1912	 */
1913	wr	%l0, PSR_ET, %psr
1914	call	_C_LABEL(memerr4_4c)	! memerr(0, ser, sva, aer, ava)
1915	 clr	%o0
1916
1917	ld	[%sp + CCFSZ + 20], %g1	! restore g1 through g7
1918	wr	%l0, 0, %psr		! and disable traps, 3 instr delay
1919	ldd	[%sp + CCFSZ + 24], %g2
1920	ldd	[%sp + CCFSZ + 32], %g4
1921	ldd	[%sp + CCFSZ + 40], %g6
1922	/* now safe to set IE_ALLIE again */
1923	ldub	[%l5 + %lo(INTRREG_VA)], %o1
1924	or	%o1, IE_ALLIE, %o1
1925	stb	%o1, [%l5 + %lo(INTRREG_VA)]
1926	b	return_from_trap
1927	 wr	%l4, 0, %y		! restore y
1928
1929	/*
1930	 * Trap was a synchronous memory error.
1931	 * %o1 through %o4 still hold the error reg contents.
1932	 */
19331:
1934	call	_C_LABEL(memerr4_4c)	! memerr(1, ser, sva, aer, ava)
1935	 mov	1, %o0
1936
1937	ld	[%sp + CCFSZ + 20], %g1	! restore g1 through g7
1938	ldd	[%sp + CCFSZ + 24], %g2
1939	ldd	[%sp + CCFSZ + 32], %g4
1940	ldd	[%sp + CCFSZ + 40], %g6
1941	wr	%l4, 0, %y		! restore y
1942	b	return_from_trap
1943	 wr	%l0, 0, %psr
1944	/* NOTREACHED */
1945#endif /* SUN4C */
1946
1947#if defined(SUN4M)
1948memfault_sun4m:
1949	! DANGER: we use the fact that %lo(CPUINFO_VA) is zero
1950.if CPUINFO_VA & 0x1fff
1951BARF
1952.endif
1953	sethi	%hi(CPUINFO_VA), %l4
1954	ld	[%l4 + %lo(CPUINFO_VA+CPUINFO_GETSYNCFLT)], %l5
1955	jmpl	%l5, %l7
1956	 or	%l4, %lo(CPUINFO_SYNCFLTDUMP), %l4
1957	TRAP_SETUP(-CCFSZ-80)
1958	INCR(_C_LABEL(uvmexp)+V_FAULTS)	! cnt.v_faults++ (clobbers %o0,%o1)
1959
1960	st	%g1, [%sp + CCFSZ + 20]	! save g1
1961	rd	%y, %l4			! save y
1962
1963	std	%g2, [%sp + CCFSZ + 24]	! save g2, g3
1964	std	%g4, [%sp + CCFSZ + 32]	! save g4, g5
1965	std	%g6, [%sp + CCFSZ + 40]	! sneak in g6, g7
1966
1967	! retrieve sync fault status/address
1968	sethi	%hi(CPUINFO_VA+CPUINFO_SYNCFLTDUMP), %o0
1969	ld	[%o0 + %lo(CPUINFO_VA+CPUINFO_SYNCFLTDUMP)], %o1
1970	ld	[%o0 + %lo(CPUINFO_VA+CPUINFO_SYNCFLTDUMP+4)], %o2
1971
1972	wr	%l0, PSR_ET, %psr	! reenable traps
1973
1974	/* Finish stackframe, call C trap handler */
1975	std	%l0, [%sp + CCFSZ + 0]	! set tf.tf_psr, tf.tf_pc
1976	mov	%l3, %o0		! (argument: type)
1977	st	%l2, [%sp + CCFSZ + 8]	! set tf.tf_npc
1978	st	%l4, [%sp + CCFSZ + 12]	! set tf.tf_y
1979	std	%i0, [%sp + CCFSZ + 48]	! tf.tf_out[0], etc
1980	std	%i2, [%sp + CCFSZ + 56]
1981	std	%i4, [%sp + CCFSZ + 64]
1982	std	%i6, [%sp + CCFSZ + 72]
1983					! mem_access_fault(type,sfsr,sfva,&tf);
1984	call	_C_LABEL(mem_access_fault4m)
1985	 add	%sp, CCFSZ, %o3		! (argument: &tf)
1986
1987	ldd	[%sp + CCFSZ + 0], %l0	! load new values
1988	ldd	[%sp + CCFSZ + 8], %l2
1989	wr	%l3, 0, %y
1990	ld	[%sp + CCFSZ + 20], %g1
1991	ldd	[%sp + CCFSZ + 24], %g2
1992	ldd	[%sp + CCFSZ + 32], %g4
1993	ldd	[%sp + CCFSZ + 40], %g6
1994	ldd	[%sp + CCFSZ + 48], %i0
1995	ldd	[%sp + CCFSZ + 56], %i2
1996	ldd	[%sp + CCFSZ + 64], %i4
1997	ldd	[%sp + CCFSZ + 72], %i6
1998
1999	b	return_from_trap	! go return
2000	 wr	%l0, 0, %psr		! (but first disable traps again)
2001#endif /* SUN4M */
2002
2003normal_mem_fault:
2004	/*
2005	 * Trap was some other error; call C code to deal with it.
2006	 * Must finish trap frame (psr,pc,npc,%y,%o0..%o7) in case
2007	 * we decide to deliver a signal or ptrace the process.
2008	 * %g1..%g7 were already set up above.
2009	 */
2010	std	%l0, [%sp + CCFSZ + 0]	! set tf.tf_psr, tf.tf_pc
2011	mov	%l3, %o0		! (argument: type)
2012	st	%l2, [%sp + CCFSZ + 8]	! set tf.tf_npc
2013	st	%l4, [%sp + CCFSZ + 12]	! set tf.tf_y
2014	mov	%l1, %o3		! (argument: pc)
2015	std	%i0, [%sp + CCFSZ + 48]	! tf.tf_out[0], etc
2016	std	%i2, [%sp + CCFSZ + 56]
2017	mov	%l0, %o4		! (argument: psr)
2018	std	%i4, [%sp + CCFSZ + 64]
2019	std	%i6, [%sp + CCFSZ + 72]
2020	call	_C_LABEL(mem_access_fault)! mem_access_fault(type, ser, sva,
2021					!		pc, psr, &tf);
2022	 add	%sp, CCFSZ, %o5		! (argument: &tf)
2023
2024	ldd	[%sp + CCFSZ + 0], %l0	! load new values
2025	ldd	[%sp + CCFSZ + 8], %l2
2026	wr	%l3, 0, %y
2027	ld	[%sp + CCFSZ + 20], %g1
2028	ldd	[%sp + CCFSZ + 24], %g2
2029	ldd	[%sp + CCFSZ + 32], %g4
2030	ldd	[%sp + CCFSZ + 40], %g6
2031	ldd	[%sp + CCFSZ + 48], %i0
2032	ldd	[%sp + CCFSZ + 56], %i2
2033	ldd	[%sp + CCFSZ + 64], %i4
2034	ldd	[%sp + CCFSZ + 72], %i6
2035
2036	b	return_from_trap	! go return
2037	 wr	%l0, 0, %psr		! (but first disable traps again)
2038
2039
2040/*
2041 * fp_exception has to check to see if we are trying to save
2042 * the FP state, and if so, continue to save the FP state.
2043 *
2044 * We do not even bother checking to see if we were in kernel mode,
2045 * since users have no access to the special_fp_store instruction.
2046 *
2047 * This whole idea was stolen from Sprite.
2048 */
2049fp_exception:
2050	set	special_fp_store, %l4	! see if we came from the special one
2051	cmp	%l1, %l4		! pc == special_fp_store?
2052	bne	slowtrap		! no, go handle per usual
2053	 EMPTY
2054	sethi	%hi(savefpcont), %l4	! yes, "return" to the special code
2055	or	%lo(savefpcont), %l4, %l4
2056	jmp	%l4
2057	 rett	%l4 + 4
2058
2059/*
2060 * slowtrap() builds a trap frame and calls trap().
2061 * This is called `slowtrap' because it *is*....
2062 * We have to build a full frame for ptrace(), for instance.
2063 *
2064 * Registers:
2065 *	%l0 = %psr
2066 *	%l1 = return pc
2067 *	%l2 = return npc
2068 *	%l3 = trap code
2069 */
2070slowtrap:
2071	TRAP_SETUP(-CCFSZ-80)
2072	/*
2073	 * Phew, ready to enable traps and call C code.
2074	 */
2075	mov	%l3, %o0		! put type in %o0 for later
2076Lslowtrap_reenter:
2077	wr	%l0, PSR_ET, %psr	! traps on again
2078	std	%l0, [%sp + CCFSZ]	! tf.tf_psr = psr; tf.tf_pc = ret_pc;
2079	rd	%y, %l3
2080	std	%l2, [%sp + CCFSZ + 8]	! tf.tf_npc = return_npc; tf.tf_y = %y;
2081	st	%g1, [%sp + CCFSZ + 20]
2082	std	%g2, [%sp + CCFSZ + 24]
2083	std	%g4, [%sp + CCFSZ + 32]
2084	std	%g6, [%sp + CCFSZ + 40]
2085	std	%i0, [%sp + CCFSZ + 48]
2086	mov	%l0, %o1		! (psr)
2087	std	%i2, [%sp + CCFSZ + 56]
2088	mov	%l1, %o2		! (pc)
2089	std	%i4, [%sp + CCFSZ + 64]
2090	add	%sp, CCFSZ, %o3		! (&tf)
2091	call	_C_LABEL(trap)		! trap(type, psr, pc, &tf)
2092	 std	%i6, [%sp + CCFSZ + 72]
2093
2094	ldd	[%sp + CCFSZ], %l0	! load new values
2095	ldd	[%sp + CCFSZ + 8], %l2
2096	wr	%l3, 0, %y
2097	ld	[%sp + CCFSZ + 20], %g1
2098	ldd	[%sp + CCFSZ + 24], %g2
2099	ldd	[%sp + CCFSZ + 32], %g4
2100	ldd	[%sp + CCFSZ + 40], %g6
2101	ldd	[%sp + CCFSZ + 48], %i0
2102	ldd	[%sp + CCFSZ + 56], %i2
2103	ldd	[%sp + CCFSZ + 64], %i4
2104	ldd	[%sp + CCFSZ + 72], %i6
2105	b	return_from_trap
2106	 wr	%l0, 0, %psr
2107
2108/*
2109 * Do a `software' trap by re-entering the trap code, possibly first
2110 * switching from interrupt stack to kernel stack.  This is used for
2111 * scheduling and signal ASTs (which generally occur from softclock or
2112 * tty or net interrupts) and register window saves (which might occur
2113 * from anywhere).
2114 *
2115 * The current window is the trap window, and it is by definition clean.
2116 * We enter with the trap type in %o0.  All we have to do is jump to
2117 * Lslowtrap_reenter above, but maybe after switching stacks....
2118 */
2119softtrap:
2120#if defined(MULTIPROCESSOR)
2121	/*
2122	 * The interrupt stack is not at a fixed location
2123	 * and %sp must be checked against both ends.
2124	 */
2125	sethi	%hi(_EINTSTACKP), %l7
2126	ld	[%l7 + %lo(_EINTSTACKP)], %l7
2127	cmp	%sp, %l7
2128	bge	Lslowtrap_reenter
2129	 EMPTY
2130	set	INT_STACK_SIZE, %l6
2131	sub	%l7, %l6, %l7
2132	cmp	%sp, %l7
2133	blu	Lslowtrap_reenter
2134	 EMPTY
2135#else
2136	sethi	%hi(_C_LABEL(eintstack)), %l7
2137	cmp	%sp, %l7
2138	bge	Lslowtrap_reenter
2139	 EMPTY
2140#endif
2141	sethi	%hi(cpcb), %l6
2142	ld	[%l6 + %lo(cpcb)], %l6
2143	set	USPACE-CCFSZ-80, %l5
2144	add	%l6, %l5, %l7
2145	SET_SP_REDZONE(%l6, %l5)
2146	b	Lslowtrap_reenter
2147	 mov	%l7, %sp
2148
2149#ifdef KGDB
2150/*
2151 * bpt is entered on all breakpoint traps.
2152 * If this is a kernel breakpoint, we do not want to call trap().
2153 * Among other reasons, this way we can set breakpoints in trap().
2154 */
2155bpt:
2156	btst	PSR_PS, %l0		! breakpoint from kernel?
2157	bz	slowtrap		! no, go do regular trap
2158	 nop
2159
2160/* XXXSMP */
2161	/*
2162	 * Build a trap frame for kgdb_trap_glue to copy.
2163	 * Enable traps but set ipl high so that we will not
2164	 * see interrupts from within breakpoints.
2165	 */
2166	TRAP_SETUP(-CCFSZ-80)
2167	or	%l0, PSR_PIL, %l4	! splhigh()
2168	wr	%l4, 0, %psr		! the manual claims that this
2169	wr	%l4, PSR_ET, %psr	! song and dance is necessary
2170	std	%l0, [%sp + CCFSZ + 0]	! tf.tf_psr, tf.tf_pc
2171	mov	%l3, %o0		! trap type arg for kgdb_trap_glue
2172	rd	%y, %l3
2173	std	%l2, [%sp + CCFSZ + 8]	! tf.tf_npc, tf.tf_y
2174	rd	%wim, %l3
2175	st	%l3, [%sp + CCFSZ + 16]	! tf.tf_wim (a kgdb-only r/o field)
2176	st	%g1, [%sp + CCFSZ + 20]	! tf.tf_global[1]
2177	std	%g2, [%sp + CCFSZ + 24]	! etc
2178	std	%g4, [%sp + CCFSZ + 32]
2179	std	%g6, [%sp + CCFSZ + 40]
2180	std	%i0, [%sp + CCFSZ + 48]	! tf.tf_in[0..1]
2181	std	%i2, [%sp + CCFSZ + 56]	! etc
2182	std	%i4, [%sp + CCFSZ + 64]
2183	std	%i6, [%sp + CCFSZ + 72]
2184
2185	/*
2186	 * Now call kgdb_trap_glue(); if it returns, call trap().
2187	 */
2188	mov	%o0, %l3		! gotta save trap type
2189	call	_C_LABEL(kgdb_trap_glue)! kgdb_trap_glue(type, &trapframe)
2190	 add	%sp, CCFSZ, %o1		! (&trapframe)
2191
2192	/*
2193	 * Use slowtrap to call trap---but first erase our tracks
2194	 * (put the registers back the way they were).
2195	 */
2196	mov	%l3, %o0		! slowtrap will need trap type
2197	ld	[%sp + CCFSZ + 12], %l3
2198	wr	%l3, 0, %y
2199	ld	[%sp + CCFSZ + 20], %g1
2200	ldd	[%sp + CCFSZ + 24], %g2
2201	ldd	[%sp + CCFSZ + 32], %g4
2202	b	Lslowtrap_reenter
2203	 ldd	[%sp + CCFSZ + 40], %g6
2204
2205/*
2206 * Enter kernel breakpoint.  Write all the windows (not including the
2207 * current window) into the stack, so that backtrace works.  Copy the
2208 * supplied trap frame to the kgdb stack and switch stacks.
2209 *
2210 * kgdb_trap_glue(type, tf0)
2211 *	int type;
2212 *	struct trapframe *tf0;
2213 */
2214_ENTRY(_C_LABEL(kgdb_trap_glue))
2215	save	%sp, -CCFSZ, %sp
2216
2217	call	_C_LABEL(write_all_windows)
2218	 mov	%sp, %l4		! %l4 = current %sp
2219
2220	/* copy trapframe to top of kgdb stack */
2221	set	_C_LABEL(kgdb_stack) + KGDB_STACK_SIZE - 80, %l0
2222					! %l0 = tfcopy -> end_of_kgdb_stack
2223	mov	80, %l1
22241:	ldd	[%i1], %l2
2225	inc	8, %i1
2226	deccc	8, %l1
2227	std	%l2, [%l0]
2228	bg	1b
2229	 inc	8, %l0
2230
2231#ifdef DEBUG
2232	/* save old red zone and then turn it off */
2233	sethi	%hi(_redzone), %l7
2234	ld	[%l7 + %lo(_redzone)], %l6
2235	st	%g0, [%l7 + %lo(_redzone)]
2236#endif
2237	/* switch to kgdb stack */
2238	add	%l0, -CCFSZ-80, %sp
2239
2240	/* if (kgdb_trap(type, tfcopy)) kgdb_rett(tfcopy); */
2241	mov	%i0, %o0
2242	call	_C_LABEL(kgdb_trap)
2243	add	%l0, -80, %o1
2244	tst	%o0
2245	bnz,a	kgdb_rett
2246	 add	%l0, -80, %g1
2247
2248	/*
2249	 * kgdb_trap() did not handle the trap at all so the stack is
2250	 * still intact.  A simple `restore' will put everything back,
2251	 * after we reset the stack pointer.
2252	 */
2253	mov	%l4, %sp
2254#ifdef DEBUG
2255	st	%l6, [%l7 + %lo(_redzone)]	! restore red zone
2256#endif
2257	ret
2258	restore
2259
2260/*
2261 * Return from kgdb trap.  This is sort of special.
2262 *
2263 * We know that kgdb_trap_glue wrote the window above it, so that we will
2264 * be able to (and are sure to have to) load it up.  We also know that we
2265 * came from kernel land and can assume that the %fp (%i6) we load here
2266 * is proper.  We must also be sure not to lower ipl (it is at splhigh())
2267 * until we have traps disabled, due to the SPARC taking traps at the
2268 * new ipl before noticing that PSR_ET has been turned off.  We are on
2269 * the kgdb stack, so this could be disastrous.
2270 *
2271 * Note that the trapframe argument in %g1 points into the current stack
2272 * frame (current window).  We abandon this window when we move %g1->tf_psr
2273 * into %psr, but we will not have loaded the new %sp yet, so again traps
2274 * must be disabled.
2275 */
2276kgdb_rett:
2277	rd	%psr, %g4		! turn off traps
2278	wr	%g4, PSR_ET, %psr
2279	/* use the three-instruction delay to do something useful */
2280	ld	[%g1], %g2		! pick up new %psr
2281	ld	[%g1 + 12], %g3		! set %y
2282	wr	%g3, 0, %y
2283#ifdef DEBUG
2284	st	%l6, [%l7 + %lo(_redzone)] ! and restore red zone
2285#endif
2286	wr	%g0, 0, %wim		! enable window changes
2287	nop; nop; nop
2288	/* now safe to set the new psr (changes CWP, leaves traps disabled) */
2289	wr	%g2, 0, %psr		! set rett psr (including cond codes)
2290	/* 3 instruction delay before we can use the new window */
2291/*1*/	ldd	[%g1 + 24], %g2		! set new %g2, %g3
2292/*2*/	ldd	[%g1 + 32], %g4		! set new %g4, %g5
2293/*3*/	ldd	[%g1 + 40], %g6		! set new %g6, %g7
2294
2295	/* now we can use the new window */
2296	mov	%g1, %l4
2297	ld	[%l4 + 4], %l1		! get new pc
2298	ld	[%l4 + 8], %l2		! get new npc
2299	ld	[%l4 + 20], %g1		! set new %g1
2300
2301	/* set up returnee's out registers, including its %sp */
2302	ldd	[%l4 + 48], %i0
2303	ldd	[%l4 + 56], %i2
2304	ldd	[%l4 + 64], %i4
2305	ldd	[%l4 + 72], %i6
2306
2307	/* load returnee's window, making the window above it be invalid */
2308	restore
2309	restore	%g0, 1, %l1		! move to inval window and set %l1 = 1
2310	rd	%psr, %l0
2311	sll	%l1, %l0, %l1
2312	wr	%l1, 0, %wim		! %wim = 1 << (%psr & 31)
2313	sethi	%hi(cpcb), %l1
2314	ld	[%l1 + %lo(cpcb)], %l1
2315	and	%l0, 31, %l0		! CWP = %psr & 31;
2316	st	%l0, [%l1 + PCB_WIM]	! cpcb->pcb_wim = CWP;
2317	save	%g0, %g0, %g0		! back to window to reload
2318	LOADWIN(%sp)
2319	save	%g0, %g0, %g0		! back to trap window
2320	/* note, we have not altered condition codes; safe to just rett */
2321	RETT
2322#endif
2323
2324/*
2325 * syscall() builds a trap frame and calls syscall().
2326 * sun_syscall is same but delivers sun system call number
2327 * XXX	should not have to save&reload ALL the registers just for
2328 *	ptrace...
2329 */
2330_C_LABEL(_syscall):
2331	TRAP_SETUP(-CCFSZ-80)
2332	wr	%l0, PSR_ET, %psr
2333	std	%l0, [%sp + CCFSZ + 0]	! tf_psr, tf_pc
2334	rd	%y, %l3
2335	std	%l2, [%sp + CCFSZ + 8]	! tf_npc, tf_y
2336	st	%g1, [%sp + CCFSZ + 20]	! tf_g[1]
2337	std	%g2, [%sp + CCFSZ + 24]	! tf_g[2], tf_g[3]
2338	std	%g4, [%sp + CCFSZ + 32]	! etc
2339	std	%g6, [%sp + CCFSZ + 40]
2340	mov	%g1, %o0		! (code)
2341	std	%i0, [%sp + CCFSZ + 48]
2342	add	%sp, CCFSZ, %o1		! (&tf)
2343	std	%i2, [%sp + CCFSZ + 56]
2344	mov	%l1, %o2		! (pc)
2345	std	%i4, [%sp + CCFSZ + 64]
2346	call	_C_LABEL(syscall)	! syscall(code, &tf, pc, suncompat)
2347	 std	%i6, [%sp + CCFSZ + 72]
2348	! now load em all up again, sigh
2349	ldd	[%sp + CCFSZ + 0], %l0	! new %psr, new pc
2350	ldd	[%sp + CCFSZ + 8], %l2	! new npc, new %y
2351	wr	%l3, 0, %y
2352	/* see `proc_trampoline' for the reason for this label */
2353return_from_syscall:
2354	ld	[%sp + CCFSZ + 20], %g1
2355	ldd	[%sp + CCFSZ + 24], %g2
2356	ldd	[%sp + CCFSZ + 32], %g4
2357	ldd	[%sp + CCFSZ + 40], %g6
2358	ldd	[%sp + CCFSZ + 48], %i0
2359	ldd	[%sp + CCFSZ + 56], %i2
2360	ldd	[%sp + CCFSZ + 64], %i4
2361	ldd	[%sp + CCFSZ + 72], %i6
2362	b	return_from_trap
2363	 wr	%l0, 0, %psr
2364
2365/*
2366 * Interrupts.  Software interrupts must be cleared from the software
2367 * interrupt enable register.  Rather than calling ienab_bic for each,
2368 * we do them in-line before enabling traps.
2369 *
2370 * After preliminary setup work, the interrupt is passed to each
2371 * registered handler in turn.  These are expected to return nonzero if
2372 * they took care of the interrupt.  If a handler claims the interrupt,
2373 * we exit (hardware interrupts are latched in the requestor so we'll
2374 * just take another interrupt in the unlikely event of simultaneous
2375 * interrupts from two different devices at the same level).  If we go
2376 * through all the registered handlers and no one claims it, we report a
2377 * stray interrupt.  This is more or less done as:
2378 *
2379 *	for (ih = intrhand[intlev]; ih; ih = ih->ih_next)
2380 *		if ((*ih->ih_fun)(ih->ih_arg ? ih->ih_arg : &frame))
2381 *			return;
2382 *	strayintr(&frame);
2383 *
2384 * Software interrupts are almost the same with three exceptions:
2385 * (1) we clear the interrupt from the software interrupt enable
2386 *     register before calling any handler (we have to clear it first
2387 *     to avoid an interrupt-losing race),
2388 * (2) we always call all the registered handlers (there is no way
2389 *     to tell if the single bit in the software interrupt register
2390 *     represents one or many requests)
2391 * (3) we never announce a stray interrupt (because of (1), another
2392 *     interrupt request can come in while we're in the handler.  If
2393 *     the handler deals with everything for both the original & the
2394 *     new request, we'll erroneously report a stray interrupt when
2395 *     we take the software interrupt for the new request.
2396 *
2397 * Inputs:
2398 *	%l0 = %psr
2399 *	%l1 = return pc
2400 *	%l2 = return npc
2401 *	%l3 = interrupt level
2402 *	(software interrupt only) %l4 = bits to clear in interrupt register
2403 *
2404 * Internal:
2405 *	%l4, %l5: local variables
2406 *	%l6 = %y
2407 *	%l7 = %g1
2408 *	%g2..%g7 go to stack
2409 *
2410 * An interrupt frame is built in the space for a full trapframe;
2411 * this contains the psr, pc, npc, and interrupt level.
2412 */
2413softintr_sun44c:
2414	sethi	%hi(INTRREG_VA), %l6
2415	ldub	[%l6 + %lo(INTRREG_VA)], %l5
2416	andn	%l5, %l4, %l5
2417	stb	%l5, [%l6 + %lo(INTRREG_VA)]
2418
2419softintr_common:
2420	INTR_SETUP(-CCFSZ-80)
2421	std	%g2, [%sp + CCFSZ + 24]	! save registers
2422	INCR(_C_LABEL(uvmexp)+V_INTR)	! cnt.v_intr++; (clobbers %o0,%o1)
2423	mov	%g1, %l7
2424	rd	%y, %l6
2425	std	%g4, [%sp + CCFSZ + 32]
2426	andn	%l0, PSR_PIL, %l4	! %l4 = psr & ~PSR_PIL |
2427	sll	%l3, 8, %l5		!	intlev << IPLSHIFT
2428	std	%g6, [%sp + CCFSZ + 40]
2429	or	%l5, %l4, %l4		!			;
2430	wr	%l4, 0, %psr		! the manual claims this
2431	wr	%l4, PSR_ET, %psr	! song and dance is necessary
2432	std	%l0, [%sp + CCFSZ + 0]	! set up intrframe/clockframe
2433	sll	%l3, 2, %l5
2434	set	_C_LABEL(intrcnt), %l4	! intrcnt[intlev]++;
2435	ld	[%l4 + %l5], %o0
2436	std	%l2, [%sp + CCFSZ + 8]
2437	inc	%o0
2438	st	%o0, [%l4 + %l5]
2439	set	_C_LABEL(intrhand), %l4	! %l4 = intrhand[intlev];
2440	ld	[%l4 + %l5], %l4
2441	b	3f
2442	 st	%fp, [%sp + CCFSZ + 16]
2443
24441:	ld	[%l4], %o1
2445	ld	[%l4 + 4], %o0
2446	tst	%o0
2447	bz,a	2f
2448	 add	%sp, CCFSZ, %o0
24492:	jmpl	%o1, %o7		!	(void)(*ih->ih_fun)(...)
2450	 ld	[%l4 + 8], %l4		!	and ih = ih->ih_next
24513:	tst	%l4			! while ih != NULL
2452	bnz	1b
2453	 nop
2454	mov	%l7, %g1
2455	wr	%l6, 0, %y
2456	ldd	[%sp + CCFSZ + 24], %g2
2457	ldd	[%sp + CCFSZ + 32], %g4
2458	ldd	[%sp + CCFSZ + 40], %g6
2459	b	return_from_trap
2460	 wr	%l0, 0, %psr
2461
2462	/*
2463	 * _sparc_interrupt{44c,4m} is exported for paranoia checking
2464	 * (see intr.c).
2465	 */
2466#if defined(SUN4M)
2467_ENTRY(_C_LABEL(sparc_interrupt4m))
2468#if !defined(MSIIEP)	/* "normal" sun4m */
2469	mov	1, %l4
2470	sethi	%hi(CPUINFO_VA+CPUINFO_INTREG), %l6
2471	ld	[%l6 + %lo(CPUINFO_VA+CPUINFO_INTREG)], %l6
2472	ld	[%l6 + ICR_PI_PEND_OFFSET], %l5	! get pending interrupts
2473	sll	%l4, %l3, %l4			! test SOFTINT bit
2474	andcc	%l5, %l4, %g0
2475	bne	sparc_interrupt_common
2476	 nop
2477
2478	! a soft interrupt; clear bit in interrupt-pending register
2479	sll	%l4, 16, %l5
2480	st	%l5, [%l6 + ICR_PI_CLR_OFFSET]
2481	b,a	softintr_common
2482#else /* MSIIEP */
2483	sethi	%hi(MSIIEP_PCIC_VA), %l6
2484	mov	1, %l4
2485	ld	[%l6 + PCIC_PROC_IPR_REG], %l5 ! get pending interrupts
2486	sll	%l4, %l3, %l4
2487	btst	%l4, %l5	!  has pending hw intr at this level?
2488	bnz	sparc_interrupt_common
2489	 nop
2490
2491	! a soft interrupt; clear its bit in softintr clear register
2492	b	softintr_common
2493	 sth	%l4, [%l6 + PCIC_SOFT_INTR_CLEAR_REG]
2494#endif /* MSIIEP */
2495#endif /* SUN4M */
2496
2497_ENTRY(_C_LABEL(sparc_interrupt44c))
2498sparc_interrupt_common:
2499	INTR_SETUP(-CCFSZ-80)
2500	std	%g2, [%sp + CCFSZ + 24]	! save registers
2501	INCR(_C_LABEL(uvmexp)+V_INTR)	! cnt.v_intr++; (clobbers %o0,%o1)
2502	mov	%g1, %l7
2503	rd	%y, %l6
2504	std	%g4, [%sp + CCFSZ + 32]
2505	andn	%l0, PSR_PIL, %l4	! %l4 = psr & ~PSR_PIL |
2506	sll	%l3, 8, %l5		!	intlev << IPLSHIFT
2507	std	%g6, [%sp + CCFSZ + 40]
2508	or	%l5, %l4, %l4		!			;
2509	wr	%l4, 0, %psr		! the manual claims this
2510	wr	%l4, PSR_ET, %psr	! song and dance is necessary
2511	std	%l0, [%sp + CCFSZ + 0]	! set up intrframe/clockframe
2512	sll	%l3, 2, %l5
2513	set	_C_LABEL(intrcnt), %l4	! intrcnt[intlev]++;
2514	ld	[%l4 + %l5], %o0
2515	std	%l2, [%sp + CCFSZ + 8]	! set up intrframe/clockframe
2516	inc	%o0
2517	st	%o0, [%l4 + %l5]
2518	set	_C_LABEL(intrhand), %l4	! %l4 = intrhand[intlev];
2519	ld	[%l4 + %l5], %l4
2520
2521#if defined(MULTIPROCESSOR) && defined(SUN4M) /* XXX */
2522	call	_C_LABEL(intr_lock_kernel)
2523	 nop
2524#endif
2525
2526	b	3f
2527	 st	%fp, [%sp + CCFSZ + 16]
2528
25291:	ld	[%l4], %o1
2530	ld	[%l4 + 4], %o0
2531	tst	%o0
2532	bz,a	2f
2533	 add	%sp, CCFSZ, %o0
25342:	jmpl	%o1, %o7		!	handled = (*ih->ih_fun)(...)
2535	 ld	[%l4 + 8], %l4		!	and ih = ih->ih_next
2536	tst	%o0
2537	bnz	4f			! if (handled) break
2538	 nop
25393:	tst	%l4
2540	bnz	1b			! while (ih)
2541	 nop
2542
2543	/* Unhandled interrupts while cold cause IPL to be raised to `high' */
2544	sethi	%hi(_C_LABEL(cold)), %o0
2545	ld	[%o0 + %lo(_C_LABEL(cold))], %o0
2546	tst	%o0			! if (cold) {
2547	bnz,a	4f			!	splhigh();
2548	 or	%l0, 0xf00, %l0		! } else
2549
2550	call	_C_LABEL(strayintr)	!	strayintr(&intrframe)
2551	 add	%sp, CCFSZ, %o0
2552	/* all done: restore registers and go return */
25534:
2554#if defined(MULTIPROCESSOR) && defined(SUN4M) /* XXX */
2555	call	_C_LABEL(intr_unlock_kernel)
2556	 nop
2557#endif
2558	mov	%l7, %g1
2559	wr	%l6, 0, %y
2560	ldd	[%sp + CCFSZ + 24], %g2
2561	ldd	[%sp + CCFSZ + 32], %g4
2562	ldd	[%sp + CCFSZ + 40], %g6
2563	b	return_from_trap
2564	 wr	%l0, 0, %psr
2565
2566#ifdef notyet
2567/*
2568 * Level 12 (ZS serial) interrupt.  Handle it quickly, schedule a
2569 * software interrupt, and get out.  Do the software interrupt directly
2570 * if we would just take it on the way out.
2571 *
2572 * Input:
2573 *	%l0 = %psr
2574 *	%l1 = return pc
2575 *	%l2 = return npc
2576 * Internal:
2577 *	%l3 = zs device
2578 *	%l4, %l5 = temporary
2579 *	%l6 = rr3 (or temporary data) + 0x100 => need soft int
2580 *	%l7 = zs soft status
2581 */
2582zshard:
2583#endif /* notyet */
2584
2585/*
2586 * Level 15 interrupt.  An async memory error has occurred;
2587 * take care of it (typically by panicking, but hey...).
2588 *	%l0 = %psr
2589 *	%l1 = return pc
2590 *	%l2 = return npc
2591 *	%l3 = 15 * 4 (why? just because!)
2592 *
2593 * Internal:
2594 *	%l4 = %y
2595 *	%l5 = %g1
2596 *	%l6 = %g6
2597 *	%l7 = %g7
2598 *  g2, g3, g4, g5 go to stack
2599 *
2600 * This code is almost the same as that in mem_access_fault,
2601 * except that we already know the problem is not a `normal' fault,
2602 * and that we must be extra-careful with interrupt enables.
2603 */
2604
2605#if defined(SUN4)
2606nmi_sun4:
2607	INTR_SETUP(-CCFSZ-80)
2608	INCR(_C_LABEL(uvmexp)+V_INTR)	! cnt.v_intr++; (clobbers %o0,%o1)
2609	/*
2610	 * Level 15 interrupts are nonmaskable, so with traps off,
2611	 * disable all interrupts to prevent recursion.
2612	 */
2613	sethi	%hi(INTRREG_VA), %o0
2614	ldub	[%o0 + %lo(INTRREG_VA)], %o1
2615	andn	%o0, IE_ALLIE, %o1
2616	stb	%o1, [%o0 + %lo(INTRREG_VA)]
2617	wr	%l0, PSR_ET, %psr	! okay, turn traps on again
2618
2619	std	%g2, [%sp + CCFSZ + 0]	! save g2, g3
2620	rd	%y, %l4			! save y
2621
2622	std	%g4, [%sp + CCFSZ + 8]	! save g4, g5
2623	mov	%g1, %l5		! save g1, g6, g7
2624	mov	%g6, %l6
2625	mov	%g7, %l7
2626#if defined(SUN4C) || defined(SUN4M)
2627	b,a	nmi_common
2628#endif /* SUN4C || SUN4M */
2629#endif
2630
2631#if defined(SUN4C)
2632nmi_sun4c:
2633	INTR_SETUP(-CCFSZ-80)
2634	INCR(_C_LABEL(uvmexp)+V_INTR)	! cnt.v_intr++; (clobbers %o0,%o1)
2635	/*
2636	 * Level 15 interrupts are nonmaskable, so with traps off,
2637	 * disable all interrupts to prevent recursion.
2638	 */
2639	sethi	%hi(INTRREG_VA), %o0
2640	ldub	[%o0 + %lo(INTRREG_VA)], %o1
2641	andn	%o0, IE_ALLIE, %o1
2642	stb	%o1, [%o0 + %lo(INTRREG_VA)]
2643	wr	%l0, PSR_ET, %psr	! okay, turn traps on again
2644
2645	std	%g2, [%sp + CCFSZ + 0]	! save g2, g3
2646	rd	%y, %l4			! save y
2647
2648	! must read the sync error register too.
2649	set	AC_SYNC_ERR, %o0
2650	lda	[%o0] ASI_CONTROL, %o1	! sync err reg
2651	inc	4, %o0
2652	lda	[%o0] ASI_CONTROL, %o2	! sync virt addr
2653	std	%g4, [%sp + CCFSZ + 8]	! save g4,g5
2654	mov	%g1, %l5		! save g1,g6,g7
2655	mov	%g6, %l6
2656	mov	%g7, %l7
2657	inc	4, %o0
2658	lda	[%o0] ASI_CONTROL, %o3	! async err reg
2659	inc	4, %o0
2660	lda	[%o0] ASI_CONTROL, %o4	! async virt addr
2661#if defined(SUN4M)
2662	!!b,a	nmi_common
2663#endif /* SUN4M */
2664#endif /* SUN4C */
2665
2666nmi_common:
2667	! and call C code
2668	call	_C_LABEL(memerr4_4c)	! memerr(0, ser, sva, aer, ava)
2669	 clr	%o0
2670
2671	mov	%l5, %g1		! restore g1 through g7
2672	ldd	[%sp + CCFSZ + 0], %g2
2673	ldd	[%sp + CCFSZ + 8], %g4
2674	wr	%l0, 0, %psr		! re-disable traps
2675	mov	%l6, %g6
2676	mov	%l7, %g7
2677
2678	! set IE_ALLIE again (safe, we disabled traps again above)
2679	sethi	%hi(INTRREG_VA), %o0
2680	ldub	[%o0 + %lo(INTRREG_VA)], %o1
2681	or	%o1, IE_ALLIE, %o1
2682	stb	%o1, [%o0 + %lo(INTRREG_VA)]
2683	b	return_from_trap
2684	 wr	%l4, 0, %y		! restore y
2685
2686#if defined(SUN4M)
2687nmi_sun4m:
2688	INTR_SETUP(-CCFSZ-80)
2689	INCR(_C_LABEL(uvmexp)+V_INTR)	! cnt.v_intr++; (clobbers %o0,%o1)
2690
2691	/* Read the Pending Interrupts register */
2692	sethi	%hi(CPUINFO_VA+CPUINFO_INTREG), %l6
2693	ld	[%l6 + %lo(CPUINFO_VA+CPUINFO_INTREG)], %l6
2694	ld	[%l6 + ICR_PI_PEND_OFFSET], %l5	! get pending interrupts
2695
2696	set	_C_LABEL(nmi_soft), %o3		! assume a softint
2697	set	PINTR_IC, %o1			! hard lvl 15 bit
2698	sethi	%hi(PINTR_SINTRLEV(15)), %o0	! soft lvl 15 bit
2699	btst	%o0, %l5		! soft level 15?
2700	bnz,a	1f			!
2701	 mov	%o0, %o1		! shift int clear bit to SOFTINT 15
2702
2703	set	_C_LABEL(nmi_hard), %o3	! it's a hardint; switch handler
2704
2705	/*
2706	 * Level 15 interrupts are nonmaskable, so with traps off,
2707	 * disable all interrupts to prevent recursion.
2708	 */
2709	sethi	%hi(ICR_SI_SET), %o0
2710	set	SINTR_MA, %o2
2711	st	%o2, [%o0 + %lo(ICR_SI_SET)]
2712#if defined(MULTIPROCESSOR) && defined(DDB)
2713	b	2f
2714	 clr	%o0
2715#endif
2716
27171:
2718#if defined(MULTIPROCESSOR) && defined(DDB)
2719	/*
2720	 * Setup a trapframe for nmi_soft; this might be an IPI telling
2721	 * us to pause, so lets save some state for DDB to get at.
2722	 */
2723	std	%l0, [%sp + CCFSZ]	! tf.tf_psr = psr; tf.tf_pc = ret_pc;
2724	rd	%y, %l3
2725	std	%l2, [%sp + CCFSZ + 8]	! tf.tf_npc = return_npc; tf.tf_y = %y;
2726	st	%g1, [%sp + CCFSZ + 20]
2727	std	%g2, [%sp + CCFSZ + 24]
2728	std	%g4, [%sp + CCFSZ + 32]
2729	std	%g6, [%sp + CCFSZ + 40]
2730	std	%i0, [%sp + CCFSZ + 48]
2731	std	%i2, [%sp + CCFSZ + 56]
2732	std	%i4, [%sp + CCFSZ + 64]
2733	std	%i6, [%sp + CCFSZ + 72]
2734	add	%sp, CCFSZ, %o0
27352:
2736#else
2737	clr	%o0
2738#endif
2739	/*
2740	 * Now clear the NMI. Apparently, we must allow some time
2741	 * to let the bits sink in..
2742	 */
2743	st	%o1, [%l6 + ICR_PI_CLR_OFFSET]
2744	 nop; nop; nop;
2745	ld	[%l6 + ICR_PI_PEND_OFFSET], %g0	! drain register!?
2746	 nop; nop; nop;
2747
2748	wr	%l0, PSR_ET, %psr	! okay, turn traps on again
2749
2750	std	%g2, [%sp + CCFSZ + 80]	! save g2, g3
2751	rd	%y, %l4			! save y
2752	std	%g4, [%sp + CCFSZ + 88]	! save g4,g5
2753
2754	/* Finish stackframe, call C trap handler */
2755	mov	%g1, %l5		! save g1,g6,g7
2756	mov	%g6, %l6
2757
2758	jmpl	%o3, %o7		! nmi_hard(0) or nmi_soft(&tf)
2759	 mov	%g7, %l7
2760
2761	mov	%l5, %g1		! restore g1 through g7
2762	ldd	[%sp + CCFSZ + 80], %g2
2763	ldd	[%sp + CCFSZ + 88], %g4
2764	wr	%l0, 0, %psr		! re-disable traps
2765	mov	%l6, %g6
2766	mov	%l7, %g7
2767
2768	!cmp	%o0, 0			! was this a soft nmi
2769	!be	4f
2770	!XXX - we need to unblock `mask all ints' only on a hard nmi
2771
2772	! enable interrupts again (safe, we disabled traps again above)
2773	sethi	%hi(ICR_SI_CLR), %o0
2774	set	SINTR_MA, %o1
2775	st	%o1, [%o0 + %lo(ICR_SI_CLR)]
2776
27774:
2778	b	return_from_trap
2779	 wr	%l4, 0, %y		! restore y
2780#endif /* SUN4M */
2781
2782#ifdef GPROF
2783	.globl	window_of, winof_user
2784	.globl	window_uf, winuf_user, winuf_ok, winuf_invalid
2785	.globl	return_from_trap, rft_kernel, rft_user, rft_invalid
2786	.globl	softtrap, slowtrap
2787	.globl	clean_trap_window, _C_LABEL(_syscall)
2788#endif
2789
2790/*
2791 * Window overflow trap handler.
2792 *	%l0 = %psr
2793 *	%l1 = return pc
2794 *	%l2 = return npc
2795 */
2796window_of:
2797#ifdef TRIVIAL_WINDOW_OVERFLOW_HANDLER
2798	/* a trivial version that assumes %sp is ok */
2799	/* (for testing only!) */
2800	save	%g0, %g0, %g0
2801	std	%l0, [%sp + (0*8)]
2802	rd	%psr, %l0
2803	mov	1, %l1
2804	sll	%l1, %l0, %l0
2805	wr	%l0, 0, %wim
2806	std	%l2, [%sp + (1*8)]
2807	std	%l4, [%sp + (2*8)]
2808	std	%l6, [%sp + (3*8)]
2809	std	%i0, [%sp + (4*8)]
2810	std	%i2, [%sp + (5*8)]
2811	std	%i4, [%sp + (6*8)]
2812	std	%i6, [%sp + (7*8)]
2813	restore
2814	RETT
2815#else
2816	/*
2817	 * This is similar to TRAP_SETUP, but we do not want to spend
2818	 * a lot of time, so we have separate paths for kernel and user.
2819	 * We also know for sure that the window has overflowed.
2820	 */
2821	btst	PSR_PS, %l0
2822	bz	winof_user
2823	 sethi	%hi(clean_trap_window), %l7
2824
2825	/*
2826	 * Overflow from kernel mode.  Call clean_trap_window to
2827	 * do the dirty work, then just return, since we know prev
2828	 * window is valid.  clean_trap_windows might dump all *user*
2829	 * windows into the pcb, but we do not care: there is at
2830	 * least one kernel window (a trap or interrupt frame!)
2831	 * above us.
2832	 */
2833	jmpl	%l7 + %lo(clean_trap_window), %l4
2834	 mov	%g7, %l7		! for clean_trap_window
2835
2836	wr	%l0, 0, %psr		! put back the @%*! cond. codes
2837	nop				! (let them settle in)
2838	RETT
2839
2840winof_user:
2841	/*
2842	 * Overflow from user mode.
2843	 * If clean_trap_window dumps the registers into the pcb,
2844	 * rft_user will need to call trap(), so we need space for
2845	 * a trap frame.  We also have to compute pcb_nw.
2846	 *
2847	 * SHOULD EXPAND IN LINE TO AVOID BUILDING TRAP FRAME ON
2848	 * `EASY' SAVES
2849	 */
2850	sethi	%hi(cpcb), %l6
2851	ld	[%l6 + %lo(cpcb)], %l6
2852	ld	[%l6 + PCB_WIM], %l5
2853	and	%l0, 31, %l3
2854	sub	%l3, %l5, %l5 		/* l5 = CWP - pcb_wim */
2855	set	uwtab, %l4
2856	ldub	[%l4 + %l5], %l5	/* l5 = uwtab[l5] */
2857	st	%l5, [%l6 + PCB_UW]
2858	jmpl	%l7 + %lo(clean_trap_window), %l4
2859	 mov	%g7, %l7		! for clean_trap_window
2860	sethi	%hi(cpcb), %l6
2861	ld	[%l6 + %lo(cpcb)], %l6
2862	set	USPACE-CCFSZ-80, %l5
2863	add	%l6, %l5, %sp		/* over to kernel stack */
2864	CHECK_SP_REDZONE(%l6, %l5)
2865
2866	/*
2867	 * Copy return_from_trap far enough to allow us
2868	 * to jump directly to rft_user_or_recover_pcb_windows
2869	 * (since we know that is where we are headed).
2870	 */
2871!	and	%l0, 31, %l3		! still set (clean_trap_window
2872					! leaves this register alone)
2873	set	wmask, %l6
2874	ldub	[%l6 + %l3], %l5	! %l5 = 1 << ((CWP + 1) % nwindows)
2875	b	rft_user_or_recover_pcb_windows
2876	 rd	%wim, %l4		! (read %wim first)
2877#endif /* end `real' version of window overflow trap handler */
2878
2879/*
2880 * Window underflow trap handler.
2881 *	%l0 = %psr
2882 *	%l1 = return pc
2883 *	%l2 = return npc
2884 *
2885 * A picture:
2886 *
2887 *	  T R I X
2888 *	0 0 0 1 0 0 0	(%wim)
2889 * [bit numbers increase towards the right;
2890 * `restore' moves right & `save' moves left]
2891 *
2892 * T is the current (Trap) window, R is the window that attempted
2893 * a `Restore' instruction, I is the Invalid window, and X is the
2894 * window we want to make invalid before we return.
2895 *
2896 * Since window R is valid, we cannot use rft_user to restore stuff
2897 * for us.  We have to duplicate its logic.  YUCK.
2898 *
2899 * Incidentally, TRIX are for kids.  Silly rabbit!
2900 */
2901window_uf:
2902#ifdef TRIVIAL_WINDOW_UNDERFLOW_HANDLER
2903	wr	%g0, 0, %wim		! allow us to enter I
2904	restore				! to R
2905	nop
2906	nop
2907	restore				! to I
2908	restore	%g0, 1, %l1		! to X
2909	rd	%psr, %l0
2910	sll	%l1, %l0, %l0
2911	wr	%l0, 0, %wim
2912	save	%g0, %g0, %g0		! back to I
2913	LOADWIN(%sp)
2914	save	%g0, %g0, %g0		! back to R
2915	save	%g0, %g0, %g0		! back to T
2916	RETT
2917#else
2918	wr	%g0, 0, %wim		! allow us to enter I
2919	btst	PSR_PS, %l0
2920	restore				! enter window R
2921	bz	winuf_user
2922	 restore			! enter window I
2923
2924	/*
2925	 * Underflow from kernel mode.  Just recover the
2926	 * registers and go (except that we have to update
2927	 * the blasted user pcb fields).
2928	 */
2929	restore	%g0, 1, %l1		! enter window X, then set %l1 to 1
2930	rd	%psr, %l0		! cwp = %psr & 31;
2931	and	%l0, 31, %l0
2932	sll	%l1, %l0, %l1		! wim = 1 << cwp;
2933	wr	%l1, 0, %wim		! setwim(wim);
2934	sethi	%hi(cpcb), %l1
2935	ld	[%l1 + %lo(cpcb)], %l1
2936	st	%l0, [%l1 + PCB_WIM]	! cpcb->pcb_wim = cwp;
2937	save	%g0, %g0, %g0		! back to window I
2938	LOADWIN(%sp)
2939	save	%g0, %g0, %g0		! back to R
2940	save	%g0, %g0, %g0		! and then to T
2941	wr	%l0, 0, %psr		! fix those cond codes....
2942	nop				! (let them settle in)
2943	RETT
2944
2945winuf_user:
2946	/*
2947	 * Underflow from user mode.
2948	 *
2949	 * We cannot use rft_user (as noted above) because
2950	 * we must re-execute the `restore' instruction.
2951	 * Since it could be, e.g., `restore %l0,0,%l0',
2952	 * it is not okay to touch R's registers either.
2953	 *
2954	 * We are now in window I.
2955	 */
2956	btst	7, %sp			! if unaligned, it is invalid
2957	bne	winuf_invalid
2958	 EMPTY
2959
2960	sethi	%hi(_C_LABEL(pgofset)), %l4
2961	ld	[%l4 + %lo(_C_LABEL(pgofset))], %l4
2962	PTE_OF_ADDR(%sp, %l7, winuf_invalid, %l4, NOP_ON_4M_5)
2963	CMP_PTE_USER_READ(%l7, %l5, NOP_ON_4M_6) ! if first page not readable,
2964	bne	winuf_invalid		! it is invalid
2965	 EMPTY
2966	SLT_IF_1PAGE_RW(%sp, %l7, %l4)	! first page is readable
2967	bl,a	winuf_ok		! if only one page, enter window X
2968	 restore %g0, 1, %l1		! and goto ok, & set %l1 to 1
2969	add	%sp, 7*8, %l5
2970	add     %l4, 62, %l4
2971	PTE_OF_ADDR(%l5, %l7, winuf_invalid, %l4, NOP_ON_4M_7)
2972	CMP_PTE_USER_READ(%l7, %l5, NOP_ON_4M_8) ! check second page too
2973	be,a	winuf_ok		! enter window X and goto ok
2974	 restore %g0, 1, %l1		! (and then set %l1 to 1)
2975
2976winuf_invalid:
2977	/*
2978	 * We were unable to restore the window because %sp
2979	 * is invalid or paged out.  Return to the trap window
2980	 * and call trap(T_WINUF).  This will save R to the user
2981	 * stack, then load both R and I into the pcb rw[] area,
2982	 * and return with pcb_nsaved set to -1 for success, 0 for
2983	 * failure.  `Failure' indicates that someone goofed with the
2984	 * trap registers (e.g., signals), so that we need to return
2985	 * from the trap as from a syscall (probably to a signal handler)
2986	 * and let it retry the restore instruction later.  Note that
2987	 * window R will have been pushed out to user space, and thus
2988	 * be the invalid window, by the time we get back here.  (We
2989	 * continue to label it R anyway.)  We must also set %wim again,
2990	 * and set pcb_uw to 1, before enabling traps.  (Window R is the
2991	 * only window, and it is a user window).
2992	 */
2993	save	%g0, %g0, %g0		! back to R
2994	save	%g0, 1, %l4		! back to T, then %l4 = 1
2995	sethi	%hi(cpcb), %l6
2996	ld	[%l6 + %lo(cpcb)], %l6
2997	st	%l4, [%l6 + PCB_UW]	! pcb_uw = 1
2998	ld	[%l6 + PCB_WIM], %l5	! get log2(%wim)
2999	sll	%l4, %l5, %l4		! %l4 = old %wim
3000	wr	%l4, 0, %wim		! window I is now invalid again
3001	set	USPACE-CCFSZ-80, %l5
3002	add	%l6, %l5, %sp		! get onto kernel stack
3003	CHECK_SP_REDZONE(%l6, %l5)
3004
3005	/*
3006	 * Okay, call trap(T_WINUF, psr, pc, &tf).
3007	 * See `slowtrap' above for operation.
3008	 */
3009	wr	%l0, PSR_ET, %psr
3010	std	%l0, [%sp + CCFSZ + 0]	! tf.tf_psr, tf.tf_pc
3011	rd	%y, %l3
3012	std	%l2, [%sp + CCFSZ + 8]	! tf.tf_npc, tf.tf_y
3013	mov	T_WINUF, %o0
3014	st	%g1, [%sp + CCFSZ + 20]	! tf.tf_global[1]
3015	mov	%l0, %o1
3016	std	%g2, [%sp + CCFSZ + 24]	! etc
3017	mov	%l1, %o2
3018	std	%g4, [%sp + CCFSZ + 32]
3019	add	%sp, CCFSZ, %o3
3020	std	%g6, [%sp + CCFSZ + 40]
3021	std	%i0, [%sp + CCFSZ + 48]	! tf.tf_out[0], etc
3022	std	%i2, [%sp + CCFSZ + 56]
3023	std	%i4, [%sp + CCFSZ + 64]
3024	call	_C_LABEL(trap)		! trap(T_WINUF, pc, psr, &tf)
3025	 std	%i6, [%sp + CCFSZ + 72]	! tf.tf_out[6]
3026
3027	ldd	[%sp + CCFSZ + 0], %l0	! new psr, pc
3028	ldd	[%sp + CCFSZ + 8], %l2	! new npc, %y
3029	wr	%l3, 0, %y
3030	ld	[%sp + CCFSZ + 20], %g1
3031	ldd	[%sp + CCFSZ + 24], %g2
3032	ldd	[%sp + CCFSZ + 32], %g4
3033	ldd	[%sp + CCFSZ + 40], %g6
3034	ldd	[%sp + CCFSZ + 48], %i0	! %o0 for window R, etc
3035	ldd	[%sp + CCFSZ + 56], %i2
3036	ldd	[%sp + CCFSZ + 64], %i4
3037	wr	%l0, 0, %psr		! disable traps: test must be atomic
3038	ldd	[%sp + CCFSZ + 72], %i6
3039	sethi	%hi(cpcb), %l6
3040	ld	[%l6 + %lo(cpcb)], %l6
3041	ld	[%l6 + PCB_NSAVED], %l7	! if nsaved is -1, we have our regs
3042	tst	%l7
3043	bl,a	1f			! got them
3044	 wr	%g0, 0, %wim		! allow us to enter windows R, I
3045	b,a	return_from_trap
3046
3047	/*
3048	 * Got 'em.  Load 'em up.
3049	 */
30501:
3051	mov	%g6, %l3		! save %g6; set %g6 = cpcb
3052	mov	%l6, %g6
3053	st	%g0, [%g6 + PCB_NSAVED]	! and clear magic flag
3054	restore				! from T to R
3055	restore				! from R to I
3056	restore	%g0, 1, %l1		! from I to X, then %l1 = 1
3057	rd	%psr, %l0		! cwp = %psr;
3058	sll	%l1, %l0, %l1
3059	wr	%l1, 0, %wim		! make window X invalid
3060	and	%l0, 31, %l0
3061	st	%l0, [%g6 + PCB_WIM]	! cpcb->pcb_wim = cwp;
3062	nop				! unnecessary? old wim was 0...
3063	save	%g0, %g0, %g0		! back to I
3064	LOADWIN(%g6 + PCB_RW + 64)	! load from rw[1]
3065	save	%g0, %g0, %g0		! back to R
3066	LOADWIN(%g6 + PCB_RW)		! load from rw[0]
3067	save	%g0, %g0, %g0		! back to T
3068	wr	%l0, 0, %psr		! restore condition codes
3069	mov	%l3, %g6		! fix %g6
3070	RETT
3071
3072	/*
3073	 * Restoring from user stack, but everything has checked out
3074	 * as good.  We are now in window X, and %l1 = 1.  Window R
3075	 * is still valid and holds user values.
3076	 */
3077winuf_ok:
3078	rd	%psr, %l0
3079	sll	%l1, %l0, %l1
3080	wr	%l1, 0, %wim		! make this one invalid
3081	sethi	%hi(cpcb), %l2
3082	ld	[%l2 + %lo(cpcb)], %l2
3083	and	%l0, 31, %l0
3084	st	%l0, [%l2 + PCB_WIM]	! cpcb->pcb_wim = cwp;
3085	save	%g0, %g0, %g0		! back to I
3086	LOADWIN(%sp)
3087	save	%g0, %g0, %g0		! back to R
3088	save	%g0, %g0, %g0		! back to T
3089	wr	%l0, 0, %psr		! restore condition codes
3090	nop				! it takes three to tangle
3091	RETT
3092#endif /* end `real' version of window underflow trap handler */
3093
3094/*
3095 * Various return-from-trap routines (see return_from_trap).
3096 */
3097
3098/*
3099 * Return from trap, to kernel.
3100 *	%l0 = %psr
3101 *	%l1 = return pc
3102 *	%l2 = return npc
3103 *	%l4 = %wim
3104 *	%l5 = bit for previous window
3105 */
3106rft_kernel:
3107	btst	%l5, %l4		! if (wim & l5)
3108	bnz	1f			!	goto reload;
3109	 wr	%l0, 0, %psr		! but first put !@#*% cond codes back
3110
3111	/* previous window is valid; just rett */
3112	nop				! wait for cond codes to settle in
3113	RETT
3114
3115	/*
3116	 * Previous window is invalid.
3117	 * Update %wim and then reload l0..i7 from frame.
3118	 *
3119	 *	  T I X
3120	 *	0 0 1 0 0   (%wim)
3121	 * [see picture in window_uf handler]
3122	 *
3123	 * T is the current (Trap) window, I is the Invalid window,
3124	 * and X is the window we want to make invalid.  Window X
3125	 * currently has no useful values.
3126	 */
31271:
3128	wr	%g0, 0, %wim		! allow us to enter window I
3129	nop; nop; nop			! (it takes a while)
3130	restore				! enter window I
3131	restore	%g0, 1, %l1		! enter window X, then %l1 = 1
3132	rd	%psr, %l0		! CWP = %psr & 31;
3133	and	%l0, 31, %l0
3134	sll	%l1, %l0, %l1		! wim = 1 << CWP;
3135	wr	%l1, 0, %wim		! setwim(wim);
3136	sethi	%hi(cpcb), %l1
3137	ld	[%l1 + %lo(cpcb)], %l1
3138	st	%l0, [%l1 + PCB_WIM]	! cpcb->pcb_wim = l0 & 31;
3139	save	%g0, %g0, %g0		! back to window I
3140	LOADWIN(%sp)
3141	save	%g0, %g0, %g0		! back to window T
3142	/*
3143	 * Note that the condition codes are still set from
3144	 * the code at rft_kernel; we can simply return.
3145	 */
3146	RETT
3147
3148/*
3149 * Return from trap, to user.  Checks for scheduling trap (`ast') first;
3150 * will re-enter trap() if set.  Note that we may have to switch from
3151 * the interrupt stack to the kernel stack in this case.
3152 *	%l0 = %psr
3153 *	%l1 = return pc
3154 *	%l2 = return npc
3155 *	%l4 = %wim
3156 *	%l5 = bit for previous window
3157 *	%l6 = cpcb
3158 * If returning to a valid window, just set psr and return.
3159 */
3160rft_user:
3161!	sethi	%hi(_C_LABEL(want_ast)), %l7	! (done below)
3162	ld	[%l7 + %lo(_C_LABEL(want_ast))], %l7
3163	tst	%l7			! want AST trap?
3164	bne,a	softtrap		! yes, re-enter trap with type T_AST
3165	 mov	T_AST, %o0
3166
3167	btst	%l5, %l4		! if (wim & l5)
3168	bnz	1f			!	goto reload;
3169	 wr	%l0, 0, %psr		! restore cond codes
3170	nop				! (three instruction delay)
3171	RETT
3172
3173	/*
3174	 * Previous window is invalid.
3175	 * Before we try to load it, we must verify its stack pointer.
3176	 * This is much like the underflow handler, but a bit easier
3177	 * since we can use our own local registers.
3178	 */
31791:
3180	btst	7, %fp			! if unaligned, address is invalid
3181	bne	rft_invalid
3182	 EMPTY
3183
3184	sethi	%hi(_C_LABEL(pgofset)), %l3
3185	ld	[%l3 + %lo(_C_LABEL(pgofset))], %l3
3186	PTE_OF_ADDR(%fp, %l7, rft_invalid, %l3, NOP_ON_4M_9)
3187	CMP_PTE_USER_READ(%l7, %l5, NOP_ON_4M_10)	! try first page
3188	bne	rft_invalid		! no good
3189	 EMPTY
3190	SLT_IF_1PAGE_RW(%fp, %l7, %l3)
3191	bl,a	rft_user_ok		! only 1 page: ok
3192	 wr	%g0, 0, %wim
3193	add	%fp, 7*8, %l5
3194	add	%l3, 62, %l3
3195	PTE_OF_ADDR(%l5, %l7, rft_invalid, %l3, NOP_ON_4M_11)
3196	CMP_PTE_USER_READ(%l7, %l5, NOP_ON_4M_12)	! check 2nd page too
3197	be,a	rft_user_ok
3198	 wr	%g0, 0, %wim
3199
3200	/*
3201	 * The window we wanted to pull could not be pulled.  Instead,
3202	 * re-enter trap with type T_RWRET.  This will pull the window
3203	 * into cpcb->pcb_rw[0] and set cpcb->pcb_nsaved to -1, which we
3204	 * will detect when we try to return again.
3205	 */
3206rft_invalid:
3207	b	softtrap
3208	 mov	T_RWRET, %o0
3209
3210	/*
3211	 * The window we want to pull can be pulled directly.
3212	 */
3213rft_user_ok:
3214!	wr	%g0, 0, %wim		! allow us to get into it
3215	wr	%l0, 0, %psr		! fix up the cond codes now
3216	nop; nop; nop
3217	restore				! enter window I
3218	restore	%g0, 1, %l1		! enter window X, then %l1 = 1
3219	rd	%psr, %l0		! l0 = (junk << 5) + CWP;
3220	sll	%l1, %l0, %l1		! %wim = 1 << CWP;
3221	wr	%l1, 0, %wim
3222	sethi	%hi(cpcb), %l1
3223	ld	[%l1 + %lo(cpcb)], %l1
3224	and	%l0, 31, %l0
3225	st	%l0, [%l1 + PCB_WIM]	! cpcb->pcb_wim = l0 & 31;
3226	save	%g0, %g0, %g0		! back to window I
3227	LOADWIN(%sp)			! suck hard
3228	save	%g0, %g0, %g0		! back to window T
3229	RETT
3230
3231/*
3232 * Return from trap.  Entered after a
3233 *	wr	%l0, 0, %psr
3234 * which disables traps so that we can rett; registers are:
3235 *
3236 *	%l0 = %psr
3237 *	%l1 = return pc
3238 *	%l2 = return npc
3239 *
3240 * (%l3..%l7 anything).
3241 *
3242 * If we are returning to user code, we must:
3243 *  1.  Check for register windows in the pcb that belong on the stack.
3244 *	If there are any, reenter trap with type T_WINOF.
3245 *  2.  Make sure the register windows will not underflow.  This is
3246 *	much easier in kernel mode....
3247 */
3248return_from_trap:
3249!	wr	%l0, 0, %psr		! disable traps so we can rett
3250! (someone else did this already)
3251	and	%l0, 31, %l5
3252	set	wmask, %l6
3253	ldub	[%l6 + %l5], %l5	! %l5 = 1 << ((CWP + 1) % nwindows)
3254	btst	PSR_PS, %l0		! returning to userland?
3255	bnz	rft_kernel		! no, go return to kernel
3256	 rd	%wim, %l4		! (read %wim in any case)
3257
3258rft_user_or_recover_pcb_windows:
3259	/*
3260	 * (entered with %l4=%wim, %l5=wmask[cwp]; %l0..%l2 as usual)
3261	 *
3262	 * check cpcb->pcb_nsaved:
3263	 * if 0, do a `normal' return to user (see rft_user);
3264	 * if > 0, cpcb->pcb_rw[] holds registers to be copied to stack;
3265	 * if -1, cpcb->pcb_rw[0] holds user registers for rett window
3266	 * from an earlier T_RWRET pseudo-trap.
3267	 */
3268	sethi	%hi(cpcb), %l6
3269	ld	[%l6 + %lo(cpcb)], %l6
3270	ld	[%l6 + PCB_NSAVED], %l7
3271	tst	%l7
3272	bz,a	rft_user
3273	 sethi	%hi(_C_LABEL(want_ast)), %l7	! first instr of rft_user
3274
3275	bg,a	softtrap		! if (pcb_nsaved > 0)
3276	 mov	T_WINOF, %o0		!	trap(T_WINOF);
3277
3278	/*
3279	 * To get here, we must have tried to return from a previous
3280	 * trap and discovered that it would cause a window underflow.
3281	 * We then must have tried to pull the registers out of the
3282	 * user stack (from the address in %fp==%i6) and discovered
3283	 * that it was either unaligned or not loaded in memory, and
3284	 * therefore we ran a trap(T_RWRET), which loaded one set of
3285	 * registers into cpcb->pcb_pcb_rw[0] (if it had killed the
3286	 * process due to a bad stack, we would not be here).
3287	 *
3288	 * We want to load pcb_rw[0] into the previous window, which
3289	 * we know is currently invalid.  In other words, we want
3290	 * %wim to be 1 << ((cwp + 2) % nwindows).
3291	 */
3292	wr	%g0, 0, %wim		! enable restores
3293	mov	%g6, %l3		! save g6 in l3
3294	mov	%l6, %g6		! set g6 = &u
3295	st	%g0, [%g6 + PCB_NSAVED]	! clear cpcb->pcb_nsaved
3296	restore				! enter window I
3297	restore	%g0, 1, %l1		! enter window X, then %l1 = 1
3298	rd	%psr, %l0
3299	sll	%l1, %l0, %l1		! %wim = 1 << CWP;
3300	wr	%l1, 0, %wim
3301	and	%l0, 31, %l0
3302	st	%l0, [%g6 + PCB_WIM]	! cpcb->pcb_wim = CWP;
3303	nop				! unnecessary? old wim was 0...
3304	save	%g0, %g0, %g0		! back to window I
3305	LOADWIN(%g6 + PCB_RW)
3306	save	%g0, %g0, %g0		! back to window T (trap window)
3307	wr	%l0, 0, %psr		! cond codes, cond codes everywhere
3308	mov	%l3, %g6		! restore g6
3309	RETT
3310
3311! exported end marker for kernel gdb
3312	.globl	_C_LABEL(endtrapcode)
3313_C_LABEL(endtrapcode):
3314
3315/*
3316 * init_tables(nwin) int nwin;
3317 *
3318 * Set up the uwtab and wmask tables.
3319 * We know nwin > 1.
3320 */
3321init_tables:
3322	/*
3323	 * for (i = -nwin, j = nwin - 2; ++i < 0; j--)
3324	 *	uwtab[i] = j;
3325	 * (loop runs at least once)
3326	 */
3327	set	uwtab, %o3
3328	sub	%g0, %o0, %o1		! i = -nwin + 1
3329	inc	%o1
3330	add	%o0, -2, %o2		! j = nwin - 2;
33310:
3332	stb	%o2, [%o3 + %o1]	! uwtab[i] = j;
33331:
3334	inccc	%o1			! ++i < 0?
3335	bl	0b			! yes, continue loop
3336	 dec	%o2			! in any case, j--
3337
3338	/*
3339	 * (i now equals 0)
3340	 * for (j = nwin - 1; i < nwin; i++, j--)
3341	 *	uwtab[i] = j;
3342	 * (loop runs at least twice)
3343	 */
3344	sub	%o0, 1, %o2		! j = nwin - 1
33450:
3346	stb	%o2, [%o3 + %o1]	! uwtab[i] = j
3347	inc	%o1			! i++
33481:
3349	cmp	%o1, %o0		! i < nwin?
3350	bl	0b			! yes, continue
3351	 dec	%o2			! in any case, j--
3352
3353	/*
3354	 * We observe that, for i in 0..nwin-2, (i+1)%nwin == i+1;
3355	 * for i==nwin-1, (i+1)%nwin == 0.
3356	 * To avoid adding 1, we run i from 1 to nwin and set
3357	 * wmask[i-1].
3358	 *
3359	 * for (i = j = 1; i < nwin; i++) {
3360	 *	j <<= 1;	(j now == 1 << i)
3361	 *	wmask[i - 1] = j;
3362	 * }
3363	 * (loop runs at least once)
3364	 */
3365	set	wmask - 1, %o3
3366	mov	1, %o1			! i = 1;
3367	mov	2, %o2			! j = 2;
33680:
3369	stb	%o2, [%o3 + %o1]	! (wmask - 1)[i] = j;
3370	inc	%o1			! i++
3371	cmp	%o1, %o0		! i < nwin?
3372	bl,a	0b			! yes, continue
3373	 sll	%o2, 1, %o2		! (and j <<= 1)
3374
3375	/*
3376	 * Now i==nwin, so we want wmask[i-1] = 1.
3377	 */
3378	mov	1, %o2			! j = 1;
3379	retl
3380	 stb	%o2, [%o3 + %o1]	! (wmask - 1)[i] = j;
3381
3382#ifdef SUN4
3383/*
3384 * getidprom(struct idprom *, sizeof(struct idprom))
3385 */
3386_ENTRY(_C_LABEL(getidprom))
3387	set	AC_IDPROM, %o2
33881:	lduba	[%o2] ASI_CONTROL, %o3
3389	stb	%o3, [%o0]
3390	inc	%o0
3391	inc	%o2
3392	dec	%o1
3393	cmp	%o1, 0
3394	bne	1b
3395	 nop
3396	retl
3397	 nop
3398#endif
3399
3400dostart:
3401	/*
3402	 * Startup.
3403	 *
3404	 * We have been loaded in low RAM, at some address which
3405	 * is page aligned (PROM_LOADADDR actually) rather than where we
3406	 * want to run (KERNBASE+PROM_LOADADDR).  Until we get everything set,
3407	 * we have to be sure to use only pc-relative addressing.
3408	 */
3409
3410	/*
3411	 * We now use the bootinfo method to pass arguments, and the new
3412	 * magic number indicates that. A pointer to the kernel top, i.e.
3413	 * the first address after the load kernel image (including DDB
3414	 * symbols, if any) is passed in %o4[0] and the bootinfo structure
3415	 * is passed in %o4[1].
3416	 *
3417	 * A magic number is passed in %o5 to allow for bootloaders
3418	 * that know nothing about the bootinfo structure or previous
3419	 * DDB symbol loading conventions.
3420	 *
3421	 * For compatibility with older versions, we check for DDB arguments
3422	 * if the older magic number is there. The loader passes `kernel_top'
3423	 * (previously known as `esym') in %o4.
3424	 *
3425	 * Note: we don't touch %o1-%o3; SunOS bootloaders seem to use them
3426	 * for their own mirky business.
3427	 *
3428	 * Pre-NetBSD 1.3 bootblocks had KERNBASE compiled in, and used it
3429	 * to compute the value of `kernel_top' (previously known as `esym').
3430	 * In order to successfully boot a kernel built with a different value
3431	 * for KERNBASE using old bootblocks, we fixup `kernel_top' here by
3432	 * the difference between KERNBASE and the old value (known to be
3433	 * 0xf8000000) compiled into pre-1.3 bootblocks.
3434	 */
3435	set	KERNBASE, %l4
3436
3437	set	0x44444232, %l3		! bootinfo magic
3438	cmp	%o5, %l3
3439	bne	1f
3440	 nop
3441
3442	/* The loader has passed to us a `bootinfo' structure */
3443	ld	[%o4], %l3		! 1st word is kernel_top
3444	add	%l3, %l4, %o5		! relocate: + KERNBASE
3445	sethi	%hi(_C_LABEL(kernel_top) - KERNBASE), %l3 ! and store it
3446	st	%o5, [%l3 + %lo(_C_LABEL(kernel_top) - KERNBASE)]
3447
3448	ld	[%o4 + 4], %l3		! 2nd word is bootinfo
3449	add	%l3, %l4, %o5		! relocate
3450	sethi	%hi(_C_LABEL(bootinfo) - KERNBASE), %l3	! store bootinfo
3451	st	%o5, [%l3 + %lo(_C_LABEL(bootinfo) - KERNBASE)]
3452	b,a	4f
3453
34541:
3455#ifdef DDB
3456	/* Check for old-style DDB loader magic */
3457	set	0x44444231, %l3		! Is it DDB_MAGIC1?
3458	cmp	%o5, %l3
3459	be,a	2f
3460	 clr	%l4			! if DDB_MAGIC1, clear %l4
3461
3462	set	0x44444230, %l3		! Is it DDB_MAGIC0?
3463	cmp	%o5, %l3		! if so, need to relocate %o4
3464	bne	3f			! if not, there's no bootloader info
3465
3466					! note: %l4 set to KERNBASE above.
3467	set	0xf8000000, %l5		! compute correction term:
3468	sub	%l5, %l4, %l4		!  old KERNBASE (0xf8000000 ) - KERNBASE
3469
34702:
3471	tst	%o4			! do we have the symbols?
3472	bz	3f
3473	 sub	%o4, %l4, %o4		! apply compat correction
3474	sethi	%hi(_C_LABEL(kernel_top) - KERNBASE), %l3 ! and store it
3475	st	%o4, [%l3 + %lo(_C_LABEL(kernel_top) - KERNBASE)]
3476	b,a	4f
34773:
3478#endif
3479	/*
3480	 * The boot loader did not pass in a value for `kernel_top';
3481	 * let it default to `end'.
3482	 */
3483	set	end, %o4
3484	sethi	%hi(_C_LABEL(kernel_top) - KERNBASE), %l3 ! store kernel_top
3485	st	%o4, [%l3 + %lo(_C_LABEL(kernel_top) - KERNBASE)]
3486
34874:
3488
3489	/*
3490	 * Sun4 passes in the `load address'.  Although possible, its highly
3491	 * unlikely that OpenBoot would place the prom vector there.
3492	 */
3493	set	PROM_LOADADDR, %g7
3494	cmp	%o0, %g7
3495	be	is_sun4
3496	 nop
3497
3498#if defined(SUN4C) || defined(SUN4M)
3499	/*
3500	 * Be prepared to get OF client entry in either %o0 or %o3.
3501	 */
3502	cmp	%o0, 0
3503	be	is_openfirm
3504	 nop
3505
3506	mov	%o0, %g7		! save romp passed by boot code
3507
3508	/* First, check `romp->pv_magic' */
3509	ld	[%g7 + PV_MAGIC], %o0	! v = pv->pv_magic
3510	set	OBP_MAGIC, %o1
3511	cmp	%o0, %o1		! if ( v != OBP_MAGIC) {
3512	bne	is_sun4m		!    assume this is an OPENFIRM machine
3513	 nop				! }
3514
3515	/*
3516	 * are we on a sun4c or a sun4m?
3517	 */
3518	ld	[%g7 + PV_NODEOPS], %o4	! node = pv->pv_nodeops->no_nextnode(0)
3519	ld	[%o4 + NO_NEXTNODE], %o4
3520	call	%o4
3521	 mov	0, %o0			! node
3522
3523	mov	%o0, %l0
3524	set	cputypvar-KERNBASE, %o1	! name = "compatible"
3525	set	cputypval-KERNBASE, %o2	! buffer ptr (assume buffer long enough)
3526	ld	[%g7 + PV_NODEOPS], %o4	! (void)pv->pv_nodeops->no_getprop(...)
3527	ld	[%o4 + NO_GETPROP], %o4
3528	call	 %o4
3529	 nop
3530	set	cputypval-KERNBASE, %o2	! buffer ptr
3531	ldub	[%o2 + 4], %o0		! which is it... "sun4c", "sun4m", "sun4d"?
3532	cmp	%o0, 'c'
3533	be	is_sun4c
3534	 nop
3535	cmp	%o0, 'm'
3536	be	is_sun4m
3537	 nop
3538#endif /* SUN4C || SUN4M */
3539
3540	! ``on a sun4d?!  hell no!''
3541	ld	[%g7 + PV_HALT], %o1	! by this kernel, then halt
3542	call	%o1
3543	 nop
3544
3545is_openfirm:
3546	! OF client entry in %o3 (kernel booted directly by PROM?)
3547	mov	%o3, %g7
3548	/* FALLTHROUGH to sun4m case */
3549
3550is_sun4m:
3551#if defined(SUN4M)
3552	set	trapbase_sun4m, %g6
3553	mov	SUN4CM_PGSHIFT, %g5
3554	b	start_havetype
3555	 mov	CPU_SUN4M, %g4
3556#else
3557	set	sun4m_notsup-KERNBASE, %o0
3558	ld	[%g7 + PV_EVAL], %o1
3559	call	%o1			! print a message saying that the
3560	 nop				! sun4m architecture is not supported
3561	ld	[%g7 + PV_HALT], %o1	! by this kernel, then halt
3562	call	%o1
3563	 nop
3564	/*NOTREACHED*/
3565#endif
3566is_sun4c:
3567#if defined(SUN4C)
3568	set	trapbase_sun4c, %g6
3569	mov	SUN4CM_PGSHIFT, %g5
3570
3571	set	AC_CONTEXT, %g1		! paranoia: set context to kernel
3572	stba	%g0, [%g1] ASI_CONTROL
3573
3574	b	start_havetype
3575	 mov	CPU_SUN4C, %g4		! XXX CPU_SUN4
3576#else
3577	set	sun4c_notsup-KERNBASE, %o0
3578
3579	ld	[%g7 + PV_ROMVEC_VERS], %o1
3580	cmp	%o1, 0
3581	bne	1f
3582	 nop
3583
3584	! stupid version 0 rom interface is pv_eval(int length, char *string)
3585	mov	%o0, %o1
35862:	ldub	[%o0], %o4
3587	bne	2b
3588	 inc	%o0
3589	dec	%o0
3590	sub	%o0, %o1, %o0
3591
35921:	ld	[%g7 + PV_EVAL], %o2
3593	call	%o2			! print a message saying that the
3594	 nop				! sun4c architecture is not supported
3595	ld	[%g7 + PV_HALT], %o1	! by this kernel, then halt
3596	call	%o1
3597	 nop
3598	/*NOTREACHED*/
3599#endif
3600is_sun4:
3601#if defined(SUN4)
3602	set	trapbase_sun4, %g6
3603	mov	SUN4_PGSHIFT, %g5
3604
3605	set	AC_CONTEXT, %g1		! paranoia: set context to kernel
3606	stba	%g0, [%g1] ASI_CONTROL
3607
3608	b	start_havetype
3609	 mov	CPU_SUN4, %g4
3610#else
3611	set	PROM_BASE, %g7
3612
3613	set	sun4_notsup-KERNBASE, %o0
3614	ld	[%g7 + OLDMON_PRINTF], %o1
3615	call	%o1			! print a message saying that the
3616	 nop				! sun4 architecture is not supported
3617	ld	[%g7 + OLDMON_HALT], %o1 ! by this kernel, then halt
3618	call	%o1
3619	 nop
3620	/*NOTREACHED*/
3621#endif
3622
3623start_havetype:
3624	/*
3625	 * Step 1: double map low RAM (addresses [0.._end-start-1])
3626	 * to KERNBASE (addresses [KERNBASE.._end-1]).  None of these
3627	 * are `bad' aliases (since they are all on segment boundaries)
3628	 * so we do not have to worry about cache aliasing.
3629	 *
3630	 * We map in another couple of segments just to have some
3631	 * more memory (512K, actually) guaranteed available for
3632	 * bootstrap code (pmap_bootstrap needs memory to hold MMU
3633	 * and context data structures). Note: this is only relevant
3634	 * for 2-level MMU sun4/sun4c machines.
3635	 */
3636	clr	%l0			! lowva
3637	set	KERNBASE, %l1		! highva
3638
3639	sethi	%hi(_C_LABEL(kernel_top) - KERNBASE), %o0
3640	ld	[%o0 + %lo(_C_LABEL(kernel_top) - KERNBASE)], %o1
3641	set	(2 << 18), %o2		! add slack for sun4c MMU
3642	add	%o1, %o2, %l2		! last va that must be remapped
3643
3644	/*
3645	 * Need different initial mapping functions for different
3646	 * types of machines.
3647	 */
3648#if defined(SUN4C)
3649	cmp	%g4, CPU_SUN4C
3650	bne	1f
3651	 set	1 << 18, %l3		! segment size in bytes
36520:
3653	lduba	[%l0] ASI_SEGMAP, %l4	! segmap[highva] = segmap[lowva];
3654	stba	%l4, [%l1] ASI_SEGMAP
3655	add	%l3, %l1, %l1		! highva += segsiz;
3656	cmp	%l1, %l2		! done?
3657	blu	0b			! no, loop
3658	 add	%l3, %l0, %l0		! (and lowva += segsz)
3659	b,a	startmap_done
36601:
3661#endif /* SUN4C */
3662
3663#if defined(SUN4)
3664	cmp	%g4, CPU_SUN4
3665	bne	2f
3666#if defined(SUN4_MMU3L)
3667	set	AC_IDPROM+1, %l3
3668	lduba	[%l3] ASI_CONTROL, %l3
3669	cmp	%l3, 0x24 ! XXX - SUN4_400
3670	bne	no_3mmu
3671	 nop
3672
3673	/*
3674	 * Three-level sun4 MMU.
3675	 * Double-map by duplicating a single region entry (which covers
3676	 * 16MB) corresponding to the kernel's virtual load address.
3677	 */
3678	add	%l0, 2, %l0		! get to proper half-word in RG space
3679	add	%l1, 2, %l1
3680	lduha	[%l0] ASI_REGMAP, %l4	! regmap[highva] = regmap[lowva];
3681	stha	%l4, [%l1] ASI_REGMAP
3682	b,a	startmap_done
3683no_3mmu:
3684#endif
3685
3686	/*
3687	 * Three-level sun4 MMU.
3688	 * Double-map by duplicating the required number of segment
3689	 * entries corresponding to the kernel's virtual load address.
3690	 */
3691	set	1 << 18, %l3		! segment size in bytes
36920:
3693	lduha	[%l0] ASI_SEGMAP, %l4	! segmap[highva] = segmap[lowva];
3694	stha	%l4, [%l1] ASI_SEGMAP
3695	add	%l3, %l1, %l1		! highva += segsiz;
3696	cmp	%l1, %l2		! done?
3697	blu	0b			! no, loop
3698	 add	%l3, %l0, %l0		! (and lowva += segsz)
3699	b,a	startmap_done
37002:
3701#endif /* SUN4 */
3702
3703#if defined(SUN4M)
3704	cmp	%g4, CPU_SUN4M		! skip for sun4m!
3705	bne	3f
3706
3707	/*
3708	 * The OBP guarantees us a 16MB mapping using a level 1 PTE at
3709	 * the start of the memory bank in which we were loaded. All we
3710	 * have to do is copy the entry.
3711	 * Also, we must check to see if we have a TI Viking in non-mbus mode,
3712	 * and if so do appropriate flipping and turning off traps before
3713	 * we dork with MMU passthrough.  -grrr
3714	 */
3715
3716	sethi	%hi(0x40000000), %o1	! TI version bit
3717	rd	%psr, %o0
3718	andcc	%o0, %o1, %g0
3719	be	remap_notvik		! is non-TI normal MBUS module
3720	lda	[%g0] ASI_SRMMU, %o0	! load MMU
3721	andcc	%o0, 0x800, %g0
3722	bne	remap_notvik		! It is a viking MBUS module
3723	nop
3724
3725	/*
3726	 * Ok, we have a non-Mbus TI Viking, a MicroSparc.
3727	 * In this scenerio, in order to play with the MMU
3728	 * passthrough safely, we need turn off traps, flip
3729	 * the AC bit on in the mmu status register, do our
3730	 * passthroughs, then restore the mmu reg and %psr
3731	 */
3732	rd	%psr, %o4		! saved here till done
3733	andn	%o4, 0x20, %o5
3734	wr	%o5, 0x0, %psr
3735	nop; nop; nop;
3736	set	SRMMU_CXTPTR, %o0
3737	lda	[%o0] ASI_SRMMU, %o0	! get context table ptr
3738	sll	%o0, 4, %o0		! make physical
3739	lda	[%g0] ASI_SRMMU, %o3	! hold mmu-sreg here
3740	/* 0x8000 is AC bit in Viking mmu-ctl reg */
3741	set	0x8000, %o2
3742	or	%o3, %o2, %o2
3743	sta	%o2, [%g0] ASI_SRMMU	! AC bit on
3744
3745	lda	[%o0] ASI_BYPASS, %o1
3746	srl	%o1, 4, %o1
3747	sll	%o1, 8, %o1		! get phys addr of l1 entry
3748	lda	[%o1] ASI_BYPASS, %l4
3749	srl	%l1, 22, %o2		! note: 22 == RGSHIFT - 2
3750	add	%o1, %o2, %o1
3751	sta	%l4, [%o1] ASI_BYPASS
3752
3753	sta	%o3, [%g0] ASI_SRMMU	! restore mmu-sreg
3754	wr	%o4, 0x0, %psr		! restore psr
3755	b,a	startmap_done
3756
3757	/*
3758	 * The following is generic and should work on all
3759	 * Mbus based SRMMU's.
3760	 */
3761remap_notvik:
3762	set	SRMMU_CXTPTR, %o0
3763	lda	[%o0] ASI_SRMMU, %o0	! get context table ptr
3764	sll	%o0, 4, %o0		! make physical
3765	lda	[%o0] ASI_BYPASS, %o1
3766	srl	%o1, 4, %o1
3767	sll	%o1, 8, %o1		! get phys addr of l1 entry
3768	lda	[%o1] ASI_BYPASS, %l4
3769	srl	%l1, 22, %o2		! note: 22 == RGSHIFT - 2
3770	add	%o1, %o2, %o1
3771	sta	%l4, [%o1] ASI_BYPASS
3772	!b,a	startmap_done
3773
37743:
3775#endif /* SUN4M */
3776	! botch! We should blow up.
3777
3778startmap_done:
3779	/*
3780	 * All set, fix pc and npc.  Once we are where we should be,
3781	 * we can give ourselves a stack and enable traps.
3782	 */
3783	set	1f, %g1
3784	jmp	%g1
3785	 nop
37861:
3787	sethi	%hi(_C_LABEL(cputyp)), %o0	! what type of cpu we are on
3788	st	%g4, [%o0 + %lo(_C_LABEL(cputyp))]
3789
3790	sethi	%hi(_C_LABEL(pgshift)), %o0	! pgshift = log2(nbpg)
3791	st	%g5, [%o0 + %lo(_C_LABEL(pgshift))]
3792
3793	mov	1, %o0			! nbpg = 1 << pgshift
3794	sll	%o0, %g5, %g5
3795	sethi	%hi(_C_LABEL(nbpg)), %o0	! nbpg = bytes in a page
3796	st	%g5, [%o0 + %lo(_C_LABEL(nbpg))]
3797
3798	sub	%g5, 1, %g5
3799	sethi	%hi(_C_LABEL(pgofset)), %o0 ! page offset = bytes in a page - 1
3800	st	%g5, [%o0 + %lo(_C_LABEL(pgofset))]
3801
3802	rd	%psr, %g3		! paranoia: make sure ...
3803	andn	%g3, PSR_ET, %g3	! we have traps off
3804	wr	%g3, 0, %psr		! so that we can fiddle safely
3805	nop; nop; nop
3806
3807	wr	%g0, 0, %wim		! make sure we can set psr
3808	nop; nop; nop
3809	wr	%g0, PSR_S|PSR_PS|PSR_PIL, %psr	! set initial psr
3810	 nop; nop; nop
3811
3812	wr	%g0, 2, %wim		! set initial %wim (w1 invalid)
3813	mov	1, %g1			! set pcb_wim (log2(%wim) = 1)
3814	sethi	%hi(_C_LABEL(u0) + PCB_WIM), %g2
3815	st	%g1, [%g2 + %lo(_C_LABEL(u0) + PCB_WIM)]
3816
3817	set	USRSTACK - CCFSZ, %fp	! as if called from user code
3818	set	estack0 - CCFSZ - 80, %sp ! via syscall(boot_me_up) or somesuch
3819	rd	%psr, %l0
3820	wr	%l0, PSR_ET, %psr
3821	nop; nop; nop
3822
3823	/* Export actual trapbase */
3824	sethi	%hi(_C_LABEL(trapbase)), %o0
3825	st	%g6, [%o0+%lo(_C_LABEL(trapbase))]
3826
3827#ifdef notdef
3828	/*
3829	 * Step 2: clear BSS.  This may just be paranoia; the boot
3830	 * loader might already do it for us; but what the hell.
3831	 */
3832	set	_edata, %o0		! bzero(edata, end - edata)
3833	set	_end, %o1
3834	call	_C_LABEL(bzero)
3835	 sub	%o1, %o0, %o1
3836#endif
3837
3838	/*
3839	 * Stash prom vectors now, after bzero, as it lives in bss
3840	 * (which we just zeroed).
3841	 * This depends on the fact that bzero does not use %g7.
3842	 */
3843	sethi	%hi(_C_LABEL(romp)), %l0
3844	st	%g7, [%l0 + %lo(_C_LABEL(romp))]
3845
3846	/*
3847	 * Step 3: compute number of windows and set up tables.
3848	 * We could do some of this later.
3849	 */
3850	save	%sp, -64, %sp
3851	rd	%psr, %g1
3852	restore
3853	and	%g1, 31, %g1		! want just the CWP bits
3854	add	%g1, 1, %o0		! compute nwindows
3855	sethi	%hi(_C_LABEL(nwindows)), %o1	! may as well tell everyone
3856	call	init_tables
3857	 st	%o0, [%o1 + %lo(_C_LABEL(nwindows))]
3858
3859#if defined(SUN4) || defined(SUN4C)
3860	/*
3861	 * Some sun4/sun4c models have fewer than 8 windows. For extra
3862	 * speed, we do not need to save/restore those windows
3863	 * The save/restore code has 7 "save"'s followed by 7
3864	 * "restore"'s -- we "nop" out the last "save" and first
3865	 * "restore"
3866	 */
3867	cmp	%o0, 8
3868	be	1f
3869noplab:	 nop
3870	sethi	%hi(noplab), %l0
3871	ld	[%l0 + %lo(noplab)], %l1
3872	set	wb1, %l0
3873	st	%l1, [%l0 + 6*4]
3874	st	%l1, [%l0 + 7*4]
38751:
3876#endif
3877
3878#if ((defined(SUN4) || defined(SUN4C)) && defined(SUN4M))
3879
3880	/*
3881	 * Patch instructions at specified labels that start
3882	 * per-architecture code-paths.
3883	 */
3884Lgandul:	nop
3885
3886#define MUNGE(label) \
3887	sethi	%hi(label), %o0; \
3888	st	%l0, [%o0 + %lo(label)]
3889
3890	sethi	%hi(Lgandul), %o0
3891	ld	[%o0 + %lo(Lgandul)], %l0	! %l0 = NOP
3892
3893	cmp	%g4, CPU_SUN4M
3894	bne,a	1f
3895	 nop
3896
3897	! this should be automated!
3898	MUNGE(NOP_ON_4M_1)
3899	MUNGE(NOP_ON_4M_2)
3900	MUNGE(NOP_ON_4M_3)
3901	MUNGE(NOP_ON_4M_4)
3902	MUNGE(NOP_ON_4M_5)
3903	MUNGE(NOP_ON_4M_6)
3904	MUNGE(NOP_ON_4M_7)
3905	MUNGE(NOP_ON_4M_8)
3906	MUNGE(NOP_ON_4M_9)
3907	MUNGE(NOP_ON_4M_10)
3908	MUNGE(NOP_ON_4M_11)
3909	MUNGE(NOP_ON_4M_12)
3910	MUNGE(NOP_ON_4M_13)
3911	MUNGE(NOP_ON_4M_14)
3912	MUNGE(NOP_ON_4M_15)
3913	b,a	2f
3914
39151:
3916	MUNGE(NOP_ON_4_4C_1)
3917
39182:
3919
3920#undef MUNGE
3921#endif
3922
3923	/*
3924	 * Step 4: change the trap base register, now that our trap handlers
3925	 * will function (they need the tables we just set up).
3926	 * This depends on the fact that bzero does not use %g6.
3927	 */
3928	wr	%g6, 0, %tbr
3929	nop; nop; nop			! paranoia
3930
3931
3932	/* Clear `cpuinfo' */
3933	sethi	%hi(CPUINFO_VA), %o0		! bzero(&cpuinfo, NBPG)
3934	sethi	%hi(CPUINFO_STRUCTSIZE), %o1
3935	call	_C_LABEL(bzero)
3936	 add	%o1, %lo(CPUINFO_STRUCTSIZE), %o1
3937
3938	/*
3939	 * Initialize `cpuinfo' fields which are needed early.  Note
3940	 * we make the cpuinfo self-reference at the local VA for now.
3941	 * It may be changed to reference a global VA later.
3942	 */
3943	set	_C_LABEL(u0), %o0		! cpuinfo.curpcb = u0;
3944	sethi	%hi(cpcb), %l0
3945	st	%o0, [%l0 + %lo(cpcb)]
3946
3947	sethi	%hi(CPUINFO_VA), %o0		! cpuinfo.ci_self = &cpuinfo;
3948	sethi	%hi(_CISELFP), %l0
3949	st	%o0, [%l0 + %lo(_CISELFP)]
3950
3951	set	_C_LABEL(eintstack), %o0	! cpuinfo.eintstack= _eintstack;
3952	sethi	%hi(_EINTSTACKP), %l0
3953	st	%o0, [%l0 + %lo(_EINTSTACKP)]
3954
3955	/*
3956	 * Ready to run C code; finish bootstrap.
3957	 */
3958	call	_C_LABEL(bootstrap)
3959	 nop
3960
3961	/*
3962	 * Call main.  This returns to us after loading /sbin/init into
3963	 * user space.  (If the exec fails, main() does not return.)
3964	 */
3965	call	_C_LABEL(main)
3966	 clr	%o0			! our frame arg is ignored
3967	/*NOTREACHED*/
3968
3969#if defined(MULTIPROCESSOR)
3970	/*
3971	 * Entry point for non-boot CPUs in MP systems.
3972	 */
3973	.globl	_C_LABEL(cpu_hatch)
3974_C_LABEL(cpu_hatch):
3975	rd	%psr, %g3		! paranoia: make sure ...
3976	andn	%g3, PSR_ET, %g3	! we have traps off
3977	wr	%g3, 0, %psr		! so that we can fiddle safely
3978	nop; nop; nop
3979
3980	wr	%g0, 0, %wim		! make sure we can set psr
3981	nop; nop; nop
3982	wr	%g0, PSR_S|PSR_PS|PSR_PIL, %psr	! set initial psr
3983	nop; nop; nop
3984
3985	wr	%g0, 2, %wim		! set initial %wim (w1 invalid)
3986
3987	/* Initialize Trap Base register */
3988	sethi	%hi(_C_LABEL(trapbase)), %o0
3989	ld	[%o0+%lo(_C_LABEL(trapbase))], %g6
3990	wr	%g6, 0, %tbr
3991	nop; nop; nop			! paranoia
3992
3993	/* Set up a stack */
3994	set	USRSTACK - CCFSZ, %fp	! as if called from user code
3995	sethi	%hi(_C_LABEL(cpu_hatchstack)), %o0
3996	ld	[%o0+%lo(_C_LABEL(cpu_hatchstack))], %o0
3997	set	USPACE - CCFSZ - 80, %sp
3998	add	%sp, %o0, %sp
3999
4000	/* Enable traps */
4001	rd	%psr, %l0
4002	wr	%l0, PSR_ET, %psr
4003	nop; nop; nop
4004
4005	/* Call C code */
4006	sethi	%hi(_C_LABEL(cpu_hatch_sc)), %o0
4007	call	_C_LABEL(cpu_setup)
4008	 ld	[%o0+%lo(_C_LABEL(cpu_hatch_sc))], %o0
4009
4010	/* Wait for go_smp_cpus to go */
4011	set	_C_LABEL(go_smp_cpus), %l1
4012	ld	[%l1], %l0
40131:
4014	cmp	%l0, %g0
4015	be	1b
4016	 ld	[%l1], %l0
4017
4018#if 0	/* doesn't quite work yet */
4019
4020	set	_C_LABEL(proc0), %g3		! p = proc0
4021	sethi	%hi(_C_LABEL(sched_whichqs)), %g2
4022	sethi	%hi(cpcb), %g6
4023	sethi	%hi(curproc), %g7
4024	st	%g0, [%g7 + %lo(curproc)]	! curproc = NULL;
4025
4026	mov	PSR_S|PSR_ET, %g1		! oldpsr = PSR_S | PSR_ET;
4027	sethi	%hi(IDLE_UP), %g5
4028	ld	[%g5 + %lo(IDLE_UP)], %g5
4029	st	%g5, [%g6 + %lo(cpcb)]		! cpcb = &idle_u
4030	set	USPACE-CCFSZ, %o1
4031	add	%g5, %o1, %sp			! set new %sp
4032
4033#ifdef DEBUG
4034	mov	%g5, %o2			! %o2 = _idle_u
4035	SET_SP_REDZONE(%o2, %o1)
4036#endif /* DEBUG */
4037
4038	b	idle_enter_no_schedlock
4039	 clr	%g4				! lastproc = NULL;
4040#else
4041	/* Idle here .. */
4042	rd	%psr, %l0
4043	andn	%l0, PSR_PIL, %l0	! psr &= ~PSR_PIL;
4044	wr	%l0, 0, %psr		! (void) spl0();
4045	nop; nop; nop
40469:	ba 9b
4047	 nop
4048	/*NOTREACHED*/
4049#endif
4050
4051#endif /* MULTIPROCESSOR */
4052
4053#include "sigcode_state.s"
4054
4055	.globl	_C_LABEL(sigcode)
4056	.globl	_C_LABEL(esigcode)
4057_C_LABEL(sigcode):
4058
4059	SAVE_STATE
4060
4061	ldd	[%fp + 64], %o0		! sig, code
4062	ld	[%fp + 76], %o3		! arg3
4063	call	%g1			! (*sa->sa_handler)(sig,code,scp,arg3)
4064	 add	%fp, 64 + 16, %o2	! scp
4065
4066	RESTORE_STATE
4067
4068	! get registers back & set syscall #
4069	restore	%g0, SYS___sigreturn14, %g1
4070	add	%sp, 64 + 16, %o0	! compute scp
4071	t	ST_SYSCALL		! sigreturn(scp)
4072	! sigreturn does not return unless it fails
4073	mov	SYS_exit, %g1		! exit(errno)
4074	t	ST_SYSCALL
4075_C_LABEL(esigcode):
4076
4077/*
4078 * Primitives
4079 */
4080
4081/*
4082 * General-purpose NULL routine.
4083 */
4084ENTRY(sparc_noop)
4085	retl
4086	 nop
4087
4088/*
4089 * getfp() - get stack frame pointer
4090 */
4091ENTRY(getfp)
4092	retl
4093	 mov %fp, %o0
4094
4095/*
4096 * copyinstr(fromaddr, toaddr, maxlength, &lencopied)
4097 *
4098 * Copy a null terminated string from the user address space into
4099 * the kernel address space.
4100 */
4101ENTRY(copyinstr)
4102	! %o0 = fromaddr, %o1 = toaddr, %o2 = maxlen, %o3 = &lencopied
4103	mov	%o1, %o5		! save = toaddr;
4104	tst	%o2			! maxlen == 0?
4105	beq,a	Lcstoolong		! yes, return ENAMETOOLONG
4106	 sethi	%hi(cpcb), %o4
4107
4108	set	KERNBASE, %o4
4109	cmp	%o0, %o4		! fromaddr < KERNBASE?
4110	blu	Lcsdocopy		! yes, go do it
4111	 sethi	%hi(cpcb), %o4		! (first instr of copy)
4112
4113	b	Lcsdone			! no, return EFAULT
4114	 mov	EFAULT, %o0
4115
4116/*
4117 * copyoutstr(fromaddr, toaddr, maxlength, &lencopied)
4118 *
4119 * Copy a null terminated string from the kernel
4120 * address space to the user address space.
4121 */
4122ENTRY(copyoutstr)
4123	! %o0 = fromaddr, %o1 = toaddr, %o2 = maxlen, %o3 = &lencopied
4124	mov	%o1, %o5		! save = toaddr;
4125	tst	%o2			! maxlen == 0?
4126	beq,a	Lcstoolong		! yes, return ENAMETOOLONG
4127	 sethi	%hi(cpcb), %o4
4128
4129	set	KERNBASE, %o4
4130	cmp	%o1, %o4		! toaddr < KERNBASE?
4131	blu	Lcsdocopy		! yes, go do it
4132	 sethi	%hi(cpcb), %o4		! (first instr of copy)
4133
4134	b	Lcsdone			! no, return EFAULT
4135	 mov	EFAULT, %o0
4136
4137Lcsdocopy:
4138!	sethi	%hi(cpcb), %o4		! (done earlier)
4139	ld	[%o4 + %lo(cpcb)], %o4	! catch faults
4140	set	Lcsdone, %g1
4141	st	%g1, [%o4 + PCB_ONFAULT]
4142
4143! XXX should do this in bigger chunks when possible
41440:					! loop:
4145	ldsb	[%o0], %g1		!	c = *fromaddr;
4146	tst	%g1
4147	stb	%g1, [%o1]		!	*toaddr++ = c;
4148	be	1f			!	if (c == NULL)
4149	 inc	%o1			!		goto ok;
4150	deccc	%o2			!	if (--len > 0) {
4151	bgu	0b			!		fromaddr++;
4152	 inc	%o0			!		goto loop;
4153					!	}
4154Lcstoolong:				!
4155	b	Lcsdone			!	error = ENAMETOOLONG;
4156	 mov	ENAMETOOLONG, %o0	!	goto done;
41571:					! ok:
4158	clr	%o0			!    error = 0;
4159Lcsdone:				! done:
4160	sub	%o1, %o5, %o1		!	len = to - save;
4161	tst	%o3			!	if (lencopied)
4162	bnz,a	3f
4163	 st	%o1, [%o3]		!		*lencopied = len;
41643:
4165	retl				! cpcb->pcb_onfault = 0;
4166	 st	%g0, [%o4 + PCB_ONFAULT]! return (error);
4167
4168/*
4169 * copystr(fromaddr, toaddr, maxlength, &lencopied)
4170 *
4171 * Copy a null terminated string from one point to another in
4172 * the kernel address space.  (This is a leaf procedure, but
4173 * it does not seem that way to the C compiler.)
4174 */
4175ENTRY(copystr)
4176	mov	%o1, %o5		!	to0 = to;
4177	tst	%o2			! if (maxlength == 0)
4178	beq,a	2f			!
4179	 mov	ENAMETOOLONG, %o0	!	ret = ENAMETOOLONG; goto done;
4180
41810:					! loop:
4182	ldsb	[%o0], %o4		!	c = *from;
4183	tst	%o4
4184	stb	%o4, [%o1]		!	*to++ = c;
4185	be	1f			!	if (c == 0)
4186	 inc	%o1			!		goto ok;
4187	deccc	%o2			!	if (--len > 0) {
4188	bgu,a	0b			!		from++;
4189	 inc	%o0			!		goto loop;
4190	b	2f			!	}
4191	 mov	ENAMETOOLONG, %o0	!	ret = ENAMETOOLONG; goto done;
41921:					! ok:
4193	clr	%o0			!	ret = 0;
41942:
4195	sub	%o1, %o5, %o1		!	len = to - to0;
4196	tst	%o3			!	if (lencopied)
4197	bnz,a	3f
4198	 st	%o1, [%o3]		!		*lencopied = len;
41993:
4200	retl
4201	 nop
4202
4203/*
4204 * Copyin(src, dst, len)
4205 *
4206 * Copy specified amount of data from user space into the kernel.
4207 */
4208ENTRY(copyin)
4209	set	KERNBASE, %o3
4210	cmp	%o0, %o3		! src < KERNBASE?
4211	blu,a	Ldocopy			! yes, can try it
4212	 sethi	%hi(cpcb), %o3
4213
4214	/* source address points into kernel space: return EFAULT */
4215	retl
4216	 mov	EFAULT, %o0
4217
4218/*
4219 * Copyout(src, dst, len)
4220 *
4221 * Copy specified amount of data from kernel to user space.
4222 * Just like copyin, except that the `dst' addresses are user space
4223 * rather than the `src' addresses.
4224 */
4225ENTRY(copyout)
4226	set	KERNBASE, %o3
4227	cmp	%o1, %o3		! dst < KERBASE?
4228	blu,a	Ldocopy
4229	 sethi	%hi(cpcb), %o3
4230
4231	/* destination address points into kernel space: return EFAULT */
4232	retl
4233	 mov	EFAULT, %o0
4234
4235	/*
4236	 * ******NOTE****** this depends on bcopy() not using %g7
4237	 */
4238Ldocopy:
4239!	sethi	%hi(cpcb), %o3
4240	ld	[%o3 + %lo(cpcb)], %o3
4241	set	Lcopyfault, %o4
4242	mov	%o7, %g7		! save return address
4243	call	_C_LABEL(bcopy)		! bcopy(src, dst, len)
4244	 st	%o4, [%o3 + PCB_ONFAULT]
4245
4246	sethi	%hi(cpcb), %o3
4247	ld	[%o3 + %lo(cpcb)], %o3
4248	st	%g0, [%o3 + PCB_ONFAULT]
4249	jmp	%g7 + 8
4250	 clr	%o0			! return 0
4251
4252! Copyin or copyout fault.  Clear cpcb->pcb_onfault and return EFAULT.
4253! Note that although we were in bcopy, there is no state to clean up;
4254! the only special thing is that we have to return to [g7 + 8] rather than
4255! [o7 + 8].
4256Lcopyfault:
4257	sethi	%hi(cpcb), %o3
4258	ld	[%o3 + %lo(cpcb)], %o3
4259	jmp	%g7 + 8
4260	 st	%g0, [%o3 + PCB_ONFAULT]
4261
4262
4263/*
4264 * Write all user windows presently in the CPU back to the user's stack.
4265 * We just do `save' instructions until pcb_uw == 0.
4266 *
4267 *	p = cpcb;
4268 *	nsaves = 0;
4269 *	while (p->pcb_uw > 0)
4270 *		save(), nsaves++;
4271 *	while (--nsaves >= 0)
4272 *		restore();
4273 */
4274ENTRY(write_user_windows)
4275	sethi	%hi(cpcb), %g6
4276	ld	[%g6 + %lo(cpcb)], %g6
4277	b	2f
4278	 clr	%g5
42791:
4280	save	%sp, -64, %sp
42812:
4282	ld	[%g6 + PCB_UW], %g7
4283	tst	%g7
4284	bg,a	1b
4285	 inc	%g5
42863:
4287	deccc	%g5
4288	bge,a	3b
4289	 restore
4290	retl
4291	 nop
4292
4293
4294	.comm	_C_LABEL(want_resched),4
4295	.comm	_C_LABEL(want_ast),4
4296/*
4297 * Masterpaddr is the p->p_addr of the last process on the processor.
4298 * XXX masterpaddr is almost the same as cpcb
4299 * XXX should delete this entirely
4300 */
4301	.comm	_C_LABEL(masterpaddr), 4
4302
4303/*
4304 * Switch statistics (for later tweaking):
4305 *	nswitchdiff = p1 => p2 (i.e., chose different process)
4306 *	nswitchexit = number of calls to switchexit()
4307 *	cnt.v_swtch = total calls to swtch+swtchexit
4308 */
4309	.comm	_C_LABEL(nswitchdiff), 4
4310	.comm	_C_LABEL(nswitchexit), 4
4311
4312/*
4313 * REGISTER USAGE IN cpu_switch AND switchexit:
4314 * This is split into two phases, more or less
4315 * `before we locate a new proc' and `after'.
4316 * Some values are the same in both phases.
4317 * Note that the %o0-registers are not preserved across
4318 * the psr change when entering a new process, since this
4319 * usually changes the CWP field (hence heavy usage of %g's).
4320 *
4321 *	%g1 = oldpsr (excluding ipl bits)
4322 *	%g2 = %hi(whichqs); newpsr
4323 *	%g3 = p
4324 *	%g4 = lastproc
4325 *	%g5 = <free>; newpcb
4326 *	%g6 = %hi(cpcb)
4327 *	%g7 = %hi(curproc)
4328 *	%o0 = tmp 1
4329 *	%o1 = tmp 2
4330 *	%o2 = tmp 3
4331 *	%o3 = tmp 4; whichqs; vm
4332 *	%o4 = tmp 4; which; sswap
4333 *	%o5 = tmp 5; q; <free>
4334 */
4335
4336/*
4337 * When calling external functions from cpu_switch() and idle(), we must
4338 * preserve the global registers mentioned above across the call.  We also
4339 * set up a stack frame since we will be running in our caller's frame
4340 * in cpu_switch().
4341 */
4342#define SAVE_GLOBALS_AND_CALL(name)	\
4343	save	%sp, -CCFSZ, %sp;	\
4344	mov	%g1, %i0;		\
4345	mov	%g2, %i1;		\
4346	mov	%g3, %i2;		\
4347	mov	%g4, %i3;		\
4348	mov	%g6, %i4;		\
4349	call	_C_LABEL(name);		\
4350	 mov	%g7, %i5;		\
4351	mov	%i5, %g7;		\
4352	mov	%i4, %g6;		\
4353	mov	%i3, %g4;		\
4354	mov	%i2, %g3;		\
4355	mov	%i1, %g2;		\
4356	mov	%i0, %g1;		\
4357	restore
4358
4359
4360/*
4361 * switchexit is called only from cpu_exit() before the current process
4362 * has freed its vmspace and kernel stack; we must schedule them to be
4363 * freed.  (curproc is already NULL.)
4364 *
4365 * We lay the process to rest by changing to the `idle' kernel stack,
4366 * and note that the `last loaded process' is nonexistent.
4367 */
4368ENTRY(switchexit)
4369	mov	%o0, %g2		! save proc for exit2() call
4370
4371	/*
4372	 * Change pcb to idle u. area, i.e., set %sp to top of stack
4373	 * and %psr to PSR_S|PSR_ET, and set cpcb to point to idle_u.
4374	 * Once we have left the old stack, we can call exit2() to
4375	 * destroy it.  Call it any sooner and the register windows
4376	 * go bye-bye.
4377	 */
4378#if defined(MULTIPROCESSOR)
4379	sethi	%hi(IDLE_UP), %g5
4380	ld	[%g5 + %lo(IDLE_UP)], %g5
4381#else
4382	set	_C_LABEL(idle_u), %g5
4383#endif
4384	sethi	%hi(cpcb), %g6
4385	mov	1, %g7
4386	wr	%g0, PSR_S, %psr	! change to window 0, traps off
4387	wr	%g0, 2, %wim		! and make window 1 the trap window
4388	st	%g5, [%g6 + %lo(cpcb)]	! cpcb = &idle_u
4389	st	%g7, [%g5 + PCB_WIM]	! idle_u.pcb_wim = log2(2) = 1
4390#if defined(MULTIPROCESSOR)
4391	set	USPACE-CCFSZ, %o1	!
4392	add	%g5, %o1, %sp		! set new %sp
4393#else
4394	set	_C_LABEL(idle_u) + USPACE-CCFSZ, %sp	! set new %sp
4395#endif
4396
4397#ifdef DEBUG
4398	mov	%g5, %l6		! %l6 = _idle_u
4399	SET_SP_REDZONE(%l6, %l5)
4400#endif
4401
4402	wr	%g0, PSR_S|PSR_ET, %psr	! and then enable traps
4403	call	_C_LABEL(exit2)		! exit2(p)
4404	 mov	%g2, %o0
4405
4406	/*
4407	 * Now fall through to `the last switch'.  %g6 was set to
4408	 * %hi(cpcb), but may have been clobbered in exit2(),
4409	 * so all the registers described below will be set here.
4410	 *
4411	 * REGISTER USAGE AT THIS POINT:
4412	 *	%g1 = oldpsr (excluding ipl bits)
4413	 *	%g2 = %hi(whichqs)
4414	 *	%g4 = lastproc
4415	 *	%g6 = %hi(cpcb)
4416	 *	%g7 = %hi(curproc)
4417	 *	%o0 = tmp 1
4418	 *	%o1 = tmp 2
4419	 *	%o3 = whichqs
4420	 */
4421
4422	INCR(_C_LABEL(nswitchexit))	! nswitchexit++;
4423	INCR(_C_LABEL(uvmexp)+V_SWTCH)	! cnt.v_switch++;
4424
4425	mov	PSR_S|PSR_ET, %g1	! oldpsr = PSR_S | PSR_ET;
4426	sethi	%hi(_C_LABEL(sched_whichqs)), %g2
4427	clr	%g4			! lastproc = NULL;
4428	sethi	%hi(cpcb), %g6
4429	sethi	%hi(curproc), %g7
4430	st	%g0, [%g7 + %lo(curproc)]	! curproc = NULL;
4431	b,a	idle_enter_no_schedlock
4432	/* FALLTHROUGH */
4433
4434
4435/* Macro used for register window flushing in the context switch code */
4436#define	SAVE save %sp, -64, %sp
4437
4438/*
4439 * When no processes are on the runq, switch
4440 * idles here waiting for something to come ready.
4441 * The registers are set up as noted above.
4442 */
4443idle:
4444#if defined(MULTIPROCESSOR)
4445	/*
4446	 * Change pcb to idle u. area, i.e., set %sp to top of stack
4447	 * and %psr to PSR_S, and set cpcb to point to idle_u.
4448	 */
4449	/* XXX: FIXME
4450	 * 7 of each:
4451	 */
4452	SAVE;    SAVE;    SAVE;    SAVE;    SAVE;    SAVE;    SAVE
4453	restore; restore; restore; restore; restore; restore; restore
4454
4455	sethi	%hi(IDLE_UP), %g5
4456	ld	[%g5 + %lo(IDLE_UP)], %g5
4457	rd	%psr, %g1		! oldpsr = %psr;
4458	andn	%g1, PSR_PIL|PSR_PS, %g1! oldpsr &= ~(PSR_PIL|PSR_PS);
4459	and	%g1, PSR_S|PSR_ET, %g1	! oldpsr |= PSR_S|PSR_ET;
4460	st	%g5, [%g6 + %lo(cpcb)]	! cpcb = &idle_u
4461	set	USPACE-CCFSZ, %o1
4462	add	%g5, %o1, %sp		! set new %sp
4463	clr	%g4			! lastproc = NULL;
4464
4465#ifdef DEBUG
4466	mov	%g5, %o2		! %o2 = _idle_u
4467	SET_SP_REDZONE(%o2, %o1)
4468#endif /* DEBUG */
4469#endif /* MULTIPROCESSOR */
4470
4471#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG)
4472	/* Release the scheduler lock */
4473	SAVE_GLOBALS_AND_CALL(sched_unlock_idle)
4474#endif
4475
4476idle_enter_no_schedlock:
4477	wr	%g1, 0, %psr		! spl0();
44781:					! spin reading whichqs until nonzero
4479	ld	[%g2 + %lo(_C_LABEL(sched_whichqs))], %o3
4480	tst	%o3
4481#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG)
4482	bnz,a	idle_leave
4483#else
4484	bnz,a	Lsw_scan
4485#endif
4486	! NB: annulled delay slot (executed when we leave the idle loop)
4487	 wr	%g1, PSR_PIL, %psr	! (void) splhigh();
4488
4489	! Check uvm.page_idle_zero
4490	sethi	%hi(_C_LABEL(uvm) + UVM_PAGE_IDLE_ZERO), %o3
4491	ld	[%o3 + %lo(_C_LABEL(uvm) + UVM_PAGE_IDLE_ZERO)], %o3
4492	tst	%o3
4493	bz	1b
4494	 nop
4495
4496	SAVE_GLOBALS_AND_CALL(uvm_pageidlezero)
4497	b,a	1b
4498
4499#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG)
4500idle_leave:
4501	/* Before we leave the idle loop, detain the scheduler lock */
4502	nop;nop;nop;	! just wrote to %psr; delay before doing a `save'
4503	SAVE_GLOBALS_AND_CALL(sched_lock_idle)
4504	b,a	Lsw_scan
4505#endif
4506
4507Lsw_panic_rq:
4508	sethi	%hi(1f), %o0
4509	call	_C_LABEL(panic)
4510	 or	%lo(1f), %o0, %o0
4511Lsw_panic_wchan:
4512	sethi	%hi(2f), %o0
4513	call	_C_LABEL(panic)
4514	 or	%lo(2f), %o0, %o0
4515Lsw_panic_srun:
4516	sethi	%hi(3f), %o0
4517	call	_C_LABEL(panic)
4518	 or	%lo(3f), %o0, %o0
45191:	.asciz	"switch rq"
45202:	.asciz	"switch wchan"
45213:	.asciz	"switch SRUN"
4522	_ALIGN
4523
4524/*
4525 * cpu_switch() picks a process to run and runs it, saving the current
4526 * one away.  On the assumption that (since most workstations are
4527 * single user machines) the chances are quite good that the new
4528 * process will turn out to be the current process, we defer saving
4529 * it here until we have found someone to load.  If that someone
4530 * is the current process we avoid both store and load.
4531 *
4532 * cpu_switch() is always entered at splstatclock or splhigh.
4533 *
4534 * IT MIGHT BE WORTH SAVING BEFORE ENTERING idle TO AVOID HAVING TO
4535 * SAVE LATER WHEN SOMEONE ELSE IS READY ... MUST MEASURE!
4536 */
4537	.globl	_C_LABEL(__ffstab)
4538ENTRY(cpu_switch)
4539	/*
4540	 * REGISTER USAGE AT THIS POINT:
4541	 *	%g1 = oldpsr (excluding ipl bits)
4542	 *	%g2 = %hi(whichqs)
4543	 *	%g3 = p
4544	 *	%g4 = lastproc
4545	 *	%g5 = tmp 0
4546	 *	%g6 = %hi(cpcb)
4547	 *	%g7 = %hi(curproc)
4548	 *	%o0 = tmp 1
4549	 *	%o1 = tmp 2
4550	 *	%o2 = tmp 3
4551	 *	%o3 = tmp 4, then at Lsw_scan, whichqs
4552	 *	%o4 = tmp 5, then at Lsw_scan, which
4553	 *	%o5 = tmp 6, then at Lsw_scan, q
4554	 */
4555	mov	%o0, %g4			! lastproc = p;
4556	sethi	%hi(_C_LABEL(sched_whichqs)), %g2	! set up addr regs
4557	sethi	%hi(cpcb), %g6
4558	ld	[%g6 + %lo(cpcb)], %o0
4559	std	%o6, [%o0 + PCB_SP]		! cpcb->pcb_<sp,pc> = <sp,pc>;
4560	rd	%psr, %g1			! oldpsr = %psr;
4561	st	%g1, [%o0 + PCB_PSR]		! cpcb->pcb_psr = oldpsr;
4562	andn	%g1, PSR_PIL, %g1		! oldpsr &= ~PSR_PIL;
4563	sethi	%hi(curproc), %g7
4564	st	%g0, [%g7 + %lo(curproc)]	! curproc = NULL;
4565
4566Lsw_scan:
4567	nop; nop; nop				! paranoia
4568	ld	[%g2 + %lo(_C_LABEL(sched_whichqs))], %o3
4569
4570	/*
4571	 * Optimized inline expansion of `which = ffs(whichqs) - 1';
4572	 * branches to idle if ffs(whichqs) was 0.
4573	 */
4574	set	_C_LABEL(__ffstab), %o2
4575	andcc	%o3, 0xff, %o1		! byte 0 zero?
4576	bz,a	1f			! yes, try byte 1
4577	 srl	%o3, 8, %o0
4578	b	2f			! ffs = ffstab[byte0]; which = ffs - 1;
4579	 ldsb	[%o2 + %o1], %o0
45801:	andcc	%o0, 0xff, %o1		! byte 1 zero?
4581	bz,a	1f			! yes, try byte 2
4582	 srl	%o0, 8, %o0
4583	ldsb	[%o2 + %o1], %o0	! which = ffstab[byte1] + 7;
4584	b	3f
4585	 add	%o0, 7, %o4
45861:	andcc	%o0, 0xff, %o1		! byte 2 zero?
4587	bz,a	1f			! yes, try byte 3
4588	 srl	%o0, 8, %o0
4589	ldsb	[%o2 + %o1], %o0	! which = ffstab[byte2] + 15;
4590	b	3f
4591	 add	%o0, 15, %o4
45921:	ldsb	[%o2 + %o0], %o0	! ffs = ffstab[byte3] + 24
4593	addcc	%o0, 24, %o0		! (note that ffstab[0] == -24)
4594	bz	idle			! if answer was 0, go idle
4595	 EMPTY
45962:	sub	%o0, 1, %o4		! which = ffs(whichqs) - 1
45973:	/* end optimized inline expansion */
4598
4599	/*
4600	 * We found a nonempty run queue.  Take its first process.
4601	 */
4602	set	_C_LABEL(sched_qs), %o5	! q = &qs[which];
4603	sll	%o4, 3, %o0
4604	add	%o0, %o5, %o5
4605	ld	[%o5], %g3		! p = q->ph_link;
4606	cmp	%g3, %o5		! if (p == q)
4607	be	Lsw_panic_rq		!	panic("switch rq");
4608	 EMPTY
4609	ld	[%g3], %o0		! tmp0 = p->p_forw;
4610	st	%o0, [%o5]		! q->ph_link = tmp0;
4611	st	%o5, [%o0 + 4]		! tmp0->p_back = q;
4612	cmp	%o0, %o5		! if (tmp0 == q)
4613	bne	1f
4614	 EMPTY
4615	mov	1, %o1			!	whichqs &= ~(1 << which);
4616	sll	%o1, %o4, %o1
4617	andn	%o3, %o1, %o3
4618	st	%o3, [%g2 + %lo(_C_LABEL(sched_whichqs))]
46191:
4620	/*
4621	 * PHASE TWO: NEW REGISTER USAGE:
4622	 *	%g1 = oldpsr (excluding ipl bits)
4623	 *	%g2 = newpsr
4624	 *	%g3 = p
4625	 *	%g4 = lastproc
4626	 *	%g5 = newpcb
4627	 *	%g6 = %hi(cpcb)
4628	 *	%g7 = %hi(curproc)
4629	 *	%o0 = tmp 1
4630	 *	%o1 = tmp 2
4631	 *	%o2 = tmp 3
4632	 *	%o3 = vm
4633	 */
4634
4635	/* firewalls */
4636	ld	[%g3 + P_WCHAN], %o0	! if (p->p_wchan)
4637	tst	%o0
4638	bne	Lsw_panic_wchan		!	panic("switch wchan");
4639	 EMPTY
4640	ldsb	[%g3 + P_STAT], %o0	! if (p->p_stat != SRUN)
4641	cmp	%o0, SRUN
4642	bne	Lsw_panic_srun		!	panic("switch SRUN");
4643	 EMPTY
4644
4645	/*
4646	 * Committed to running process p.
4647	 * It may be the same as the one we were running before.
4648	 */
4649	mov	SONPROC, %o0			! p->p_stat = SONPROC;
4650	stb	%o0, [%g3 + P_STAT]
4651
4652	/* p->p_cpu initialized in fork1() for single-processor */
4653#if defined(MULTIPROCESSOR)
4654	sethi	%hi(_CISELFP), %o0		! p->p_cpu = cpuinfo.ci_self;
4655	ld	[%o0 + %lo(_CISELFP)], %o0
4656	st	%o0, [%g3 + P_CPU]
4657#endif
4658
4659	sethi	%hi(_C_LABEL(want_resched)), %o0	! want_resched = 0;
4660	st	%g0, [%o0 + %lo(_C_LABEL(want_resched))]
4661#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG)
4662	/* Done with the run queues; release the scheduler lock */
4663	SAVE_GLOBALS_AND_CALL(sched_unlock_idle)
4664#endif
4665	ld	[%g3 + P_ADDR], %g5		! newpcb = p->p_addr;
4666	st	%g0, [%g3 + 4]			! p->p_back = NULL;
4667	ld	[%g5 + PCB_PSR], %g2		! newpsr = newpcb->pcb_psr;
4668	st	%g3, [%g7 + %lo(curproc)]	! curproc = p;
4669
4670	cmp	%g3, %g4		! p == lastproc?
4671	be,a	Lsw_sameproc		! yes, go return 0
4672	 wr	%g2, 0, %psr		! (after restoring ipl)
4673
4674	/*
4675	 * Not the old process.  Save the old process, if any;
4676	 * then load p.
4677	 */
4678	tst	%g4
4679	be,a	Lsw_load		! if no old process, go load
4680	 wr	%g1, (PIL_CLOCK << 8) | PSR_ET, %psr
4681
4682	INCR(_C_LABEL(nswitchdiff))	! clobbers %o0,%o1
4683	/*
4684	 * save: write back all windows (including the current one).
4685	 * XXX	crude; knows nwindows <= 8
4686	 */
4687wb1:	/* 7 of each: */
4688	SAVE;    SAVE;    SAVE;    SAVE;    SAVE;    SAVE;    SAVE
4689	restore; restore; restore; restore; restore; restore; restore
4690
4691	/*
4692	 * Load the new process.  To load, we must change stacks and
4693	 * alter cpcb and %wim, hence we must disable traps.  %psr is
4694	 * currently equal to oldpsr (%g1) ^ (PIL_CLOCK << 8);
4695	 * this means that PSR_ET is on.  Likewise, PSR_ET is on
4696	 * in newpsr (%g2), although we do not know newpsr's ipl.
4697	 *
4698	 * We also must load up the `in' and `local' registers.
4699	 */
4700	wr	%g1, (PIL_CLOCK << 8) | PSR_ET, %psr
4701Lsw_load:
4702!	wr	%g1, (PIL_CLOCK << 8) | PSR_ET, %psr	! done above
4703	/* compute new wim */
4704	ld	[%g5 + PCB_WIM], %o0
4705	mov	1, %o1
4706	sll	%o1, %o0, %o0
4707	wr	%o0, 0, %wim		! %wim = 1 << newpcb->pcb_wim;
4708	/* Clear FP & CP enable bits, as well as the PIL field */
4709	/* now must not change %psr for 3 more instrs */
4710/*1*/	set	PSR_EF|PSR_EC|PSR_PIL, %o0
4711/*2*/	andn	%g2, %o0, %g2		! newpsr &= ~(PSR_EF|PSR_EC|PSR_PIL);
4712/*3*/	nop
4713	/* set new psr, but with traps disabled */
4714	wr	%g2, PSR_ET, %psr	! %psr = newpsr ^ PSR_ET;
4715	/* set new cpcb */
4716	st	%g5, [%g6 + %lo(cpcb)]	! cpcb = newpcb;
4717	ldd	[%g5 + PCB_SP], %o6	! <sp,pc> = newpcb->pcb_<sp,pc>
4718	/* load window */
4719	ldd	[%sp + (0*8)], %l0
4720	ldd	[%sp + (1*8)], %l2
4721	ldd	[%sp + (2*8)], %l4
4722	ldd	[%sp + (3*8)], %l6
4723	ldd	[%sp + (4*8)], %i0
4724	ldd	[%sp + (5*8)], %i2
4725	ldd	[%sp + (6*8)], %i4
4726	ldd	[%sp + (7*8)], %i6
4727#ifdef DEBUG
4728	mov	%g5, %o0
4729	SET_SP_REDZONE(%o0, %o1)
4730	CHECK_SP_REDZONE(%o0, %o1)
4731#endif
4732	/* finally, enable traps and continue at splclock() */
4733	wr	%g2, PIL_CLOCK << 8 , %psr	! psr = newpsr;
4734
4735	/*
4736	 * Now running p.  Make sure it has a context so that it
4737	 * can talk about user space stuff.  (Its pcb_uw is currently
4738	 * zero so it is safe to have interrupts going here.)
4739	 */
4740	ld	[%g3 + P_VMSPACE], %o3	! vm = p->p_vmspace;
4741	ld	[%o3 + VM_PMAP], %o3	! pm = vm->vm_map.vm_pmap;
4742	ld	[%o3 + PMAP_CTX], %o0	! if (pm->pm_ctx != NULL)
4743	tst	%o0
4744	bnz,a	Lsw_havectx		!	goto havecontext;
4745	 ld	[%o3 + PMAP_CTXNUM], %o0	! load context number
4746
4747	/* p does not have a context: call ctx_alloc to get one */
4748	save	%sp, -CCFSZ, %sp
4749	call	_C_LABEL(ctx_alloc)	! ctx_alloc(pm);
4750	 mov	%i3, %o0
4751
4752	ret
4753	 restore
4754
4755	/* p does have a context: just switch to it */
4756Lsw_havectx:
4757	! context is in %o0
4758	! pmap is in %o3
4759#if (defined(SUN4) || defined(SUN4C)) && defined(SUN4M)
4760NOP_ON_4M_15:
4761	b,a	1f
4762	b,a	2f
4763#endif
47641:
4765#if defined(SUN4) || defined(SUN4C)
4766	set	AC_CONTEXT, %o1
4767	retl
4768	 stba	%o0, [%o1] ASI_CONTROL	! setcontext(vm->vm_pmap.pm_ctxnum);
4769#endif
47702:
4771#if defined(SUN4M)
4772	/*
4773	 * Flush caches that need to be flushed on context switch.
4774	 * We know this is currently only necessary on the sun4m hypersparc.
4775	 */
4776	set	CPUINFO_VA+CPUINFO_PURE_VCACHE_FLS, %o2
4777	ld	[%o2], %o2
4778	mov	%o7, %g7	! save return address
4779	jmpl	%o2, %o7	! this function must not clobber %o0 and %g7
4780	 nop
4781
4782	set	SRMMU_CXR, %o1
4783	jmp	%g7 + 8
4784	 sta	%o0, [%o1] ASI_SRMMU	! setcontext(vm->vm_pmap.pm_ctxnum);
4785#endif
4786
4787Lsw_sameproc:
4788	/*
4789	 * We are resuming the process that was running at the
4790	 * call to switch().  Just set psr ipl and return.
4791	 */
4792!	wr	%g2, 0 %psr		! %psr = newpsr; (done earlier)
4793	nop
4794	retl
4795	 nop
4796
4797
4798/*
4799 * Snapshot the current process so that stack frames are up to date.
4800 * Only used just before a crash dump.
4801 */
4802ENTRY(snapshot)
4803	std	%o6, [%o0 + PCB_SP]	! save sp
4804	rd	%psr, %o1		! save psr
4805	st	%o1, [%o0 + PCB_PSR]
4806
4807	/*
4808	 * Just like switch(); same XXX comments apply.
4809	 * 7 of each.  Minor tweak: the 7th restore is
4810	 * done after a ret.
4811	 */
4812	SAVE; SAVE; SAVE; SAVE; SAVE; SAVE; SAVE
4813	restore; restore; restore; restore; restore; restore; ret; restore
4814
4815
4816/*
4817 * cpu_fork() arrange for proc_trampoline() to run after a process gets
4818 * chosen in switch(). The stack frame will contain a function pointer
4819 * in %l0, and an argument to pass to it in %l2.
4820 *
4821 * If the function *(%l0) returns, we arrange for an immediate return
4822 * to user mode. This happens in two known cases: after execve(2) of init,
4823 * and when returning a child to user mode after a fork(2).
4824 *
4825 * If were setting up a kernel thread, the function *(%l0) will not return.
4826 */
4827ENTRY(proc_trampoline)
4828	/*
4829	 * Note: cpu_fork() has set up a stack frame for us to run in,
4830	 * so we can call other functions from here without using
4831	 * `save ... restore'.
4832	 */
4833#if defined(MULTIPROCESSOR)
4834	/* Finish setup in SMP environment: acquire locks etc. */
4835	call _C_LABEL(proc_trampoline_mp)
4836	 nop
4837#endif
4838
4839	/* Reset interrupt level */
4840	rd	%psr, %o0
4841	andn	%o0, PSR_PIL, %o0	! psr &= ~PSR_PIL;
4842	wr	%o0, 0, %psr		! (void) spl0();
4843	 nop				! psr delay; the next 2 instructions
4844					! can safely be made part of the
4845					! required 3 instructions psr delay
4846	call	%l0
4847	 mov	%l1, %o0
4848
4849	/*
4850	 * Here we finish up as in syscall, but simplified.
4851	 * cpu_fork() or sendsig() (if we took a pending signal
4852	 * in child_return()) will have set the user-space return
4853	 * address in tf_pc. In both cases, %npc should be %pc + 4.
4854	 */
4855	mov	PSR_S, %l0		! user psr (no need to load it)
4856	!?wr	%g0, 2, %wim		! %wim = 2
4857	ld	[%sp + CCFSZ + 4], %l1	! pc = tf->tf_pc from cpu_fork()
4858	b	return_from_syscall
4859	 add	%l1, 4, %l2		! npc = pc+4
4860
4861/*
4862 * {fu,su}{,i}{byte,word}
4863 */
4864_ENTRY(fuiword)
4865ENTRY(fuword)
4866	set	KERNBASE, %o2
4867	cmp	%o0, %o2		! if addr >= KERNBASE...
4868	bgeu	Lfsbadaddr
4869	EMPTY
4870	btst	3, %o0			! or has low bits set...
4871	bnz	Lfsbadaddr		!	go return -1
4872	EMPTY
4873	sethi	%hi(cpcb), %o2		! cpcb->pcb_onfault = Lfserr;
4874	ld	[%o2 + %lo(cpcb)], %o2
4875	set	Lfserr, %o3
4876	st	%o3, [%o2 + PCB_ONFAULT]
4877	ld	[%o0], %o0		! fetch the word
4878	retl				! phew, made it, return the word
4879	 st	%g0, [%o2 + PCB_ONFAULT]! but first clear onfault
4880
4881Lfserr:
4882	st	%g0, [%o2 + PCB_ONFAULT]! error in r/w, clear pcb_onfault
4883Lfsbadaddr:
4884	retl				! and return error indicator
4885	 mov	-1, %o0
4886
4887	/*
4888	 * This is just like Lfserr, but it's a global label that allows
4889	 * mem_access_fault() to check to see that we don't want to try to
4890	 * page in the fault.  It's used by fuswintr() etc.
4891	 */
4892	.globl	_C_LABEL(Lfsbail)
4893_C_LABEL(Lfsbail):
4894	st	%g0, [%o2 + PCB_ONFAULT]! error in r/w, clear pcb_onfault
4895	retl				! and return error indicator
4896	 mov	-1, %o0
4897
4898	/*
4899	 * Like fusword but callable from interrupt context.
4900	 * Fails if data isn't resident.
4901	 */
4902ENTRY(fuswintr)
4903	set	KERNBASE, %o2
4904	cmp	%o0, %o2		! if addr >= KERNBASE
4905	bgeu	Lfsbadaddr		!	return error
4906	EMPTY
4907	sethi	%hi(cpcb), %o2		! cpcb->pcb_onfault = Lfsbail;
4908	ld	[%o2 + %lo(cpcb)], %o2
4909	set	_C_LABEL(Lfsbail), %o3
4910	st	%o3, [%o2 + PCB_ONFAULT]
4911	lduh	[%o0], %o0		! fetch the halfword
4912	retl				! made it
4913	st	%g0, [%o2 + PCB_ONFAULT]! but first clear onfault
4914
4915ENTRY(fusword)
4916	set	KERNBASE, %o2
4917	cmp	%o0, %o2		! if addr >= KERNBASE
4918	bgeu	Lfsbadaddr		!	return error
4919	EMPTY
4920	sethi	%hi(cpcb), %o2		! cpcb->pcb_onfault = Lfserr;
4921	ld	[%o2 + %lo(cpcb)], %o2
4922	set	Lfserr, %o3
4923	st	%o3, [%o2 + PCB_ONFAULT]
4924	lduh	[%o0], %o0		! fetch the halfword
4925	retl				! made it
4926	st	%g0, [%o2 + PCB_ONFAULT]! but first clear onfault
4927
4928_ENTRY(fuibyte)
4929ENTRY(fubyte)
4930	set	KERNBASE, %o2
4931	cmp	%o0, %o2		! if addr >= KERNBASE
4932	bgeu	Lfsbadaddr		!	return error
4933	EMPTY
4934	sethi	%hi(cpcb), %o2		! cpcb->pcb_onfault = Lfserr;
4935	ld	[%o2 + %lo(cpcb)], %o2
4936	set	Lfserr, %o3
4937	st	%o3, [%o2 + PCB_ONFAULT]
4938	ldub	[%o0], %o0		! fetch the byte
4939	retl				! made it
4940	st	%g0, [%o2 + PCB_ONFAULT]! but first clear onfault
4941
4942_ENTRY(suiword)
4943ENTRY(suword)
4944	set	KERNBASE, %o2
4945	cmp	%o0, %o2		! if addr >= KERNBASE ...
4946	bgeu	Lfsbadaddr
4947	EMPTY
4948	btst	3, %o0			! or has low bits set ...
4949	bnz	Lfsbadaddr		!	go return error
4950	EMPTY
4951	sethi	%hi(cpcb), %o2		! cpcb->pcb_onfault = Lfserr;
4952	ld	[%o2 + %lo(cpcb)], %o2
4953	set	Lfserr, %o3
4954	st	%o3, [%o2 + PCB_ONFAULT]
4955	st	%o1, [%o0]		! store the word
4956	st	%g0, [%o2 + PCB_ONFAULT]! made it, clear onfault
4957	retl				! and return 0
4958	clr	%o0
4959
4960ENTRY(suswintr)
4961	set	KERNBASE, %o2
4962	cmp	%o0, %o2		! if addr >= KERNBASE
4963	bgeu	Lfsbadaddr		!	go return error
4964	EMPTY
4965	sethi	%hi(cpcb), %o2		! cpcb->pcb_onfault = Lfsbail;
4966	ld	[%o2 + %lo(cpcb)], %o2
4967	set	_C_LABEL(Lfsbail), %o3
4968	st	%o3, [%o2 + PCB_ONFAULT]
4969	sth	%o1, [%o0]		! store the halfword
4970	st	%g0, [%o2 + PCB_ONFAULT]! made it, clear onfault
4971	retl				! and return 0
4972	clr	%o0
4973
4974ENTRY(susword)
4975	set	KERNBASE, %o2
4976	cmp	%o0, %o2		! if addr >= KERNBASE
4977	bgeu	Lfsbadaddr		!	go return error
4978	EMPTY
4979	sethi	%hi(cpcb), %o2		! cpcb->pcb_onfault = Lfserr;
4980	ld	[%o2 + %lo(cpcb)], %o2
4981	set	Lfserr, %o3
4982	st	%o3, [%o2 + PCB_ONFAULT]
4983	sth	%o1, [%o0]		! store the halfword
4984	st	%g0, [%o2 + PCB_ONFAULT]! made it, clear onfault
4985	retl				! and return 0
4986	clr	%o0
4987
4988_ENTRY(suibyte)
4989ENTRY(subyte)
4990	set	KERNBASE, %o2
4991	cmp	%o0, %o2		! if addr >= KERNBASE
4992	bgeu	Lfsbadaddr		!	go return error
4993	EMPTY
4994	sethi	%hi(cpcb), %o2		! cpcb->pcb_onfault = Lfserr;
4995	ld	[%o2 + %lo(cpcb)], %o2
4996	set	Lfserr, %o3
4997	st	%o3, [%o2 + PCB_ONFAULT]
4998	stb	%o1, [%o0]		! store the byte
4999	st	%g0, [%o2 + PCB_ONFAULT]! made it, clear onfault
5000	retl				! and return 0
5001	clr	%o0
5002
5003/* probeget and probeset are meant to be used during autoconfiguration */
5004
5005/*
5006 * probeget(addr, size) caddr_t addr; int size;
5007 *
5008 * Read or write a (byte,word,longword) from the given address.
5009 * Like {fu,su}{byte,halfword,word} but our caller is supposed
5010 * to know what he is doing... the address can be anywhere.
5011 *
5012 * We optimize for space, rather than time, here.
5013 */
5014ENTRY(probeget)
5015	! %o0 = addr, %o1 = (1,2,4)
5016	sethi	%hi(cpcb), %o2
5017	ld	[%o2 + %lo(cpcb)], %o2	! cpcb->pcb_onfault = Lfserr;
5018	set	Lfserr, %o5
5019	st	%o5, [%o2 + PCB_ONFAULT]
5020	btst	1, %o1
5021	bnz,a	0f			! if (len & 1)
5022	 ldub	[%o0], %o0		!	value = *(char *)addr;
50230:	btst	2, %o1
5024	bnz,a	0f			! if (len & 2)
5025	 lduh	[%o0], %o0		!	value = *(short *)addr;
50260:	btst	4, %o1
5027	bnz,a	0f			! if (len & 4)
5028	 ld	[%o0], %o0		!	value = *(int *)addr;
50290:	retl				! made it, clear onfault and return
5030	 st	%g0, [%o2 + PCB_ONFAULT]
5031
5032/*
5033 * probeset(addr, size, val) caddr_t addr; int size, val;
5034 *
5035 * As above, but we return 0 on success.
5036 */
5037ENTRY(probeset)
5038	! %o0 = addr, %o1 = (1,2,4), %o2 = val
5039	sethi	%hi(cpcb), %o3
5040	ld	[%o3 + %lo(cpcb)], %o3	! cpcb->pcb_onfault = Lfserr;
5041	set	Lfserr, %o5
5042	st	%o5, [%o3 + PCB_ONFAULT]
5043	btst	1, %o1
5044	bnz,a	0f			! if (len & 1)
5045	 stb	%o2, [%o0]		!	*(char *)addr = value;
50460:	btst	2, %o1
5047	bnz,a	0f			! if (len & 2)
5048	 sth	%o2, [%o0]		!	*(short *)addr = value;
50490:	btst	4, %o1
5050	bnz,a	0f			! if (len & 4)
5051	 st	%o2, [%o0]		!	*(int *)addr = value;
50520:	clr	%o0			! made it, clear onfault and return 0
5053	retl
5054	 st	%g0, [%o3 + PCB_ONFAULT]
5055
5056/*
5057 * int xldcontrolb(caddr_t, pcb)
5058 *		    %o0     %o1
5059 *
5060 * read a byte from the specified address in ASI_CONTROL space.
5061 */
5062ENTRY(xldcontrolb)
5063	!sethi	%hi(cpcb), %o2
5064	!ld	[%o2 + %lo(cpcb)], %o2	! cpcb->pcb_onfault = Lfsbail;
5065	or	%o1, %g0, %o2		! %o2 = %o1
5066	set	_C_LABEL(Lfsbail), %o5
5067	st	%o5, [%o2 + PCB_ONFAULT]
5068	lduba	[%o0] ASI_CONTROL, %o0	! read
50690:	retl
5070	 st	%g0, [%o2 + PCB_ONFAULT]
5071
5072/*
5073 * int fkbyte(caddr_t, pcb)
5074 *	      %o0      %o1
5075 *
5076 * Just like fubyte(), but for kernel space.
5077 * (currently used to work around unexplained transient bus errors
5078 *  when reading the VME interrupt vector)
5079 */
5080ENTRY(fkbyte)
5081	or	%o1, %g0, %o2		! %o2 = %o1
5082	set	_C_LABEL(Lfsbail), %o5
5083	st	%o5, [%o2 + PCB_ONFAULT]
5084	ldub	[%o0], %o0		! fetch the byte
5085	retl				! made it
5086	 st	%g0, [%o2 + PCB_ONFAULT]! but first clear onfault
5087
5088
5089/*
5090 * copywords(src, dst, nbytes)
5091 *
5092 * Copy `nbytes' bytes from src to dst, both of which are word-aligned;
5093 * nbytes is a multiple of four.  It may, however, be zero, in which case
5094 * nothing is to be copied.
5095 */
5096ENTRY(copywords)
5097	! %o0 = src, %o1 = dst, %o2 = nbytes
5098	b	1f
5099	deccc	4, %o2
51000:
5101	st	%o3, [%o1 + %o2]
5102	deccc	4, %o2			! while ((n -= 4) >= 0)
51031:
5104	bge,a	0b			!    *(int *)(dst+n) = *(int *)(src+n);
5105	ld	[%o0 + %o2], %o3
5106	retl
5107	nop
5108
5109/*
5110 * qcopy(src, dst, nbytes)
5111 *
5112 * (q for `quad' or `quick', as opposed to b for byte/block copy)
5113 *
5114 * Just like copywords, but everything is multiples of 8.
5115 */
5116ENTRY(qcopy)
5117	b	1f
5118	deccc	8, %o2
51190:
5120	std	%o4, [%o1 + %o2]
5121	deccc	8, %o2
51221:
5123	bge,a	0b
5124	ldd	[%o0 + %o2], %o4
5125	retl
5126	nop
5127
5128/*
5129 * qzero(addr, nbytes)
5130 *
5131 * Zeroes `nbytes' bytes of a quad-aligned virtual address,
5132 * where nbytes is itself a multiple of 8.
5133 */
5134ENTRY(qzero)
5135	! %o0 = addr, %o1 = len (in bytes)
5136	clr	%g1
51370:
5138	deccc	8, %o1			! while ((n =- 8) >= 0)
5139	bge,a	0b
5140	std	%g0, [%o0 + %o1]	!	*(quad *)(addr + n) = 0;
5141	retl
5142	nop
5143
5144/*
5145 * kernel bcopy
5146 * Assumes regions do not overlap; has no useful return value.
5147 *
5148 * Must not use %g7 (see copyin/copyout above).
5149 */
5150
5151#define	BCOPY_SMALL	32	/* if < 32, copy by bytes */
5152
5153ENTRY(bcopy)
5154	cmp	%o2, BCOPY_SMALL
5155Lbcopy_start:
5156	bge,a	Lbcopy_fancy	! if >= this many, go be fancy.
5157	btst	7, %o0		! (part of being fancy)
5158
5159	/*
5160	 * Not much to copy, just do it a byte at a time.
5161	 */
5162	deccc	%o2		! while (--len >= 0)
5163	bl	1f
5164	EMPTY
51650:
5166	inc	%o0
5167	ldsb	[%o0 - 1], %o4	!	(++dst)[-1] = *src++;
5168	stb	%o4, [%o1]
5169	deccc	%o2
5170	bge	0b
5171	inc	%o1
51721:
5173	retl
5174	 nop
5175	/* NOTREACHED */
5176
5177	/*
5178	 * Plenty of data to copy, so try to do it optimally.
5179	 */
5180Lbcopy_fancy:
5181	! check for common case first: everything lines up.
5182!	btst	7, %o0		! done already
5183	bne	1f
5184	EMPTY
5185	btst	7, %o1
5186	be,a	Lbcopy_doubles
5187	dec	8, %o2		! if all lined up, len -= 8, goto bcopy_doubes
5188
5189	! If the low bits match, we can make these line up.
51901:
5191	xor	%o0, %o1, %o3	! t = src ^ dst;
5192	btst	1, %o3		! if (t & 1) {
5193	be,a	1f
5194	btst	1, %o0		! [delay slot: if (src & 1)]
5195
5196	! low bits do not match, must copy by bytes.
51970:
5198	ldsb	[%o0], %o4	!	do {
5199	inc	%o0		!		(++dst)[-1] = *src++;
5200	inc	%o1
5201	deccc	%o2
5202	bnz	0b		!	} while (--len != 0);
5203	stb	%o4, [%o1 - 1]
5204	retl
5205	 nop
5206	/* NOTREACHED */
5207
5208	! lowest bit matches, so we can copy by words, if nothing else
52091:
5210	be,a	1f		! if (src & 1) {
5211	btst	2, %o3		! [delay slot: if (t & 2)]
5212
5213	! although low bits match, both are 1: must copy 1 byte to align
5214	ldsb	[%o0], %o4	!	*dst++ = *src++;
5215	stb	%o4, [%o1]
5216	inc	%o0
5217	inc	%o1
5218	dec	%o2		!	len--;
5219	btst	2, %o3		! } [if (t & 2)]
52201:
5221	be,a	1f		! if (t & 2) {
5222	btst	2, %o0		! [delay slot: if (src & 2)]
5223	dec	2, %o2		!	len -= 2;
52240:
5225	ldsh	[%o0], %o4	!	do {
5226	sth	%o4, [%o1]	!		*(short *)dst = *(short *)src;
5227	inc	2, %o0		!		dst += 2, src += 2;
5228	deccc	2, %o2		!	} while ((len -= 2) >= 0);
5229	bge	0b
5230	inc	2, %o1
5231	b	Lbcopy_mopb	!	goto mop_up_byte;
5232	btst	1, %o2		! } [delay slot: if (len & 1)]
5233	/* NOTREACHED */
5234
5235	! low two bits match, so we can copy by longwords
52361:
5237	be,a	1f		! if (src & 2) {
5238	btst	4, %o3		! [delay slot: if (t & 4)]
5239
5240	! although low 2 bits match, they are 10: must copy one short to align
5241	ldsh	[%o0], %o4	!	(*short *)dst = *(short *)src;
5242	sth	%o4, [%o1]
5243	inc	2, %o0		!	dst += 2;
5244	inc	2, %o1		!	src += 2;
5245	dec	2, %o2		!	len -= 2;
5246	btst	4, %o3		! } [if (t & 4)]
52471:
5248	be,a	1f		! if (t & 4) {
5249	btst	4, %o0		! [delay slot: if (src & 4)]
5250	dec	4, %o2		!	len -= 4;
52510:
5252	ld	[%o0], %o4	!	do {
5253	st	%o4, [%o1]	!		*(int *)dst = *(int *)src;
5254	inc	4, %o0		!		dst += 4, src += 4;
5255	deccc	4, %o2		!	} while ((len -= 4) >= 0);
5256	bge	0b
5257	inc	4, %o1
5258	b	Lbcopy_mopw	!	goto mop_up_word_and_byte;
5259	btst	2, %o2		! } [delay slot: if (len & 2)]
5260	/* NOTREACHED */
5261
5262	! low three bits match, so we can copy by doublewords
52631:
5264	be	1f		! if (src & 4) {
5265	dec	8, %o2		! [delay slot: len -= 8]
5266	ld	[%o0], %o4	!	*(int *)dst = *(int *)src;
5267	st	%o4, [%o1]
5268	inc	4, %o0		!	dst += 4, src += 4, len -= 4;
5269	inc	4, %o1
5270	dec	4, %o2		! }
52711:
5272Lbcopy_doubles:
5273	ldd	[%o0], %o4	! do {
5274	std	%o4, [%o1]	!	*(double *)dst = *(double *)src;
5275	inc	8, %o0		!	dst += 8, src += 8;
5276	deccc	8, %o2		! } while ((len -= 8) >= 0);
5277	bge	Lbcopy_doubles
5278	inc	8, %o1
5279
5280	! check for a usual case again (save work)
5281	btst	7, %o2		! if ((len & 7) == 0)
5282	be	Lbcopy_done	!	goto bcopy_done;
5283
5284	btst	4, %o2		! if ((len & 4)) == 0)
5285	be,a	Lbcopy_mopw	!	goto mop_up_word_and_byte;
5286	btst	2, %o2		! [delay slot: if (len & 2)]
5287	ld	[%o0], %o4	!	*(int *)dst = *(int *)src;
5288	st	%o4, [%o1]
5289	inc	4, %o0		!	dst += 4;
5290	inc	4, %o1		!	src += 4;
5291	btst	2, %o2		! } [if (len & 2)]
5292
52931:
5294	! mop up trailing word (if present) and byte (if present).
5295Lbcopy_mopw:
5296	be	Lbcopy_mopb	! no word, go mop up byte
5297	btst	1, %o2		! [delay slot: if (len & 1)]
5298	ldsh	[%o0], %o4	! *(short *)dst = *(short *)src;
5299	be	Lbcopy_done	! if ((len & 1) == 0) goto done;
5300	sth	%o4, [%o1]
5301	ldsb	[%o0 + 2], %o4	! dst[2] = src[2];
5302	retl
5303	 stb	%o4, [%o1 + 2]
5304	/* NOTREACHED */
5305
5306	! mop up trailing byte (if present).
5307Lbcopy_mopb:
5308	bne,a	1f
5309	ldsb	[%o0], %o4
5310
5311Lbcopy_done:
5312	retl
5313	 nop
5314
53151:
5316	retl
5317	 stb	%o4,[%o1]
5318/*
5319 * ovbcopy(src, dst, len): like bcopy, but regions may overlap.
5320 */
5321ENTRY(ovbcopy)
5322	cmp	%o0, %o1	! src < dst?
5323	bgeu	Lbcopy_start	! no, go copy forwards as via bcopy
5324	cmp	%o2, BCOPY_SMALL! (check length for doublecopy first)
5325
5326	/*
5327	 * Since src comes before dst, and the regions might overlap,
5328	 * we have to do the copy starting at the end and working backwards.
5329	 */
5330	add	%o2, %o0, %o0	! src += len
5331	add	%o2, %o1, %o1	! dst += len
5332	bge,a	Lback_fancy	! if len >= BCOPY_SMALL, go be fancy
5333	btst	3, %o0
5334
5335	/*
5336	 * Not much to copy, just do it a byte at a time.
5337	 */
5338	deccc	%o2		! while (--len >= 0)
5339	bl	1f
5340	EMPTY
53410:
5342	dec	%o0		!	*--dst = *--src;
5343	ldsb	[%o0], %o4
5344	dec	%o1
5345	deccc	%o2
5346	bge	0b
5347	stb	%o4, [%o1]
53481:
5349	retl
5350	nop
5351
5352	/*
5353	 * Plenty to copy, try to be optimal.
5354	 * We only bother with word/halfword/byte copies here.
5355	 */
5356Lback_fancy:
5357!	btst	3, %o0		! done already
5358	bnz	1f		! if ((src & 3) == 0 &&
5359	btst	3, %o1		!     (dst & 3) == 0)
5360	bz,a	Lback_words	!	goto words;
5361	dec	4, %o2		! (done early for word copy)
5362
53631:
5364	/*
5365	 * See if the low bits match.
5366	 */
5367	xor	%o0, %o1, %o3	! t = src ^ dst;
5368	btst	1, %o3
5369	bz,a	3f		! if (t & 1) == 0, can do better
5370	btst	1, %o0
5371
5372	/*
5373	 * Nope; gotta do byte copy.
5374	 */
53752:
5376	dec	%o0		! do {
5377	ldsb	[%o0], %o4	!	*--dst = *--src;
5378	dec	%o1
5379	deccc	%o2		! } while (--len != 0);
5380	bnz	2b
5381	stb	%o4, [%o1]
5382	retl
5383	nop
5384
53853:
5386	/*
5387	 * Can do halfword or word copy, but might have to copy 1 byte first.
5388	 */
5389!	btst	1, %o0		! done earlier
5390	bz,a	4f		! if (src & 1) {	/* copy 1 byte */
5391	btst	2, %o3		! (done early)
5392	dec	%o0		!	*--dst = *--src;
5393	ldsb	[%o0], %o4
5394	dec	%o1
5395	stb	%o4, [%o1]
5396	dec	%o2		!	len--;
5397	btst	2, %o3		! }
5398
53994:
5400	/*
5401	 * See if we can do a word copy ((t&2) == 0).
5402	 */
5403!	btst	2, %o3		! done earlier
5404	bz,a	6f		! if (t & 2) == 0, can do word copy
5405	btst	2, %o0		! (src&2, done early)
5406
5407	/*
5408	 * Gotta do halfword copy.
5409	 */
5410	dec	2, %o2		! len -= 2;
54115:
5412	dec	2, %o0		! do {
5413	ldsh	[%o0], %o4	!	src -= 2;
5414	dec	2, %o1		!	dst -= 2;
5415	deccc	2, %o0		!	*(short *)dst = *(short *)src;
5416	bge	5b		! } while ((len -= 2) >= 0);
5417	sth	%o4, [%o1]
5418	b	Lback_mopb	! goto mop_up_byte;
5419	btst	1, %o2		! (len&1, done early)
5420
54216:
5422	/*
5423	 * We can do word copies, but we might have to copy
5424	 * one halfword first.
5425	 */
5426!	btst	2, %o0		! done already
5427	bz	7f		! if (src & 2) {
5428	dec	4, %o2		! (len -= 4, done early)
5429	dec	2, %o0		!	src -= 2, dst -= 2;
5430	ldsh	[%o0], %o4	!	*(short *)dst = *(short *)src;
5431	dec	2, %o1
5432	sth	%o4, [%o1]
5433	dec	2, %o2		!	len -= 2;
5434				! }
5435
54367:
5437Lback_words:
5438	/*
5439	 * Do word copies (backwards), then mop up trailing halfword
5440	 * and byte if any.
5441	 */
5442!	dec	4, %o2		! len -= 4, done already
54430:				! do {
5444	dec	4, %o0		!	src -= 4;
5445	dec	4, %o1		!	src -= 4;
5446	ld	[%o0], %o4	!	*(int *)dst = *(int *)src;
5447	deccc	4, %o2		! } while ((len -= 4) >= 0);
5448	bge	0b
5449	st	%o4, [%o1]
5450
5451	/*
5452	 * Check for trailing shortword.
5453	 */
5454	btst	2, %o2		! if (len & 2) {
5455	bz,a	1f
5456	btst	1, %o2		! (len&1, done early)
5457	dec	2, %o0		!	src -= 2, dst -= 2;
5458	ldsh	[%o0], %o4	!	*(short *)dst = *(short *)src;
5459	dec	2, %o1
5460	sth	%o4, [%o1]	! }
5461	btst	1, %o2
5462
5463	/*
5464	 * Check for trailing byte.
5465	 */
54661:
5467Lback_mopb:
5468!	btst	1, %o2		! (done already)
5469	bnz,a	1f		! if (len & 1) {
5470	ldsb	[%o0 - 1], %o4	!	b = src[-1];
5471	retl
5472	nop
54731:
5474	retl			!	dst[-1] = b;
5475	stb	%o4, [%o1 - 1]	! }
5476
5477/*
5478 * kcopy() is exactly like bcopy except that it set pcb_onfault such that
5479 * when a fault occurs, it is able to return -1 to indicate this to the
5480 * caller.
5481 */
5482ENTRY(kcopy)
5483	sethi	%hi(cpcb), %o5		! cpcb->pcb_onfault = Lkcerr;
5484	ld	[%o5 + %lo(cpcb)], %o5
5485	set	Lkcerr, %o3
5486	ld	[%o5 + PCB_ONFAULT], %g1! save current onfault handler
5487	st	%o3, [%o5 + PCB_ONFAULT]
5488
5489	cmp	%o2, BCOPY_SMALL
5490Lkcopy_start:
5491	bge,a	Lkcopy_fancy	! if >= this many, go be fancy.
5492	 btst	7, %o0		! (part of being fancy)
5493
5494	/*
5495	 * Not much to copy, just do it a byte at a time.
5496	 */
5497	deccc	%o2		! while (--len >= 0)
5498	bl	1f
5499	 EMPTY
55000:
5501	ldsb	[%o0], %o4	!	*dst++ = *src++;
5502	inc	%o0
5503	stb	%o4, [%o1]
5504	deccc	%o2
5505	bge	0b
5506	 inc	%o1
55071:
5508	st	%g1, [%o5 + PCB_ONFAULT]	! restore onfault
5509	retl
5510	 mov	0, %o0		! delay slot: return success
5511	/* NOTREACHED */
5512
5513	/*
5514	 * Plenty of data to copy, so try to do it optimally.
5515	 */
5516Lkcopy_fancy:
5517	! check for common case first: everything lines up.
5518!	btst	7, %o0		! done already
5519	bne	1f
5520	 EMPTY
5521	btst	7, %o1
5522	be,a	Lkcopy_doubles
5523	 dec	8, %o2		! if all lined up, len -= 8, goto bcopy_doubes
5524
5525	! If the low bits match, we can make these line up.
55261:
5527	xor	%o0, %o1, %o3	! t = src ^ dst;
5528	btst	1, %o3		! if (t & 1) {
5529	be,a	1f
5530	 btst	1, %o0		! [delay slot: if (src & 1)]
5531
5532	! low bits do not match, must copy by bytes.
55330:
5534	ldsb	[%o0], %o4	!	do {
5535	inc	%o0		!		*dst++ = *src++;
5536	stb	%o4, [%o1]
5537	deccc	%o2
5538	bnz	0b		!	} while (--len != 0);
5539	 inc	%o1
5540	st	%g1, [%o5 + PCB_ONFAULT]	! restore onfault
5541	retl
5542	 mov	0, %o0		! delay slot: return success
5543	/* NOTREACHED */
5544
5545	! lowest bit matches, so we can copy by words, if nothing else
55461:
5547	be,a	1f		! if (src & 1) {
5548	 btst	2, %o3		! [delay slot: if (t & 2)]
5549
5550	! although low bits match, both are 1: must copy 1 byte to align
5551	ldsb	[%o0], %o4	!	*dst++ = *src++;
5552	inc	%o0
5553	stb	%o4, [%o1]
5554	dec	%o2		!	len--;
5555	inc	%o1
5556	btst	2, %o3		! } [if (t & 2)]
55571:
5558	be,a	1f		! if (t & 2) {
5559	 btst	2, %o0		! [delay slot: if (src & 2)]
5560	dec	2, %o2		!	len -= 2;
55610:
5562	ldsh	[%o0], %o4	!	do {
5563	inc	2, %o0		!		dst += 2, src += 2;
5564	sth	%o4, [%o1]	!		*(short *)dst = *(short *)src;
5565	deccc	2, %o2		!	} while ((len -= 2) >= 0);
5566	bge	0b
5567	 inc	2, %o1
5568	b	Lkcopy_mopb	!	goto mop_up_byte;
5569	 btst	1, %o2		! } [delay slot: if (len & 1)]
5570	/* NOTREACHED */
5571
5572	! low two bits match, so we can copy by longwords
55731:
5574	be,a	1f		! if (src & 2) {
5575	 btst	4, %o3		! [delay slot: if (t & 4)]
5576
5577	! although low 2 bits match, they are 10: must copy one short to align
5578	ldsh	[%o0], %o4	!	(*short *)dst = *(short *)src;
5579	inc	2, %o0		!	dst += 2;
5580	sth	%o4, [%o1]
5581	dec	2, %o2		!	len -= 2;
5582	inc	2, %o1		!	src += 2;
5583	btst	4, %o3		! } [if (t & 4)]
55841:
5585	be,a	1f		! if (t & 4) {
5586	 btst	4, %o0		! [delay slot: if (src & 4)]
5587	dec	4, %o2		!	len -= 4;
55880:
5589	ld	[%o0], %o4	!	do {
5590	inc	4, %o0		!		dst += 4, src += 4;
5591	st	%o4, [%o1]	!		*(int *)dst = *(int *)src;
5592	deccc	4, %o2		!	} while ((len -= 4) >= 0);
5593	bge	0b
5594	 inc	4, %o1
5595	b	Lkcopy_mopw	!	goto mop_up_word_and_byte;
5596	 btst	2, %o2		! } [delay slot: if (len & 2)]
5597	/* NOTREACHED */
5598
5599	! low three bits match, so we can copy by doublewords
56001:
5601	be	1f		! if (src & 4) {
5602	 dec	8, %o2		! [delay slot: len -= 8]
5603	ld	[%o0], %o4	!	*(int *)dst = *(int *)src;
5604	inc	4, %o0		!	dst += 4, src += 4, len -= 4;
5605	st	%o4, [%o1]
5606	dec	4, %o2		! }
5607	inc	4, %o1
56081:
5609Lkcopy_doubles:
5610	! swap %o4 with %o2 during doubles copy, since %o5 is verboten
5611	mov     %o2, %o4
5612Lkcopy_doubles2:
5613	ldd	[%o0], %o2	! do {
5614	inc	8, %o0		!	dst += 8, src += 8;
5615	std	%o2, [%o1]	!	*(double *)dst = *(double *)src;
5616	deccc	8, %o4		! } while ((len -= 8) >= 0);
5617	bge	Lkcopy_doubles2
5618	 inc	8, %o1
5619	mov	%o4, %o2	! restore len
5620
5621	! check for a usual case again (save work)
5622	btst	7, %o2		! if ((len & 7) == 0)
5623	be	Lkcopy_done	!	goto bcopy_done;
5624
5625	 btst	4, %o2		! if ((len & 4)) == 0)
5626	be,a	Lkcopy_mopw	!	goto mop_up_word_and_byte;
5627	 btst	2, %o2		! [delay slot: if (len & 2)]
5628	ld	[%o0], %o4	!	*(int *)dst = *(int *)src;
5629	inc	4, %o0		!	dst += 4;
5630	st	%o4, [%o1]
5631	inc	4, %o1		!	src += 4;
5632	btst	2, %o2		! } [if (len & 2)]
5633
56341:
5635	! mop up trailing word (if present) and byte (if present).
5636Lkcopy_mopw:
5637	be	Lkcopy_mopb	! no word, go mop up byte
5638	 btst	1, %o2		! [delay slot: if (len & 1)]
5639	ldsh	[%o0], %o4	! *(short *)dst = *(short *)src;
5640	be	Lkcopy_done	! if ((len & 1) == 0) goto done;
5641	 sth	%o4, [%o1]
5642	ldsb	[%o0 + 2], %o4	! dst[2] = src[2];
5643	stb	%o4, [%o1 + 2]
5644	st	%g1, [%o5 + PCB_ONFAULT]! restore onfault
5645	retl
5646	 mov	0, %o0		! delay slot: return success
5647	/* NOTREACHED */
5648
5649	! mop up trailing byte (if present).
5650Lkcopy_mopb:
5651	bne,a	1f
5652	 ldsb	[%o0], %o4
5653
5654Lkcopy_done:
5655	st	%g1, [%o5 + PCB_ONFAULT]	! restore onfault
5656	retl
5657	 mov	0, %o0		! delay slot: return success
5658	/* NOTREACHED */
5659
56601:
5661	stb	%o4, [%o1]
5662	st	%g1, [%o5 + PCB_ONFAULT]	! restore onfault
5663	retl
5664	 mov	0, %o0		! delay slot: return success
5665	/* NOTREACHED */
5666
5667Lkcerr:
5668	retl
5669	 st	%g1, [%o5 + PCB_ONFAULT]	! restore onfault
5670	/* NOTREACHED */
5671
5672/*
5673 * savefpstate(f) struct fpstate *f;
5674 *
5675 * Store the current FPU state.  The first `st %fsr' may cause a trap;
5676 * our trap handler knows how to recover (by `returning' to savefpcont).
5677 */
5678ENTRY(savefpstate)
5679	rd	%psr, %o1		! enable FP before we begin
5680	set	PSR_EF, %o2
5681	or	%o1, %o2, %o1
5682	wr	%o1, 0, %psr
5683	/* do some setup work while we wait for PSR_EF to turn on */
5684	set	FSR_QNE, %o5		! QNE = 0x2000, too big for immediate
5685	clr	%o3			! qsize = 0;
5686	nop				! (still waiting for PSR_EF)
5687special_fp_store:
5688	st	%fsr, [%o0 + FS_FSR]	! f->fs_fsr = getfsr();
5689	/*
5690	 * Even if the preceding instruction did not trap, the queue
5691	 * is not necessarily empty: this state save might be happening
5692	 * because user code tried to store %fsr and took the FPU
5693	 * from `exception pending' mode to `exception' mode.
5694	 * So we still have to check the blasted QNE bit.
5695	 * With any luck it will usually not be set.
5696	 */
5697	ld	[%o0 + FS_FSR], %o4	! if (f->fs_fsr & QNE)
5698	btst	%o5, %o4
5699	bnz	Lfp_storeq		!	goto storeq;
5700	 std	%f0, [%o0 + FS_REGS + (4*0)]	! f->fs_f0 = etc;
5701Lfp_finish:
5702	st	%o3, [%o0 + FS_QSIZE]	! f->fs_qsize = qsize;
5703	std	%f2, [%o0 + FS_REGS + (4*2)]
5704	std	%f4, [%o0 + FS_REGS + (4*4)]
5705	std	%f6, [%o0 + FS_REGS + (4*6)]
5706	std	%f8, [%o0 + FS_REGS + (4*8)]
5707	std	%f10, [%o0 + FS_REGS + (4*10)]
5708	std	%f12, [%o0 + FS_REGS + (4*12)]
5709	std	%f14, [%o0 + FS_REGS + (4*14)]
5710	std	%f16, [%o0 + FS_REGS + (4*16)]
5711	std	%f18, [%o0 + FS_REGS + (4*18)]
5712	std	%f20, [%o0 + FS_REGS + (4*20)]
5713	std	%f22, [%o0 + FS_REGS + (4*22)]
5714	std	%f24, [%o0 + FS_REGS + (4*24)]
5715	std	%f26, [%o0 + FS_REGS + (4*26)]
5716	std	%f28, [%o0 + FS_REGS + (4*28)]
5717	retl
5718	 std	%f30, [%o0 + FS_REGS + (4*30)]
5719
5720/*
5721 * Store the (now known nonempty) FP queue.
5722 * We have to reread the fsr each time in order to get the new QNE bit.
5723 */
5724Lfp_storeq:
5725	add	%o0, FS_QUEUE, %o1	! q = &f->fs_queue[0];
57261:
5727	std	%fq, [%o1 + %o3]	! q[qsize++] = fsr_qfront();
5728	st	%fsr, [%o0 + FS_FSR]	! reread fsr
5729	ld	[%o0 + FS_FSR], %o4	! if fsr & QNE, loop
5730	btst	%o5, %o4
5731	bnz	1b
5732	 inc	8, %o3
5733	b	Lfp_finish		! set qsize and finish storing fregs
5734	 srl	%o3, 3, %o3		! (but first fix qsize)
5735
5736/*
5737 * The fsr store trapped.  Do it again; this time it will not trap.
5738 * We could just have the trap handler return to the `st %fsr', but
5739 * if for some reason it *does* trap, that would lock us into a tight
5740 * loop.  This way we panic instead.  Whoopee.
5741 */
5742savefpcont:
5743	b	special_fp_store + 4	! continue
5744	 st	%fsr, [%o0 + FS_FSR]	! but first finish the %fsr store
5745
5746/*
5747 * Load FPU state.
5748 */
5749ENTRY(loadfpstate)
5750	rd	%psr, %o1		! enable FP before we begin
5751	set	PSR_EF, %o2
5752	or	%o1, %o2, %o1
5753	wr	%o1, 0, %psr
5754	nop; nop; nop			! paranoia
5755	ldd	[%o0 + FS_REGS + (4*0)], %f0
5756	ldd	[%o0 + FS_REGS + (4*2)], %f2
5757	ldd	[%o0 + FS_REGS + (4*4)], %f4
5758	ldd	[%o0 + FS_REGS + (4*6)], %f6
5759	ldd	[%o0 + FS_REGS + (4*8)], %f8
5760	ldd	[%o0 + FS_REGS + (4*10)], %f10
5761	ldd	[%o0 + FS_REGS + (4*12)], %f12
5762	ldd	[%o0 + FS_REGS + (4*14)], %f14
5763	ldd	[%o0 + FS_REGS + (4*16)], %f16
5764	ldd	[%o0 + FS_REGS + (4*18)], %f18
5765	ldd	[%o0 + FS_REGS + (4*20)], %f20
5766	ldd	[%o0 + FS_REGS + (4*22)], %f22
5767	ldd	[%o0 + FS_REGS + (4*24)], %f24
5768	ldd	[%o0 + FS_REGS + (4*26)], %f26
5769	ldd	[%o0 + FS_REGS + (4*28)], %f28
5770	ldd	[%o0 + FS_REGS + (4*30)], %f30
5771	retl
5772	 ld	[%o0 + FS_FSR], %fsr	! setfsr(f->fs_fsr);
5773
5774/*
5775 * ienab_bis(bis) int bis;
5776 * ienab_bic(bic) int bic;
5777 *
5778 * Set and clear bits in the interrupt register.
5779 */
5780
5781#if defined(SUN4M) && (defined(SUN4) || defined(SUN4C))
5782ENTRY(ienab_bis)
5783NOP_ON_4M_13:
5784	b,a	_C_LABEL(ienab_bis_4_4c)
5785	b,a	_C_LABEL(ienab_bis_4m)
5786
5787ENTRY(ienab_bic)
5788NOP_ON_4M_14:
5789	b,a	_C_LABEL(ienab_bic_4_4c)
5790	b,a	_C_LABEL(ienab_bic_4m)
5791#endif
5792
5793#if defined(SUN4) || defined(SUN4C)
5794/*
5795 * Since there are no read-modify-write instructions for this,
5796 * and one of the interrupts is nonmaskable, we must disable traps.
5797 */
5798#if defined(SUN4M)
5799ENTRY(ienab_bis_4_4c)
5800#else
5801ENTRY(ienab_bis)
5802#endif
5803	! %o0 = bits to set
5804	rd	%psr, %o2
5805	wr	%o2, PSR_ET, %psr	! disable traps
5806	nop; nop			! 3-instr delay until ET turns off
5807	sethi	%hi(INTRREG_VA), %o3
5808	ldub	[%o3 + %lo(INTRREG_VA)], %o4
5809	or	%o4, %o0, %o4		! *INTRREG_VA |= bis;
5810	stb	%o4, [%o3 + %lo(INTRREG_VA)]
5811	wr	%o2, 0, %psr		! reenable traps
5812	nop
5813	retl
5814	 nop
5815
5816#if defined(SUN4M)
5817ENTRY(ienab_bic_4_4c)
5818#else
5819ENTRY(ienab_bic)
5820#endif
5821	! %o0 = bits to clear
5822	rd	%psr, %o2
5823	wr	%o2, PSR_ET, %psr	! disable traps
5824	nop; nop
5825	sethi	%hi(INTRREG_VA), %o3
5826	ldub	[%o3 + %lo(INTRREG_VA)], %o4
5827	andn	%o4, %o0, %o4		! *INTRREG_VA &=~ bic;
5828	stb	%o4, [%o3 + %lo(INTRREG_VA)]
5829	wr	%o2, 0, %psr		! reenable traps
5830	nop
5831	retl
5832	 nop
5833#endif
5834
5835#if defined(SUN4M)
5836/*
5837 * sun4m has separate registers for clearing/setting the interrupt mask.
5838 */
5839#if defined(SUN4) || defined(SUN4C)
5840ENTRY(ienab_bis_4m)
5841#else
5842ENTRY(ienab_bis)
5843#endif
5844	set	ICR_SI_SET, %o1
5845	retl
5846	 st	%o0, [%o1]
5847
5848#if defined(SUN4) || defined(SUN4C)
5849ENTRY(ienab_bic_4m)
5850#else
5851ENTRY(ienab_bic)
5852#endif
5853	set	ICR_SI_CLR, %o1
5854	retl
5855	 st	%o0, [%o1]
5856
5857/*
5858 * raise(cpu, level)
5859 */
5860ENTRY(raise)
5861#if !defined(MSIIEP) /* normal suns */
5862	! *(ICR_PI_SET + cpu*_MAXNBPG) = PINTR_SINTRLEV(level)
5863	sethi	%hi(1 << 16), %o2
5864	sll	%o2, %o1, %o2
5865	set	ICR_PI_SET, %o1
5866	set	_MAXNBPG, %o3
58671:
5868	subcc	%o0, 1, %o0
5869	bpos,a	1b
5870	 add	%o1, %o3, %o1
5871	retl
5872	 st	%o2, [%o1]
5873#else /* MSIIEP - ignore %o0, only one cpu ever */
5874	mov	1, %o2
5875	sethi	%hi(MSIIEP_PCIC_VA), %o0
5876	sll	%o2, %o1, %o2
5877	retl
5878	 sth	%o2, [%o0 + PCIC_SOFT_INTR_SET_REG]
5879#endif
5880
5881/*
5882 * Read Synchronous Fault Status registers.
5883 * On entry: %l1 == PC, %l3 == fault type, %l4 == storage, %l7 == return address
5884 * Only use %l5 and %l6.
5885 * Note: not C callable.
5886 */
5887_ENTRY(_C_LABEL(srmmu_get_syncflt))
5888_ENTRY(_C_LABEL(hypersparc_get_syncflt))
5889	set	SRMMU_SFAR, %l5
5890	lda	[%l5] ASI_SRMMU, %l5	! sync virt addr; must be read first
5891	st	%l5, [%l4 + 4]		! => dump.sfva
5892	set	SRMMU_SFSR, %l5
5893	lda	[%l5] ASI_SRMMU, %l5	! get sync fault status register
5894	jmp	%l7 + 8			! return to caller
5895	 st	%l5, [%l4]		! => dump.sfsr
5896
5897_ENTRY(_C_LABEL(viking_get_syncflt))
5898_ENTRY(_C_LABEL(ms1_get_syncflt))
5899_ENTRY(_C_LABEL(swift_get_syncflt))
5900_ENTRY(_C_LABEL(turbosparc_get_syncflt))
5901_ENTRY(_C_LABEL(cypress_get_syncflt))
5902	cmp	%l3, T_TEXTFAULT
5903	be,a	1f
5904	 mov	%l1, %l5		! use PC if type == T_TEXTFAULT
5905
5906	set	SRMMU_SFAR, %l5
5907	lda	[%l5] ASI_SRMMU, %l5	! sync virt addr; must be read first
59081:
5909	st	%l5, [%l4 + 4]		! => dump.sfva
5910
5911	set	SRMMU_SFSR, %l5
5912	lda	[%l5] ASI_SRMMU, %l5	! get sync fault status register
5913	jmp	%l7 + 8			! return to caller
5914	 st	%l5, [%l4]		! => dump.sfsr
5915
5916#if defined(MULTIPROCESSOR) && 0 /* notyet *
5917/*
5918 * Read Synchronous Fault Status registers.
5919 * On entry: %o0 == &sfsr, %o1 == &sfar
5920 */
5921_ENTRY(_C_LABEL(smp_get_syncflt))
5922	save    %sp, -CCFSZ, %sp
5923
5924	sethi	%hi(CPUINFO_VA), %o4
5925	ld	[%l4 + %lo(CPUINFO_VA+CPUINFO_GETSYNCFLT)], %o5
5926	clr	%l1
5927	clr	%l3
5928	jmpl	%o5, %l7
5929	 or	%o4, %lo(CPUINFO_SYNCFLTDUMP), %l4
5930
5931	! load values out of the dump
5932	ld	[%o4 + %lo(CPUINFO_VA+CPUINFO_SYNCFLTDUMP)], %o5
5933	st	%o5, [%i0]
5934	ld	[%o4 + %lo(CPUINFO_VA+CPUINFO_SYNCFLTDUMP+4)], %o5
5935	st	%o5, [%i1]
5936	ret
5937	 restore
5938#endif /* MULTIPROCESSOR */
5939
5940/*
5941 * Read Asynchronous Fault Status registers.
5942 * On entry: %o0 == &afsr, %o1 == &afar
5943 * Return 0 if async register are present.
5944 */
5945_ENTRY(_C_LABEL(srmmu_get_asyncflt))
5946	set	SRMMU_AFAR, %o4
5947	lda	[%o4] ASI_SRMMU, %o4	! get async fault address
5948	set	SRMMU_AFSR, %o3	!
5949	st	%o4, [%o1]
5950	lda	[%o3] ASI_SRMMU, %o3	! get async fault status
5951	st	%o3, [%o0]
5952	retl
5953	 clr	%o0			! return value
5954
5955_ENTRY(_C_LABEL(cypress_get_asyncflt))
5956_ENTRY(_C_LABEL(hypersparc_get_asyncflt))
5957	set	SRMMU_AFSR, %o3		! must read status before fault on HS
5958	lda	[%o3] ASI_SRMMU, %o3	! get async fault status
5959	st	%o3, [%o0]
5960	btst	AFSR_AFO, %o3		! and only read fault address
5961	bz	1f			! if valid.
5962	set	SRMMU_AFAR, %o4
5963	lda	[%o4] ASI_SRMMU, %o4	! get async fault address
5964	clr	%o0			! return value
5965	retl
5966	 st	%o4, [%o1]
59671:
5968	retl
5969	 clr	%o0			! return value
5970
5971_ENTRY(_C_LABEL(no_asyncflt_regs))
5972	retl
5973	 mov	1, %o0			! return value
5974
5975_ENTRY(_C_LABEL(hypersparc_pure_vcache_flush))
5976	/*
5977	 * Flush entire on-chip instruction cache, which is
5978	 * a pure vitually-indexed/virtually-tagged cache.
5979	 */
5980	retl
5981	 sta	%g0, [%g0] ASI_HICACHECLR
5982
5983#endif /* SUN4M */
5984
5985#if !defined(MSIIEP)	/* normal suns */
5986/*
5987 * void lo_microtime(struct timeval *tv)
5988 *
5989 * LBL's sparc bsd 'microtime': We don't need to spl (so this routine
5990 * can be a leaf routine) and we don't keep a 'last' timeval (there
5991 * can't be two calls to this routine in a microsecond).  This seems to
5992 * be about 20 times faster than the Sun code on an SS-2. - vj
5993 *
5994 * Read time values from slowest-changing to fastest-changing,
5995 * then re-read out to slowest.  If the values read before
5996 * the innermost match those read after, the innermost value
5997 * is consistent with the outer values.  If not, it may not
5998 * be and we must retry.  Typically this loop runs only once;
5999 * occasionally it runs twice, and only rarely does it run longer.
6000 */
6001#if defined(SUN4)
6002ENTRY(lo_microtime)
6003#else
6004ENTRY(microtime)
6005#endif
6006	sethi	%hi(_C_LABEL(time)), %g2
6007
6008#if defined(SUN4M) && !(defined(SUN4C) || defined(SUN4))
6009	sethi	%hi(TIMERREG_VA+4), %g3
6010	or	%g3, %lo(TIMERREG_VA+4), %g3
6011#elif (defined(SUN4C) || defined(SUN4)) && !defined(SUN4M)
6012	sethi	%hi(TIMERREG_VA), %g3
6013	or	%g3, %lo(TIMERREG_VA), %g3
6014#else
6015	sethi	%hi(TIMERREG_VA), %g3
6016	or	%g3, %lo(TIMERREG_VA), %g3
6017NOP_ON_4_4C_1:
6018	 add	%g3, 4, %g3
6019#endif
6020
60212:
6022	ldd	[%g2+%lo(_C_LABEL(time))], %o2	! time.tv_sec & time.tv_usec
6023	ld	[%g3], %o4			! usec counter
6024	ldd	[%g2+%lo(_C_LABEL(time))], %g4	! see if time values changed
6025	cmp	%g4, %o2
6026	bne	2b				! if time.tv_sec changed
6027	 cmp	%g5, %o3
6028	bne	2b				! if time.tv_usec changed
6029	 tst	%o4
6030
6031	bpos	3f				! reached limit?
6032	 srl	%o4, TMR_SHIFT, %o4		! convert counter to usec
6033	sethi	%hi(_C_LABEL(tick)), %g4	! bump usec by 1 tick
6034	ld	[%g4+%lo(_C_LABEL(tick))], %o1
6035	set	TMR_MASK, %g5
6036	add	%o1, %o3, %o3
6037	and	%o4, %g5, %o4
60383:
6039	add	%o4, %o3, %o3
6040	set	1000000, %g5			! normalize usec value
6041	cmp	%o3, %g5
6042	bl,a	4f
6043	 st	%o2, [%o0]			! (should be able to std here)
6044	add	%o2, 1, %o2			! overflow
6045	sub	%o3, %g5, %o3
6046	st	%o2, [%o0]			! (should be able to std here)
60474:
6048	retl
6049	 st	%o3, [%o0+4]
6050
6051#else /* MSIIEP */
6052/* XXX: uwe: can be merged with 4c/4m version above */
6053/*
6054 * ms-IIep version of
6055 * void microtime(struct timeval *tv)
6056 *
6057 * This is similar to 4c/4m microtime.   The difference is that
6058 * counter uses 31 bits and ticks every 4 CPU cycles (cpu is @100MHz)
6059 * the magic to divide by 25 is stolen from gcc
6060 */
6061ENTRY(microtime)
6062	sethi	%hi(_C_LABEL(time)), %g2
6063
6064	sethi	%hi(MSIIEP_PCIC_VA), %g3
6065	or	%g3, PCIC_SCCR_REG, %g3
6066
60672:
6068	ldd	[%g2+%lo(_C_LABEL(time))], %o2	! time.tv_sec & time.tv_usec
6069	ld	[%g3], %o4			! system (timer) counter
6070	ldd	[%g2+%lo(_C_LABEL(time))], %g4	! see if time values changed
6071	cmp	%g4, %o2
6072	bne	2b				! if time.tv_sec changed
6073	 cmp	%g5, %o3
6074	bne	2b				! if time.tv_usec changed
6075	 tst	%o4
6076	!! %o2 - time.tv_sec;  %o3 - time.tv_usec;  %o4 - timer counter
6077
6078!!! BEGIN ms-IIep specific code
6079	bpos	3f				! if limit not reached yet
6080	 clr	%g4				!  then use timer as is
6081
6082	sethi	%hi(0x80000000), %g5
6083	sethi	%hi(_C_LABEL(tick)), %g4
6084	andn	%o4, %g5, %o4			! cleat limit reached flag
6085	ld	[%g4+%lo(_C_LABEL(tick))], %g4
6086
6087	!! %g4 - either 0 or tick (if timer has hit the limit)
60883:
6089	inc	-1, %o4				! timer is 1-based, adjust
6090	!! divide by 25 magic stollen from a gcc output
6091	sethi	%hi(1374389535), %g5
6092	or	%g5, %lo(1374389535), %g5
6093	umul	%o4, %g5, %g0
6094	rd	%y, %o4
6095	srl	%o4, 3, %o4
6096	add	%o4, %g4, %o4			! may be bump usec by tick
6097!!! END ms-IIep specific code
6098
6099	add	%o3, %o4, %o3			! add timer to time.tv_usec
6100	set	1000000, %g5			! normalize usec value
6101	cmp	%o3, %g5
6102	bl	4f
6103	 nop
6104	inc	%o2				! overflow into tv_sec
6105	sub	%o3, %g5, %o3
61064:
6107	retl
6108	 std	%o2, [%o0]
6109#endif /* MSIIEP */
6110
6111/*
6112 * delay function
6113 *
6114 * void delay(N)  -- delay N microseconds
6115 *
6116 * Register usage: %o0 = "N" number of usecs to go (counts down to zero)
6117 *		   %o1 = "timerblurb" (stays constant)
6118 *		   %o2 = counter for 1 usec (counts down from %o1 to zero)
6119 *
6120 */
6121
6122ENTRY(delay)			! %o0 = n
6123	subcc	%o0, %g0, %g0
6124	be	2f
6125
6126	sethi	%hi(_C_LABEL(timerblurb)), %o1
6127	ld	[%o1 + %lo(_C_LABEL(timerblurb))], %o1	! %o1 = timerblurb
6128
6129	 addcc	%o1, %g0, %o2		! %o2 = cntr (start @ %o1), clear CCs
6130					! first time through only
6131
6132					! delay 1 usec
61331:	bne	1b			! come back here if not done
6134	 subcc	%o2, 1, %o2		! %o2 = %o2 - 1 [delay slot]
6135
6136	subcc	%o0, 1, %o0		! %o0 = %o0 - 1
6137	bne	1b			! done yet?
6138	 addcc	%o1, %g0, %o2		! reinit %o2 and CCs  [delay slot]
6139					! harmless if not branching
61402:
6141	retl				! return
6142	 nop				! [delay slot]
6143
6144#if defined(KGDB) || defined(DDB) || defined(DIAGNOSTIC)
6145/*
6146 * Write all windows (user or otherwise), except the current one.
6147 *
6148 * THIS COULD BE DONE IN USER CODE
6149 */
6150ENTRY(write_all_windows)
6151	/*
6152	 * g2 = g1 = nwindows - 1;
6153	 * while (--g1 > 0) save();
6154	 * while (--g2 > 0) restore();
6155	 */
6156	sethi	%hi(_C_LABEL(nwindows)), %g1
6157	ld	[%g1 + %lo(_C_LABEL(nwindows))], %g1
6158	dec	%g1
6159	mov	%g1, %g2
6160
61611:	deccc	%g1
6162	bg,a	1b
6163	 save	%sp, -64, %sp
6164
61652:	deccc	%g2
6166	bg,a	2b
6167	 restore
6168
6169	retl
6170	nop
6171#endif /* KGDB */
6172
6173ENTRY(setjmp)
6174	std	%sp, [%o0+0]	! stack pointer & return pc
6175	st	%fp, [%o0+8]	! frame pointer
6176	retl
6177	 clr	%o0
6178
6179Lpanic_ljmp:
6180	.asciz	"longjmp botch"
6181	_ALIGN
6182
6183ENTRY(longjmp)
6184	addcc	%o1, %g0, %g6	! compute v ? v : 1 in a global register
6185	be,a	0f
6186	 mov	1, %g6
61870:
6188	mov	%o0, %g1	! save a in another global register
6189	ld	[%g1+8], %g7	/* get caller's frame */
61901:
6191	cmp	%fp, %g7	! compare against desired frame
6192	bl,a	1b		! if below,
6193	 restore		!    pop frame and loop
6194	be,a	2f		! if there,
6195	 ldd	[%g1+0], %o2	!    fetch return %sp and pc, and get out
6196
6197Llongjmpbotch:
6198				! otherwise, went too far; bomb out
6199	save	%sp, -CCFSZ, %sp	/* preserve current window */
6200	sethi	%hi(Lpanic_ljmp), %o0
6201	call	_C_LABEL(panic)
6202	or %o0, %lo(Lpanic_ljmp), %o0;
6203	unimp	0
6204
62052:
6206	cmp	%o2, %sp	! %sp must not decrease
6207	bge,a	3f
6208	 mov	%o2, %sp	! it is OK, put it in place
6209	b,a	Llongjmpbotch
62103:
6211	jmp	%o3 + 8		! success, return %g6
6212	 mov	%g6, %o0
6213
6214	.data
6215	.globl	_C_LABEL(kernel_top)
6216_C_LABEL(kernel_top):
6217	.word	0
6218	.globl	_C_LABEL(bootinfo)
6219_C_LABEL(bootinfo):
6220	.word	0
6221
6222	.globl	_C_LABEL(proc0paddr)
6223_C_LABEL(proc0paddr):
6224	.word	_C_LABEL(u0)	! KVA of proc0 uarea
6225
6226/* interrupt counters	XXX THESE BELONG ELSEWHERE (if anywhere) */
6227	.globl	_C_LABEL(intrcnt), _C_LABEL(eintrcnt)
6228	.globl	_C_LABEL(intrnames), _C_LABEL(eintrnames)
6229_C_LABEL(intrnames):
6230	.asciz	"spur"
6231	.asciz	"lev1"
6232	.asciz	"lev2"
6233	.asciz	"lev3"
6234	.asciz	"lev4"
6235	.asciz	"lev5"
6236	.asciz	"lev6"
6237	.asciz	"lev7"
6238	.asciz  "lev8"
6239	.asciz	"lev9"
6240	.asciz	"clock"
6241	.asciz	"lev11"
6242	.asciz	"lev12"
6243	.asciz	"lev13"
6244	.asciz	"prof"
6245_C_LABEL(eintrnames):
6246	_ALIGN
6247_C_LABEL(intrcnt):
6248	.skip	4*15
6249_C_LABEL(eintrcnt):
6250
6251	.comm	_C_LABEL(nwindows), 4
6252	.comm	_C_LABEL(romp), 4
6253