1/*	$NetBSD: locore.s,v 1.434 2024/02/17 19:36:07 palle Exp $	*/
2
3/*
4 * Copyright (c) 2006-2010 Matthew R. Green
5 * Copyright (c) 1996-2002 Eduardo Horvath
6 * Copyright (c) 1996 Paul Kranenburg
7 * Copyright (c) 1996
8 * 	The President and Fellows of Harvard College.
9 *	All rights reserved.
10 * Copyright (c) 1992, 1993
11 *	The Regents of the University of California.
12 *	All rights reserved.
13 *
14 * This software was developed by the Computer Systems Engineering group
15 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
16 * contributed to Berkeley.
17 *
18 * All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 *	This product includes software developed by the University of
21 *	California, Lawrence Berkeley Laboratory.
22 *	This product includes software developed by Harvard University.
23 *
24 * Redistribution and use in source and binary forms, with or without
25 * modification, are permitted provided that the following conditions
26 * are met:
27 * 1. Redistributions of source code must retain the above copyright
28 *    notice, this list of conditions and the following disclaimer.
29 * 2. Redistributions in binary form must reproduce the above copyright
30 *    notice, this list of conditions and the following disclaimer in the
31 *    documentation and/or other materials provided with the
32 *    distribution.
33 * 3. All advertising materials mentioning features or use of this
34 *    software must display the following acknowledgement:
35 *	This product includes software developed by the University of
36 *	California, Berkeley and its contributors.
37 *	This product includes software developed by Harvard University.
38 *	This product includes software developed by Paul Kranenburg.
39 * 4. Neither the name of the University nor the names of its
40 *    contributors may be used to endorse or promote products derived
41 *    from this software without specific prior written permission.
42 *
43 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS''
44 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
45 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
46 * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR
47 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
48 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
49 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
50 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
51 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
52 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
53 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
54 * DAMAGE.
55 *
56 *	@(#)locore.s	8.4 (Berkeley) 12/10/93
57 */
58
59#undef	PARANOID		/* Extremely expensive consistency checks */
60#undef	NO_VCACHE		/* Map w/D$ disabled */
61#undef	TRAPSTATS		/* Count traps */
62#undef	TRAPS_USE_IG		/* Use Interrupt Globals for all traps */
63#define	HWREF			/* Track ref/mod bits in trap handlers */
64#undef	DCACHE_BUG		/* Flush D$ around ASI_PHYS accesses */
65#undef	NO_TSB			/* Don't use TSB */
66#define	BB_ERRATA_1		/* writes to TICK_CMPR may fail */
67#undef	TLB_FLUSH_LOWVA		/* also flush 32-bit entries from the MMU */
68
69#include "opt_ddb.h"
70#include "opt_kgdb.h"
71#include "opt_multiprocessor.h"
72#include "opt_compat_netbsd.h"
73#include "opt_compat_netbsd32.h"
74#include "opt_lockdebug.h"
75
76#include "assym.h"
77#include <machine/param.h>
78#include <machine/types.h>
79#include <sparc64/sparc64/intreg.h>
80#include <sparc64/sparc64/timerreg.h>
81#include <machine/ctlreg.h>
82#include <machine/psl.h>
83#include <machine/signal.h>
84#include <machine/trap.h>
85#include <machine/frame.h>
86#include <machine/pmap.h>
87#include <machine/intr.h>
88#include <machine/asm.h>
89#include <machine/locore.h>
90#ifdef SUN4V
91#include <machine/hypervisor.h>
92#endif
93#include <sys/syscall.h>
94
95#define BLOCK_SIZE SPARC64_BLOCK_SIZE
96#define BLOCK_ALIGN SPARC64_BLOCK_ALIGN
97
98#ifdef SUN4V
99#define SUN4V_N_REG_WINDOWS    8  /* As per UA2005 spec */
100#define SUN4V_NWINDOWS           (SUN4V_N_REG_WINDOWS-1) /* This is an index number, so subtract one */
101#endif
102
103#include "ksyms.h"
104
105	/* Misc. macros */
106
107	.macro	GET_MAXCWP reg
108#ifdef SUN4V
109	sethi	%hi(cputyp), \reg
110	ld	[\reg + %lo(cputyp)], \reg
111	cmp	\reg, CPU_SUN4V
112	bne,pt	%icc, 2f
113	 nop
114	/* sun4v */
115	ba	3f
116	 mov	SUN4V_NWINDOWS, \reg
1172:
118#endif
119	/* sun4u */
120	rdpr	%ver, \reg
121	and	\reg, CWP, \reg
1223:
123	.endm
124
125	.macro	SET_MMU_CONTEXTID_SUN4U ctxid,ctx
126	stxa	\ctxid, [\ctx] ASI_DMMU;
127	.endm
128
129#ifdef SUN4V
130	.macro	SET_MMU_CONTEXTID_SUN4V ctxid,ctx
131	stxa	\ctxid, [\ctx] ASI_MMU_CONTEXTID;
132	.endm
133#endif
134
135	.macro	SET_MMU_CONTEXTID ctxid,ctx,scratch
136#ifdef SUN4V
137	sethi	%hi(cputyp), \scratch
138	ld	[\scratch + %lo(cputyp)], \scratch
139	cmp	\scratch, CPU_SUN4V
140	bne,pt	%icc, 2f
141	 nop
142	/* sun4v */
143	SET_MMU_CONTEXTID_SUN4V \ctxid,\ctx
144	ba	3f
145	 nop
1462:
147#endif
148	/* sun4u */
149	SET_MMU_CONTEXTID_SUN4U \ctxid,\ctx
1503:
151	.endm
152
153	.macro	GET_MMU_CONTEXTID_SUN4U ctxid,ctx
154	ldxa	[\ctx] ASI_DMMU, \ctxid
155	.endm
156
157#ifdef SUN4V
158	.macro	GET_MMU_CONTEXTID_SUN4V ctxid,ctx
159	ldxa	[\ctx] ASI_MMU_CONTEXTID, \ctxid
160	.endm
161#endif
162
163	.macro	GET_MMU_CONTEXTID ctxid,ctx,scratch
164#ifdef SUN4V
165	sethi	%hi(cputyp), \scratch
166	ld	[\scratch + %lo(cputyp)], \scratch
167	cmp	\scratch, CPU_SUN4V
168	bne,pt	%icc, 2f
169	 nop
170	/* sun4v */
171	GET_MMU_CONTEXTID_SUN4V \ctxid,\ctx
172	ba	3f
173	 nop
1742:
175#endif
176	/* sun4u */
177	GET_MMU_CONTEXTID_SUN4U \ctxid,\ctx
1783:
179	.endm
180
181#ifdef SUN4V
182	.macro	NORMAL_GLOBALS_SUN4V
183	 wrpr	%g0, 0, %gl				! Set globals to level 0
184	.endm
185#endif
186	.macro	NORMAL_GLOBALS_SUN4U
187	wrpr	%g0, PSTATE_KERN, %pstate		! Alternate Globals (AG) bit set to zero
188	.endm
189
190#ifdef SUN4V
191	.macro	ALTERNATE_GLOBALS_SUN4V
192	 wrpr	%g0, 1, %gl				! Set globals to level 1
193	.endm
194#endif
195	.macro	ALTERNATE_GLOBALS_SUN4U
196	 wrpr    %g0, PSTATE_KERN|PSTATE_AG, %pstate	! Alternate Globals (AG) bit set to one
197	.endm
198
199	.macro	ENABLE_INTERRUPTS scratch
200	rdpr	 %pstate, \scratch
201	or	\scratch, PSTATE_IE, \scratch	! Interrupt Enable (IE) bit set to one
202	wrpr	%g0, \scratch, %pstate
203	.endm
204
205	.macro	DISABLE_INTERRUPTS scratch
206	rdpr	 %pstate, \scratch
207	and	\scratch, ~PSTATE_IE, \scratch	! Interrupt Enable (IE) bit set to zero
208	wrpr	%g0, \scratch, %pstate
209	.endm
210
211
212#ifdef SUN4V
213	/* Misc. sun4v macros */
214
215	.macro	GET_MMFSA reg
216	sethi	%hi(CPUINFO_VA + CI_MMUFSA), \reg
217	LDPTR	[\reg + %lo(CPUINFO_VA + CI_MMUFSA)], \reg
218	.endm
219
220	.macro	GET_CTXBUSY reg
221	sethi	%hi(CPUINFO_VA + CI_CTXBUSY), \reg
222	LDPTR	[\reg + %lo(CPUINFO_VA + CI_CTXBUSY)], \reg
223	.endm
224
225	.macro	GET_TSB_DMMU reg
226	sethi	%hi(CPUINFO_VA + CI_TSB_DMMU), \reg
227	LDPTR	[\reg + %lo(CPUINFO_VA + CI_TSB_DMMU)], \reg
228	.endm
229
230	.macro sun4v_tl1_uspill_normal
231	ba,a,pt	%xcc, spill_normal_to_user_stack
232	 nop
233	.align 128
234	.endm
235
236	.macro sun4v_tl1_uspill_other
237	ba,a,pt	%xcc, pcbspill_other
238	 nop
239	.align 128
240	.endm
241
242#endif
243
244#if 1
245/*
246 * Try to issue an elf note to ask the Solaris
247 * bootloader to align the kernel properly.
248 */
249	.section	.note
250	.word	0x0d
251	.word	4		! Dunno why
252	.word	1
2530:	.asciz	"SUNW Solaris"
2541:
255	.align	4
256	.word	0x0400000
257#endif
258
259	.register	%g2,#scratch
260	.register	%g3,#scratch
261
262
263	.data
264	.globl	_C_LABEL(data_start)
265_C_LABEL(data_start):					! Start of data segment
266
267#ifdef KGDB
268/*
269 * Another item that must be aligned, easiest to put it here.
270 */
271KGDB_STACK_SIZE = 2048
272	.globl	_C_LABEL(kgdb_stack)
273_C_LABEL(kgdb_stack):
274	.space	KGDB_STACK_SIZE		! hope this is enough
275#endif
276
277#ifdef NOTDEF_DEBUG
278/*
279 * This stack is used when we detect kernel stack corruption.
280 */
281	.space	USPACE
282	.align	16
283panicstack:
284#endif
285
286/*
287 * romp is the prom entry pointer
288 * romtba is the prom trap table base address
289 */
290	.globl	romp
291romp:	POINTER	0
292	.globl	romtba
293romtba:	POINTER	0
294
295	.globl	cputyp
296cputyp:	.word	CPU_SUN4U ! Default to sun4u
297
298	_ALIGN
299	.text
300
301/*
302 * The v9 trap frame is stored in the special trap registers.  The
303 * register window is only modified on window overflow, underflow,
304 * and clean window traps, where it points to the register window
305 * needing service.  Traps have space for 8 instructions, except for
306 * the window overflow, underflow, and clean window traps which are
307 * 32 instructions long, large enough to in-line.
308 *
309 * The spitfire CPU (Ultra I) has 4 different sets of global registers.
310 * (blah blah...)
311 *
312 * I used to generate these numbers by address arithmetic, but gas's
313 * expression evaluator has about as much sense as your average slug
314 * (oddly enough, the code looks about as slimy too).  Thus, all the
315 * trap numbers are given as arguments to the trap macros.  This means
316 * there is one line per trap.  Sigh.
317 *
318 * Hardware interrupt vectors can be `linked'---the linkage is to regular
319 * C code---or rewired to fast in-window handlers.  The latter are good
320 * for unbuffered hardware like the Zilog serial chip and the AMD audio
321 * chip, where many interrupts can be handled trivially with pseudo-DMA
322 * or similar.  Only one `fast' interrupt can be used per level, however,
323 * and direct and `fast' interrupts are incompatible.  Routines in intr.c
324 * handle setting these, with optional paranoia.
325 */
326
327/*
328 *	TA8 -- trap align for 8 instruction traps
329 *	TA32 -- trap align for 32 instruction traps
330 */
331#define TA8	.align 32
332#define TA32	.align 128
333
334/*
335 * v9 trap macros:
336 *
337 *	We have a problem with v9 traps; we have no registers to put the
338 *	trap type into.  But we do have a %tt register which already has
339 *	that information.  Trap types in these macros are all dummys.
340 */
341	/* regular vectored traps */
342
343#define	VTRAP(type, label) \
344	ba,a,pt	%icc,label; nop; NOTREACHED; TA8
345
346	/* hardware interrupts (can be linked or made `fast') */
347#define	HARDINT4U(lev) \
348	VTRAP(lev, _C_LABEL(sparc_interrupt))
349#ifdef SUN4V
350#define HARDINT4V(lev) HARDINT4U(lev)
351#endif
352
353	/* software interrupts (may not be made direct, sorry---but you
354	   should not be using them trivially anyway) */
355#define	SOFTINT4U(lev, bit) \
356	HARDINT4U(lev)
357
358	/* traps that just call trap() */
359#define	TRAP(type)	VTRAP(type, slowtrap)
360
361	/* architecturally undefined traps (cause panic) */
362#ifndef DEBUG
363#define	UTRAP(type)	sir; VTRAP(type, slowtrap)
364#else
365#define	UTRAP(type)	VTRAP(type, slowtrap)
366#endif
367
368	/* software undefined traps (may be replaced) */
369#define	STRAP(type)	VTRAP(type, slowtrap)
370
371/* breakpoint acts differently under kgdb */
372#ifdef KGDB
373#define	BPT		VTRAP(T_BREAKPOINT, bpt)
374#define	BPT_KGDB_EXEC	VTRAP(T_KGDB_EXEC, bpt)
375#else
376#define	BPT		TRAP(T_BREAKPOINT)
377#define	BPT_KGDB_EXEC	TRAP(T_KGDB_EXEC)
378#endif
379
380#define	SYSCALL		VTRAP(0x100, syscall_setup)
381#ifdef notyet
382#define	ZS_INTERRUPT	ba,a,pt %icc, zshard; nop; TA8
383#else
384#define	ZS_INTERRUPT4U	HARDINT4U(12)
385#endif
386
387
388/*
389 * Macro to clear %tt so we don't get confused with old traps.
390 */
391#ifdef DEBUG
392#define CLRTT	wrpr	%g0,0x1ff,%tt
393#else
394#define CLRTT
395#endif
396
397
398/*
399 * Some macros to load and store a register window
400 */
401
402	.macro	SPILL storer,base,size,asi
403
404	.irpc n,01234567
405		\storer %l\n, [\base + (\n * \size)] \asi
406	.endr
407	.irpc n,01234567
408		\storer %i\n, [\base + ((8+\n) * \size)] \asi
409	.endr
410
411	.endm
412
413
414	.macro FILL loader, base, size, asi
415
416	.irpc n,01234567
417		\loader [\base + (\n * \size)] \asi, %l\n
418	.endr
419
420	.irpc n,01234567
421		\loader [\base + ((8+\n) * \size)] \asi, %i\n
422	.endr
423
424	.endm
425
426/*
427 * Here are some oft repeated traps as macros.
428 */
429
430	/* spill a 64-bit register window */
431#define SPILL64(label,as) \
432label:	\
433	wr	%g0, as, %asi; \
434	stxa	%l0, [%sp+BIAS+0x00]%asi; \
435	stxa	%l1, [%sp+BIAS+0x08]%asi; \
436	stxa	%l2, [%sp+BIAS+0x10]%asi; \
437	stxa	%l3, [%sp+BIAS+0x18]%asi; \
438	stxa	%l4, [%sp+BIAS+0x20]%asi; \
439	stxa	%l5, [%sp+BIAS+0x28]%asi; \
440	stxa	%l6, [%sp+BIAS+0x30]%asi; \
441	\
442	stxa	%l7, [%sp+BIAS+0x38]%asi; \
443	stxa	%i0, [%sp+BIAS+0x40]%asi; \
444	stxa	%i1, [%sp+BIAS+0x48]%asi; \
445	stxa	%i2, [%sp+BIAS+0x50]%asi; \
446	stxa	%i3, [%sp+BIAS+0x58]%asi; \
447	stxa	%i4, [%sp+BIAS+0x60]%asi; \
448	stxa	%i5, [%sp+BIAS+0x68]%asi; \
449	stxa	%i6, [%sp+BIAS+0x70]%asi; \
450	\
451	stxa	%i7, [%sp+BIAS+0x78]%asi; \
452	saved; \
453	CLRTT; \
454	retry; \
455	NOTREACHED; \
456	TA32
457
458	/* spill a 32-bit register window */
459#define SPILL32(label,as) \
460label:	\
461	wr	%g0, as, %asi; \
462	srl	%sp, 0, %sp; /* fixup 32-bit pointers */ \
463	stwa	%l0, [%sp+0x00]%asi; \
464	stwa	%l1, [%sp+0x04]%asi; \
465	stwa	%l2, [%sp+0x08]%asi; \
466	stwa	%l3, [%sp+0x0c]%asi; \
467	stwa	%l4, [%sp+0x10]%asi; \
468	stwa	%l5, [%sp+0x14]%asi; \
469	\
470	stwa	%l6, [%sp+0x18]%asi; \
471	stwa	%l7, [%sp+0x1c]%asi; \
472	stwa	%i0, [%sp+0x20]%asi; \
473	stwa	%i1, [%sp+0x24]%asi; \
474	stwa	%i2, [%sp+0x28]%asi; \
475	stwa	%i3, [%sp+0x2c]%asi; \
476	stwa	%i4, [%sp+0x30]%asi; \
477	stwa	%i5, [%sp+0x34]%asi; \
478	\
479	stwa	%i6, [%sp+0x38]%asi; \
480	stwa	%i7, [%sp+0x3c]%asi; \
481	saved; \
482	CLRTT; \
483	retry; \
484	NOTREACHED; \
485	TA32
486
487	/* Spill either 32-bit or 64-bit register window. */
488#define SPILLBOTH(label64,label32,as) \
489	andcc	%sp, 1, %g0; \
490	bnz,pt	%xcc, label64+4;	/* Is it a v9 or v8 stack? */ \
491	 wr	%g0, as, %asi; \
492	ba,pt	%xcc, label32+8; \
493	 srl	%sp, 0, %sp; /* fixup 32-bit pointers */ \
494	NOTREACHED; \
495	TA32
496
497	/* fill a 64-bit register window */
498#define FILL64(label,as) \
499label: \
500	wr	%g0, as, %asi; \
501	ldxa	[%sp+BIAS+0x00]%asi, %l0; \
502	ldxa	[%sp+BIAS+0x08]%asi, %l1; \
503	ldxa	[%sp+BIAS+0x10]%asi, %l2; \
504	ldxa	[%sp+BIAS+0x18]%asi, %l3; \
505	ldxa	[%sp+BIAS+0x20]%asi, %l4; \
506	ldxa	[%sp+BIAS+0x28]%asi, %l5; \
507	ldxa	[%sp+BIAS+0x30]%asi, %l6; \
508	\
509	ldxa	[%sp+BIAS+0x38]%asi, %l7; \
510	ldxa	[%sp+BIAS+0x40]%asi, %i0; \
511	ldxa	[%sp+BIAS+0x48]%asi, %i1; \
512	ldxa	[%sp+BIAS+0x50]%asi, %i2; \
513	ldxa	[%sp+BIAS+0x58]%asi, %i3; \
514	ldxa	[%sp+BIAS+0x60]%asi, %i4; \
515	ldxa	[%sp+BIAS+0x68]%asi, %i5; \
516	ldxa	[%sp+BIAS+0x70]%asi, %i6; \
517	\
518	ldxa	[%sp+BIAS+0x78]%asi, %i7; \
519	restored; \
520	CLRTT; \
521	retry; \
522	NOTREACHED; \
523	TA32
524
525	/* fill a 32-bit register window */
526#define FILL32(label,as) \
527label:	\
528	wr	%g0, as, %asi; \
529	srl	%sp, 0, %sp; /* fixup 32-bit pointers */ \
530	lda	[%sp+0x00]%asi, %l0; \
531	lda	[%sp+0x04]%asi, %l1; \
532	lda	[%sp+0x08]%asi, %l2; \
533	lda	[%sp+0x0c]%asi, %l3; \
534	lda	[%sp+0x10]%asi, %l4; \
535	lda	[%sp+0x14]%asi, %l5; \
536	\
537	lda	[%sp+0x18]%asi, %l6; \
538	lda	[%sp+0x1c]%asi, %l7; \
539	lda	[%sp+0x20]%asi, %i0; \
540	lda	[%sp+0x24]%asi, %i1; \
541	lda	[%sp+0x28]%asi, %i2; \
542	lda	[%sp+0x2c]%asi, %i3; \
543	lda	[%sp+0x30]%asi, %i4; \
544	lda	[%sp+0x34]%asi, %i5; \
545	\
546	lda	[%sp+0x38]%asi, %i6; \
547	lda	[%sp+0x3c]%asi, %i7; \
548	restored; \
549	CLRTT; \
550	retry; \
551	NOTREACHED; \
552	TA32
553
554	/* fill either 32-bit or 64-bit register window. */
555#define FILLBOTH(label64,label32,as) \
556	andcc	%sp, 1, %i0; \
557	bnz	(label64)+4; /* See if it's a v9 stack or v8 */ \
558	 wr	%g0, as, %asi; \
559	ba	(label32)+8; \
560	 srl	%sp, 0, %sp; /* fixup 32-bit pointers */ \
561	NOTREACHED; \
562	TA32
563
564	/* handle clean window trap when trap level = 0 */
565	.macro CLEANWIN0
566	rdpr %cleanwin, %o7
567	inc %o7				!	This handler is in-lined and cannot fault
568#ifdef DEBUG
569	set	0xbadcafe, %l0		! DEBUG -- compiler should not rely on zero-ed registers.
570#else
571	clr	%l0
572#endif
573	wrpr %g0, %o7, %cleanwin	!       Nucleus (trap&IRQ) code does not need clean windows
574
575	mov %l0,%l1; mov %l0,%l2	!	Clear out %l0-%l8 and %o0-%o8 and inc %cleanwin and done
576	mov %l0,%l3; mov %l0,%l4
577#if 0
578#ifdef DIAGNOSTIC
579	!!
580	!! Check the sp redzone
581	!!
582	!! Since we can't spill the current window, we'll just keep
583	!! track of the frame pointer.  Problems occur when the routine
584	!! allocates and uses stack storage.
585	!!
586!	rdpr	%wstate, %l5	! User stack?
587!	cmp	%l5, WSTATE_KERN
588!	bne,pt	%icc, 7f
589	 sethi	%hi(CPCB), %l5
590	LDPTR	[%l5 + %lo(CPCB)], %l5	! If pcb < fp < pcb+sizeof(pcb)
591	inc	PCB_SIZE, %l5		! then we have a stack overflow
592	btst	%fp, 1			! 64-bit stack?
593	sub	%fp, %l5, %l7
594	bnz,a,pt	%icc, 1f
595	 inc	BIAS, %l7		! Remove BIAS
5961:
597	cmp	%l7, PCB_SIZE
598	blu	%xcc, cleanwin_overflow
599#endif
600#endif
601	mov %l0, %l5
602	mov %l0, %l6; mov %l0, %l7; mov %l0, %o0; mov %l0, %o1
603
604	mov %l0, %o2; mov %l0, %o3; mov %l0, %o4; mov %l0, %o5;
605	mov %l0, %o6; mov %l0, %o7
606	CLRTT
607	retry; nop; NOTREACHED; TA32
608	.endm
609
610	/* handle clean window trap when trap level = 1 */
611	.macro CLEANWIN1
612	clr	%l0
613#ifdef DEBUG
614	set	0xbadbeef, %l0		! DEBUG
615#endif
616	mov %l0, %l1; mov %l0, %l2
617	rdpr %cleanwin, %o7		!	This handler is in-lined and cannot fault
618	inc %o7; mov %l0, %l3		!       Nucleus (trap&IRQ) code does not need clean windows
619	wrpr %g0, %o7, %cleanwin	!	Clear out %l0-%l8 and %o0-%o8 and inc %cleanwin and done
620#ifdef NOT_DEBUG
621	!!
622	!! Check the sp redzone
623	!!
624	rdpr	%wstate, t1
625	cmp	t1, WSTATE_KERN
626	bne,pt	icc, 7f
627	 sethi	%hi(_C_LABEL(redzone)), t1
628	ldx	[t1 + %lo(_C_LABEL(redzone))], t2
629	cmp	%sp, t2			! if sp >= t2, not in red zone
630	blu	panic_red		! and can continue normally
6317:
632#endif
633	mov %l0, %l4; mov %l0, %l5; mov %l0, %l6; mov %l0, %l7
634	mov %l0, %o0; mov %l0, %o1; mov %l0, %o2; mov %l0, %o3
635
636	mov %l0, %o4; mov %l0, %o5; mov %l0, %o6; mov %l0, %o7
637	CLRTT
638	retry; nop; TA32
639	.endm
640
641	.globl	start, _C_LABEL(kernel_text)
642	_C_LABEL(kernel_text) = kernel_start		! for kvm_mkdb(8)
643kernel_start:
644	/* Traps from TL=0 -- traps from user mode */
645#ifdef __STDC__
646#define TABLE(name)	user_ ## name
647#else
648#define	TABLE(name)	user_/**/name
649#endif
650	.globl	_C_LABEL(trapbase)
651_C_LABEL(trapbase):
652	b dostart; nop; TA8	! 000 = reserved -- Use it to boot
653	/* We should not get the next 5 traps */
654	UTRAP(0x001)		! 001 = POR Reset -- ROM should get this
655	UTRAP(0x002)		! 002 = WDR -- ROM should get this
656	UTRAP(0x003)		! 003 = XIR -- ROM should get this
657	UTRAP(0x004)		! 004 = SIR -- ROM should get this
658	UTRAP(0x005)		! 005 = RED state exception
659	UTRAP(0x006); UTRAP(0x007)
660	VTRAP(T_INST_EXCEPT, textfault)	! 008 = instr. access except
661	VTRAP(T_TEXTFAULT, textfault)	! 009 = instr access MMU miss
662	VTRAP(T_INST_ERROR, textfault)	! 00a = instr. access err
663	UTRAP(0x00b); UTRAP(0x00c); UTRAP(0x00d); UTRAP(0x00e); UTRAP(0x00f)
664	TRAP(T_ILLINST)			! 010 = illegal instruction
665	TRAP(T_PRIVINST)		! 011 = privileged instruction
666	UTRAP(0x012)			! 012 = unimplemented LDD
667	UTRAP(0x013)			! 013 = unimplemented STD
668	UTRAP(0x014); UTRAP(0x015); UTRAP(0x016); UTRAP(0x017); UTRAP(0x018)
669	UTRAP(0x019); UTRAP(0x01a); UTRAP(0x01b); UTRAP(0x01c); UTRAP(0x01d)
670	UTRAP(0x01e); UTRAP(0x01f)
671	TRAP(T_FPDISABLED)		! 020 = fp instr, but EF bit off in psr
672	TRAP(T_FP_IEEE_754)		! 021 = ieee 754 exception
673	TRAP(T_FP_OTHER)		! 022 = other fp exception
674	TRAP(T_TAGOF)			! 023 = tag overflow
675	CLEANWIN0			! 024-027 = clean window trap
676	TRAP(T_DIV0)			! 028 = divide by zero
677	UTRAP(0x029)			! 029 = internal processor error
678	UTRAP(0x02a); UTRAP(0x02b); UTRAP(0x02c); UTRAP(0x02d); UTRAP(0x02e); UTRAP(0x02f)
679	VTRAP(T_DATAFAULT, winfault)	! 030 = data fetch fault
680	UTRAP(0x031)			! 031 = data MMU miss -- no MMU
681	VTRAP(T_DATA_ERROR, winfault)	! 032 = data access error
682	VTRAP(T_DATA_PROT, winfault)	! 033 = data protection fault
683	TRAP(T_ALIGN)			! 034 = address alignment error -- we could fix it inline...
684	TRAP(T_LDDF_ALIGN)		! 035 = LDDF address alignment error -- we could fix it inline...
685	TRAP(T_STDF_ALIGN)		! 036 = STDF address alignment error -- we could fix it inline...
686	TRAP(T_PRIVACT)			! 037 = privileged action
687	UTRAP(0x038); UTRAP(0x039); UTRAP(0x03a); UTRAP(0x03b); UTRAP(0x03c);
688	UTRAP(0x03d); UTRAP(0x03e); UTRAP(0x03f);
689	VTRAP(T_ASYNC_ERROR, winfault)	! 040 = data fetch fault
690	SOFTINT4U(1, IE_L1)		! 041 = level 1 interrupt
691	HARDINT4U(2)			! 042 = level 2 interrupt
692	HARDINT4U(3)			! 043 = level 3 interrupt
693	SOFTINT4U(4, IE_L4)		! 044 = level 4 interrupt
694	HARDINT4U(5)			! 045 = level 5 interrupt
695	SOFTINT4U(6, IE_L6)		! 046 = level 6 interrupt
696	HARDINT4U(7)			! 047 = level 7 interrupt
697	HARDINT4U(8)			! 048 = level 8 interrupt
698	HARDINT4U(9)			! 049 = level 9 interrupt
699	HARDINT4U(10)			! 04a = level 10 interrupt
700	HARDINT4U(11)			! 04b = level 11 interrupt
701	ZS_INTERRUPT4U			! 04c = level 12 (zs) interrupt
702	HARDINT4U(13)			! 04d = level 13 interrupt
703	HARDINT4U(14)			! 04e = level 14 interrupt
704	HARDINT4U(15)			! 04f = nonmaskable interrupt
705	UTRAP(0x050); UTRAP(0x051); UTRAP(0x052); UTRAP(0x053); UTRAP(0x054); UTRAP(0x055)
706	UTRAP(0x056); UTRAP(0x057); UTRAP(0x058); UTRAP(0x059); UTRAP(0x05a); UTRAP(0x05b)
707	UTRAP(0x05c); UTRAP(0x05d); UTRAP(0x05e); UTRAP(0x05f)
708	VTRAP(0x060, interrupt_vector); ! 060 = interrupt vector
709	TRAP(T_PA_WATCHPT)		! 061 = physical address data watchpoint
710	TRAP(T_VA_WATCHPT)		! 062 = virtual address data watchpoint
711	TRAP(T_ECCERR)			! 063 = corrected ECC error
712ufast_IMMU_miss:			! 064 = fast instr access MMU miss
713	ldxa	[%g0] ASI_IMMU_8KPTR, %g2 ! Load IMMU 8K TSB pointer
714#ifdef NO_TSB
715	ba,a	%icc, instr_miss
716#endif
717	ldxa	[%g0] ASI_IMMU, %g1	! Load IMMU tag target register
718	ldda	[%g2] ASI_NUCLEUS_QUAD_LDD, %g4	! Load TSB tag:data into %g4:%g5
719	brgez,pn %g5, instr_miss	! Entry invalid?  Punt
720	 cmp	%g1, %g4		! Compare TLB tags
721	bne,pn %xcc, instr_miss		! Got right tag?
722	 nop
723	CLRTT
724	stxa	%g5, [%g0] ASI_IMMU_DATA_IN ! Enter new mapping
725	retry				! Try new mapping
7261:
727	sir
728	TA32
729ufast_DMMU_miss:			! 068 = fast data access MMU miss
730	ldxa	[%g0] ASI_DMMU_8KPTR, %g2! Load DMMU 8K TSB pointer
731#ifdef NO_TSB
732	ba,a	%icc, data_miss
733#endif
734	ldxa	[%g0] ASI_DMMU, %g1	! Load DMMU tag target register
735	ldda	[%g2] ASI_NUCLEUS_QUAD_LDD, %g4	! Load TSB tag and data into %g4 and %g5
736	brgez,pn %g5, data_miss		! Entry invalid?  Punt
737	 cmp	%g1, %g4		! Compare TLB tags
738	bnz,pn	%xcc, data_miss		! Got right tag?
739	 nop
740	CLRTT
741#ifdef TRAPSTATS
742	sethi	%hi(_C_LABEL(udhit)), %g1
743	lduw	[%g1+%lo(_C_LABEL(udhit))], %g2
744	inc	%g2
745	stw	%g2, [%g1+%lo(_C_LABEL(udhit))]
746#endif
747	stxa	%g5, [%g0] ASI_DMMU_DATA_IN ! Enter new mapping
748	retry				! Try new mapping
7491:
750	sir
751	TA32
752ufast_DMMU_protection:			! 06c = fast data access MMU protection
753#ifdef TRAPSTATS
754	sethi	%hi(_C_LABEL(udprot)), %g1
755	lduw	[%g1+%lo(_C_LABEL(udprot))], %g2
756	inc	%g2
757	stw	%g2, [%g1+%lo(_C_LABEL(udprot))]
758#endif
759#ifdef HWREF
760	ba,a,pt	%xcc, dmmu_write_fault
761#else
762	ba,a,pt	%xcc, winfault
763#endif
764	nop
765	TA32
766	TRAP(0x070)			! 0x070 fast_ECC_error
767					! Implementation dependent traps
768	UTRAP(0x071); UTRAP(0x072); UTRAP(0x073); UTRAP(0x074); UTRAP(0x075); UTRAP(0x076)
769	UTRAP(0x077); UTRAP(0x078); UTRAP(0x079); UTRAP(0x07a); UTRAP(0x07b); UTRAP(0x07c)
770	UTRAP(0x07d); UTRAP(0x07e); UTRAP(0x07f)
771TABLE(uspill):
772	SPILL64(uspill8,ASI_AIUS)	! 0x080 spill_0_normal -- used to save user windows in user mode
773	SPILL32(uspill4,ASI_AIUS)	! 0x084 spill_1_normal
774	SPILLBOTH(uspill8,uspill4,ASI_AIUS)	 ! 0x088 spill_2_normal
775	UTRAP(0x08c); TA32		! 0x08c spill_3_normal
776TABLE(kspill):
777	SPILL64(kspill8,ASI_N)		! 0x090 spill_4_normal -- used to save supervisor windows
778	SPILL32(kspill4,ASI_N)		! 0x094 spill_5_normal
779	SPILLBOTH(kspill8,kspill4,ASI_N) ! 0x098 spill_6_normal
780	UTRAP(0x09c); TA32		! 0x09c spill_7_normal
781TABLE(uspillk):
782	SPILL64(uspillk8,ASI_AIUS)	! 0x0a0 spill_0_other -- used to save user windows in supervisor mode
783	SPILL32(uspillk4,ASI_AIUS)	! 0x0a4 spill_1_other
784	SPILLBOTH(uspillk8,uspillk4,ASI_AIUS) ! 0x0a8 spill_2_other
785	UTRAP(0x0ac); TA32		! 0x0ac spill_3_other
786	UTRAP(0x0b0); TA32		! 0x0b0 spill_4_other
787	UTRAP(0x0b4); TA32		! 0x0b4 spill_5_other
788	UTRAP(0x0b8); TA32		! 0x0b8 spill_6_other
789	UTRAP(0x0bc); TA32		! 0x0bc spill_7_other
790TABLE(ufill):
791	FILL64(ufill8,ASI_AIUS)		! 0x0c0 fill_0_normal -- used to fill windows when running user mode
792	FILL32(ufill4,ASI_AIUS)		! 0x0c4 fill_1_normal
793	FILLBOTH(ufill8,ufill4,ASI_AIUS) ! 0x0c8 fill_2_normal
794	UTRAP(0x0cc); TA32		! 0x0cc fill_3_normal
795TABLE(kfill):
796	FILL64(kfill8,ASI_N)		! 0x0d0 fill_4_normal -- used to fill windows when running supervisor mode
797	FILL32(kfill4,ASI_N)		! 0x0d4 fill_5_normal
798	FILLBOTH(kfill8,kfill4,ASI_N)	! 0x0d8 fill_6_normal
799	UTRAP(0x0dc); TA32		! 0x0dc fill_7_normal
800TABLE(ufillk):
801	FILL64(ufillk8,ASI_AIUS)	! 0x0e0 fill_0_other
802	FILL32(ufillk4,ASI_AIUS)	! 0x0e4 fill_1_other
803	FILLBOTH(ufillk8,ufillk4,ASI_AIUS) ! 0x0e8 fill_2_other
804	UTRAP(0x0ec); TA32		! 0x0ec fill_3_other
805	UTRAP(0x0f0); TA32		! 0x0f0 fill_4_other
806	UTRAP(0x0f4); TA32		! 0x0f4 fill_5_other
807	UTRAP(0x0f8); TA32		! 0x0f8 fill_6_other
808	UTRAP(0x0fc); TA32		! 0x0fc fill_7_other
809TABLE(syscall):
810	SYSCALL				! 0x100 = sun syscall
811	BPT				! 0x101 = pseudo breakpoint instruction
812	STRAP(0x102); STRAP(0x103); STRAP(0x104); STRAP(0x105); STRAP(0x106); STRAP(0x107)
813	SYSCALL				! 0x108 = svr4 syscall
814	SYSCALL				! 0x109 = bsd syscall
815	BPT_KGDB_EXEC			! 0x10a = enter kernel gdb on kernel startup
816	STRAP(0x10b); STRAP(0x10c); STRAP(0x10d); STRAP(0x10e); STRAP(0x10f);
817	STRAP(0x110); STRAP(0x111); STRAP(0x112); STRAP(0x113); STRAP(0x114); STRAP(0x115); STRAP(0x116); STRAP(0x117)
818	STRAP(0x118); STRAP(0x119); STRAP(0x11a); STRAP(0x11b); STRAP(0x11c); STRAP(0x11d); STRAP(0x11e); STRAP(0x11f)
819	STRAP(0x120); STRAP(0x121); STRAP(0x122); STRAP(0x123); STRAP(0x124); STRAP(0x125); STRAP(0x126); STRAP(0x127)
820	STRAP(0x128); STRAP(0x129); STRAP(0x12a); STRAP(0x12b); STRAP(0x12c); STRAP(0x12d); STRAP(0x12e); STRAP(0x12f)
821	STRAP(0x130); STRAP(0x131); STRAP(0x132); STRAP(0x133); STRAP(0x134); STRAP(0x135); STRAP(0x136); STRAP(0x137)
822	STRAP(0x138); STRAP(0x139); STRAP(0x13a); STRAP(0x13b); STRAP(0x13c); STRAP(0x13d); STRAP(0x13e); STRAP(0x13f)
823	SYSCALL				! 0x140 SVID syscall (Solaris 2.7)
824	SYSCALL				! 0x141 SPARC International syscall
825	SYSCALL				! 0x142	OS Vendor syscall
826	SYSCALL				! 0x143 HW OEM syscall
827	STRAP(0x144); STRAP(0x145); STRAP(0x146); STRAP(0x147)
828	STRAP(0x148); STRAP(0x149); STRAP(0x14a); STRAP(0x14b); STRAP(0x14c); STRAP(0x14d); STRAP(0x14e); STRAP(0x14f)
829	STRAP(0x150); STRAP(0x151); STRAP(0x152); STRAP(0x153); STRAP(0x154); STRAP(0x155); STRAP(0x156); STRAP(0x157)
830	STRAP(0x158); STRAP(0x159); STRAP(0x15a); STRAP(0x15b); STRAP(0x15c); STRAP(0x15d); STRAP(0x15e); STRAP(0x15f)
831	STRAP(0x160); STRAP(0x161); STRAP(0x162); STRAP(0x163); STRAP(0x164); STRAP(0x165); STRAP(0x166); STRAP(0x167)
832	STRAP(0x168); STRAP(0x169); STRAP(0x16a); STRAP(0x16b); STRAP(0x16c); STRAP(0x16d); STRAP(0x16e); STRAP(0x16f)
833	STRAP(0x170); STRAP(0x171); STRAP(0x172); STRAP(0x173); STRAP(0x174); STRAP(0x175); STRAP(0x176); STRAP(0x177)
834	STRAP(0x178); STRAP(0x179); STRAP(0x17a); STRAP(0x17b); STRAP(0x17c); STRAP(0x17d); STRAP(0x17e); STRAP(0x17f)
835	! Traps beyond 0x17f are reserved
836	UTRAP(0x180); UTRAP(0x181); UTRAP(0x182); UTRAP(0x183); UTRAP(0x184); UTRAP(0x185); UTRAP(0x186); UTRAP(0x187)
837	UTRAP(0x188); UTRAP(0x189); UTRAP(0x18a); UTRAP(0x18b); UTRAP(0x18c); UTRAP(0x18d); UTRAP(0x18e); UTRAP(0x18f)
838	UTRAP(0x190); UTRAP(0x191); UTRAP(0x192); UTRAP(0x193); UTRAP(0x194); UTRAP(0x195); UTRAP(0x196); UTRAP(0x197)
839	UTRAP(0x198); UTRAP(0x199); UTRAP(0x19a); UTRAP(0x19b); UTRAP(0x19c); UTRAP(0x19d); UTRAP(0x19e); UTRAP(0x19f)
840	UTRAP(0x1a0); UTRAP(0x1a1); UTRAP(0x1a2); UTRAP(0x1a3); UTRAP(0x1a4); UTRAP(0x1a5); UTRAP(0x1a6); UTRAP(0x1a7)
841	UTRAP(0x1a8); UTRAP(0x1a9); UTRAP(0x1aa); UTRAP(0x1ab); UTRAP(0x1ac); UTRAP(0x1ad); UTRAP(0x1ae); UTRAP(0x1af)
842	UTRAP(0x1b0); UTRAP(0x1b1); UTRAP(0x1b2); UTRAP(0x1b3); UTRAP(0x1b4); UTRAP(0x1b5); UTRAP(0x1b6); UTRAP(0x1b7)
843	UTRAP(0x1b8); UTRAP(0x1b9); UTRAP(0x1ba); UTRAP(0x1bb); UTRAP(0x1bc); UTRAP(0x1bd); UTRAP(0x1be); UTRAP(0x1bf)
844	UTRAP(0x1c0); UTRAP(0x1c1); UTRAP(0x1c2); UTRAP(0x1c3); UTRAP(0x1c4); UTRAP(0x1c5); UTRAP(0x1c6); UTRAP(0x1c7)
845	UTRAP(0x1c8); UTRAP(0x1c9); UTRAP(0x1ca); UTRAP(0x1cb); UTRAP(0x1cc); UTRAP(0x1cd); UTRAP(0x1ce); UTRAP(0x1cf)
846	UTRAP(0x1d0); UTRAP(0x1d1); UTRAP(0x1d2); UTRAP(0x1d3); UTRAP(0x1d4); UTRAP(0x1d5); UTRAP(0x1d6); UTRAP(0x1d7)
847	UTRAP(0x1d8); UTRAP(0x1d9); UTRAP(0x1da); UTRAP(0x1db); UTRAP(0x1dc); UTRAP(0x1dd); UTRAP(0x1de); UTRAP(0x1df)
848	UTRAP(0x1e0); UTRAP(0x1e1); UTRAP(0x1e2); UTRAP(0x1e3); UTRAP(0x1e4); UTRAP(0x1e5); UTRAP(0x1e6); UTRAP(0x1e7)
849	UTRAP(0x1e8); UTRAP(0x1e9); UTRAP(0x1ea); UTRAP(0x1eb); UTRAP(0x1ec); UTRAP(0x1ed); UTRAP(0x1ee); UTRAP(0x1ef)
850	UTRAP(0x1f0); UTRAP(0x1f1); UTRAP(0x1f2); UTRAP(0x1f3); UTRAP(0x1f4); UTRAP(0x1f5); UTRAP(0x1f6); UTRAP(0x1f7)
851	UTRAP(0x1f8); UTRAP(0x1f9); UTRAP(0x1fa); UTRAP(0x1fb); UTRAP(0x1fc); UTRAP(0x1fd); UTRAP(0x1fe); UTRAP(0x1ff)
852
853	/* Traps from TL>0 -- traps from supervisor mode */
854#undef TABLE
855#ifdef __STDC__
856#define	TABLE(name)	nucleus_ ## name
857#else
858#define	TABLE(name)	nucleus_/**/name
859#endif
860trapbase_priv:
861	UTRAP(0x000)			! 000 = reserved -- Use it to boot
862	/* We should not get the next 5 traps */
863	UTRAP(0x001)			! 001 = POR Reset -- ROM should get this
864	UTRAP(0x002)			! 002 = WDR Watchdog -- ROM should get this
865	UTRAP(0x003)			! 003 = XIR -- ROM should get this
866	UTRAP(0x004)			! 004 = SIR -- ROM should get this
867	UTRAP(0x005)			! 005 = RED state exception
868	UTRAP(0x006); UTRAP(0x007)
869ktextfault:
870	VTRAP(T_INST_EXCEPT, textfault)	! 008 = instr. access except
871	VTRAP(T_TEXTFAULT, textfault)	! 009 = instr access MMU miss -- no MMU
872	VTRAP(T_INST_ERROR, textfault)	! 00a = instr. access err
873	UTRAP(0x00b); UTRAP(0x00c); UTRAP(0x00d); UTRAP(0x00e); UTRAP(0x00f)
874	TRAP(T_ILLINST)			! 010 = illegal instruction
875	TRAP(T_PRIVINST)		! 011 = privileged instruction
876	UTRAP(0x012)			! 012 = unimplemented LDD
877	UTRAP(0x013)			! 013 = unimplemented STD
878	UTRAP(0x014); UTRAP(0x015); UTRAP(0x016); UTRAP(0x017); UTRAP(0x018)
879	UTRAP(0x019); UTRAP(0x01a); UTRAP(0x01b); UTRAP(0x01c); UTRAP(0x01d)
880	UTRAP(0x01e); UTRAP(0x01f)
881	TRAP(T_FPDISABLED)		! 020 = fp instr, but EF bit off in psr
882	TRAP(T_FP_IEEE_754)		! 021 = ieee 754 exception
883	TRAP(T_FP_OTHER)		! 022 = other fp exception
884	TRAP(T_TAGOF)			! 023 = tag overflow
885	CLEANWIN1			! 024-027 = clean window trap
886	TRAP(T_DIV0)			! 028 = divide by zero
887	UTRAP(0x029)			! 029 = internal processor error
888	UTRAP(0x02a); UTRAP(0x02b); UTRAP(0x02c); UTRAP(0x02d); UTRAP(0x02e); UTRAP(0x02f)
889kdatafault:
890	VTRAP(T_DATAFAULT, winfault)	! 030 = data fetch fault
891	UTRAP(0x031)			! 031 = data MMU miss -- no MMU
892	VTRAP(T_DATA_ERROR, winfault)	! 032 = data fetch fault
893	VTRAP(T_DATA_PROT, winfault)	! 033 = data fetch fault
894	VTRAP(T_ALIGN, checkalign)	! 034 = address alignment error -- we could fix it inline...
895	TRAP(T_LDDF_ALIGN)		! 035 = LDDF address alignment error -- we could fix it inline...
896	TRAP(T_STDF_ALIGN)		! 036 = STDF address alignment error -- we could fix it inline...
897	TRAP(T_PRIVACT)			! 037 = privileged action
898	UTRAP(0x038); UTRAP(0x039); UTRAP(0x03a); UTRAP(0x03b); UTRAP(0x03c);
899	UTRAP(0x03d); UTRAP(0x03e); UTRAP(0x03f);
900	VTRAP(T_ASYNC_ERROR, winfault)	! 040 = data fetch fault
901	SOFTINT4U(1, IE_L1)		! 041 = level 1 interrupt
902	HARDINT4U(2)			! 042 = level 2 interrupt
903	HARDINT4U(3)			! 043 = level 3 interrupt
904	SOFTINT4U(4, IE_L4)		! 044 = level 4 interrupt
905	HARDINT4U(5)			! 045 = level 5 interrupt
906	SOFTINT4U(6, IE_L6)		! 046 = level 6 interrupt
907	HARDINT4U(7)			! 047 = level 7 interrupt
908	HARDINT4U(8)			! 048 = level 8 interrupt
909	HARDINT4U(9)			! 049 = level 9 interrupt
910	HARDINT4U(10)			! 04a = level 10 interrupt
911	HARDINT4U(11)			! 04b = level 11 interrupt
912	ZS_INTERRUPT4U			! 04c = level 12 (zs) interrupt
913	HARDINT4U(13)			! 04d = level 13 interrupt
914	HARDINT4U(14)			! 04e = level 14 interrupt
915	HARDINT4U(15)			! 04f = nonmaskable interrupt
916	UTRAP(0x050); UTRAP(0x051); UTRAP(0x052); UTRAP(0x053); UTRAP(0x054); UTRAP(0x055)
917	UTRAP(0x056); UTRAP(0x057); UTRAP(0x058); UTRAP(0x059); UTRAP(0x05a); UTRAP(0x05b)
918	UTRAP(0x05c); UTRAP(0x05d); UTRAP(0x05e); UTRAP(0x05f)
919	VTRAP(0x060, interrupt_vector); ! 060 = interrupt vector
920	TRAP(T_PA_WATCHPT)		! 061 = physical address data watchpoint
921	TRAP(T_VA_WATCHPT)		! 062 = virtual address data watchpoint
922	TRAP(T_ECCERR)			! 063 = corrected ECC error
923kfast_IMMU_miss:			! 064 = fast instr access MMU miss
924	ldxa	[%g0] ASI_IMMU_8KPTR, %g2 ! Load IMMU 8K TSB pointer
925#ifdef NO_TSB
926	ba,a	%icc, instr_miss
927#endif
928	ldxa	[%g0] ASI_IMMU, %g1	! Load IMMU tag target register
929	ldda	[%g2] ASI_NUCLEUS_QUAD_LDD, %g4	! Load TSB tag:data into %g4:%g5
930	brgez,pn %g5, instr_miss	! Entry invalid?  Punt
931	 cmp	%g1, %g4		! Compare TLB tags
932	bne,pn %xcc, instr_miss		! Got right tag?
933	 nop
934	CLRTT
935	stxa	%g5, [%g0] ASI_IMMU_DATA_IN ! Enter new mapping
936	retry				! Try new mapping
9371:
938	sir
939	TA32
940kfast_DMMU_miss:			! 068 = fast data access MMU miss
941	ldxa	[%g0] ASI_DMMU_8KPTR, %g2! Load DMMU 8K TSB pointer
942#ifdef NO_TSB
943	ba,a	%icc, data_miss
944#endif
945	ldxa	[%g0] ASI_DMMU, %g1	! Load DMMU tag target register
946	ldda	[%g2] ASI_NUCLEUS_QUAD_LDD, %g4	! Load TSB tag and data into %g4 and %g5
947	brgez,pn %g5, data_miss		! Entry invalid?  Punt
948	 cmp	%g1, %g4		! Compare TLB tags
949	bnz,pn	%xcc, data_miss		! Got right tag?
950	 nop
951	CLRTT
952#ifdef TRAPSTATS
953	sethi	%hi(_C_LABEL(kdhit)), %g1
954	lduw	[%g1+%lo(_C_LABEL(kdhit))], %g2
955	inc	%g2
956	stw	%g2, [%g1+%lo(_C_LABEL(kdhit))]
957#endif
958	stxa	%g5, [%g0] ASI_DMMU_DATA_IN ! Enter new mapping
959	retry				! Try new mapping
9601:
961	sir
962	TA32
963kfast_DMMU_protection:			! 06c = fast data access MMU protection
964#ifdef TRAPSTATS
965	sethi	%hi(_C_LABEL(kdprot)), %g1
966	lduw	[%g1+%lo(_C_LABEL(kdprot))], %g2
967	inc	%g2
968	stw	%g2, [%g1+%lo(_C_LABEL(kdprot))]
969#endif
970#ifdef HWREF
971	ba,a,pt	%xcc, dmmu_write_fault
972#else
973	ba,a,pt	%xcc, winfault
974#endif
975	nop
976	TA32
977	TRAP(0x070)			! 0x070 fast_ECC_error
978					! Implementation dependent traps
979	UTRAP(0x071); UTRAP(0x072); UTRAP(0x073); UTRAP(0x074); UTRAP(0x075); UTRAP(0x076)
980	UTRAP(0x077); UTRAP(0x078); UTRAP(0x079); UTRAP(0x07a); UTRAP(0x07b); UTRAP(0x07c)
981	UTRAP(0x07d); UTRAP(0x07e); UTRAP(0x07f)
982TABLE(uspill):
983	SPILL64(1,ASI_AIUS)		! 0x080 spill_0_normal -- used to save user windows
984	SPILL32(2,ASI_AIUS)		! 0x084 spill_1_normal
985	SPILLBOTH(1b,2b,ASI_AIUS)	! 0x088 spill_2_normal
986	UTRAP(0x08c); TA32		! 0x08c spill_3_normal
987TABLE(kspill):
988	SPILL64(1,ASI_N)		! 0x090 spill_4_normal -- used to save supervisor windows
989	SPILL32(2,ASI_N)		! 0x094 spill_5_normal
990	SPILLBOTH(1b,2b,ASI_N)		! 0x098 spill_6_normal
991	UTRAP(0x09c); TA32		! 0x09c spill_7_normal
992TABLE(uspillk):
993	SPILL64(1,ASI_AIUS)		! 0x0a0 spill_0_other -- used to save user windows in nucleus mode
994	SPILL32(2,ASI_AIUS)		! 0x0a4 spill_1_other
995	SPILLBOTH(1b,2b,ASI_AIUS)	! 0x0a8 spill_2_other
996	UTRAP(0x0ac); TA32		! 0x0ac spill_3_other
997	UTRAP(0x0b0); TA32		! 0x0b0 spill_4_other
998	UTRAP(0x0b4); TA32		! 0x0b4 spill_5_other
999	UTRAP(0x0b8); TA32		! 0x0b8 spill_6_other
1000	UTRAP(0x0bc); TA32		! 0x0bc spill_7_other
1001TABLE(ufill):
1002	FILL64(nufill8,ASI_AIUS)	! 0x0c0 fill_0_normal -- used to fill windows when running nucleus mode from user
1003	FILL32(nufill4,ASI_AIUS)	! 0x0c4 fill_1_normal
1004	FILLBOTH(nufill8,nufill4,ASI_AIUS) ! 0x0c8 fill_2_normal
1005	UTRAP(0x0cc); TA32		! 0x0cc fill_3_normal
1006TABLE(sfill):
1007	FILL64(sfill8,ASI_N)		! 0x0d0 fill_4_normal -- used to fill windows when running nucleus mode from supervisor
1008	FILL32(sfill4,ASI_N)		! 0x0d4 fill_5_normal
1009	FILLBOTH(sfill8,sfill4,ASI_N)	! 0x0d8 fill_6_normal
1010	UTRAP(0x0dc); TA32		! 0x0dc fill_7_normal
1011TABLE(kfill):
1012	FILL64(nkfill8,ASI_AIUS)	! 0x0e0 fill_0_other -- used to fill user windows when running nucleus mode -- will we ever use this?
1013	FILL32(nkfill4,ASI_AIUS)	! 0x0e4 fill_1_other
1014	FILLBOTH(nkfill8,nkfill4,ASI_AIUS)! 0x0e8 fill_2_other
1015	UTRAP(0x0ec); TA32		! 0x0ec fill_3_other
1016	UTRAP(0x0f0); TA32		! 0x0f0 fill_4_other
1017	UTRAP(0x0f4); TA32		! 0x0f4 fill_5_other
1018	UTRAP(0x0f8); TA32		! 0x0f8 fill_6_other
1019	UTRAP(0x0fc); TA32		! 0x0fc fill_7_other
1020TABLE(syscall):
1021	SYSCALL				! 0x100 = sun syscall
1022	BPT				! 0x101 = pseudo breakpoint instruction
1023	STRAP(0x102); STRAP(0x103); STRAP(0x104); STRAP(0x105); STRAP(0x106); STRAP(0x107)
1024	SYSCALL				! 0x108 = svr4 syscall
1025	SYSCALL				! 0x109 = bsd syscall
1026	BPT_KGDB_EXEC			! 0x10a = enter kernel gdb on kernel startup
1027	STRAP(0x10b); STRAP(0x10c); STRAP(0x10d); STRAP(0x10e); STRAP(0x10f);
1028	STRAP(0x110); STRAP(0x111); STRAP(0x112); STRAP(0x113); STRAP(0x114); STRAP(0x115); STRAP(0x116); STRAP(0x117)
1029	STRAP(0x118); STRAP(0x119); STRAP(0x11a); STRAP(0x11b); STRAP(0x11c); STRAP(0x11d); STRAP(0x11e); STRAP(0x11f)
1030	STRAP(0x120); STRAP(0x121); STRAP(0x122); STRAP(0x123); STRAP(0x124); STRAP(0x125); STRAP(0x126); STRAP(0x127)
1031	STRAP(0x128); STRAP(0x129); STRAP(0x12a); STRAP(0x12b); STRAP(0x12c); STRAP(0x12d); STRAP(0x12e); STRAP(0x12f)
1032	STRAP(0x130); STRAP(0x131); STRAP(0x132); STRAP(0x133); STRAP(0x134); STRAP(0x135); STRAP(0x136); STRAP(0x137)
1033	STRAP(0x138); STRAP(0x139); STRAP(0x13a); STRAP(0x13b); STRAP(0x13c); STRAP(0x13d); STRAP(0x13e); STRAP(0x13f)
1034	STRAP(0x140); STRAP(0x141); STRAP(0x142); STRAP(0x143); STRAP(0x144); STRAP(0x145); STRAP(0x146); STRAP(0x147)
1035	STRAP(0x148); STRAP(0x149); STRAP(0x14a); STRAP(0x14b); STRAP(0x14c); STRAP(0x14d); STRAP(0x14e); STRAP(0x14f)
1036	STRAP(0x150); STRAP(0x151); STRAP(0x152); STRAP(0x153); STRAP(0x154); STRAP(0x155); STRAP(0x156); STRAP(0x157)
1037	STRAP(0x158); STRAP(0x159); STRAP(0x15a); STRAP(0x15b); STRAP(0x15c); STRAP(0x15d); STRAP(0x15e); STRAP(0x15f)
1038	STRAP(0x160); STRAP(0x161); STRAP(0x162); STRAP(0x163); STRAP(0x164); STRAP(0x165); STRAP(0x166); STRAP(0x167)
1039	STRAP(0x168); STRAP(0x169); STRAP(0x16a); STRAP(0x16b); STRAP(0x16c); STRAP(0x16d); STRAP(0x16e); STRAP(0x16f)
1040	STRAP(0x170); STRAP(0x171); STRAP(0x172); STRAP(0x173); STRAP(0x174); STRAP(0x175); STRAP(0x176); STRAP(0x177)
1041	STRAP(0x178); STRAP(0x179); STRAP(0x17a); STRAP(0x17b); STRAP(0x17c); STRAP(0x17d); STRAP(0x17e); STRAP(0x17f)
1042	! Traps beyond 0x17f are reserved
1043	UTRAP(0x180); UTRAP(0x181); UTRAP(0x182); UTRAP(0x183); UTRAP(0x184); UTRAP(0x185); UTRAP(0x186); UTRAP(0x187)
1044	UTRAP(0x188); UTRAP(0x189); UTRAP(0x18a); UTRAP(0x18b); UTRAP(0x18c); UTRAP(0x18d); UTRAP(0x18e); UTRAP(0x18f)
1045	UTRAP(0x190); UTRAP(0x191); UTRAP(0x192); UTRAP(0x193); UTRAP(0x194); UTRAP(0x195); UTRAP(0x196); UTRAP(0x197)
1046	UTRAP(0x198); UTRAP(0x199); UTRAP(0x19a); UTRAP(0x19b); UTRAP(0x19c); UTRAP(0x19d); UTRAP(0x19e); UTRAP(0x19f)
1047	UTRAP(0x1a0); UTRAP(0x1a1); UTRAP(0x1a2); UTRAP(0x1a3); UTRAP(0x1a4); UTRAP(0x1a5); UTRAP(0x1a6); UTRAP(0x1a7)
1048	UTRAP(0x1a8); UTRAP(0x1a9); UTRAP(0x1aa); UTRAP(0x1ab); UTRAP(0x1ac); UTRAP(0x1ad); UTRAP(0x1ae); UTRAP(0x1af)
1049	UTRAP(0x1b0); UTRAP(0x1b1); UTRAP(0x1b2); UTRAP(0x1b3); UTRAP(0x1b4); UTRAP(0x1b5); UTRAP(0x1b6); UTRAP(0x1b7)
1050	UTRAP(0x1b8); UTRAP(0x1b9); UTRAP(0x1ba); UTRAP(0x1bb); UTRAP(0x1bc); UTRAP(0x1bd); UTRAP(0x1be); UTRAP(0x1bf)
1051	UTRAP(0x1c0); UTRAP(0x1c1); UTRAP(0x1c2); UTRAP(0x1c3); UTRAP(0x1c4); UTRAP(0x1c5); UTRAP(0x1c6); UTRAP(0x1c7)
1052	UTRAP(0x1c8); UTRAP(0x1c9); UTRAP(0x1ca); UTRAP(0x1cb); UTRAP(0x1cc); UTRAP(0x1cd); UTRAP(0x1ce); UTRAP(0x1cf)
1053	UTRAP(0x1d0); UTRAP(0x1d1); UTRAP(0x1d2); UTRAP(0x1d3); UTRAP(0x1d4); UTRAP(0x1d5); UTRAP(0x1d6); UTRAP(0x1d7)
1054	UTRAP(0x1d8); UTRAP(0x1d9); UTRAP(0x1da); UTRAP(0x1db); UTRAP(0x1dc); UTRAP(0x1dd); UTRAP(0x1de); UTRAP(0x1df)
1055	UTRAP(0x1e0); UTRAP(0x1e1); UTRAP(0x1e2); UTRAP(0x1e3); UTRAP(0x1e4); UTRAP(0x1e5); UTRAP(0x1e6); UTRAP(0x1e7)
1056	UTRAP(0x1e8); UTRAP(0x1e9); UTRAP(0x1ea); UTRAP(0x1eb); UTRAP(0x1ec); UTRAP(0x1ed); UTRAP(0x1ee); UTRAP(0x1ef)
1057	UTRAP(0x1f0); UTRAP(0x1f1); UTRAP(0x1f2); UTRAP(0x1f3); UTRAP(0x1f4); UTRAP(0x1f5); UTRAP(0x1f6); UTRAP(0x1f7)
1058	UTRAP(0x1f8); UTRAP(0x1f9); UTRAP(0x1fa); UTRAP(0x1fb); UTRAP(0x1fc); UTRAP(0x1fd); UTRAP(0x1fe); UTRAP(0x1ff)
1059
1060#ifdef SUN4V
1061
1062/* Macros for sun4v traps */
1063
1064	.macro	sun4v_trap_entry count
1065	.rept	\count
1066	ba	slowtrap
1067	 nop
1068	.align	32
1069	.endr
1070	.endm
1071
1072	.macro	sun4v_trap_entry_fail count
1073	.rept	\count
1074	sir
1075	.align	32
1076	.endr
1077	.endm
1078
1079	.macro	sun4v_trap_entry_spill_fill_fail count
1080	.rept	\count
1081	sir
1082	.align	128
1083	.endr
1084	.endm
1085
1086/* The actual trap base for sun4v */
1087	.align	0x8000
1088	.globl	_C_LABEL(trapbase_sun4v)
1089_C_LABEL(trapbase_sun4v):
1090	!
1091	! trap level 0
1092	!
1093	sun4v_trap_entry 8					! 0x000-0x007
1094	VTRAP(T_INST_EXCEPT, sun4v_tl0_itsb_miss)		! 0x008 - inst except
1095	VTRAP(T_TEXTFAULT, sun4v_tl0_itsb_miss)			! 0x009 - inst MMU miss
1096	sun4v_trap_entry 26					! 0x00a-0x023
1097	CLEANWIN0						! 0x24-0x27 = clean window
1098	sun4v_trap_entry 9					! 0x028-0x030
1099	VTRAP(T_DATA_MMU_MISS, sun4v_dtsb_miss)			! 0x031 = data MMU miss
1100	sun4v_trap_entry 2					! 0x032-0x033
1101	TRAP(T_ALIGN)						! 0x034 = address alignment error
1102	sun4v_trap_entry 12					! 0x035-0x040
1103	HARDINT4V(1)						! 0x041 = level 1 interrupt
1104	HARDINT4V(2)						! 0x042 = level 2 interrupt
1105	HARDINT4V(3)						! 0x043 = level 3 interrupt
1106	HARDINT4V(4)						! 0x044 = level 4 interrupt
1107	HARDINT4V(5)						! 0x045 = level 5 interrupt
1108	HARDINT4V(6)						! 0x046 = level 6 interrupt
1109	HARDINT4V(7)						! 0x047 = level 7 interrupt
1110	HARDINT4V(8)						! 0x048 = level 8 interrupt
1111	HARDINT4V(9)						! 0x049 = level 9 interrupt
1112	HARDINT4V(10)						! 0x04a = level 10 interrupt
1113	HARDINT4V(11)						! 0x04b = level 11 interrupt
1114	HARDINT4V(12)						! 0x04c = level 12 interrupt
1115	HARDINT4V(13)						! 0x04d = level 13 interrupt
1116	HARDINT4V(14)						! 0x04e = level 14 interrupt
1117	HARDINT4V(15)						! 0x04f = level 15 interrupt
1118	sun4v_trap_entry 28					! 0x050-0x06b
1119	VTRAP(T_FDMMU_PROT, sun4v_tl0_dtsb_prot)		! 0x06c
1120	sun4v_trap_entry 15					! 0x06d-0x07b
1121	VTRAP(T_CPU_MONDO, sun4v_cpu_mondo)			! 0x07c = cpu mondo
1122	VTRAP(T_DEV_MONDO, sun4v_dev_mondo)			! 0x07d = dev mondo
1123	sun4v_trap_entry 2					! 0x07e-0x07f
1124	SPILL64(uspill8_sun4vt0,ASI_AIUS)			! 0x080 spill_0_normal -- used to save user windows in user mode
1125	SPILL32(uspill4_sun4vt0,ASI_AIUS)			! 0x084 spill_1_normal
1126	SPILLBOTH(uspill8_sun4vt0,uspill4_sun4vt0,ASI_AIUS)	! 0x088 spill_2_normal
1127	sun4v_trap_entry_spill_fill_fail 1			! 0x08c spill_3_normal
1128	SPILL64(kspill8_sun4vt0,ASI_N)				! 0x090 spill_4_normal  -- used to save supervisor windows
1129	SPILL32(kspill4_sun4vt0,ASI_N)				! 0x094 spill_5_normal
1130	SPILLBOTH(kspill8_sun4vt0,kspill4_sun4vt0,ASI_N)	! 0x098 spill_6_normal
1131	sun4v_trap_entry_spill_fill_fail 1			! 0x09c spill_7_normal
1132	SPILL64(uspillk8_sun4vt0,ASI_AIUS)			! 0x0a0 spill_0_other -- used to save user windows in supervisor mode
1133	SPILL32(uspillk4_sun4vt0,ASI_AIUS)			! 0x0a4 spill_1_other
1134	SPILLBOTH(uspillk8_sun4vt0,uspillk4_sun4vt0,ASI_AIUS)	! 0x0a8 spill_2_other
1135	sun4v_trap_entry_spill_fill_fail 1			! 0x0ac spill_3_other
1136	sun4v_trap_entry_spill_fill_fail 1			! 0x0b0 spill_4_other
1137	sun4v_trap_entry_spill_fill_fail 1			! 0x0b4 spill_5_other
1138	sun4v_trap_entry_spill_fill_fail 1			! 0x0b8 spill_6_other
1139	sun4v_trap_entry_spill_fill_fail 1			! 0x0bc spill_7_other
1140	FILL64(ufill8_sun4vt0,ASI_AIUS)				! 0x0c0 fill_0_normal -- used to fill windows when running user mode
1141	FILL32(ufill4_sun4vt0,ASI_AIUS)				! 0x0c4 fill_1_normal
1142	FILLBOTH(ufill8_sun4vt0,ufill4_sun4vt0,ASI_AIUS)	! 0x0c8 fill_2_normal
1143	sun4v_trap_entry_spill_fill_fail 1			! 0x0cc fill_3_normal
1144	FILL64(kfill8_sun4vt0,ASI_N)				! 0x0d0 fill_4_normal  -- used to fill windows when running supervisor mode
1145	FILL32(kfill4_sun4vt0,ASI_N)				! 0x0d4 fill_5_normal
1146	FILLBOTH(kfill8_sun4vt0,kfill4_sun4vt0,ASI_N)		! 0x0d8 fill_6_normal
1147	sun4v_trap_entry_spill_fill_fail 1			! 0x0dc fill_7_normal
1148	FILL64(ufillk8_sun4vt0,ASI_AIUS)			! 0x0e0 fill_0_other
1149	FILL32(ufillk4_sun4vt0,ASI_AIUS)			! 0x0e4 fill_1_other
1150	FILLBOTH(ufillk8_sun4vt0,ufillk4_sun4vt0,ASI_AIUS)	! 0x0e8 fill_2_other
1151	sun4v_trap_entry_spill_fill_fail 1			! 0x0ec fill_3_other
1152	sun4v_trap_entry_spill_fill_fail 1			! 0x0f0 fill_4_other
1153	sun4v_trap_entry_spill_fill_fail 1			! 0x0f4 fill_5_other
1154	sun4v_trap_entry_spill_fill_fail 1			! 0x0f8 fill_6_other
1155	sun4v_trap_entry_spill_fill_fail 1			! 0x0fc fill_7_other
1156	SYSCALL							! 0x100 = syscall
1157	BPT							! 0x101 = pseudo breakpoint instruction
1158	sun4v_trap_entry 254					! 0x102-0x1ff
1159	!
1160	! trap level 1
1161	!
1162	sun4v_trap_entry 36					! 0x000-0x023
1163	CLEANWIN1						! 0x24-0x27 = clean window
1164	sun4v_trap_entry 8					! 0x028-0x02F
1165	VTRAP(T_DATAFAULT, sun4v_tl1_ptbl_miss)			! 0x030 = ???
1166	VTRAP(T_DATA_MMU_MISS, sun4v_tl1_dtsb_miss)		! 0x031 = data MMU miss
1167	VTRAP(T_DATA_ERROR, sun4v_tl1_ptbl_miss)		! 0x032 = ???
1168	VTRAP(T_DATA_PROT, sun4v_tl1_ptbl_miss)			! 0x033 = ???
1169	sun4v_trap_entry 56					! 0x034-0x06b
1170	VTRAP(T_FDMMU_PROT, sun4v_tl1_dtsb_prot)		! 0x06c
1171	sun4v_trap_entry 19					! 0x06d-0x07f
1172	sun4v_tl1_uspill_normal					! 0x080 spill_0_normal -- save user windows
1173	sun4v_tl1_uspill_normal					! 0x084 spill_1_normal
1174	sun4v_tl1_uspill_normal					! 0x088 spill_2_normal
1175	sun4v_trap_entry_spill_fill_fail 1			! 0x08c spill_3_normal
1176	SPILL64(kspill8_sun4vt1,ASI_N)				! 0x090 spill_4_normal -- save supervisor windows
1177	SPILL32(kspill4_sun4vt1,ASI_N)				! 0x094 spill_5_normal
1178	SPILLBOTH(kspill8_sun4vt1,kspill4_sun4vt1,ASI_N)	! 0x098 spill_6_normal
1179	sun4v_trap_entry_spill_fill_fail 1			! 0x09c spill_7_normal
1180	sun4v_tl1_uspill_other					! 0x0a0 spill_0_other -- save user windows in nucleus mode
1181	sun4v_tl1_uspill_other					! 0x0a4 spill_1_other
1182	sun4v_tl1_uspill_other					! 0x0a8 spill_2_other
1183	sun4v_trap_entry_spill_fill_fail 1			! 0x0ac spill_3_other
1184	sun4v_trap_entry_spill_fill_fail 1			! 0x0b0 spill_4_other
1185	sun4v_trap_entry_spill_fill_fail 1			! 0x0b4 spill_5_other
1186	sun4v_trap_entry_spill_fill_fail 1			! 0x0b8 spill_6_other
1187	sun4v_trap_entry_spill_fill_fail 1			! 0x0bc spill_7_other
1188	FILL64(ufill8_sun4vt1,ASI_AIUS)				! 0x0c0 fill_0_normal -- fill windows when running nucleus mode from user
1189	FILL32(ufill4_sun4vt1,ASI_AIUS)				! 0x0c4 fill_1_normal
1190	FILLBOTH(ufill8_sun4vt1,ufill4_sun4vt1,ASI_AIUS)	! 0x0c8 fill_2_normal
1191	sun4v_trap_entry_spill_fill_fail 1			! 0x0cc fill_3_normal
1192	FILL64(kfill8_sun4vt1,ASI_N)				! 0x0d0 fill_4_normal -- fill windows when running nucleus mode from supervisor
1193	FILL32(kfill4_sun4vt1,ASI_N)				! 0x0d4 fill_5_normal
1194	FILLBOTH(kfill8_sun4vt1,kfill4_sun4vt1,ASI_N)		! 0x0d8 fill_6_normal
1195	sun4v_trap_entry_spill_fill_fail 1			! 0x0dc fill_7_normal
1196	FILL64(ufillk8_sun4vt1,ASI_AIUS)			! 0x0e0 fill_0_other -- fill user windows when running nucleus mode -- will we ever use this?
1197	FILL32(ufillk4_sun4vt1,ASI_AIUS)			! 0x0e4 fill_1_other
1198	FILLBOTH(ufillk8_sun4vt1,ufillk4_sun4vt1,ASI_AIUS)	! 0x0e8 fill_2_other
1199	sun4v_trap_entry_spill_fill_fail 1			! 0x0ec fill_3_other
1200	sun4v_trap_entry_spill_fill_fail 1			! 0x0f0 fill_4_other
1201	sun4v_trap_entry_spill_fill_fail 1			! 0x0f4 fill_5_other
1202	sun4v_trap_entry_spill_fill_fail 1			! 0x0f8 fill_6_other
1203	sun4v_trap_entry_spill_fill_fail 1			! 0x0fc fill_7_other
1204	sun4v_trap_entry_fail 256				! 0x100-0x1ff
1205
1206#endif
1207
1208#if 0
1209/*
1210 * If the cleanwin trap handler detects an overflow we come here.
1211 * We need to fix up the window registers, switch to the interrupt
1212 * stack, and then trap to the debugger.
1213 */
1214cleanwin_overflow:
1215	!! We've already incremented %cleanwin
1216	!! So restore %cwp
1217	rdpr	%cwp, %l0
1218	dec	%l0
1219	wrpr	%l0, %g0, %cwp
1220	set	EINTSTACK-STKB-CC64FSZ, %l0
1221	save	%l0, 0, %sp
1222
1223	ta	1		! Enter debugger
1224	sethi	%hi(1f), %o0
1225	call	_C_LABEL(panic)
1226	 or	%o0, %lo(1f), %o0
1227	restore
1228	retry
1229	.data
12301:
1231	.asciz	"Kernel stack overflow!"
1232	_ALIGN
1233	.text
1234#endif
1235
1236#ifdef NOTDEF_DEBUG
1237/*
1238 * A hardware red zone is impossible.  We simulate one in software by
1239 * keeping a `red zone' pointer; if %sp becomes less than this, we panic.
1240 * This is expensive and is only enabled when debugging.
1241 */
1242#define	REDSIZE	(PCB_SIZE)	/* Mark used portion of pcb structure out of bounds */
1243#define	REDSTACK 2048		/* size of `panic: stack overflow' region */
1244	.data
1245	_ALIGN
1246redzone:
1247	.xword	_C_LABEL(XXX) + REDSIZE
1248redstack:
1249	.space	REDSTACK
1250eredstack:
1251Lpanic_red:
1252	.asciz	"kernel stack overflow"
1253	_ALIGN
1254	.text
1255
1256	/* set stack pointer redzone to base+minstack; alters base */
1257#define	SET_SP_REDZONE(base, tmp) \
1258	add	base, REDSIZE, base; \
1259	sethi	%hi(_C_LABEL(redzone)), tmp; \
1260	stx	base, [tmp + %lo(_C_LABEL(redzone))]
1261
1262	/* variant with a constant */
1263#define	SET_SP_REDZONE_CONST(const, tmp1, tmp2) \
1264	set	(const) + REDSIZE, tmp1; \
1265	sethi	%hi(_C_LABEL(redzone)), tmp2; \
1266	stx	tmp1, [tmp2 + %lo(_C_LABEL(redzone))]
1267
1268	/* check stack pointer against redzone (uses two temps) */
1269#define	CHECK_SP_REDZONE(t1, t2) \
1270	sethi	KERNBASE, t1;	\
1271	cmp	%sp, t1;	\
1272	blu,pt	%xcc, 7f;	\
1273	 sethi	%hi(_C_LABEL(redzone)), t1; \
1274	ldx	[t1 + %lo(_C_LABEL(redzone))], t2; \
1275	cmp	%sp, t2;	/* if sp >= t2, not in red zone */ \
1276	blu	panic_red; nop;	/* and can continue normally */ \
12777:
1278
1279panic_red:
1280	/* move to panic stack */
1281	stx	%g0, [t1 + %lo(_C_LABEL(redzone))];
1282	set	eredstack - BIAS, %sp;
1283	/* prevent panic() from lowering ipl */
1284	sethi	%hi(_C_LABEL(panicstr)), t2;
1285	set	Lpanic_red, t2;
1286	st	t2, [t1 + %lo(_C_LABEL(panicstr))];
1287	wrpr	g0, 15, %pil		/* t1 = splhigh() */
1288	save	%sp, -CCF64SZ, %sp;	/* preserve current window */
1289	sethi	%hi(Lpanic_red), %o0;
1290	call	_C_LABEL(panic);
1291	 or %o0, %lo(Lpanic_red), %o0;
1292
1293
1294#else
1295
1296#define	SET_SP_REDZONE(base, tmp)
1297#define	SET_SP_REDZONE_CONST(const, t1, t2)
1298#define	CHECK_SP_REDZONE(t1, t2)
1299#endif
1300
1301#define TRACESIZ	0x01000
1302	.globl	_C_LABEL(trap_trace)
1303	.globl	_C_LABEL(trap_trace_ptr)
1304	.globl	_C_LABEL(trap_trace_end)
1305	.globl	_C_LABEL(trap_trace_dis)
1306	.data
1307_C_LABEL(trap_trace_dis):
1308	.word	1, 1		! Starts disabled.  DDB turns it on.
1309_C_LABEL(trap_trace_ptr):
1310	.word	0, 0, 0, 0
1311_C_LABEL(trap_trace):
1312	.space	TRACESIZ
1313_C_LABEL(trap_trace_end):
1314	.space	0x20		! safety margin
1315
1316
1317/*
1318 * v9 machines do not have a trap window.
1319 *
1320 * When we take a trap the trap state is pushed on to the stack of trap
1321 * registers, interrupts are disabled, then we switch to an alternate set
1322 * of global registers.
1323 *
1324 * The trap handling code needs to allocate a trap frame on the kernel, or
1325 * for interrupts, the interrupt stack, save the out registers to the trap
1326 * frame, then switch to the normal globals and save them to the trap frame
1327 * too.
1328 *
1329 * XXX it would be good to save the interrupt stack frame to the kernel
1330 * stack so we wouldn't have to copy it later if we needed to handle a AST.
1331 *
1332 * Since kernel stacks are all on one page and the interrupt stack is entirely
1333 * within the locked TLB, we can use physical addressing to save out our
1334 * trap frame so we don't trap during the TRAP_SETUP() operation.  There
1335 * is unfortunately no supportable method for issuing a non-trapping save.
1336 *
1337 * However, if we use physical addresses to save our trapframe, we will need
1338 * to clear out the data cache before continuing much further.
1339 *
1340 * In short, what we need to do is:
1341 *
1342 *	all preliminary processing is done using the alternate globals
1343 *
1344 *	When we allocate our trap windows we must give up our globals because
1345 *	their state may have changed during the save operation
1346 *
1347 *	we need to save our normal globals as soon as we have a stack
1348 *
1349 * Finally, we may now call C code.
1350 *
1351 * This macro will destroy %g5-%g7.  %g0-%g4 remain unchanged.
1352 *
1353 * In order to properly handle nested traps without lossage, alternate
1354 * global %g6 is used as a kernel stack pointer.  It is set to the last
1355 * allocated stack pointer (trapframe) and the old value is stored in
1356 * tf_kstack.  It is restored when returning from a trap.  It is cleared
1357 * on entering user mode.
1358 */
1359
1360 /*
1361  * Other misc. design criteria:
1362  *
1363  * When taking an address fault, fault info is in the sfsr, sfar,
1364  * TLB_TAG_ACCESS registers.  If we take another address fault
1365  * while trying to handle the first fault then that information,
1366  * the only information that tells us what address we trapped on,
1367  * can potentially be lost.  This trap can be caused when allocating
1368  * a register window with which to handle the trap because the save
1369  * may try to store or restore a register window that corresponds
1370  * to part of the stack that is not mapped.  Preventing this trap,
1371  * while possible, is much too complicated to do in a trap handler,
1372  * and then we will need to do just as much work to restore the processor
1373  * window state.
1374  *
1375  * Possible solutions to the problem:
1376  *
1377  * Since we have separate AG, MG, and IG, we could have all traps
1378  * above level-1 preserve AG and use other registers.  This causes
1379  * a problem for the return from trap code which is coded to use
1380  * alternate globals only.
1381  *
1382  * We could store the trapframe and trap address info to the stack
1383  * using physical addresses.  Then we need to read it back using
1384  * physical addressing, or flush the D$.
1385  *
1386  * We could identify certain registers to hold address fault info.
1387  * this means that these registers need to be preserved across all
1388  * fault handling.  But since we only have 7 useable globals, that
1389  * really puts a cramp in our style.
1390  *
1391  * Finally, there is the issue of returning from kernel mode to user
1392  * mode.  If we need to issue a restore of a user window in kernel
1393  * mode, we need the window control registers in a user mode setup.
1394  * If the trap handlers notice the register windows are in user mode,
1395  * they will allocate a trapframe at the bottom of the kernel stack,
1396  * overwriting the frame we were trying to return to.  This means that
1397  * we must complete the restoration of all registers *before* switching
1398  * to a user-mode window configuration.
1399  *
1400  * Essentially we need to be able to write re-entrant code w/no stack.
1401  */
1402	.data
1403trap_setup_msg:
1404	.asciz	"TRAP_SETUP: tt=%x osp=%x nsp=%x tl=%x tpc=%x\n"
1405	_ALIGN
1406intr_setup_msg:
1407	.asciz	"INTR_SETUP: tt=%x osp=%x nsp=%x tl=%x tpc=%x\n"
1408	_ALIGN
1409	.text
1410
1411#ifdef DEBUG
1412	/* Only save a snapshot of locals and ins in DEBUG kernels */
1413#define	SAVE_LOCALS_INS	\
1414	/* Save local registers to trap frame */ \
1415	stx	%l0, [%g6 + CC64FSZ + STKB + TF_L + (0*8)]; \
1416	stx	%l1, [%g6 + CC64FSZ + STKB + TF_L + (1*8)]; \
1417	stx	%l2, [%g6 + CC64FSZ + STKB + TF_L + (2*8)]; \
1418	stx	%l3, [%g6 + CC64FSZ + STKB + TF_L + (3*8)]; \
1419	stx	%l4, [%g6 + CC64FSZ + STKB + TF_L + (4*8)]; \
1420	stx	%l5, [%g6 + CC64FSZ + STKB + TF_L + (5*8)]; \
1421	stx	%l6, [%g6 + CC64FSZ + STKB + TF_L + (6*8)]; \
1422	stx	%l7, [%g6 + CC64FSZ + STKB + TF_L + (7*8)]; \
1423\
1424	/* Save in registers to trap frame */ \
1425	stx	%i0, [%g6 + CC64FSZ + STKB + TF_I + (0*8)]; \
1426	stx	%i1, [%g6 + CC64FSZ + STKB + TF_I + (1*8)]; \
1427	stx	%i2, [%g6 + CC64FSZ + STKB + TF_I + (2*8)]; \
1428	stx	%i3, [%g6 + CC64FSZ + STKB + TF_I + (3*8)]; \
1429	stx	%i4, [%g6 + CC64FSZ + STKB + TF_I + (4*8)]; \
1430	stx	%i5, [%g6 + CC64FSZ + STKB + TF_I + (5*8)]; \
1431	stx	%i6, [%g6 + CC64FSZ + STKB + TF_I + (6*8)]; \
1432	stx	%i7, [%g6 + CC64FSZ + STKB + TF_I + (7*8)]; \
1433\
1434	stx	%g1, [%g6 + CC64FSZ + STKB + TF_FAULT];
1435#else
1436#define	SAVE_LOCALS_INS
1437#endif
1438
1439#ifdef _LP64
1440#define	FIXUP_TRAP_STACK \
1441	btst	1, %g6;						/* Fixup 64-bit stack if necessary */ \
1442	bnz,pt	%icc, 1f; \
1443	 add	%g6, %g5, %g6;					/* Allocate a stack frame */ \
1444	inc	-BIAS, %g6; \
14451:
1446#else
1447#define	FIXUP_TRAP_STACK \
1448	srl	%g6, 0, %g6;					/* truncate at 32-bits */ \
1449	btst	1, %g6;						/* Fixup 64-bit stack if necessary */ \
1450	add	%g6, %g5, %g6;					/* Allocate a stack frame */ \
1451	add	%g6, BIAS, %g5; \
1452	movne	%icc, %g5, %g6;
1453#endif
1454
1455#ifdef _LP64
1456#define	TRAP_SETUP(stackspace) \
1457	sethi	%hi(CPCB), %g6; \
1458	sethi	%hi((stackspace)), %g5; \
1459	LDPTR	[%g6 + %lo(CPCB)], %g6; \
1460	sethi	%hi(USPACE), %g7;				/* Always multiple of page size */ \
1461	or	%g5, %lo((stackspace)), %g5; \
1462	add	%g6, %g7, %g6; \
1463	rdpr	%wstate, %g7;					/* Find if we're from user mode */ \
1464	sra	%g5, 0, %g5;					/* Sign extend the damn thing */ \
1465	\
1466	sub	%g7, WSTATE_KERN, %g7;				/* Compare & leave in register */ \
1467	movrz	%g7, %sp, %g6;					/* Select old (kernel) stack or base of kernel stack */ \
1468	FIXUP_TRAP_STACK \
1469	SAVE_LOCALS_INS	\
1470	save	%g6, 0, %sp;					/* If we fault we should come right back here */ \
1471	stx	%i0, [%sp + CC64FSZ + BIAS + TF_O + (0*8)];		/* Save out registers to trap frame */ \
1472	stx	%i1, [%sp + CC64FSZ + BIAS + TF_O + (1*8)]; \
1473	stx	%i2, [%sp + CC64FSZ + BIAS + TF_O + (2*8)]; \
1474	stx	%i3, [%sp + CC64FSZ + BIAS + TF_O + (3*8)]; \
1475	stx	%i4, [%sp + CC64FSZ + BIAS + TF_O + (4*8)]; \
1476	stx	%i5, [%sp + CC64FSZ + BIAS + TF_O + (5*8)]; \
1477\
1478	stx	%i6, [%sp + CC64FSZ + BIAS + TF_O + (6*8)]; \
1479	brz,pt	%g7, 1f;					/* If we were in kernel mode start saving globals */ \
1480	 stx	%i7, [%sp + CC64FSZ + BIAS + TF_O + (7*8)]; \
1481	mov	CTX_PRIMARY, %g7; \
1482	/* came from user mode -- switch to kernel mode stack */ \
1483	rdpr	%canrestore, %g5;				/* Fixup register window state registers */ \
1484	wrpr	%g0, 0, %canrestore; \
1485	wrpr	%g0, %g5, %otherwin; \
1486	wrpr	%g0, WSTATE_KERN, %wstate;			/* Enable kernel mode window traps -- now we can trap again */ \
1487\
1488	SET_MMU_CONTEXTID %g0, %g7,%g5; 			/* Switch MMU to kernel primary context */ \
1489	sethi	%hi(KERNBASE), %g5; \
1490	flush	%g5;						/* Some convenient address that won't trap */ \
14911:
1492
1493/*
1494 * Interrupt setup is almost exactly like trap setup, but we need to
1495 * go to the interrupt stack if (a) we came from user mode or (b) we
1496 * came from kernel mode on the kernel stack.
1497 *
1498 * We don't guarantee any registers are preserved during this operation.
1499 * So we can be more efficient.
1500 */
1501#define	INTR_SETUP(stackspace) \
1502	rdpr	%wstate, %g7;					/* Find if we're from user mode */ \
1503	\
1504	sethi	%hi(EINTSTACK-BIAS), %g6; \
1505	sethi	%hi(EINTSTACK-INTSTACK), %g4; \
1506	\
1507	or	%g6, %lo(EINTSTACK-BIAS), %g6;			/* Base of interrupt stack */ \
1508	dec	%g4;						/* Make it into a mask */ \
1509	\
1510	sub	%g6, %sp, %g1;					/* Offset from interrupt stack */ \
1511	sethi	%hi((stackspace)), %g5; \
1512	\
1513	or	%g5, %lo((stackspace)), %g5; \
1514\
1515	andn	%g1, %g4, %g4;					/* Are we out of the interrupt stack range? */ \
1516	xor	%g7, WSTATE_KERN, %g3;				/* Are we on the user stack ? */ \
1517	\
1518	sra	%g5, 0, %g5;					/* Sign extend the damn thing */ \
1519	orcc	%g3, %g4, %g0;					/* Definitely not off the interrupt stack */ \
1520	\
1521	sethi	%hi(CPUINFO_VA + CI_EINTSTACK), %g4; \
1522	bz,a,pt	%xcc, 1f; \
1523	 mov	%sp, %g6; \
1524	\
1525	ldx	[%g4 + %lo(CPUINFO_VA + CI_EINTSTACK)], %g4; \
1526	movrnz	%g4, %g4, %g6;					/* Use saved intr stack if exists */ \
1527	\
15281:	add	%g6, %g5, %g5;					/* Allocate a stack frame */ \
1529	btst	1, %g6; \
1530	bnz,pt	%icc, 1f; \
1531\
1532	 mov	%g5, %g6; \
1533	\
1534	add	%g5, -BIAS, %g6; \
1535	\
15361:	SAVE_LOCALS_INS	\
1537	save	%g6, 0, %sp;					/* If we fault we should come right back here */ \
1538	stx	%i0, [%sp + CC64FSZ + BIAS + TF_O + (0*8)];		/* Save out registers to trap frame */ \
1539	stx	%i1, [%sp + CC64FSZ + BIAS + TF_O + (1*8)]; \
1540	stx	%i2, [%sp + CC64FSZ + BIAS + TF_O + (2*8)]; \
1541	stx	%i3, [%sp + CC64FSZ + BIAS + TF_O + (3*8)]; \
1542	stx	%i4, [%sp + CC64FSZ + BIAS + TF_O + (4*8)]; \
1543\
1544	stx	%i5, [%sp + CC64FSZ + BIAS + TF_O + (5*8)]; \
1545	stx	%i6, [%sp + CC64FSZ + BIAS + TF_O + (6*8)]; \
1546	stx	%i6, [%sp + CC64FSZ + BIAS + TF_G + (0*8)];		/* Save fp in clockframe->cf_fp */ \
1547	brz,pt	%g3, 1f;					/* If we were in kernel mode start saving globals */ \
1548	 stx	%i7, [%sp + CC64FSZ + BIAS + TF_O + (7*8)]; \
1549	/* came from user mode -- switch to kernel mode stack */ \
1550	 rdpr	%otherwin, %g5;					/* Has this already been done? */ \
1551	\
1552	brnz,pn	%g5, 1f;					/* Don't set this twice */ \
1553	\
1554	 rdpr	%canrestore, %g5;				/* Fixup register window state registers */ \
1555\
1556	wrpr	%g0, 0, %canrestore; \
1557	\
1558	wrpr	%g0, %g5, %otherwin; \
1559	\
1560	mov	CTX_PRIMARY, %g7; \
1561	\
1562	wrpr	%g0, WSTATE_KERN, %wstate;			/* Enable kernel mode window traps -- now we can trap again */ \
1563	\
1564	SET_MMU_CONTEXTID %g0, %g7, %g5;			/* Switch MMU to kernel primary context */ \
1565	\
1566	sethi	%hi(KERNBASE), %g5; \
1567	flush	%g5;						/* Some convenient address that won't trap */ \
15681:
1569
1570#else /* _LP64 */
1571
1572#define	TRAP_SETUP(stackspace) \
1573	sethi	%hi(CPCB), %g6; \
1574	sethi	%hi((stackspace)), %g5; \
1575	LDPTR	[%g6 + %lo(CPCB)], %g6; \
1576	sethi	%hi(USPACE), %g7; \
1577	or	%g5, %lo((stackspace)), %g5; \
1578	add	%g6, %g7, %g6; \
1579	rdpr	%wstate, %g7;					/* Find if we're from user mode */ \
1580	\
1581	sra	%g5, 0, %g5;					/* Sign extend the damn thing */ \
1582	subcc	%g7, WSTATE_KERN, %g7;				/* Compare & leave in register */ \
1583	movz	%icc, %sp, %g6;					/* Select old (kernel) stack or base of kernel stack */ \
1584	FIXUP_TRAP_STACK \
1585	SAVE_LOCALS_INS \
1586	save	%g6, 0, %sp;					/* If we fault we should come right back here */ \
1587	stx	%i0, [%sp + CC64FSZ + STKB + TF_O + (0*8)];		/* Save out registers to trap frame */ \
1588	stx	%i1, [%sp + CC64FSZ + STKB + TF_O + (1*8)]; \
1589	stx	%i2, [%sp + CC64FSZ + STKB + TF_O + (2*8)]; \
1590	stx	%i3, [%sp + CC64FSZ + STKB + TF_O + (3*8)]; \
1591	stx	%i4, [%sp + CC64FSZ + STKB + TF_O + (4*8)]; \
1592	stx	%i5, [%sp + CC64FSZ + STKB + TF_O + (5*8)]; \
1593	\
1594	stx	%i6, [%sp + CC64FSZ + STKB + TF_O + (6*8)]; \
1595	brz,pn	%g7, 1f;					/* If we were in kernel mode start saving globals */ \
1596	 stx	%i7, [%sp + CC64FSZ + STKB + TF_O + (7*8)]; \
1597	mov	CTX_PRIMARY, %g7; \
1598	/* came from user mode -- switch to kernel mode stack */ \
1599	rdpr	%canrestore, %g5;				/* Fixup register window state registers */ \
1600	wrpr	%g0, 0, %canrestore; \
1601	wrpr	%g0, %g5, %otherwin; \
1602	wrpr	%g0, WSTATE_KERN, %wstate;			/* Enable kernel mode window traps -- now we can trap again */ \
1603	\
1604	SET_MMU_CONTEXTID %g0, %g7, %g5;			/* Switch MMU to kernel primary context */ \
1605	sethi	%hi(KERNBASE), %g5; \
1606	flush	%g5;						/* Some convenient address that won't trap */ \
16071:
1608
1609/*
1610 * Interrupt setup is almost exactly like trap setup, but we need to
1611 * go to the interrupt stack if (a) we came from user mode or (b) we
1612 * came from kernel mode on the kernel stack.
1613 *
1614 * We don't guarantee any registers are preserved during this operation.
1615 */
1616#define	INTR_SETUP(stackspace) \
1617	sethi	%hi(EINTSTACK), %g1; \
1618	sethi	%hi((stackspace)), %g5; \
1619	btst	1, %sp; \
1620	add	%sp, BIAS, %g6; \
1621	movz	%icc, %sp, %g6; \
1622	or	%g1, %lo(EINTSTACK), %g1; \
1623	srl	%g6, 0, %g6;					/* truncate at 32-bits */ \
1624	set	(EINTSTACK-INTSTACK), %g7; \
1625	or	%g5, %lo((stackspace)), %g5; \
1626	sub	%g1, %g6, %g2;					/* Determine if we need to switch to intr stack or not */ \
1627	dec	%g7;						/* Make it into a mask */ \
1628	sethi	%hi(CPUINFO_VA + CI_EINTSTACK), %g3; \
1629	andncc	%g2, %g7, %g0;					/* XXXXXXXXXX This assumes kernel addresses are unique from user addresses */ \
1630	LDPTR	[%g3 + %lo(CPUINFO_VA + CI_EINTSTACK)], %g3; \
1631	rdpr	%wstate, %g7;					/* Find if we're from user mode */ \
1632	movrnz	%g3, %g3, %g1;					/* Use saved intr stack if exists */ \
1633	sra	%g5, 0, %g5;					/* Sign extend the damn thing */ \
1634	movnz	%xcc, %g1, %g6;					/* Stay on interrupt stack? */ \
1635	cmp	%g7, WSTATE_KERN;				/* User or kernel sp? */ \
1636	movnz	%icc, %g1, %g6;					/* Stay on interrupt stack? */ \
1637	add	%g6, %g5, %g6;					/* Allocate a stack frame */ \
1638	\
1639	SAVE_LOCALS_INS \
1640	save	%g6, 0, %sp;					/* If we fault we should come right back here */ \
1641	stx	%i0, [%sp + CC64FSZ + STKB + TF_O + (0*8)];		/* Save out registers to trap frame */ \
1642	stx	%i1, [%sp + CC64FSZ + STKB + TF_O + (1*8)]; \
1643	stx	%i2, [%sp + CC64FSZ + STKB + TF_O + (2*8)]; \
1644	stx	%i3, [%sp + CC64FSZ + STKB + TF_O + (3*8)]; \
1645	stx	%i4, [%sp + CC64FSZ + STKB + TF_O + (4*8)]; \
1646	stx	%i5, [%sp + CC64FSZ + STKB + TF_O + (5*8)]; \
1647	stx	%i6, [%sp + CC64FSZ + STKB + TF_O + (6*8)]; \
1648	stx	%i6, [%sp + CC64FSZ + STKB + TF_G + (0*8)];		/* Save fp in clockframe->cf_fp */ \
1649	rdpr	%wstate, %g7;					/* Find if we're from user mode */ \
1650	stx	%i7, [%sp + CC64FSZ + STKB + TF_O + (7*8)]; \
1651	cmp	%g7, WSTATE_KERN;				/* Compare & leave in register */ \
1652	be,pn	%icc, 1f;					/* If we were in kernel mode start saving globals */ \
1653	/* came from user mode -- switch to kernel mode stack */ \
1654	 rdpr	%otherwin, %g5;					/* Has this already been done? */ \
1655	tst	%g5; tnz %xcc, 1; nop; /* DEBUG -- this should _NEVER_ happen */ \
1656	brnz,pn	%g5, 1f;					/* Don't set this twice */ \
1657	 rdpr	%canrestore, %g5;				/* Fixup register window state registers */ \
1658	wrpr	%g0, 0, %canrestore; \
1659	mov	CTX_PRIMARY, %g7; \
1660	wrpr	%g0, %g5, %otherwin; \
1661	wrpr	%g0, WSTATE_KERN, %wstate;			/* Enable kernel mode window traps -- now we can trap again */ \
1662	SET_MMU_CONTEXTID %g0, %g7, %g5;			/* Switch MMU to kernel primary context */ \
1663	sethi	%hi(KERNBASE), %g5; \
1664	flush	%g5;						/* Some convenient address that won't trap */ \
16651:
1666#endif /* _LP64 */
1667
1668#ifdef DEBUG
1669
1670	/* Look up kpte to test algorithm */
1671	.globl	asmptechk
1672asmptechk:
1673	mov	%o0, %g4	! pmap->pm_segs
1674	mov	%o1, %g3	! Addr to lookup -- mind the context
1675
1676	srax	%g3, HOLESHIFT, %g5			! Check for valid address
1677	brz,pt	%g5, 0f					! Should be zero or -1
1678	 inc	%g5					! Make -1 -> 0
1679	brnz,pn	%g5, 1f					! Error!
16800:
1681	 srlx	%g3, STSHIFT, %g5
1682	and	%g5, STMASK, %g5
1683	sll	%g5, 3, %g5
1684	add	%g4, %g5, %g4
1685	DLFLUSH(%g4,%g5)
1686	ldxa	[%g4] ASI_PHYS_CACHED, %g4		! Remember -- UNSIGNED
1687	DLFLUSH2(%g5)
1688	brz,pn	%g4, 1f					! NULL entry? check somewhere else
1689
1690	 srlx	%g3, PDSHIFT, %g5
1691	and	%g5, PDMASK, %g5
1692	sll	%g5, 3, %g5
1693	add	%g4, %g5, %g4
1694	DLFLUSH(%g4,%g5)
1695	ldxa	[%g4] ASI_PHYS_CACHED, %g4		! Remember -- UNSIGNED
1696	DLFLUSH2(%g5)
1697	brz,pn	%g4, 1f					! NULL entry? check somewhere else
1698
1699	 srlx	%g3, PTSHIFT, %g5			! Convert to ptab offset
1700	and	%g5, PTMASK, %g5
1701	sll	%g5, 3, %g5
1702	add	%g4, %g5, %g4
1703	DLFLUSH(%g4,%g5)
1704	ldxa	[%g4] ASI_PHYS_CACHED, %g6
1705	DLFLUSH2(%g5)
1706	brgez,pn %g6, 1f				! Entry invalid?  Punt
1707	 srlx	%g6, 32, %o0
1708	retl
1709	 srl	%g6, 0, %o1
17101:
1711	mov	%g0, %o1
1712	retl
1713	 mov	%g0, %o0
1714
1715	.data
17162:
1717	.asciz	"asmptechk: %x %x %x %x:%x\n"
1718	_ALIGN
1719	.text
1720#endif
1721
1722/*
1723 * This is the MMU protection handler.  It's too big to fit
1724 * in the trap table so I moved it here.  It's relatively simple.
1725 * It looks up the page mapping in the page table associated with
1726 * the trapping context.  It checks to see if the S/W writable bit
1727 * is set.  If so, it sets the H/W write bit, marks the tte modified,
1728 * and enters the mapping into the MMU.  Otherwise it does a regular
1729 * data fault.
1730 */
1731	ICACHE_ALIGN
1732dmmu_write_fault:
1733	mov	TLB_TAG_ACCESS, %g3
1734	sethi	%hi(0x1fff), %g6			! 8K context mask
1735	ldxa	[%g3] ASI_DMMU, %g3			! Get fault addr from Tag Target
1736	sethi	%hi(CPUINFO_VA+CI_CTXBUSY), %g4
1737	or	%g6, %lo(0x1fff), %g6
1738	LDPTR	[%g4 + %lo(CPUINFO_VA+CI_CTXBUSY)], %g4
1739	srax	%g3, HOLESHIFT, %g5			! Check for valid address
1740	and	%g3, %g6, %g6				! Isolate context
1741
1742	inc	%g5					! (0 or -1) -> (1 or 0)
1743	sllx	%g6, 3, %g6				! Make it into an offset into ctxbusy
1744	ldx	[%g4+%g6], %g4				! Load up our page table.
1745	srlx	%g3, STSHIFT, %g6
1746	cmp	%g5, 1
1747	bgu,pn %xcc, winfix				! Error!
1748	 srlx	%g3, PDSHIFT, %g5
1749	and	%g6, STMASK, %g6
1750	sll	%g6, 3, %g6
1751
1752	and	%g5, PDMASK, %g5
1753	sll	%g5, 3, %g5
1754	add	%g6, %g4, %g4
1755	DLFLUSH(%g4,%g6)
1756	ldxa	[%g4] ASI_PHYS_CACHED, %g4
1757	DLFLUSH2(%g6)
1758	srlx	%g3, PTSHIFT, %g6			! Convert to ptab offset
1759	and	%g6, PTMASK, %g6
1760	add	%g5, %g4, %g5
1761	brz,pn	%g4, winfix				! NULL entry? check somewhere else
1762	 nop
1763
1764	ldxa	[%g5] ASI_PHYS_CACHED, %g4
1765	sll	%g6, 3, %g6
1766	brz,pn	%g4, winfix				! NULL entry? check somewhere else
1767	 add	%g6, %g4, %g6
17681:
1769	ldxa	[%g6] ASI_PHYS_CACHED, %g4
1770	brgez,pn %g4, winfix				! Entry invalid?  Punt
1771	 or	%g4, SUN4U_TTE_MODIFY|SUN4U_TTE_ACCESS|SUN4U_TTE_W, %g7	! Update the modified bit
1772
1773	btst	SUN4U_TTE_REAL_W|SUN4U_TTE_W, %g4			! Is it a ref fault?
1774	bz,pn	%xcc, winfix				! No -- really fault
1775#ifdef DEBUG
1776	/* Make sure we don't try to replace a kernel translation */
1777	/* This should not be necessary */
1778	sllx	%g3, 64-13, %g2				! Isolate context bits
1779	sethi	%hi(KERNBASE), %g5			! Don't need %lo
1780	brnz,pt	%g2, 0f					! Ignore context != 0
1781	 set	0x0800000, %g2				! 8MB
1782	sub	%g3, %g5, %g5
1783	cmp	%g5, %g2
1784	tlu	%xcc, 1; nop
1785	blu,pn	%xcc, winfix				! Next insn in delay slot is unimportant
17860:
1787#endif
1788	/* Need to check for and handle large pages. */
1789	 srlx	%g4, 61, %g5				! Isolate the size bits
1790	ldxa	[%g0] ASI_DMMU_8KPTR, %g2		! Load DMMU 8K TSB pointer
1791	andcc	%g5, 0x3, %g5				! 8K?
1792	bnz,pn	%icc, winfix				! We punt to the pmap code since we can't handle policy
1793	 ldxa	[%g0] ASI_DMMU, %g1			! Load DMMU tag target register
1794	casxa	[%g6] ASI_PHYS_CACHED, %g4, %g7		!  and write it out
1795	membar	#StoreLoad
1796	cmp	%g4, %g7
1797	bne,pn	%xcc, 1b
1798	 or	%g4, SUN4U_TTE_MODIFY|SUN4U_TTE_ACCESS|SUN4U_TTE_W, %g4	! Update the modified bit
1799	stx	%g1, [%g2]				! Update TSB entry tag
1800	mov	SFSR, %g7
1801	stx	%g4, [%g2+8]				! Update TSB entry data
1802	nop
1803
1804#ifdef TRAPSTATS
1805	sethi	%hi(_C_LABEL(protfix)), %g1
1806	lduw	[%g1+%lo(_C_LABEL(protfix))], %g2
1807	inc	%g2
1808	stw	%g2, [%g1+%lo(_C_LABEL(protfix))]
1809#endif
1810	mov	DEMAP_PAGE_SECONDARY, %g1		! Secondary flush
1811	mov	DEMAP_PAGE_NUCLEUS, %g5			! Nucleus flush
1812	stxa	%g0, [%g7] ASI_DMMU			! clear out the fault
1813	sllx	%g3, (64-13), %g7			! Need to demap old entry first
1814	andn	%g3, 0xfff, %g6
1815	movrz	%g7, %g5, %g1				! Pick one
1816	or	%g6, %g1, %g6
1817	membar	#Sync
1818	stxa	%g6, [%g6] ASI_DMMU_DEMAP		! Do the demap
1819	membar	#Sync
1820
1821	stxa	%g4, [%g0] ASI_DMMU_DATA_IN		! Enter new mapping
1822	membar	#Sync
1823	retry
1824
1825/*
1826 * Each memory data access fault from a fast access miss handler comes here.
1827 * We will quickly check if this is an original prom mapping before going
1828 * to the generic fault handler
1829 *
1830 * We will assume that %pil is not lost so we won't bother to save it
1831 * unless we're in an interrupt handler.
1832 *
1833 * On entry:
1834 *	We are on one of the alternate set of globals
1835 *	%g1 = MMU tag target
1836 *	%g2 = 8Kptr
1837 *	%g3 = TLB TAG ACCESS
1838 *
1839 * On return:
1840 *
1841 */
1842	ICACHE_ALIGN
1843data_miss:
1844#ifdef TRAPSTATS
1845	set	_C_LABEL(kdmiss), %g3
1846	set	_C_LABEL(udmiss), %g4
1847	rdpr	%tl, %g6
1848	dec	%g6
1849	movrz	%g6, %g4, %g3
1850	lduw	[%g3], %g4
1851	inc	%g4
1852	stw	%g4, [%g3]
1853#endif
1854	mov	TLB_TAG_ACCESS, %g3			! Get real fault page
1855	sethi	%hi(0x1fff), %g6			! 8K context mask
1856	ldxa	[%g3] ASI_DMMU, %g3			! from tag access register
1857	sethi	%hi(CPUINFO_VA+CI_CTXBUSY), %g4
1858	or	%g6, %lo(0x1fff), %g6
1859	LDPTR	[%g4 + %lo(CPUINFO_VA+CI_CTXBUSY)], %g4
1860	srax	%g3, HOLESHIFT, %g5			! Check for valid address
1861	and	%g3, %g6, %g6				! Isolate context
1862
1863	inc	%g5					! (0 or -1) -> (1 or 0)
1864	sllx	%g6, 3, %g6				! Make it into an offset into ctxbusy
1865	ldx	[%g4+%g6], %g4				! Load up our page table.
1866#ifdef DEBUG
1867	/* Make sure we don't try to replace a kernel translation */
1868	/* This should not be necessary */
1869	brnz,pt	%g6, 1f			! If user context continue miss
1870	sethi	%hi(KERNBASE), %g7			! Don't need %lo
1871	set	0x0800000, %g6				! 8MB
1872	sub	%g3, %g7, %g7
1873	cmp	%g7, %g6
1874	tlu	%xcc, 1; nop
18751:
1876#endif
1877	srlx	%g3, STSHIFT, %g6
1878	cmp	%g5, 1
1879	bgu,pn %xcc, winfix				! Error!
1880	 srlx	%g3, PDSHIFT, %g5
1881	and	%g6, STMASK, %g6
1882
1883	sll	%g6, 3, %g6
1884	and	%g5, PDMASK, %g5
1885	sll	%g5, 3, %g5
1886	add	%g6, %g4, %g4
1887	ldxa	[%g4] ASI_PHYS_CACHED, %g4
1888	srlx	%g3, PTSHIFT, %g6			! Convert to ptab offset
1889	and	%g6, PTMASK, %g6
1890	add	%g5, %g4, %g5
1891	brz,pn	%g4, data_nfo				! NULL entry? check somewhere else
1892
1893	 nop
1894	ldxa	[%g5] ASI_PHYS_CACHED, %g4
1895	sll	%g6, 3, %g6
1896	brz,pn	%g4, data_nfo				! NULL entry? check somewhere else
1897	 add	%g6, %g4, %g6
1898
18991:
1900	ldxa	[%g6] ASI_PHYS_CACHED, %g4
1901	brgez,pn %g4, data_nfo				! Entry invalid?  Punt
1902	 or	%g4, SUN4U_TTE_ACCESS, %g7			! Update the access bit
1903
1904	btst	SUN4U_TTE_ACCESS, %g4				! Need to update access git?
1905	bne,pt	%xcc, 1f
1906	 nop
1907	casxa	[%g6] ASI_PHYS_CACHED, %g4, %g7		!  and write it out
1908	cmp	%g4, %g7
1909	bne,pn	%xcc, 1b
1910	 or	%g4, SUN4U_TTE_ACCESS, %g4			! Update the access bit
1911
19121:
1913	stx	%g1, [%g2]				! Update TSB entry tag
1914	stx	%g4, [%g2+8]				! Update TSB entry data
1915	stxa	%g4, [%g0] ASI_DMMU_DATA_IN		! Enter new mapping
1916	membar	#Sync
1917	CLRTT
1918	retry
1919	NOTREACHED
1920/*
1921 * We had a data miss but did not find a mapping.  Insert
1922 * a NFO mapping to satisfy speculative loads and return.
1923 * If this had been a real load, it will re-execute and
1924 * result in a data fault or protection fault rather than
1925 * a TLB miss.  We insert an 8K TTE with the valid and NFO
1926 * bits set.  All others should zero.  The TTE looks like this:
1927 *
1928 *	0x9000000000000000
1929 *
1930 */
1931data_nfo:
1932	sethi	%hi(0x90000000), %g4			! V(0x8)|NFO(0x1)
1933	sllx	%g4, 32, %g4
1934	stxa	%g4, [%g0] ASI_DMMU_DATA_IN		! Enter new mapping
1935	membar	#Sync
1936	CLRTT
1937	retry
1938
1939/*
1940 * Handler for making the trap window shiny clean.
1941 *
1942 * If the store that trapped was to a kernel address, panic.
1943 *
1944 * If the store that trapped was to a user address, stick it in the PCB.
1945 * Since we don't want to force user code to use the standard register
1946 * convention if we don't have to, we will not assume that %fp points to
1947 * anything valid.
1948 *
1949 * On entry:
1950 *	We are on one of the alternate set of globals
1951 *	%g1 = %tl - 1, tstate[tl-1], scratch	- local
1952 *	%g2 = %tl				- local
1953 *	%g3 = MMU tag access			- in
1954 *	%g4 = %cwp				- local
1955 *	%g5 = scratch				- local
1956 *	%g6 = cpcb				- local
1957 *	%g7 = scratch				- local
1958 *
1959 * On return:
1960 *
1961 * NB:	 remove most of this from main codepath & cleanup I$
1962 */
1963winfault:
1964	mov	TLB_TAG_ACCESS, %g3	! Get real fault page from tag access register
1965	ldxa	[%g3] ASI_DMMU, %g3	! And put it into the non-MMU alternate regs
1966winfix:
1967	rdpr	%tl, %g2
1968	subcc	%g2, 1, %g1
1969	ble,pt	%icc, datafault		! Don't go below trap level 1
1970	 sethi	%hi(CPCB), %g6		! get current pcb
1971
1972
1973	wrpr	%g1, 0, %tl		! Pop a trap level
1974	rdpr	%tt, %g7		! Read type of prev. trap
1975	rdpr	%tstate, %g4		! Try to restore prev %cwp if we were executing a restore
1976	andn	%g7, 0x3f, %g5		!   window fill traps are all 0b 0000 11xx xxxx
1977
1978#if 1
1979	cmp	%g7, 0x30		! If we took a datafault just before this trap
1980	bne,pt	%icc, winfixfill	! our stack's probably bad so we need to switch somewhere else
1981	 nop
1982
1983	!!
1984	!! Double data fault -- bad stack?
1985	!!
1986	wrpr	%g2, %tl		! Restore trap level.
1987	sir				! Just issue a reset and don't try to recover.
1988	mov	%fp, %l6		! Save the frame pointer
1989	set	EINTSTACK+USPACE+CC64FSZ-STKB, %fp ! Set the frame pointer to the middle of the idle stack
1990	add	%fp, -CC64FSZ, %sp	! Create a stackframe
1991	wrpr	%g0, 15, %pil		! Disable interrupts, too
1992	wrpr	%g0, %g0, %canrestore	! Our stack is hozed and our PCB
1993	wrpr	%g0, 7, %cansave	!  probably is too, so blow away
1994	ba	slowtrap		!  all our register windows.
1995	 wrpr	%g0, 0x101, %tt
1996#endif
1997
1998winfixfill:
1999	cmp	%g5, 0x0c0		!   so we mask lower bits & compare to 0b 0000 1100 0000
2000	bne,pt	%icc, winfixspill	! Dump our trap frame -- we will retry the fill when the page is loaded
2001	 cmp	%g5, 0x080		!   window spill traps are all 0b 0000 10xx xxxx
2002
2003	!!
2004	!! This was a fill
2005	!!
2006#ifdef TRAPSTATS
2007	set	_C_LABEL(wfill), %g1
2008	lduw	[%g1], %g5
2009	inc	%g5
2010	stw	%g5, [%g1]
2011#endif
2012	btst	TSTATE_PRIV, %g4	! User mode?
2013	and	%g4, CWP, %g5		! %g4 = %cwp of trap
2014	wrpr	%g7, 0, %tt
2015	bz,a,pt	%icc, datafault		! We were in user mode -- normal fault
2016	 wrpr	%g5, %cwp		! Restore cwp from before fill trap -- regs should now be consistent
2017
2018	/*
2019	 * We're in a pickle here.  We were trying to return to user mode
2020	 * and the restore of the user window failed, so now we have one valid
2021	 * kernel window and a user window state.  If we do a TRAP_SETUP() now,
2022	 * our kernel window will be considered a user window and cause a
2023	 * fault when we try to save it later due to an invalid user address.
2024	 * If we return to where we faulted, our window state will not be valid
2025	 * and we will fault trying to enter user with our primary context of zero.
2026	 *
2027	 * What we'll do is arrange to have us return to return_from_trap so we will
2028	 * start the whole business over again.  But first, switch to a kernel window
2029	 * setup.  Let's see, canrestore and otherwin are zero.  Set WSTATE_KERN and
2030	 * make sure we're in kernel context and we're done.
2031	 */
2032
2033#ifdef TRAPSTATS
2034	set	_C_LABEL(kwfill), %g4
2035	lduw	[%g4], %g7
2036	inc	%g7
2037	stw	%g7, [%g4]
2038#endif
2039#if 0 /* Need to switch over to new stuff to fix WDR bug */
2040	wrpr	%g5, %cwp				! Restore cwp from before fill trap -- regs should now be consistent
2041	wrpr	%g2, %g0, %tl				! Restore trap level -- we need to reuse it
2042	set	return_from_trap, %g4			! XXX - need to set %g1 to tstate
2043	set	CTX_PRIMARY, %g7
2044	wrpr	%g4, 0, %tpc
2045	stxa	%g0, [%g7] ASI_DMMU
2046	inc	4, %g4
2047	membar	#Sync
2048	flush	%g4					! Isn't this convenient?
2049	wrpr	%g0, WSTATE_KERN, %wstate
2050	wrpr	%g0, 0, %canrestore			! These should be zero but
2051	wrpr	%g0, 0, %otherwin			! clear them just in case
2052	rdpr	%ver, %g5
2053	and	%g5, CWP, %g5
2054	wrpr	%g0, 0, %cleanwin
2055	dec	1, %g5					! NWINDOWS-1-1
2056	wrpr	%g5, 0, %cansave			! Invalidate all windows
2057!	flushw						! DEBUG
2058	ba,pt	%icc, datafault
2059	 wrpr	%g4, 0, %tnpc
2060#else
2061	wrpr	%g2, %g0, %tl				! Restore trap level
2062	cmp	%g2, 3
2063	tne	%icc, 1
2064	rdpr	%tt, %g5
2065	wrpr	%g0, 1, %tl				! Revert to TL==1 XXX what if this wasn't in rft_user? Oh well.
2066	wrpr	%g5, %g0, %tt				! Set trap type correctly
2067/*
2068 * Here we need to implement the beginning of datafault.
2069 * TRAP_SETUP expects to come from either kernel mode or
2070 * user mode with at least one valid register window.  It
2071 * will allocate a trap frame, save the out registers, and
2072 * fix the window registers to think we have one user
2073 * register window.
2074 *
2075 * However, under these circumstances we don't have any
2076 * valid register windows, so we need to clean up the window
2077 * registers to prevent garbage from being saved to either
2078 * the user stack or the PCB before calling the datafault
2079 * handler.
2080 *
2081 * We could simply jump to datafault if we could somehow
2082 * make the handler issue a `saved' instruction immediately
2083 * after creating the trapframe.
2084 *
2085 * The following is duplicated from datafault:
2086 */
2087#ifdef TRAPS_USE_IG
2088	wrpr	%g0, PSTATE_KERN|PSTATE_IG, %pstate	! We need to save volatile stuff to interrupt globals
2089#else
2090	wrpr	%g0, PSTATE_KERN|PSTATE_AG, %pstate	! We need to save volatile stuff to alternate globals
2091#endif
2092	wr	%g0, ASI_DMMU, %asi			! We need to re-load trap info
2093	ldxa	[%g0 + TLB_TAG_ACCESS] %asi, %g1	! Get fault address from tag access register
2094	ldxa	[SFAR] %asi, %g2			! sync virt addr; must be read first
2095	ldxa	[SFSR] %asi, %g3			! get sync fault status register
2096	stxa	%g0, [SFSR] %asi			! Clear out fault now
2097
2098	TRAP_SETUP(-CC64FSZ-TF_SIZE)
2099	saved						! Blow away that one register window we didn't ever use.
2100	ba,a,pt	%icc, Ldatafault_internal		! Now we should return directly to user mode
2101	 nop
2102#endif
2103winfixspill:
2104	bne,a,pt	%xcc, datafault			! Was not a spill -- handle it normally
2105	 wrpr	%g2, 0, %tl				! Restore trap level for now XXXX
2106
2107	!!
2108	!! This was a spill
2109	!!
2110#if 1
2111	btst	TSTATE_PRIV, %g4	! From user mode?
2112	wrpr	%g2, 0, %tl		! We need to load the fault type so we can
2113	rdpr	%tt, %g5		! overwrite the lower trap and get it to the fault handler
2114	wrpr	%g1, 0, %tl
2115	wrpr	%g5, 0, %tt		! Copy over trap type for the fault handler
2116	and	%g4, CWP, %g5		! find %cwp from trap
2117	be,a,pt	%xcc, datafault		! Let's do a regular datafault.  When we try a save in datafault we'll
2118	 wrpr	%g5, 0, %cwp		!  return here and write out all dirty windows.
2119#endif
2120	wrpr	%g2, 0, %tl				! Restore trap level for now XXXX
2121	LDPTR	[%g6 + %lo(CPCB)], %g6	! This is in the locked TLB and should not fault
2122#ifdef TRAPSTATS
2123	set	_C_LABEL(wspill), %g7
2124	lduw	[%g7], %g5
2125	inc	%g5
2126	stw	%g5, [%g7]
2127#endif
2128
2129	/*
2130	 * Traverse kernel map to find paddr of cpcb and only us ASI_PHYS_CACHED to
2131	 * prevent any faults while saving the windows.  BTW if it isn't mapped, we
2132	 * will trap and hopefully panic.
2133	 */
2134
2135!	ba	0f					! DEBUG -- don't use phys addresses
2136	 wr	%g0, ASI_NUCLEUS, %asi			! In case of problems finding PA
2137	sethi	%hi(CPUINFO_VA+CI_CTXBUSY), %g1
2138	LDPTR	[%g1 + %lo(CPUINFO_VA+CI_CTXBUSY)], %g1	! Load start of ctxbusy
2139#ifdef DEBUG
2140	srax	%g6, HOLESHIFT, %g7			! Check for valid address
2141	brz,pt	%g7, 1f					! Should be zero or -1
2142	 addcc	%g7, 1, %g7					! Make -1 -> 0
2143	tnz	%xcc, 1					! Invalid address??? How did this happen?
21441:
2145#endif
2146	srlx	%g6, STSHIFT, %g7
2147	ldx	[%g1], %g1				! Load pointer to kernel_pmap
2148	and	%g7, STMASK, %g7
2149	sll	%g7, 3, %g7
2150	add	%g7, %g1, %g1
2151	DLFLUSH(%g1,%g7)
2152	ldxa	[%g1] ASI_PHYS_CACHED, %g1		! Load pointer to directory
2153	DLFLUSH2(%g7)
2154
2155	srlx	%g6, PDSHIFT, %g7			! Do page directory
2156	and	%g7, PDMASK, %g7
2157	sll	%g7, 3, %g7
2158	brz,pn	%g1, 0f
2159	 add	%g7, %g1, %g1
2160	DLFLUSH(%g1,%g7)
2161	ldxa	[%g1] ASI_PHYS_CACHED, %g1
2162	DLFLUSH2(%g7)
2163
2164	srlx	%g6, PTSHIFT, %g7			! Convert to ptab offset
2165	and	%g7, PTMASK, %g7
2166	brz	%g1, 0f
2167	 sll	%g7, 3, %g7
2168	add	%g1, %g7, %g7
2169	DLFLUSH(%g7,%g1)
2170	ldxa	[%g7] ASI_PHYS_CACHED, %g7		! This one is not
2171	DLFLUSH2(%g1)
2172	brgez	%g7, 0f
2173	 srlx	%g7, PGSHIFT, %g7			! Isolate PA part
2174	sll	%g6, 32-PGSHIFT, %g6			! And offset
2175	sllx	%g7, PGSHIFT+23, %g7			! There are 23 bits to the left of the PA in the TTE
2176	srl	%g6, 32-PGSHIFT, %g6
2177	srax	%g7, 23, %g7
2178	or	%g7, %g6, %g6				! Then combine them to form PA
2179
2180	wr	%g0, ASI_PHYS_CACHED, %asi		! Use ASI_PHYS_CACHED to prevent possible page faults
21810:
2182	/*
2183	 * Now save all user windows to cpcb.
2184	 */
2185#ifdef NOTDEF_DEBUG
2186	add	%g6, PCB_NSAVED, %g7
2187	DLFLUSH(%g7,%g5)
2188	lduba	[%g6 + PCB_NSAVED] %asi, %g7		! make sure that pcb_nsaved
2189	DLFLUSH2(%g5)
2190	brz,pt	%g7, 1f					! is zero, else
2191	 nop
2192	wrpr	%g0, 4, %tl
2193	sir						! Force a watchdog
21941:
2195#endif
2196	rdpr	%otherwin, %g7
2197	brnz,pt	%g7, 1f
2198	 rdpr	%canrestore, %g5
2199	rdpr	%cansave, %g1
2200	add	%g5, 1, %g7				! add the %cwp window to the list to save
2201!	movrnz	%g1, %g5, %g7				! If we're issuing a save
2202!	mov	%g5, %g7				! DEBUG
2203	wrpr	%g0, 0, %canrestore
2204	wrpr	%g7, 0, %otherwin			! Still in user mode -- need to switch to kernel mode
22051:
2206	mov	%g7, %g1
2207	add	%g6, PCB_NSAVED, %g7
2208	DLFLUSH(%g7,%g5)
2209	lduba	[%g6 + PCB_NSAVED] %asi, %g7		! Start incrementing pcb_nsaved
2210	DLFLUSH2(%g5)
2211
2212#ifdef DEBUG
2213	wrpr	%g0, 5, %tl
2214#endif
2215	mov	%g6, %g5
2216	brz,pt	%g7, winfixsave				! If it's in use, panic
2217	 saved						! frob window registers
2218
2219	/* PANIC */
2220!	sir						! Force a watchdog
2221#ifdef DEBUG
2222	wrpr	%g2, 0, %tl
2223#endif
2224	mov	%g7, %o2
2225	rdpr	%ver, %o1
2226	sethi	%hi(2f), %o0
2227	and	%o1, CWP, %o1
2228	wrpr	%g0, %o1, %cleanwin
2229	dec	1, %o1
2230	wrpr	%g0, %o1, %cansave			! kludge away any more window problems
2231	wrpr	%g0, 0, %canrestore
2232	wrpr	%g0, 0, %otherwin
2233	or	%lo(2f), %o0, %o0
2234	wrpr	%g0, WSTATE_KERN, %wstate
2235	set	PANICSTACK-CC64FSZ-STKB, %sp
2236	ta	1; nop					! This helps out traptrace.
2237	call	_C_LABEL(panic)				! This needs to be fixed properly but we should panic here
2238	 mov	%g1, %o1
2239	NOTREACHED
2240	.data
22412:
2242	.asciz	"winfault: double invalid window at %p, nsaved=%d"
2243	_ALIGN
2244	.text
22453:
2246	saved
2247	save
2248winfixsave:
2249	stxa	%l0, [%g5 + PCB_RW + ( 0*8)] %asi	! Save the window in the pcb, we can schedule other stuff in here
2250	stxa	%l1, [%g5 + PCB_RW + ( 1*8)] %asi
2251	stxa	%l2, [%g5 + PCB_RW + ( 2*8)] %asi
2252	stxa	%l3, [%g5 + PCB_RW + ( 3*8)] %asi
2253	stxa	%l4, [%g5 + PCB_RW + ( 4*8)] %asi
2254	stxa	%l5, [%g5 + PCB_RW + ( 5*8)] %asi
2255	stxa	%l6, [%g5 + PCB_RW + ( 6*8)] %asi
2256	stxa	%l7, [%g5 + PCB_RW + ( 7*8)] %asi
2257
2258	stxa	%i0, [%g5 + PCB_RW + ( 8*8)] %asi
2259	stxa	%i1, [%g5 + PCB_RW + ( 9*8)] %asi
2260	stxa	%i2, [%g5 + PCB_RW + (10*8)] %asi
2261	stxa	%i3, [%g5 + PCB_RW + (11*8)] %asi
2262	stxa	%i4, [%g5 + PCB_RW + (12*8)] %asi
2263	stxa	%i5, [%g5 + PCB_RW + (13*8)] %asi
2264	stxa	%i6, [%g5 + PCB_RW + (14*8)] %asi
2265	stxa	%i7, [%g5 + PCB_RW + (15*8)] %asi
2266
2267!	rdpr	%otherwin, %g1	! Check to see if we's done
2268	dec	%g1
2269	wrpr	%g0, 7, %cleanwin			! BUGBUG -- we should not hardcode this, but I have no spare globals
2270	inc	16*8, %g5				! Move to next window
2271	inc	%g7					! inc pcb_nsaved
2272	brnz,pt	%g1, 3b
2273	 stxa	%o6, [%g5 + PCB_RW + (14*8)] %asi	! Save %sp so we can write these all out
2274
2275	/* fix up pcb fields */
2276	stba	%g7, [%g6 + PCB_NSAVED] %asi		! cpcb->pcb_nsaved = n
2277#if 0
2278	mov	%g7, %g5				! fixup window registers
22795:
2280	dec	%g5
2281	brgz,a,pt	%g5, 5b
2282	 restore
2283#ifdef NOT_DEBUG
2284	rdpr	%wstate, %g5				! DEBUG
2285	wrpr	%g0, WSTATE_KERN, %wstate		! DEBUG
2286	wrpr	%g0, 4, %tl
2287	rdpr	%cansave, %g7
2288	rdpr	%canrestore, %g6
2289	flushw						! DEBUG
2290	wrpr	%g2, 0, %tl
2291	wrpr	%g5, 0, %wstate				! DEBUG
2292#endif
2293#else
2294	/*
2295	 * We just issued a bunch of saves, so %cansave is now 0,
2296	 * probably (if we were doing a flushw then we may have
2297	 * come in with only partially full register windows and
2298	 * it may not be 0).
2299	 *
2300	 * %g7 contains the count of the windows we just finished
2301	 * saving.
2302	 *
2303	 * What we need to do now is move some of the windows from
2304	 * %canrestore to %cansave.  What we should do is take
2305	 * min(%canrestore, %g7) and move that over to %cansave.
2306	 *
2307	 * %g7 is the number of windows we flushed, so we should
2308	 * use that as a base.  Clear out %otherwin, set %cansave
2309	 * to min(%g7, NWINDOWS - 2), set %cleanwin to %canrestore
2310	 * + %cansave and the rest follows:
2311	 *
2312	 * %otherwin = 0
2313	 * %cansave = NWINDOWS - 2 - %canrestore
2314	 */
2315	wrpr	%g0, 0, %otherwin
2316	rdpr	%canrestore, %g1
2317	sub	%g1, %g7, %g1				! Calculate %canrestore - %g7
2318	movrlz	%g1, %g0, %g1				! Clamp at zero
2319	wrpr	%g1, 0, %canrestore			! This is the new canrestore
2320	rdpr	%ver, %g5
2321	and	%g5, CWP, %g5				! NWINDOWS-1
2322	dec	%g5					! NWINDOWS-2
2323	wrpr	%g5, 0, %cleanwin			! Set cleanwin to max, since we're in-kernel
2324	sub	%g5, %g1, %g5				! NWINDOWS-2-%canrestore
2325	wrpr	%g5, 0, %cansave
2326#ifdef NOT_DEBUG
2327	rdpr	%wstate, %g5				! DEBUG
2328	wrpr	%g0, WSTATE_KERN, %wstate		! DEBUG
2329	wrpr	%g0, 4, %tl
2330	flushw						! DEBUG
2331	wrpr	%g2, 0, %tl
2332	wrpr	%g5, 0, %wstate				! DEBUG
2333#endif
2334#endif
2335
2336#ifdef NOTDEF_DEBUG
2337	set	panicstack-CC64FSZ, %g1
2338	save	%g1, 0, %sp
2339	GLOBTOLOC
2340	rdpr	%wstate, %l0
2341	wrpr	%g0, WSTATE_KERN, %wstate
2342	set	8f, %o0
2343	mov	%g7, %o1
2344	call	printf
2345	 mov	%g5, %o2
2346	wrpr	%l0, 0, %wstate
2347	LOCTOGLOB
2348	restore
2349	.data
23508:
2351	.asciz	"winfix: spill fixup\n"
2352	_ALIGN
2353	.text
2354#endif
2355!	rdpr	%tl, %g2				! DEBUG DEBUG -- did we trap somewhere?
2356	sub	%g2, 1, %g1
2357	rdpr	%tt, %g2
2358	wrpr	%g1, 0, %tl				! We will not attempt to re-execute the spill, so dump our trap frame permanently
2359	wrpr	%g2, 0, %tt				! Move trap type from fault frame here, overwriting spill
2360
2361	/* Did we save a user or kernel window ? */
2362!	srax	%g3, 48, %g5				! User or kernel store? (TAG TARGET)
2363	sllx	%g3, (64-13), %g5			! User or kernel store? (TAG ACCESS)
2364	sethi	%hi(dcache_size), %g7
2365	ld	[%g7 + %lo(dcache_size)], %g7
2366	sethi	%hi(dcache_line_size), %g6
2367	ld	[%g6 + %lo(dcache_line_size)], %g6
2368	brnz,pt	%g5, 1f					! User fault -- save windows to pcb
2369	 sub	%g7, %g6, %g7
2370
2371	and	%g4, CWP, %g4				! %g4 = %cwp of trap
2372	wrpr	%g4, 0, %cwp				! Kernel fault -- restore %cwp and force and trap to debugger
2373	!!
2374	!! Here we managed to fault trying to access a kernel window
2375	!! This is a bug.  Switch to the interrupt stack if we aren't
2376	!! there already and then trap into the debugger or panic.
2377	!!
2378	sethi	%hi(EINTSTACK-BIAS), %g6
2379	btst	1, %sp
2380	bnz,pt	%icc, 0f
2381	 mov	%sp, %g1
2382	add	%sp, -BIAS, %g1
23830:
2384	or	%g6, %lo(EINTSTACK-BIAS), %g6
2385	set	(EINTSTACK-INTSTACK), %g7	! XXXXXXXXXX This assumes kernel addresses are unique from user addresses
2386	sub	%g6, %g1, %g2				! Determine if we need to switch to intr stack or not
2387	dec	%g7					! Make it into a mask
2388	andncc	%g2, %g7, %g0				! XXXXXXXXXX This assumes kernel addresses are unique from user addresses */ \
2389	movz	%xcc, %g1, %g6				! Stay on interrupt stack?
2390	add	%g6, -CCFSZ, %g6			! Allocate a stack frame
2391	mov	%sp, %l6				! XXXXX Save old stack pointer
2392	mov	%g6, %sp
2393	ta	1; nop					! Enter debugger
2394	NOTREACHED
23951:
2396#if 1
2397	/* Now we need to blast away the D$ to make sure we're in sync */
2398	stxa	%g0, [%g7] ASI_DCACHE_TAG
2399	brnz,pt	%g7, 1b
2400	 sub	%g7, %g6, %g7
2401#endif
2402
2403#ifdef NOTDEF_DEBUG
2404	set	panicstack-CC64FSZ, %g5
2405	save	%g5, 0, %sp
2406	GLOBTOLOC
2407	rdpr	%wstate, %l0
2408	wrpr	%g0, WSTATE_KERN, %wstate
2409	set	8f, %o0
2410	call	printf
2411	 mov	%fp, %o1
2412	wrpr	%l0, 0, %wstate
2413	LOCTOGLOB
2414	restore
2415	.data
24168:
2417	.asciz	"winfix: kernel spill retry\n"
2418	_ALIGN
2419	.text
2420#endif
2421#ifdef TRAPSTATS
2422	set	_C_LABEL(wspillskip), %g4
2423	lduw	[%g4], %g5
2424	inc	%g5
2425	stw	%g5, [%g4]
2426#endif
2427	/*
2428	 * If we had WSTATE_KERN then we had at least one valid kernel window.
2429	 * We should re-execute the trapping save.
2430	 */
2431	rdpr	%wstate, %g3
2432	mov	%g3, %g3
2433	cmp	%g3, WSTATE_KERN
2434	bne,pt	%icc, 1f
2435	 nop
2436	retry						! Now we can complete the save
24371:
2438	/*
2439	 * Since we had a WSTATE_USER, we had no valid kernel windows.  This should
2440	 * only happen inside TRAP_SETUP or INTR_SETUP. Emulate
2441	 * the instruction, clean up the register windows, then done.
2442	 */
2443	rdpr	%cwp, %g1
2444	inc	%g1
2445	rdpr	%tstate, %g2
2446	wrpr	%g1, %cwp
2447	andn	%g2, CWP, %g2
2448	wrpr	%g1, %g2, %tstate
2449#ifdef TRAPS_USE_IG
2450	wrpr	%g0, PSTATE_KERN|PSTATE_IG, %pstate	! DEBUG
2451#else
2452	wrpr	%g0, PSTATE_KERN|PSTATE_AG, %pstate
2453#endif
2454	mov	%g6, %sp
2455	done
2456
2457/*
2458 * Each memory data access fault, from user or kernel mode,
2459 * comes here.
2460 *
2461 * We will assume that %pil is not lost so we won't bother to save it
2462 * unless we're in an interrupt handler.
2463 *
2464 * On entry:
2465 *	We are on one of the alternate set of globals
2466 *	%g1 = MMU tag target
2467 *	%g2 = %tl
2468 *
2469 * On return:
2470 *
2471 */
2472datafault:
2473#ifdef TRAPS_USE_IG
2474	wrpr	%g0, PSTATE_KERN|PSTATE_IG, %pstate	! We need to save volatile stuff to interrupt globals
2475#else
2476	wrpr	%g0, PSTATE_KERN|PSTATE_AG, %pstate	! We need to save volatile stuff to alternate globals
2477#endif
2478	wr	%g0, ASI_DMMU, %asi			! We need to re-load trap info
2479	ldxa	[%g0 + TLB_TAG_ACCESS] %asi, %g1	! Get fault address from tag access register
2480	ldxa	[SFAR] %asi, %g2			! sync virt addr; must be read first
2481	ldxa	[SFSR] %asi, %g3			! get sync fault status register
2482	stxa	%g0, [SFSR] %asi			! Clear out fault now
2483
2484	TRAP_SETUP(-CC64FSZ-TF_SIZE)
2485Ldatafault_internal:
2486	INCR64(CPUINFO_VA+CI_NFAULT)			! cnt.v_faults++ (clobbers %o0,%o1)
2487!	ldx	[%sp + CC64FSZ + STKB + TF_FAULT], %g1	! DEBUG make sure this has not changed
2488	mov	%g1, %o0				! Move these to the out regs so we can save the globals
2489	mov	%g2, %o4
2490	mov	%g3, %o5
2491
2492	ldxa	[%g0] ASI_AFAR, %o2			! get async fault address
2493	ldxa	[%g0] ASI_AFSR, %o3			! get async fault status
2494	mov	-1, %g7
2495	stxa	%g7, [%g0] ASI_AFSR			! And clear this out, too
2496
2497	wrpr	%g0, PSTATE_KERN, %pstate		! Get back to normal globals
2498
2499	stx	%g1, [%sp + CC64FSZ + STKB + TF_G + (1*8)]	! save g1
2500	rdpr	%tt, %o1					! find out what trap brought us here
2501	stx	%g2, [%sp + CC64FSZ + STKB + TF_G + (2*8)]	! save g2
2502	rdpr	%tstate, %g1
2503	stx	%g3, [%sp + CC64FSZ + STKB + TF_G + (3*8)]	! (sneak g3 in here)
2504	rdpr	%tpc, %g2
2505	stx	%g4, [%sp + CC64FSZ + STKB + TF_G + (4*8)]	! sneak in g4
2506	rdpr	%tnpc, %g3
2507	stx	%g5, [%sp + CC64FSZ + STKB + TF_G + (5*8)]	! sneak in g5
2508	mov	%g2, %o7					! Make the fault address look like the return address
2509	stx	%g6, [%sp + CC64FSZ + STKB + TF_G + (6*8)]	! sneak in g6
2510	rd	%y, %g5						! save y
2511	stx	%g7, [%sp + CC64FSZ + STKB + TF_G + (7*8)]	! sneak in g7
2512
2513	sth	%o1, [%sp + CC64FSZ + STKB + TF_TT]
2514	stx	%g1, [%sp + CC64FSZ + STKB + TF_TSTATE]		! set tf.tf_psr, tf.tf_pc
2515	stx	%g2, [%sp + CC64FSZ + STKB + TF_PC]		! set tf.tf_npc
2516	stx	%g3, [%sp + CC64FSZ + STKB + TF_NPC]
2517
2518	rdpr	%pil, %g4
2519	stb	%g4, [%sp + CC64FSZ + STKB + TF_PIL]
2520	stb	%g4, [%sp + CC64FSZ + STKB + TF_OLDPIL]
2521
2522#if 1
2523	rdpr	%tl, %g7
2524	dec	%g7
2525	movrlz	%g7, %g0, %g7
2526	wrpr	%g0, %g7, %tl		! Revert to kernel mode
2527#else
2528	wrpr	%g0, 0, %tl		! Revert to kernel mode
2529#endif
2530	/* Finish stackframe, call C trap handler */
2531	flushw						! Get this clean so we won't take any more user faults
2532#ifdef NOTDEF_DEBUG
2533	set	CPCB, %o7
2534	LDPTR	[%o7], %o7
2535	ldub	[%o7 + PCB_NSAVED], %o7
2536	brz,pt	%o7, 2f
2537	 nop
2538	save	%sp, -CC64FSZ, %sp
2539	set	1f, %o0
2540	call printf
2541	 mov	%i7, %o1
2542	ta	1; nop
2543	 restore
2544	.data
25451:	.asciz	"datafault: nsaved = %d\n"
2546	_ALIGN
2547	.text
25482:
2549#endif
2550	!! In the EMBEDANY memory model %g4 points to the start of the data segment.
2551	!! In our case we need to clear it before calling any C-code
2552	clr	%g4
2553
2554	/*
2555	 * Right now the registers have the following values:
2556	 *
2557	 *	%o0 -- MMU_TAG_ACCESS
2558	 *	%o1 -- TT
2559	 *	%o2 -- afar
2560	 *	%o3 -- afsr
2561	 *	%o4 -- sfar
2562	 *	%o5 -- sfsr
2563	 */
2564
2565	cmp	%o1, T_DATA_ERROR
2566	st	%g5, [%sp + CC64FSZ + STKB + TF_Y]
2567	wr	%g0, ASI_PRIMARY_NOFAULT, %asi	! Restore default ASI
2568	be,pn	%icc, data_error
2569	 wrpr	%g0, PSTATE_INTR, %pstate	! reenable interrupts
2570
2571	mov	%o0, %o3			! (argument: trap address)
2572	mov	%g2, %o2			! (argument: trap pc)
2573	call	_C_LABEL(data_access_fault)	! data_access_fault(&tf, type,
2574						!	pc, addr, sfva, sfsr)
2575	 add	%sp, CC64FSZ + STKB, %o0	! (argument: &tf)
2576
2577data_recover:
2578#ifdef TRAPSTATS
2579	set	_C_LABEL(uintrcnt), %g1
2580	stw	%g0, [%g1]
2581	set	_C_LABEL(iveccnt), %g1
2582	stw	%g0, [%g1]
2583#endif
2584	wrpr	%g0, PSTATE_KERN, %pstate		! disable interrupts
2585	b	return_from_trap			! go return
2586	 ldx	[%sp + CC64FSZ + STKB + TF_TSTATE], %g1		! Load this for return_from_trap
2587	NOTREACHED
2588
2589data_error:
2590	call	_C_LABEL(data_access_error)	! data_access_error(&tf, type,
2591						!	afva, afsr, sfva, sfsr)
2592	 add	%sp, CC64FSZ + STKB, %o0	! (argument: &tf)
2593	ba	data_recover
2594	 nop
2595	NOTREACHED
2596
2597/*
2598 * Each memory instruction access fault from a fast access handler comes here.
2599 * We will quickly check if this is an original prom mapping before going
2600 * to the generic fault handler
2601 *
2602 * We will assume that %pil is not lost so we won't bother to save it
2603 * unless we're in an interrupt handler.
2604 *
2605 * On entry:
2606 *	We are on one of the alternate set of globals
2607 *	%g1 = MMU tag target
2608 *	%g2 = TSB entry ptr
2609 *	%g3 = TLB Tag Access
2610 *
2611 * On return:
2612 *
2613 */
2614
2615	ICACHE_ALIGN
2616instr_miss:
2617#ifdef TRAPSTATS
2618	set	_C_LABEL(ktmiss), %g3
2619	set	_C_LABEL(utmiss), %g4
2620	rdpr	%tl, %g6
2621	dec	%g6
2622	movrz	%g6, %g4, %g3
2623	lduw	[%g3], %g4
2624	inc	%g4
2625	stw	%g4, [%g3]
2626#endif
2627	mov	TLB_TAG_ACCESS, %g3			! Get real fault page
2628	sethi	%hi(0x1fff), %g7			! 8K context mask
2629	ldxa	[%g3] ASI_IMMU, %g3			! from tag access register
2630	sethi	%hi(CPUINFO_VA+CI_CTXBUSY), %g4
2631	or	%g7, %lo(0x1fff), %g7
2632	LDPTR	[%g4 + %lo(CPUINFO_VA+CI_CTXBUSY)], %g4
2633	srax	%g3, HOLESHIFT, %g5			! Check for valid address
2634	and	%g3, %g7, %g6				! Isolate context
2635	sllx	%g6, 3, %g6				! Make it into an offset into ctxbusy
2636	inc	%g5					! (0 or -1) -> (1 or 0)
2637	ldx	[%g4+%g6], %g4				! Load up our page table.
2638#ifdef DEBUG
2639	/* Make sure we don't try to replace a kernel translation */
2640	/* This should not be necessary */
2641	brnz,pt	%g6, 1f					! If user context continue miss
2642	sethi	%hi(KERNBASE), %g7			! Don't need %lo
2643	set	0x0800000, %g6				! 8MB
2644	sub	%g3, %g7, %g7
2645	cmp	%g7, %g6
2646	tlu	%xcc, 1; nop
26471:
2648#endif
2649	srlx	%g3, STSHIFT, %g6
2650	cmp	%g5, 1
2651	bgu,pn %xcc, textfault				! Error!
2652	 srlx	%g3, PDSHIFT, %g5
2653	and	%g6, STMASK, %g6
2654	sll	%g6, 3, %g6
2655	and	%g5, PDMASK, %g5
2656	nop
2657
2658	sll	%g5, 3, %g5
2659	add	%g6, %g4, %g4
2660	ldxa	[%g4] ASI_PHYS_CACHED, %g4
2661	srlx	%g3, PTSHIFT, %g6			! Convert to ptab offset
2662	and	%g6, PTMASK, %g6
2663	add	%g5, %g4, %g5
2664	brz,pn	%g4, textfault				! NULL entry? check somewhere else
2665	 nop
2666
2667	ldxa	[%g5] ASI_PHYS_CACHED, %g4
2668	sll	%g6, 3, %g6
2669	brz,pn	%g4, textfault				! NULL entry? check somewhere else
2670	 add	%g6, %g4, %g6
26711:
2672	ldxa	[%g6] ASI_PHYS_CACHED, %g4
2673	brgez,pn %g4, textfault
2674	 nop
2675
2676	/* Check if it's an executable mapping. */
2677	andcc	%g4, SUN4U_TTE_EXEC, %g0
2678	bz,pn	%xcc, textfault
2679	 nop
2680
2681	or	%g4, SUN4U_TTE_ACCESS, %g7			! Update accessed bit
2682	btst	SUN4U_TTE_ACCESS, %g4				! Need to update access git?
2683	bne,pt	%xcc, 1f
2684	 nop
2685	casxa	[%g6] ASI_PHYS_CACHED, %g4, %g7		!  and store it
2686	cmp	%g4, %g7
2687	bne,pn	%xcc, 1b
2688	 or	%g4, SUN4U_TTE_ACCESS, %g4			! Update accessed bit
26891:
2690	stx	%g1, [%g2]				! Update TSB entry tag
2691	stx	%g4, [%g2+8]				! Update TSB entry data
2692	stxa	%g4, [%g0] ASI_IMMU_DATA_IN		! Enter new mapping
2693	membar	#Sync
2694	CLRTT
2695	retry
2696	NOTREACHED
2697	!!
2698	!!  Check our prom mappings -- temporary
2699	!!
2700
2701/*
2702 * Each memory text access fault, from user or kernel mode,
2703 * comes here.
2704 *
2705 * We will assume that %pil is not lost so we won't bother to save it
2706 * unless we're in an interrupt handler.
2707 *
2708 * On entry:
2709 *	We are on one of the alternate set of globals
2710 *	%g1 = MMU tag target
2711 *	%g2 = %tl
2712 *	%g3 = %tl - 1
2713 *
2714 * On return:
2715 *
2716 */
2717
2718textfault:
2719#ifdef TRAPS_USE_IG
2720	wrpr	%g0, PSTATE_KERN|PSTATE_IG, %pstate	! We need to save volatile stuff to interrupt globals
2721#else
2722	wrpr	%g0, PSTATE_KERN|PSTATE_AG, %pstate	! We need to save volatile stuff to alternate globals
2723#endif
2724	wr	%g0, ASI_IMMU, %asi
2725	ldxa	[%g0 + TLB_TAG_ACCESS] %asi, %g1	! Get fault address from tag access register
2726	ldxa	[SFSR] %asi, %g3			! get sync fault status register
2727	membar	#LoadStore
2728	stxa	%g0, [SFSR] %asi			! Clear out old info
2729
2730	TRAP_SETUP(-CC64FSZ-TF_SIZE)
2731	INCR64(CPUINFO_VA+CI_NFAULT)			! cnt.v_faults++ (clobbers %o0,%o1)
2732
2733	mov	%g3, %o3
2734
2735	wrpr	%g0, PSTATE_KERN, %pstate		! Switch to normal globals
2736	ldxa	[%g0] ASI_AFSR, %o4			! get async fault status
2737	ldxa	[%g0] ASI_AFAR, %o5			! get async fault address
2738	mov	-1, %o0
2739	stxa	%o0, [%g0] ASI_AFSR			! Clear this out
2740	stx	%g1, [%sp + CC64FSZ + STKB + TF_G + (1*8)]	! save g1
2741	stx	%g2, [%sp + CC64FSZ + STKB + TF_G + (2*8)]	! save g2
2742	stx	%g3, [%sp + CC64FSZ + STKB + TF_G + (3*8)]	! (sneak g3 in here)
2743	rdpr	%tt, %o1					! Find out what caused this trap
2744	stx	%g4, [%sp + CC64FSZ + STKB + TF_G + (4*8)]	! sneak in g4
2745	rdpr	%tstate, %g1
2746	stx	%g5, [%sp + CC64FSZ + STKB + TF_G + (5*8)]	! sneak in g5
2747	rdpr	%tpc, %o2					! sync virt addr; must be read first
2748	stx	%g6, [%sp + CC64FSZ + STKB + TF_G + (6*8)]	! sneak in g6
2749	rdpr	%tnpc, %g3
2750	stx	%g7, [%sp + CC64FSZ + STKB + TF_G + (7*8)]	! sneak in g7
2751	rd	%y, %g5						! save y
2752
2753	/* Finish stackframe, call C trap handler */
2754	stx	%g1, [%sp + CC64FSZ + STKB + TF_TSTATE]		! set tf.tf_psr, tf.tf_pc
2755	sth	%o1, [%sp + CC64FSZ + STKB + TF_TT]		! debug
2756
2757	stx	%o2, [%sp + CC64FSZ + STKB + TF_PC]
2758	stx	%g3, [%sp + CC64FSZ + STKB + TF_NPC]		! set tf.tf_npc
2759
2760	rdpr	%pil, %g4
2761	stb	%g4, [%sp + CC64FSZ + STKB + TF_PIL]
2762	stb	%g4, [%sp + CC64FSZ + STKB + TF_OLDPIL]
2763
2764	rdpr	%tl, %g7
2765	dec	%g7
2766	movrlz	%g7, %g0, %g7
2767	wrpr	%g0, %g7, %tl		! Revert to kernel mode
2768
2769	wr	%g0, ASI_PRIMARY_NOFAULT, %asi		! Restore default ASI
2770	flushw						! Get rid of any user windows so we don't deadlock
2771
2772	!! In the EMBEDANY memory model %g4 points to the start of the data segment.
2773	!! In our case we need to clear it before calling any C-code
2774	clr	%g4
2775
2776	/* Use trap type to see what handler to call */
2777	cmp	%o1, T_INST_ERROR
2778	be,pn	%xcc, text_error
2779	 st	%g5, [%sp + CC64FSZ + STKB + TF_Y]		! set tf.tf_y
2780
2781	wrpr	%g0, PSTATE_INTR, %pstate	! reenable interrupts
2782	call	_C_LABEL(text_access_fault)	! mem_access_fault(&tf, type, pc, sfsr)
2783	 add	%sp, CC64FSZ + STKB, %o0	! (argument: &tf)
2784text_recover:
2785	wrpr	%g0, PSTATE_KERN, %pstate	! disable interrupts
2786	b	return_from_trap		! go return
2787	 ldx	[%sp + CC64FSZ + STKB + TF_TSTATE], %g1	! Load this for return_from_trap
2788	NOTREACHED
2789
2790text_error:
2791	wrpr	%g0, PSTATE_INTR, %pstate	! reenable interrupts
2792	call	_C_LABEL(text_access_error)	! mem_access_fault(&tfm type, sfva [pc], sfsr,
2793						!		afva, afsr);
2794	 add	%sp, CC64FSZ + STKB, %o0	! (argument: &tf)
2795	ba	text_recover
2796	 nop
2797	NOTREACHED
2798
2799#ifdef SUN4V
2800
2801/*
2802 * Traps for sun4v.
2803 */
2804
2805sun4v_dtsb_miss:
2806	GET_MMFSA %g1				! MMU Fault status area
2807	add	%g1, 0x48, %g3
2808	LDPTRA	[%g3] ASI_PHYS_CACHED, %g3	! Data fault address
2809	add	%g1, 0x50, %g6
2810	LDPTRA	[%g6] ASI_PHYS_CACHED, %g6	! Data fault context
2811
2812	GET_CTXBUSY %g4
2813	sllx	%g6, 3, %g6			! Make it into an offset into ctxbusy
2814	LDPTR	[%g4 + %g6], %g4		! Load up our page table.
2815
2816	srax	%g3, HOLESHIFT, %g5		! Check for valid address
2817	brz,pt	%g5, 0f				! Should be zero or -1
2818	 inc	%g5				! Make -1 -> 0
2819	brnz,pn	%g5, sun4v_datatrap		! Error! In hole!
28200:
2821	srlx	%g3, STSHIFT, %g6
2822	and	%g6, STMASK, %g6		! Index into pm_segs
2823	sll	%g6, 3, %g6
2824	add	%g4, %g6, %g4
2825	LDPTRA	[%g4] ASI_PHYS_CACHED, %g4	! Load page directory pointer
2826	srlx	%g3, PDSHIFT, %g6
2827	and	%g6, PDMASK, %g6
2828	sll	%g6, 3, %g6
2829	brz,pn	%g4, sun4v_datatrap		! NULL entry? check somewhere else
2830	 add	%g4, %g6, %g4
2831	LDPTRA	[%g4] ASI_PHYS_CACHED, %g4	! Load page table pointer
2832
2833	srlx	%g3, PTSHIFT, %g6		! Convert to ptab offset
2834	and	%g6, PTMASK, %g6
2835	sll	%g6, 3, %g6
2836	brz,pn	%g4, sun4v_datatrap		! NULL entry? check somewhere else
2837	 add	%g4, %g6, %g6
28381:
2839	LDPTRA	[%g6] ASI_PHYS_CACHED, %g4	! Fetch TTE
2840	brgez,pn %g4, sun4v_datatrap		! Entry invalid?  Punt
2841	 or	%g4, SUN4V_TLB_ACCESS, %g7	! Update the access bit
2842
2843	btst	SUN4V_TLB_ACCESS, %g4		! Need to update access bit?
2844	bne,pt	%xcc, 2f
2845	 nop
2846	casxa	[%g6] ASI_PHYS_CACHED, %g4, %g7	! and write it out
2847	cmp	%g4, %g7
2848	bne,pn	%xcc, 1b
2849	 or	%g4, SUN4V_TLB_ACCESS, %g4	! Update the access bit
28502:
2851	GET_TSB_DMMU %g2
2852
2853	/* Construct TSB tag word. */
2854	add	%g1, 0x50, %g6
2855	LDPTRA	[%g6] ASI_PHYS_CACHED, %g6	! Data fault context
2856	mov	%g3, %g1			! Data fault address
2857	srlx	%g1, 22, %g1			! 63..22 of virt addr
2858	sllx	%g6, 48, %g6			! context_id in 63..48
2859	or	%g1, %g6, %g1			! construct TTE tag
2860	srlx	%g3, PTSHIFT, %g3
2861	sethi	%hi(_C_LABEL(tsbsize)), %g5
2862	mov	512, %g6
2863	ld	[%g5 + %lo(_C_LABEL(tsbsize))], %g5
2864	sllx	%g6, %g5, %g5			! %g5 = 512 << tsbsize = TSBENTS
2865	sub	%g5, 1, %g5			! TSBENTS -> offset
2866	and	%g3, %g5, %g3			! mask out TTE index
2867	sllx	%g3, 4, %g3			! TTE size is 16 bytes
2868	add	%g2, %g3, %g2			! location of TTE in ci_tsb_dmmu
2869
2870	membar	#StoreStore
2871
2872	STPTR	%g4, [%g2 + 8]			! store TTE data
2873	STPTR	%g1, [%g2]			! store TTE tag
2874
2875	retry
2876	NOTREACHED
2877
2878sun4v_tl1_dtsb_miss:
2879	GET_MMFSA %g1				! MMU Fault status area
2880	add	%g1, 0x48, %g3
2881	LDPTRA	[%g3] ASI_PHYS_CACHED, %g3	! Data fault address
2882	add	%g1, 0x50, %g6
2883	LDPTRA	[%g6] ASI_PHYS_CACHED, %g6	! Data fault context
2884
2885	GET_CTXBUSY %g4
2886	sllx	%g6, 3, %g6			! Make it into an offset into ctxbusy
2887	LDPTR	[%g4 + %g6], %g4		! Load up our page table.
2888
2889	srax	%g3, HOLESHIFT, %g5		! Check for valid address
2890	brz,pt	%g5, 0f				! Should be zero or -1
2891	 inc	%g5				! Make -1 -> 0
2892	brnz,pn	%g5, sun4v_tl1_ptbl_miss	! Error! In hole!
28930:
2894	srlx	%g3, STSHIFT, %g6
2895	and	%g6, STMASK, %g6		! Index into pm_segs
2896	sll	%g6, 3, %g6
2897	add	%g4, %g6, %g4
2898	LDPTRA	[%g4] ASI_PHYS_CACHED, %g4	! Load page directory pointer
2899	srlx	%g3, PDSHIFT, %g6
2900	and	%g6, PDMASK, %g6
2901	sll	%g6, 3, %g6
2902	brz,pn	%g4, sun4v_tl1_ptbl_miss	! NULL entry? check somewhere else
2903	 add	%g4, %g6, %g4
2904	LDPTRA	[%g4] ASI_PHYS_CACHED, %g4	! Load page table pointer
2905
2906	srlx	%g3, PTSHIFT, %g6		! Convert to ptab offset
2907	and	%g6, PTMASK, %g6
2908	sll	%g6, 3, %g6
2909	brz,pn	%g4, sun4v_tl1_ptbl_miss	! NULL entry? check somewhere else
2910	 add	%g4, %g6, %g6
29111:
2912	LDPTRA	[%g6] ASI_PHYS_CACHED, %g4	! Fetch TTE
2913	brgez,pn %g4, sun4v_tl1_ptbl_miss	! Entry invalid?  Punt
2914	 or	%g4, SUN4V_TLB_ACCESS, %g7	! Update the access bit
2915
2916	btst	SUN4V_TLB_ACCESS, %g4		! Need to update access bit?
2917	bne,pt	%xcc, 2f
2918	 nop
2919	casxa	[%g6] ASI_PHYS_CACHED, %g4, %g7	! and write it out
2920	cmp	%g4, %g7
2921	bne,pn	%xcc, 1b
2922	 or	%g4, SUN4V_TLB_ACCESS, %g4	! Update the access bit
29232:
2924	GET_TSB_DMMU %g2
2925
2926	/* Construct TSB tag word. */
2927	add	%g1, 0x50, %g6
2928	LDPTRA	[%g6] ASI_PHYS_CACHED, %g6	! Data fault context
2929	mov	%g3, %g1			! Data fault address
2930	srlx	%g1, 22, %g1			! 63..22 of virt addr
2931	sllx	%g6, 48, %g6			! context_id in 63..48
2932	or	%g1, %g6, %g1			! construct TTE tag
2933	srlx	%g3, PTSHIFT, %g3
2934	sethi	%hi(_C_LABEL(tsbsize)), %g5
2935	mov	512, %g6
2936	ld	[%g5 + %lo(_C_LABEL(tsbsize))], %g5
2937	sllx	%g6, %g5, %g5			! %g5 = 512 << tsbsize = TSBENTS
2938	sub	%g5, 1, %g5			! TSBENTS -> offset
2939	and	%g3, %g5, %g3			! mask out TTE index
2940	sllx	%g3, 4, %g3			! TTE size is 16 bytes
2941	add	%g2, %g3, %g2			! location of TTE in ci_tsb_dmmu
2942
2943	membar	#StoreStore
2944
2945	STPTR	%g4, [%g2 + 8]			! store TTE data
2946	STPTR	%g1, [%g2]			! store TTE tag
2947
2948	retry
2949	NOTREACHED
2950
2951sun4v_datatrap:
2952	GET_MMFSA %g3				! MMU Fault status area
2953	add	%g3, 0x48, %g1
2954	LDPTRA	[%g1] ASI_PHYS_CACHED, %g1	! Data fault address
2955	add	%g3, 0x50, %g2
2956	LDPTRA	[%g2] ASI_PHYS_CACHED, %g2	! Data fault context
2957
2958	TRAP_SETUP(-CC64FSZ-TF_SIZE)
2959	or	%g1, %g2, %o3
2960	mov	%g1, %o4
2961
2962	rdpr	%tt, %g4
2963	rdpr	%tstate, %g1
2964	rdpr	%tpc, %g2
2965	rdpr	%tnpc, %g3
2966
2967	stx	%g1, [%sp + CC64FSZ + BIAS + TF_TSTATE]
2968	mov	%g4, %o1		! (type)
2969	stx	%g2, [%sp + CC64FSZ + BIAS + TF_PC]
2970	rd	%y, %g5
2971	stx	%g3, [%sp + CC64FSZ + BIAS + TF_NPC]
2972	st	%g5, [%sp + CC64FSZ + BIAS + TF_Y]
2973	mov	%g2, %o2		! (pc)
2974	sth	%o1, [%sp + CC64FSZ + BIAS + TF_TT]! debug
2975
2976	cmp	%o1, T_FDMMU_PROT
2977	bne,pn	%icc, 1f
2978	 mov	SFSR_FV, %o5
2979	or	%o5, SFSR_W, %o5
2980
29811:
2982	NORMAL_GLOBALS_SUN4V
2983
2984	stx	%g1, [%sp + CC64FSZ + BIAS + TF_G + (1*8)]
2985	stx	%g2, [%sp + CC64FSZ + BIAS + TF_G + (2*8)]
2986	add	%sp, CC64FSZ + BIAS, %o0		! (&tf)
2987	stx	%g3, [%sp + CC64FSZ + BIAS + TF_G + (3*8)]
2988	stx	%g4, [%sp + CC64FSZ + BIAS + TF_G + (4*8)]
2989	stx	%g5, [%sp + CC64FSZ + BIAS + TF_G + (5*8)]
2990	rdpr	%pil, %g5
2991	stx	%g6, [%sp + CC64FSZ + BIAS + TF_G + (6*8)]
2992	stx	%g7, [%sp + CC64FSZ + BIAS + TF_G + (7*8)]
2993	stb	%g5, [%sp + CC64FSZ + BIAS + TF_PIL]
2994	stb	%g5, [%sp + CC64FSZ + BIAS + TF_OLDPIL]
2995
2996	/*
2997	 * Phew, ready to enable traps and call C code.
2998	 */
2999	wrpr	%g0, 0, %tl
3000
3001	wr	%g0, ASI_PRIMARY_NOFAULT, %asi	! Restore default ASI
3002	wrpr	%g0, PSTATE_INTR, %pstate	! traps on again
3003	call	_C_LABEL(data_access_fault)	! data_acces_fault(tf, type, ...)
3004	 nop
3005
3006	ba,a,pt	%icc, return_from_trap
3007	 nop
3008	NOTREACHED
3009
3010sun4v_tl0_dtsb_prot:
3011	GET_MMFSA %g1				! MMU Fault status area
3012	add	%g1, 0x48, %g3
3013	LDPTRA	[%g3] ASI_PHYS_CACHED, %g3	! Data fault address
3014	add	%g1, 0x50, %g6
3015	LDPTRA	[%g6] ASI_PHYS_CACHED, %g6	! Data fault context
3016
3017	GET_CTXBUSY %g4
3018	sllx	%g6, 3, %g6			! Make it into an offset into ctxbusy
3019	LDPTR	[%g4 + %g6], %g4		! Load up our page table.
3020
3021	srax	%g3, HOLESHIFT, %g5		! Check for valid address
3022	brz,pt	%g5, 0f				! Should be zero or -1
3023	 inc	%g5				! Make -1 -> 0
3024	brnz,pn	%g5, sun4v_datatrap		! Error! In hole!
30250:
3026	srlx	%g3, STSHIFT, %g6
3027	and	%g6, STMASK, %g6		! Index into pm_segs
3028	sll	%g6, 3, %g6
3029	add	%g4, %g6, %g4
3030	LDPTRA	[%g4] ASI_PHYS_CACHED, %g4	! Load page directory pointer
3031
3032	srlx	%g3, PDSHIFT, %g6
3033	and	%g6, PDMASK, %g6
3034	sll	%g6, 3, %g6
3035	brz,pn	%g4, sun4v_datatrap		! NULL entry? check somewhere else
3036	 add	%g4, %g6, %g4
3037	LDPTRA	[%g4] ASI_PHYS_CACHED, %g4	! Load page table pointer
3038
3039	srlx	%g3, PTSHIFT, %g6		! Convert to ptab offset
3040	and	%g6, PTMASK, %g6
3041	sll	%g6, 3, %g6
3042	brz,pn	%g4, sun4v_datatrap		! NULL entry? check somewhere else
3043	 add	%g4, %g6, %g6
30441:
3045	LDPTRA	[%g6] ASI_PHYS_CACHED, %g4	! Fetch TTE
3046	brgez,pn %g4, sun4v_datatrap		! Entry invalid?  Punt
3047	 or	%g4, SUN4V_TLB_MODIFY|SUN4V_TLB_ACCESS|SUN4V_TLB_W, %g7 ! Update the modified bit
3048
3049#	btst	SUN4V_TLB_REAL_W|SUN4V_TLB_W, %g4	! Is it a ref fault?
3050	mov	1, %g2
3051	sllx	%g2, 61, %g2			! %g2 is now SUN4V_TLB_REAL_W
3052	or	%g2, SUN4V_TLB_W, %g2
3053	btst	%g2, %g4
3054	bz,pn	%xcc, sun4v_datatrap			! No -- really fault
3055	 nop
3056	casxa	[%g6] ASI_PHYS_CACHED, %g4, %g7		!  and write it out
3057	cmp	%g4, %g7
3058	bne,pn	%xcc, 1b
3059	 or	%g4, SUN4V_TLB_MODIFY|SUN4V_TLB_ACCESS|SUN4V_TLB_W, %g4 ! Update the modified bit
30602:
3061	GET_TSB_DMMU %g2
3062
3063	mov	%g1, %g7			! save MMFSA
3064
3065	/* Construct TSB tag word. */
3066	add	%g1, 0x50, %g6
3067	LDPTRA	[%g6] ASI_PHYS_CACHED, %g6	! Data fault context
3068	mov	%g3, %g1			! Data fault address
3069	srlx	%g1, 22, %g1			! 63..22 of virt addr
3070	sllx	%g6, 48, %g6			! context_id in 63..48
3071	or	%g1, %g6, %g1			! construct TTE tag
3072
3073	srlx	%g3, PTSHIFT, %g3
3074	sethi	%hi(_C_LABEL(tsbsize)), %g5
3075	mov	512, %g6
3076	ld	[%g5 + %lo(_C_LABEL(tsbsize))], %g5
3077	sllx	%g6, %g5, %g5			! %g5 = 512 << tsbsize = TSBENTS
3078	sub	%g5, 1, %g5			! TSBENTS -> offset
3079	and	%g3, %g5, %g3			! mask out TTE index
3080	sllx	%g3, 4, %g3			! TTE size is 16 bytes
3081	add	%g2, %g3, %g2			! location of TTE in ci_tsb_dmmu
3082
3083	membar	#StoreStore
3084
3085	STPTR	%g4, [%g2 + 8]		! store TTE data
3086	STPTR	%g1, [%g2]		! store TTE tag
3087
3088	mov	%o0, %g1
3089	mov	%o1, %g2
3090	mov	%o2, %g3
3091
3092	add	%g7, 0x48, %o0
3093	ldxa	[%o0] ASI_PHYS_CACHED, %o0	! Data fault address
3094	add	%g7, 0x50, %o1
3095	ldxa	[%o1] ASI_PHYS_CACHED, %o1	! Data fault context
3096	mov	MAP_DTLB, %o2
3097	ta	ST_MMU_UNMAP_ADDR
3098
3099	mov	%g1, %o0
3100	mov	%g2, %o1
3101	mov	%g3, %o2
3102
3103	retry
3104	NOTREACHED
3105
3106sun4v_tl0_itsb_miss:
3107	GET_MMFSA %g1				! MMU Fault status area
3108	add	%g1, 0x8, %g3
3109	LDPTRA	[%g3] ASI_PHYS_CACHED, %g3	! Instruction fault address
3110	add	%g1, 0x10, %g6
3111	LDPTRA	[%g6] ASI_PHYS_CACHED, %g6	! Data fault context
3112
3113	GET_CTXBUSY %g4
3114	sllx	%g6, 3, %g6			! Make it into an offset into ctxbusy
3115	LDPTR	[%g4 + %g6], %g4		! Load up our page table.
3116
3117	srax	%g3, HOLESHIFT, %g5		! Check for valid address
3118	brz,pt	%g5, 0f				! Should be zero or -1
3119	 inc	%g5				! Make -1 -> 0
3120	brnz,pn	%g5, sun4v_texttrap		! Error! In hole!
31210:
3122	srlx	%g3, STSHIFT, %g6
3123	and	%g6, STMASK, %g6		! Index into pm_segs
3124	sll	%g6, 3, %g6
3125	add	%g4, %g6, %g4
3126	LDPTRA	[%g4] ASI_PHYS_CACHED, %g4	! Load page directory pointer
3127
3128	srlx	%g3, PDSHIFT, %g6
3129	and	%g6, PDMASK, %g6
3130	sll	%g6, 3, %g6
3131	brz,pn	%g4, sun4v_texttrap		! NULL entry? check somewhere else
3132	 add	%g4, %g6, %g4
3133	LDPTRA	[%g4] ASI_PHYS_CACHED, %g4	! Load page table pointer
3134
3135	srlx	%g3, PTSHIFT, %g6		! Convert to ptab offset
3136	and	%g6, PTMASK, %g6
3137	sll	%g6, 3, %g6
3138	brz,pn	%g4, sun4v_texttrap		! NULL entry? check somewhere else
3139	 add	%g4, %g6, %g6
31401:
3141	LDPTRA	[%g6] ASI_PHYS_CACHED, %g4	! Fetch TTE
3142	brgez,pn %g4, sun4v_texttrap		! Entry invalid?  Punt
3143	 or	%g4, SUN4V_TLB_ACCESS, %g7	! Update the access bit
3144
3145	btst	SUN4V_TLB_EXEC, %g4		! Need to update exec bit?
3146	bz,pn	%xcc, sun4v_texttrap
3147	 nop
3148	btst	SUN4V_TLB_ACCESS, %g4		! Need to update access bit?
3149	bne,pt	%xcc, 2f
3150	 nop
3151	casxa	[%g6] ASI_PHYS_CACHED, %g4, %g7	! and write it out
3152	cmp	%g4, %g7
3153	bne,pn	%xcc, 1b
3154	 or	%g4, SUN4V_TLB_ACCESS, %g4	! Update the modified bit
31552:
3156	GET_TSB_DMMU %g2
3157
3158	mov	%g1, %g7
3159	/* Construct TSB tag word. */
3160	add	%g1, 0x10, %g6
3161	LDPTRA	[%g6] ASI_PHYS_CACHED, %g6	! Instruction fault context
3162	mov	%g3, %g1			! Instruction fault address
3163	srlx	%g1, 22, %g1			! 63..22 of virt addr
3164	sllx	%g6, 48, %g6			! context_id in 63..48
3165	or	%g1, %g6, %g1			! construct TTE tag
3166
3167	srlx	%g3, PTSHIFT, %g3
3168	sethi	%hi(_C_LABEL(tsbsize)), %g5
3169	mov	512, %g6
3170	ld	[%g5 + %lo(_C_LABEL(tsbsize))], %g5
3171	sllx	%g6, %g5, %g5			! %g5 = 512 << tsbsize = TSBENTS
3172	sub	%g5, 1, %g5			! TSBENTS -> offset
3173	and	%g3, %g5, %g3			! mask out TTE index
3174	sllx	%g3, 4, %g3			! TTE size is 16 bytes
3175	add	%g2, %g3, %g2			! location of TTE in ci_tsb_dmmu (FIXME ci_tsb_immu?)
3176
3177	membar	#StoreStore
3178	STPTR	%g4, [%g2 + 8]			! store TTE data
3179	stx	%g1, [%g2]			! store TTE tag
3180
3181	retry
3182	NOTREACHED
3183
3184sun4v_texttrap:
3185	GET_MMFSA %g3				! MMU Fault status area
3186	add	%g3, 0x08, %g1
3187	LDPTRA	[%g1] ASI_PHYS_CACHED, %g1	! Instruction fault address
3188	add	%g3, 0x10, %g2
3189	LDPTRA	[%g2] ASI_PHYS_CACHED, %g2	! Instruction fault context
3190
3191	TRAP_SETUP(-CC64FSZ-TF_SIZE)
3192
3193	or	%g1, %g2, %o2
3194	clr	%o3
3195
3196	rdpr	%tt, %g4
3197	rdpr	%tstate, %g1
3198	rdpr	%tpc, %g2
3199	rdpr	%tnpc, %g3
3200
3201	stx	%g1, [%sp + CC64FSZ + BIAS + TF_TSTATE]
3202	mov	%g4, %o1		! (type)
3203	stx	%g2, [%sp + CC64FSZ + BIAS + TF_PC]
3204	rd	%y, %g5
3205	stx	%g3, [%sp + CC64FSZ + BIAS + TF_NPC]
3206	st	%g5, [%sp + CC64FSZ + BIAS + TF_Y]
3207	sth	%o1, [%sp + CC64FSZ + BIAS + TF_TT]! debug
3208
3209	! Get back to normal globals
3210	wrpr	%g0, PSTATE_KERN, %pstate
3211	NORMAL_GLOBALS_SUN4V
3212
3213	stx	%g1, [%sp + CC64FSZ + BIAS + TF_G + (1*8)]
3214	stx	%g2, [%sp + CC64FSZ + BIAS + TF_G + (2*8)]
3215	add	%sp, CC64FSZ + BIAS, %o0		! (&tf)
3216	stx	%g3, [%sp + CC64FSZ + BIAS + TF_G + (3*8)]
3217	stx	%g4, [%sp + CC64FSZ + BIAS + TF_G + (4*8)]
3218	stx	%g5, [%sp + CC64FSZ + BIAS + TF_G + (5*8)]
3219	rdpr	%pil, %g5
3220	stx	%g6, [%sp + CC64FSZ + BIAS + TF_G + (6*8)]
3221	stx	%g7, [%sp + CC64FSZ + BIAS + TF_G + (7*8)]
3222	stb	%g5, [%sp + CC64FSZ + BIAS + TF_PIL]
3223	stb	%g5, [%sp + CC64FSZ + BIAS + TF_OLDPIL]
3224
3225	/*
3226	 * Phew, ready to enable traps and call C code.
3227	 */
3228	wrpr	%g0, 0, %tl
3229
3230	wr	%g0, ASI_PRIMARY_NOFAULT, %asi	! Restore default ASI
3231	wrpr	%g0, PSTATE_INTR, %pstate	! traps on again
3232	call	_C_LABEL(text_access_fault)	! text_access_fault(tf, type, ...)
3233	 nop
3234
3235	ba,a,pt	%icc, return_from_trap
3236	 nop
3237	NOTREACHED
3238
3239sun4v_tl1_dtsb_prot:
3240	GET_MMFSA %g1				! MMU Fault status area
3241	add	%g1, 0x48, %g3
3242	LDPTRA	[%g3] ASI_PHYS_CACHED, %g3	! Data fault address
3243	add	%g1, 0x50, %g6
3244	LDPTRA	[%g6] ASI_PHYS_CACHED, %g6	! Data fault context
3245
3246	GET_CTXBUSY %g4
3247	sllx	%g6, 3, %g6			! Make it into an offset into ctxbusy
3248	LDPTR	[%g4 + %g6], %g4		! Load up our page table.
3249
3250	srax	%g3, HOLESHIFT, %g5		! Check for valid address
3251	brz,pt	%g5, 0f				! Should be zero or -1
3252	 inc	%g5				! Make -1 -> 0
3253	brnz,pn	%g5, sun4v_tl1_ptbl_miss	! Error! In hole!
32540:
3255	srlx	%g3, STSHIFT, %g6
3256	and	%g6, STMASK, %g6		! Index into pm_segs
3257	sll	%g6, 3, %g6
3258	add	%g4, %g6, %g4
3259	LDPTRA	[%g4] ASI_PHYS_CACHED, %g4	! Load page directory pointer
3260
3261	srlx	%g3, PDSHIFT, %g6
3262	and	%g6, PDMASK, %g6
3263	sll	%g6, 3, %g6
3264	brz,pn	%g4, sun4v_tl1_ptbl_miss	! NULL entry? check somewhere else
3265	 add	%g4, %g6, %g4
3266	LDPTRA	[%g4] ASI_PHYS_CACHED, %g4	! Load page table pointer
3267
3268	srlx	%g3, PTSHIFT, %g6		! Convert to ptab offset
3269	and	%g6, PTMASK, %g6
3270	sll	%g6, 3, %g6
3271	brz,pn	%g4, sun4v_tl1_ptbl_miss	! NULL entry? check somewhere else
3272	 add	%g4, %g6, %g6
32731:
3274	LDPTRA	[%g6] ASI_PHYS_CACHED, %g4	! Fetch TTE
3275	brgez,pn %g4, sun4v_tl1_ptbl_miss	! Entry invalid?  Punt
3276	 or	%g4, SUN4V_TLB_MODIFY|SUN4V_TLB_ACCESS|SUN4V_TLB_W, %g7 ! Update the modified bit
3277
3278#	btst	SUN4V_TLB_REAL_W|SUN4V_TLB_W, %g4	! Is it a ref fault?
3279	mov	1, %g2
3280	sllx	%g2, 61, %g2			! %g2 is now SUN4V_TLB_REAL_W
3281	or	%g2, SUN4V_TLB_W, %g2
3282	btst	%g2, %g4
3283	bz,pn	%xcc, sun4v_tl1_ptbl_miss		! No -- really fault
3284	 nop
3285	casxa	[%g6] ASI_PHYS_CACHED, %g4, %g7		!  and write it out
3286	cmp	%g4, %g7
3287	bne,pn	%xcc, 1b
3288	 or	%g4, SUN4V_TLB_MODIFY|SUN4V_TLB_ACCESS|SUN4V_TLB_W, %g4 ! Update the modified bit
32892:
3290	GET_TSB_DMMU %g2
3291
3292	mov	%g1, %g7			! save MMFSA
3293
3294	/* Construct TSB tag word. */
3295	add	%g1, 0x50, %g6
3296	LDPTRA	[%g6] ASI_PHYS_CACHED, %g6	! Data fault context
3297	mov	%g3, %g1			! Data fault address
3298	srlx	%g1, 22, %g1			! 63..22 of virt addr
3299	sllx	%g6, 48, %g6			! context_id in 63..48
3300	or	%g1, %g6, %g1			! construct TTE tag
3301
3302	srlx	%g3, PTSHIFT, %g3
3303	sethi	%hi(_C_LABEL(tsbsize)), %g5
3304	mov	512, %g6
3305	ld	[%g5 + %lo(_C_LABEL(tsbsize))], %g5
3306	sllx	%g6, %g5, %g5			! %g5 = 512 << tsbsize = TSBENTS
3307	sub	%g5, 1, %g5			! TSBENTS -> offset
3308	and	%g3, %g5, %g3			! mask out TTE index
3309	sllx	%g3, 4, %g3			! TTE size is 16 bytes
3310	add	%g2, %g3, %g2			! location of TTE in ci_tsb_dmmu
3311
3312	membar	#StoreStore
3313
3314	STPTR	%g4, [%g2 + 8]		! store TTE data
3315	STPTR	%g1, [%g2]		! store TTE tag
3316
3317	mov	%o0, %g1
3318	mov	%o1, %g2
3319	mov	%o2, %g3
3320
3321	add	%g7, 0x48, %o0
3322	ldxa	[%o0] ASI_PHYS_CACHED, %o0	! Data fault address
3323	add	%g7, 0x50, %o1
3324	ldxa	[%o1] ASI_PHYS_CACHED, %o1	! Data fault context
3325	mov	MAP_DTLB, %o2
3326	ta	ST_MMU_UNMAP_ADDR
3327
3328	mov	%g1, %o0
3329	mov	%g2, %o1
3330	mov	%g3, %o2
3331
3332	retry
3333	NOTREACHED
3334
3335sun4v_tl1_ptbl_miss:
3336	rdpr	%tpc, %g1
3337
3338	set	rft_user_fault_start, %g2
3339	cmp	%g1, %g2
3340	blu,pt	%xcc, 1f
3341	 set	rft_user_fault_end, %g2
3342	cmp	%g1, %g2
3343	bgeu,pt	%xcc, 1f
3344	 nop
3345
3346	/* We had a miss inside rtf_user_fault_start/rtf_user_fault_end block (FILL)
3347
3348	/* Fixup %cwp. */
3349	rdpr	%cwp, %g1
3350	inc	%g1
3351	wrpr	%g1, %cwp
3352
3353	rdpr	%tt, %g1
3354	wrpr	1, %tl
3355	wrpr	%g1, %tt
3356	rdpr	%cwp, %g1
3357	set	TSTATE_KERN, %g2
3358	wrpr	%g1, %g2, %tstate
3359	set	return_from_trap, %g1
3360	wrpr	%g1, %tpc
3361	add	%g1, 4, %g1
3362	wrpr	%g1, %tnpc
3363	wrpr	%g0, 1, %gl
3364
3365	ba,pt %xcc, sun4v_datatrap
3366	 wrpr	WSTATE_KERN, %wstate
3367
33681:
3369	rdpr	%tstate, %g3
3370	rdpr	%tt, %g4
3371
3372	rdpr	%tl, %g1
3373	dec	%g1
3374	wrpr	%g1, %tl
3375	rdpr	%tt, %g2
3376	inc	%g1
3377	wrpr	%g1, %tl
3378
3379	wrpr	%g0, %g3, %tstate
3380	wrpr	%g0, %g4, %tt
3381
3382	andn	%g2, 0x00f, %g3
3383	cmp	%g3, 0x080
3384	be,pn	%icc, flush_normals
3385	 nop
3386	cmp	%g3, 0x0a0
3387	be,pn	%icc, flush_others
3388	 nop
3389	cmp	%g3, 0x0c0
3390	be,pn	%icc, ufill_trap
3391	 nop
3392
3393	Debugger()
3394	NOTREACHED
3395
3396flush_others:
3397	set	pcbspill_others, %g1
3398	wrpr	%g1, %tnpc
3399	done
3400	NOTREACHED
3401
3402flush_normals:
3403ufill_trap:
3404
3405	/*
3406	 * Rearrange our trap state such that it appears as if we got
3407	 * this trap directly from user mode.  Then process it at TL = 1.
3408	 * We'll take the spill/fill trap again once we return to user mode.
3409	 */
3410	rdpr	%tt, %g1
3411	rdpr	%tstate, %g3
3412	wrpr	%g0, 1, %tl
3413	wrpr	%g0, %g1, %tt
3414	rdpr	%tstate, %g2
3415	wrpr	%g0, 2, %tl
3416	and	%g2, TSTATE_CWP, %g2
3417	andn	%g3, TSTATE_CWP, %g3
3418	wrpr	%g2, %g3, %tstate
3419	set	sun4v_datatrap, %g4
3420	wrpr	%g0, %g4, %tnpc
3421	done
3422
3423/*
3424 * Spill user windows into the PCB.
3425 */
3426pcbspill_normals:
3427	ba,pt	%xcc, pcbspill
3428	 wrpr	0x80, %tt
3429
3430pcbspill_others:
3431	wrpr	0xa0, %tt
3432
3433pcbspill:
3434	set	CPUINFO_VA, %g6
3435	ldx	[%g6 + CI_CPCB], %g6
3436
3437	GET_CTXBUSY %g1
3438
3439	ldx	[%g1], %g1				! kernel pmap is ctx 0
3440
3441	srlx	%g6, STSHIFT, %g7
3442	and	%g7, STMASK, %g7
3443	sll	%g7, 3, %g7				! byte offset into ctxbusy
3444	add	%g7, %g1, %g1
3445	ldxa	[%g1] ASI_PHYS_CACHED, %g1		! Load pointer to directory
3446
3447	srlx	%g6, PDSHIFT, %g7			! Do page directory
3448	and	%g7, PDMASK, %g7
3449	sll	%g7, 3, %g7
3450	brz,pn	%g1, pcbspill_fail
3451	 add	%g7, %g1, %g1
3452	ldxa	[%g1] ASI_PHYS_CACHED, %g1
3453	srlx	%g6, PTSHIFT, %g7			! Convert to ptab offset
3454	and	%g7, PTMASK, %g7
3455	brz	%g1, pcbspill_fail
3456	 sll	%g7, 3, %g7
3457	add	%g1, %g7, %g7
3458	ldxa	[%g7] ASI_PHYS_CACHED, %g7		! This one is not
3459	brgez	%g7, pcbspill_fail
3460	 srlx	%g7, PGSHIFT, %g7			! Isolate PA part
3461	sll	%g6, 32-PGSHIFT, %g6			! And offset
3462	sllx	%g7, PGSHIFT+8, %g7			! There are 8 bits to the left of the PA in the TTE
3463	srl	%g6, 32-PGSHIFT, %g6
3464	srax	%g7, 8, %g7
3465	or	%g7, %g6, %g6				! Then combine them to form PA
3466
3467	wr	%g0, ASI_PHYS_CACHED, %asi		! Use ASI_PHYS_CACHED to prevent possible page faults
3468
3469	lduba	[%g6 + PCB_NSAVED] %asi, %g7		! Fetch current nsaved from the pcb
3470	sllx	%g7, 7, %g5				! 8+8 registers each 8 bytes = 128 bytes (2^7)
3471	add	%g6, %g5, %g5				! Offset into pcb_rw
3472	SPILL	stxa, %g5 + PCB_RW, 8, %asi		! Store the locals and ins
3473	saved
3474
3475	sllx	%g7, 3, %g5
3476	add	%g6, %g5, %g5
3477
3478	inc	%g7
3479	stba	%g7, [%g6 + PCB_NSAVED] %asi
3480
3481	retry
3482	NOTREACHED
3483
3484pcbspill_fail:
3485	Debugger()
3486	NOTREACHED
3487
3488
3489pcbspill_other:
3490
3491	set	CPUINFO_VA, %g6
3492	ldx	[%g6 + CI_CPCB], %g6
3493
3494	GET_CTXBUSY %g1
3495
3496	ldx	[%g1], %g1				! kernel pmap is ctx 0
3497
3498	srlx	%g6, STSHIFT, %g7
3499	and	%g7, STMASK, %g7
3500	sll	%g7, 3, %g7				! byte offset into ctxbusy
3501	add	%g7, %g1, %g1
3502	ldxa	[%g1] ASI_PHYS_CACHED, %g1		! Load pointer to directory
3503
3504	srlx	%g6, PDSHIFT, %g7			! Do page directory
3505	and	%g7, PDMASK, %g7
3506	sll	%g7, 3, %g7
3507	brz,pn	%g1, pcbspill_other_fail
3508	 add	%g7, %g1, %g1
3509	ldxa	[%g1] ASI_PHYS_CACHED, %g1
3510	srlx	%g6, PTSHIFT, %g7			! Convert to ptab offset
3511	and	%g7, PTMASK, %g7
3512	brz	%g1, pcbspill_other_fail
3513	 sll	%g7, 3, %g7
3514	add	%g1, %g7, %g7
3515	ldxa	[%g7] ASI_PHYS_CACHED, %g7		! This one is not
3516	brgez	%g7, pcbspill_other_fail
3517	 srlx	%g7, PGSHIFT, %g7			! Isolate PA part
3518	sll	%g6, 32-PGSHIFT, %g6			! And offset
3519	sllx	%g7, PGSHIFT+8, %g7			! There are 8 bits to the left of the PA in the TTE
3520	srl	%g6, 32-PGSHIFT, %g6
3521	srax	%g7, 8, %g7
3522	or	%g7, %g6, %g6				! Then combine them to form PA
3523
3524	wr	%g0, ASI_PHYS_CACHED, %asi		! Use ASI_PHYS_CACHED to prevent possible page faults
3525
3526	lduba	[%g6 + PCB_NSAVED] %asi, %g7		! Fetch current nsaved from the pcb
3527	sllx	%g7, 7, %g5				! 8+8 registers each 8 bytes = 128 bytes (2^7)
3528	add	%g6, %g5, %g5				! Offset into pcb_rw
35291:
3530	SPILL	stxa, %g5 + PCB_RW, 8, %asi		! Store the locals and ins
3531
3532	add	%g5, 16*8, %g5				! Next location for saved register windows
3533
3534	stxa	%o6, [%g5 + PCB_RW + (14*8)] %asi	! Save %sp so we can write these all out
3535
3536	saved						! Increments %cansave and decrements %otherwin
3537
3538	rdpr	%cwp, %g1				! shift register window forward
3539	inc	%g1
3540	wrpr	%g1, %cwp
3541
3542
3543	inc	%g7					! increment number of saved register windows
3544
3545	rdpr	%otherwin, %g1				! Check to see if done spill'ing otherwin
3546	brnz,pt	%g1, 1b
3547	 nop
3548
3549	stba	%g7, [%g6 + PCB_NSAVED] %asi
3550
3551	retry
3552	NOTREACHED
3553
3554pcbspill_other_fail:
3555	Debugger()
3556	NOTREACHED
3557
3558
3559spill_normal_to_user_stack:
3560	mov	%sp, %g6						! calculate virtual address of destination stack
3561	add	%g6, BIAS, %g6
3562
3563	mov	CTX_SECONDARY, %g2				! Is this context ok or should it be CTX_PRIMARY? XXX
3564	GET_MMU_CONTEXTID %g3, %g2, %g1
3565	sllx	%g3, 3, %g3					! Make it into an offset into ctxbusy (see below)
3566
3567	GET_CTXBUSY %g1
3568	ldx	[%g1 + %g3], %g1				! Fetch pmap for current context id
3569
3570	! Start of code to extract PA
3571	srlx	%g6, STSHIFT, %g7
3572	and	%g7, STMASK, %g7
3573	sll	%g7, 3, %g7						! byte offset into ctxbusy
3574	add	%g7, %g1, %g1
3575	ldxa	[%g1] ASI_PHYS_CACHED, %g1	! Load pointer to directory
3576	srlx	%g6, PDSHIFT, %g7			! Do page directory
3577	and	%g7, PDMASK, %g7
3578	sll	%g7, 3, %g7
3579	brz,pn	%g1, spill_normal_to_user_stack_fail
3580	 add	%g7, %g1, %g1
3581
3582	ldxa	[%g1] ASI_PHYS_CACHED, %g1
3583	srlx	%g6, PTSHIFT, %g7			! Convert to ptab offset
3584	and	%g7, PTMASK, %g7
3585	brz	%g1, spill_normal_to_user_stack_fail
3586	 sll	%g7, 3, %g7
3587
3588	add	%g1, %g7, %g7
3589	ldxa	[%g7] ASI_PHYS_CACHED, %g7	! This one is not
3590	brgez	%g7, spill_normal_to_user_stack_fail
3591	 srlx	%g7, PGSHIFT, %g7			! Isolate PA part
3592
3593	sll	%g6, 32-PGSHIFT, %g6			! And offset
3594	sllx	%g7, PGSHIFT+8, %g7			! There are 8 bits to the left of the PA in the TTE
3595	srl	%g6, 32-PGSHIFT, %g6
3596	srax	%g7, 8, %g7
3597	or	%g7, %g6, %g6					! Then combine them to form PA
3598	! End of code to extract PA
3599
3600	wr	%g0, ASI_PHYS_CACHED, %asi		! Use ASI_PHYS_CACHED to prevent possible page faults
3601	SPILL	stxa, %g6, 8, %asi			! Store the locals and ins
3602	saved
3603
3604	retry
3605	NOTREACHED
3606
3607spill_normal_to_user_stack_fail:
3608	sir
3609	 nop
3610
3611/*
3612 * End of traps for sun4v.
3613 */
3614
3615#endif
3616
3617/*
3618 * We're here because we took an alignment fault in NUCLEUS context.
3619 * This could be a kernel bug or it could be due to saving a user
3620 * window to an invalid stack pointer.
3621 *
3622 * If the latter is the case, we could try to emulate unaligned accesses,
3623 * but we really don't know where to store the registers since we can't
3624 * determine if there's a stack bias.  Or we could store all the regs
3625 * into the PCB and punt, until the user program uses up all the CPU's
3626 * register windows and we run out of places to store them.  So for
3627 * simplicity we'll just blow them away and enter the trap code which
3628 * will generate a bus error.  Debugging the problem will be a bit
3629 * complicated since lots of register windows will be lost, but what
3630 * can we do?
3631 */
3632checkalign:
3633	rdpr	%tl, %g2
3634	subcc	%g2, 1, %g1
3635	bneg,pn	%icc, slowtrap		! Huh?
3636	 sethi	%hi(CPCB), %g6		! get current pcb
3637
3638	wrpr	%g1, 0, %tl
3639	rdpr	%tt, %g7
3640	rdpr	%tstate, %g4
3641	andn	%g7, 0x3f, %g5
3642	cmp	%g5, 0x080		!   window spill traps are all 0b 0000 10xx xxxx
3643	bne,a,pn	%icc, slowtrap
3644	 wrpr	%g1, 0, %tl		! Revert TL  XXX wrpr in a delay slot...
3645
3646#ifdef DEBUG
3647	cmp	%g7, 0x34		! If we took a datafault just before this trap
3648	bne,pt	%icc, checkalignspill	! our stack's probably bad so we need to switch somewhere else
3649	 nop
3650
3651	!!
3652	!! Double data fault -- bad stack?
3653	!!
3654	wrpr	%g2, %tl		! Restore trap level.
3655	sir				! Just issue a reset and don't try to recover.
3656	mov	%fp, %l6		! Save the frame pointer
3657	set	EINTSTACK+USPACE+CC64FSZ-STKB, %fp ! Set the frame pointer to the middle of the idle stack
3658	add	%fp, -CC64FSZ, %sp	! Create a stackframe
3659	wrpr	%g0, 15, %pil		! Disable interrupts, too
3660	wrpr	%g0, %g0, %canrestore	! Our stack is hozed and our PCB
3661	wrpr	%g0, 7, %cansave	!  probably is too, so blow away
3662	ba	slowtrap		!  all our register windows.
3663	 wrpr	%g0, 0x101, %tt
3664#endif
3665checkalignspill:
3666	/*
3667         * %g1 -- current tl
3668	 * %g2 -- original tl
3669	 * %g4 -- tstate
3670         * %g7 -- tt
3671	 */
3672
3673	and	%g4, CWP, %g5
3674	wrpr	%g5, %cwp		! Go back to the original register win
3675
3676	/*
3677	 * Remember:
3678	 *
3679	 * %otherwin = 0
3680	 * %cansave = NWINDOWS - 2 - %canrestore
3681	 */
3682
3683	rdpr	%otherwin, %g6
3684	rdpr	%canrestore, %g3
3685	rdpr	%ver, %g5
3686	sub	%g3, %g6, %g3		! Calculate %canrestore - %g7
3687	and	%g5, CWP, %g5		! NWINDOWS-1
3688	movrlz	%g3, %g0, %g3		! Clamp at zero
3689	wrpr	%g0, 0, %otherwin
3690	wrpr	%g3, 0, %canrestore	! This is the new canrestore
3691	dec	%g5			! NWINDOWS-2
3692	wrpr	%g5, 0, %cleanwin	! Set cleanwin to max, since we're in-kernel
3693	sub	%g5, %g3, %g5		! NWINDOWS-2-%canrestore
3694	wrpr	%g5, 0, %cansave
3695
3696	wrpr	%g0, T_ALIGN, %tt	! This was an alignment fault
3697	/*
3698	 * Now we need to determine if this was a userland store or not.
3699	 * Userland stores occur in anything other than the kernel spill
3700	 * handlers (trap type 09x).
3701	 */
3702	and	%g7, 0xff0, %g5
3703	cmp	%g5, 0x90
3704	bz,pn	%icc, slowtrap
3705	 nop
3706	bclr	TSTATE_PRIV, %g4
3707	wrpr	%g4, 0, %tstate
3708	ba,a,pt	%icc, slowtrap
3709	 nop
3710
3711/*
3712 * slowtrap() builds a trap frame and calls trap().
3713 * This is called `slowtrap' because it *is*....
3714 * We have to build a full frame for ptrace(), for instance.
3715 *
3716 * Registers:
3717 *
3718 */
3719slowtrap:
3720#ifdef TRAPS_USE_IG
3721	wrpr	%g0, PSTATE_KERN|PSTATE_IG, %pstate	! DEBUG
3722#endif
3723#ifdef DIAGNOSTIC
3724	/* Make sure kernel stack is aligned */
3725	btst	0x03, %sp		! 32-bit stack OK?
3726	 and	%sp, 0x07, %g4		! 64-bit stack OK?
3727	bz,pt	%icc, 1f
3728	cmp	%g4, 0x1		! Must end in 0b001
3729	be,pt	%icc, 1f
3730	 rdpr	%wstate, %g7
3731	cmp	%g7, WSTATE_KERN
3732	bnz,pt	%icc, 1f		! User stack -- we'll blow it away
3733	 nop
3734	set	PANICSTACK-CC64FSZ-STKB, %sp
37351:
3736#endif
3737	rdpr	%tt, %g4
3738	rdpr	%tstate, %g1
3739	rdpr	%tpc, %g2
3740	rdpr	%tnpc, %g3
3741
3742	TRAP_SETUP(-CC64FSZ-TF_SIZE)
3743Lslowtrap_reenter:
3744	stx	%g1, [%sp + CC64FSZ + STKB + TF_TSTATE]
3745	mov	%g4, %o1		! (type)
3746	stx	%g2, [%sp + CC64FSZ + STKB + TF_PC]
3747	rd	%y, %g5
3748	stx	%g3, [%sp + CC64FSZ + STKB + TF_NPC]
3749	mov	%g1, %o3		! (pstate)
3750	st	%g5, [%sp + CC64FSZ + STKB + TF_Y]
3751	mov	%g2, %o2		! (pc)
3752	sth	%o1, [%sp + CC64FSZ + STKB + TF_TT]! debug
3753
3754	! Get back to normal globals
3755#ifdef SUN4V
3756	sethi	%hi(cputyp), %g5
3757	ld	[%g5 + %lo(cputyp)], %g5
3758	cmp	%g5, CPU_SUN4V
3759	bne,pt	%icc, 1f
3760	 nop
3761	NORMAL_GLOBALS_SUN4V
3762	ba	2f
3763	 nop
37641:
3765#endif
3766	NORMAL_GLOBALS_SUN4U
37672:
3768	stx	%g1, [%sp + CC64FSZ + STKB + TF_G + (1*8)]
3769	stx	%g2, [%sp + CC64FSZ + STKB + TF_G + (2*8)]
3770	add	%sp, CC64FSZ + STKB, %o0		! (&tf)
3771	stx	%g3, [%sp + CC64FSZ + STKB + TF_G + (3*8)]
3772	stx	%g4, [%sp + CC64FSZ + STKB + TF_G + (4*8)]
3773	stx	%g5, [%sp + CC64FSZ + STKB + TF_G + (5*8)]
3774	rdpr	%pil, %g5
3775	stx	%g6, [%sp + CC64FSZ + STKB + TF_G + (6*8)]
3776	stx	%g7, [%sp + CC64FSZ + STKB + TF_G + (7*8)]
3777	stb	%g5, [%sp + CC64FSZ + STKB + TF_PIL]
3778	stb	%g5, [%sp + CC64FSZ + STKB + TF_OLDPIL]
3779	/*
3780	 * Phew, ready to enable traps and call C code.
3781	 */
3782	rdpr	%tl, %g1
3783	dec	%g1
3784	movrlz	%g1, %g0, %g1
3785	wrpr	%g0, %g1, %tl		! Revert to kernel mode
3786	!! In the EMBEDANY memory model %g4 points to the start of the data segment.
3787	!! In our case we need to clear it before calling any C-code
3788	clr	%g4
3789
3790	wr	%g0, ASI_PRIMARY_NOFAULT, %asi		! Restore default ASI
3791	wrpr	%g0, PSTATE_INTR, %pstate	! traps on again
3792	call	_C_LABEL(trap)			! trap(tf, type, pc, pstate)
3793	 nop
3794
3795	b	return_from_trap
3796	 ldx	[%sp + CC64FSZ + STKB + TF_TSTATE], %g1	! Load this for return_from_trap
3797	NOTREACHED
3798#if 1
3799/*
3800 * This code is no longer needed.
3801 */
3802/*
3803 * Do a `software' trap by re-entering the trap code, possibly first
3804 * switching from interrupt stack to kernel stack.  This is used for
3805 * scheduling and signal ASTs (which generally occur from softclock or
3806 * tty or net interrupts).
3807 *
3808 * We enter with the trap type in %g1.  All we have to do is jump to
3809 * Lslowtrap_reenter above, but maybe after switching stacks....
3810 *
3811 * We should be running alternate globals.  The normal globals and
3812 * out registers were just loaded from the old trap frame.
3813 *
3814 *	Input Params:
3815 *	%g1 = tstate
3816 *	%g2 = tpc
3817 *	%g3 = tnpc
3818 *	%g4 = tt == T_AST
3819 */
3820softtrap:
3821	sethi	%hi(EINTSTACK-STKB), %g5
3822	sethi	%hi(EINTSTACK-INTSTACK), %g7
3823	or	%g5, %lo(EINTSTACK-STKB), %g5
3824	dec	%g7
3825	sub	%g5, %sp, %g5
3826	sethi	%hi(CPCB), %g6
3827	andncc	%g5, %g7, %g0
3828	bnz,pt	%xcc, Lslowtrap_reenter
3829	 LDPTR	[%g6 + %lo(CPCB)], %g7
3830	set	USPACE-CC64FSZ-TF_SIZE-STKB, %g5
3831	add	%g7, %g5, %g6
3832	SET_SP_REDZONE(%g7, %g5)
3833#ifdef DEBUG
3834	stx	%g1, [%g6 + CC64FSZ + STKB + TF_FAULT]		! Generate a new trapframe
3835#endif
3836	stx	%i0, [%g6 + CC64FSZ + STKB + TF_O + (0*8)]	!	but don't bother with
3837	stx	%i1, [%g6 + CC64FSZ + STKB + TF_O + (1*8)]	!	locals and ins
3838	stx	%i2, [%g6 + CC64FSZ + STKB + TF_O + (2*8)]
3839	stx	%i3, [%g6 + CC64FSZ + STKB + TF_O + (3*8)]
3840	stx	%i4, [%g6 + CC64FSZ + STKB + TF_O + (4*8)]
3841	stx	%i5, [%g6 + CC64FSZ + STKB + TF_O + (5*8)]
3842	stx	%i6, [%g6 + CC64FSZ + STKB + TF_O + (6*8)]
3843	stx	%i7, [%g6 + CC64FSZ + STKB + TF_O + (7*8)]
3844#ifdef DEBUG
3845	ldx	[%sp + CC64FSZ + STKB + TF_I + (0*8)], %l0	! Copy over the rest of the regs
3846	ldx	[%sp + CC64FSZ + STKB + TF_I + (1*8)], %l1	! But just dirty the locals
3847	ldx	[%sp + CC64FSZ + STKB + TF_I + (2*8)], %l2
3848	ldx	[%sp + CC64FSZ + STKB + TF_I + (3*8)], %l3
3849	ldx	[%sp + CC64FSZ + STKB + TF_I + (4*8)], %l4
3850	ldx	[%sp + CC64FSZ + STKB + TF_I + (5*8)], %l5
3851	ldx	[%sp + CC64FSZ + STKB + TF_I + (6*8)], %l6
3852	ldx	[%sp + CC64FSZ + STKB + TF_I + (7*8)], %l7
3853	stx	%l0, [%g6 + CC64FSZ + STKB + TF_I + (0*8)]
3854	stx	%l1, [%g6 + CC64FSZ + STKB + TF_I + (1*8)]
3855	stx	%l2, [%g6 + CC64FSZ + STKB + TF_I + (2*8)]
3856	stx	%l3, [%g6 + CC64FSZ + STKB + TF_I + (3*8)]
3857	stx	%l4, [%g6 + CC64FSZ + STKB + TF_I + (4*8)]
3858	stx	%l5, [%g6 + CC64FSZ + STKB + TF_I + (5*8)]
3859	stx	%l6, [%g6 + CC64FSZ + STKB + TF_I + (6*8)]
3860	stx	%l7, [%g6 + CC64FSZ + STKB + TF_I + (7*8)]
3861	ldx	[%sp + CC64FSZ + STKB + TF_L + (0*8)], %l0
3862	ldx	[%sp + CC64FSZ + STKB + TF_L + (1*8)], %l1
3863	ldx	[%sp + CC64FSZ + STKB + TF_L + (2*8)], %l2
3864	ldx	[%sp + CC64FSZ + STKB + TF_L + (3*8)], %l3
3865	ldx	[%sp + CC64FSZ + STKB + TF_L + (4*8)], %l4
3866	ldx	[%sp + CC64FSZ + STKB + TF_L + (5*8)], %l5
3867	ldx	[%sp + CC64FSZ + STKB + TF_L + (6*8)], %l6
3868	ldx	[%sp + CC64FSZ + STKB + TF_L + (7*8)], %l7
3869	stx	%l0, [%g6 + CC64FSZ + STKB + TF_L + (0*8)]
3870	stx	%l1, [%g6 + CC64FSZ + STKB + TF_L + (1*8)]
3871	stx	%l2, [%g6 + CC64FSZ + STKB + TF_L + (2*8)]
3872	stx	%l3, [%g6 + CC64FSZ + STKB + TF_L + (3*8)]
3873	stx	%l4, [%g6 + CC64FSZ + STKB + TF_L + (4*8)]
3874	stx	%l5, [%g6 + CC64FSZ + STKB + TF_L + (5*8)]
3875	stx	%l6, [%g6 + CC64FSZ + STKB + TF_L + (6*8)]
3876	stx	%l7, [%g6 + CC64FSZ + STKB + TF_L + (7*8)]
3877#endif
3878	ba,pt	%xcc, Lslowtrap_reenter
3879	 mov	%g6, %sp
3880#endif
3881
3882#if 0
3883/*
3884 * breakpoint:	capture as much info as possible and then call DDB
3885 * or trap, as the case may be.
3886 *
3887 * First, we switch to interrupt globals, and blow away %g7.  Then
3888 * switch down one stackframe -- just fiddle w/cwp, don't save or
3889 * we'll trap.  Then slowly save all the globals into our static
3890 * register buffer.  etc. etc.
3891 */
3892
3893breakpoint:
3894	wrpr	%g0, PSTATE_KERN|PSTATE_IG, %pstate	! Get IG to use
3895	rdpr	%cwp, %g7
3896	inc	1, %g7					! Equivalent of save
3897	wrpr	%g7, 0, %cwp				! Now we have some unused locals to fiddle with
3898XXX ddb_regs is now ddb-regp and is a pointer not a symbol.
3899	set	_C_LABEL(ddb_regs), %l0
3900	stx	%g1, [%l0+DBR_IG+(1*8)]			! Save IGs
3901	stx	%g2, [%l0+DBR_IG+(2*8)]
3902	stx	%g3, [%l0+DBR_IG+(3*8)]
3903	stx	%g4, [%l0+DBR_IG+(4*8)]
3904	stx	%g5, [%l0+DBR_IG+(5*8)]
3905	stx	%g6, [%l0+DBR_IG+(6*8)]
3906	stx	%g7, [%l0+DBR_IG+(7*8)]
3907	wrpr	%g0, PSTATE_KERN|PSTATE_MG, %pstate	! Get MG to use
3908	stx	%g1, [%l0+DBR_MG+(1*8)]			! Save MGs
3909	stx	%g2, [%l0+DBR_MG+(2*8)]
3910	stx	%g3, [%l0+DBR_MG+(3*8)]
3911	stx	%g4, [%l0+DBR_MG+(4*8)]
3912	stx	%g5, [%l0+DBR_MG+(5*8)]
3913	stx	%g6, [%l0+DBR_MG+(6*8)]
3914	stx	%g7, [%l0+DBR_MG+(7*8)]
3915	wrpr	%g0, PSTATE_KERN|PSTATE_AG, %pstate	! Get AG to use
3916	stx	%g1, [%l0+DBR_AG+(1*8)]			! Save AGs
3917	stx	%g2, [%l0+DBR_AG+(2*8)]
3918	stx	%g3, [%l0+DBR_AG+(3*8)]
3919	stx	%g4, [%l0+DBR_AG+(4*8)]
3920	stx	%g5, [%l0+DBR_AG+(5*8)]
3921	stx	%g6, [%l0+DBR_AG+(6*8)]
3922	stx	%g7, [%l0+DBR_AG+(7*8)]
3923	wrpr	%g0, PSTATE_KERN, %pstate	! Get G to use
3924	stx	%g1, [%l0+DBR_G+(1*8)]			! Save Gs
3925	stx	%g2, [%l0+DBR_G+(2*8)]
3926	stx	%g3, [%l0+DBR_G+(3*8)]
3927	stx	%g4, [%l0+DBR_G+(4*8)]
3928	stx	%g5, [%l0+DBR_G+(5*8)]
3929	stx	%g6, [%l0+DBR_G+(6*8)]
3930	stx	%g7, [%l0+DBR_G+(7*8)]
3931	rdpr	%canrestore, %l1
3932	stb	%l1, [%l0+DBR_CANRESTORE]
3933	rdpr	%cansave, %l2
3934	stb	%l2, [%l0+DBR_CANSAVE]
3935	rdpr	%cleanwin, %l3
3936	stb	%l3, [%l0+DBR_CLEANWIN]
3937	rdpr	%wstate, %l4
3938	stb	%l4, [%l0+DBR_WSTATE]
3939	rd	%y, %l5
3940	stw	%l5, [%l0+DBR_Y]
3941	rdpr	%tl, %l6
3942	stb	%l6, [%l0+DBR_TL]
3943	dec	1, %g7
3944#endif
3945
3946/*
3947 * I will not touch any of the DDB or KGDB stuff until I know what's going
3948 * on with the symbol table.  This is all still v7/v8 code and needs to be fixed.
3949 */
3950#ifdef KGDB
3951/*
3952 * bpt is entered on all breakpoint traps.
3953 * If this is a kernel breakpoint, we do not want to call trap().
3954 * Among other reasons, this way we can set breakpoints in trap().
3955 */
3956bpt:
3957	set	TSTATE_PRIV, %l4
3958	andcc	%l4, %l0, %g0		! breakpoint from kernel?
3959	bz	slowtrap		! no, go do regular trap
3960	 nop
3961
3962	/*
3963	 * Build a trap frame for kgdb_trap_glue to copy.
3964	 * Enable traps but set ipl high so that we will not
3965	 * see interrupts from within breakpoints.
3966	 */
3967	save	%sp, -CCFSZ-TF_SIZE, %sp		! allocate a trap frame
3968	TRAP_SETUP(-CCFSZ-TF_SIZE)
3969	or	%l0, PSR_PIL, %l4	! splhigh()
3970	wr	%l4, 0, %psr		! the manual claims that this
3971	wr	%l4, PSR_ET, %psr	! song and dance is necessary
3972	std	%l0, [%sp + CCFSZ + 0]	! tf.tf_psr, tf.tf_pc
3973	mov	%l3, %o0		! trap type arg for kgdb_trap_glue
3974	rd	%y, %l3
3975	std	%l2, [%sp + CCFSZ + 8]	! tf.tf_npc, tf.tf_y
3976	rd	%wim, %l3
3977	st	%l3, [%sp + CCFSZ + 16]	! tf.tf_wim (a kgdb-only r/o field)
3978	st	%g1, [%sp + CCFSZ + 20]	! tf.tf_global[1]
3979	std	%g2, [%sp + CCFSZ + 24]	! etc
3980	std	%g4, [%sp + CCFSZ + 32]
3981	std	%g6, [%sp + CCFSZ + 40]
3982	std	%i0, [%sp + CCFSZ + 48]	! tf.tf_in[0..1]
3983	std	%i2, [%sp + CCFSZ + 56]	! etc
3984	std	%i4, [%sp + CCFSZ + 64]
3985	std	%i6, [%sp + CCFSZ + 72]
3986
3987	/*
3988	 * Now call kgdb_trap_glue(); if it returns, call trap().
3989	 */
3990	mov	%o0, %l3		! gotta save trap type
3991	call	_C_LABEL(kgdb_trap_glue)		! kgdb_trap_glue(type, &trapframe)
3992	 add	%sp, CCFSZ, %o1		! (&trapframe)
3993
3994	/*
3995	 * Use slowtrap to call trap---but first erase our tracks
3996	 * (put the registers back the way they were).
3997	 */
3998	mov	%l3, %o0		! slowtrap will need trap type
3999	ld	[%sp + CCFSZ + 12], %l3
4000	wr	%l3, 0, %y
4001	ld	[%sp + CCFSZ + 20], %g1
4002	ldd	[%sp + CCFSZ + 24], %g2
4003	ldd	[%sp + CCFSZ + 32], %g4
4004	b	Lslowtrap_reenter
4005	 ldd	[%sp + CCFSZ + 40], %g6
4006
4007/*
4008 * Enter kernel breakpoint.  Write all the windows (not including the
4009 * current window) into the stack, so that backtrace works.  Copy the
4010 * supplied trap frame to the kgdb stack and switch stacks.
4011 *
4012 * kgdb_trap_glue(type, tf0)
4013 *	int type;
4014 *	struct trapframe *tf0;
4015 */
4016ENTRY_NOPROFILE(kgdb_trap_glue)
4017	save	%sp, -CCFSZ, %sp
4018
4019	flushw				! flush all windows
4020	mov	%sp, %l4		! %l4 = current %sp
4021
4022	/* copy trapframe to top of kgdb stack */
4023	set	_C_LABEL(kgdb_stack) + KGDB_STACK_SIZE - 80, %l0
4024					! %l0 = tfcopy -> end_of_kgdb_stack
4025	mov	80, %l1
40261:	ldd	[%i1], %l2
4027	inc	8, %i1
4028	deccc	8, %l1
4029	std	%l2, [%l0]
4030	bg	1b
4031	 inc	8, %l0
4032
4033#ifdef NOTDEF_DEBUG
4034	/* save old red zone and then turn it off */
4035	sethi	%hi(_C_LABEL(redzone)), %l7
4036	ld	[%l7 + %lo(_C_LABEL(redzone))], %l6
4037	st	%g0, [%l7 + %lo(_C_LABEL(redzone))]
4038#endif
4039	/* switch to kgdb stack */
4040	add	%l0, -CCFSZ-TF_SIZE, %sp
4041
4042	/* if (kgdb_trap(type, tfcopy)) kgdb_rett(tfcopy); */
4043	mov	%i0, %o0
4044	call	_C_LABEL(kgdb_trap)
4045	add	%l0, -80, %o1
4046	tst	%o0
4047	bnz,a	kgdb_rett
4048	 add	%l0, -80, %g1
4049
4050	/*
4051	 * kgdb_trap() did not handle the trap at all so the stack is
4052	 * still intact.  A simple `restore' will put everything back,
4053	 * after we reset the stack pointer.
4054	 */
4055	mov	%l4, %sp
4056#ifdef NOTDEF_DEBUG
4057	st	%l6, [%l7 + %lo(_C_LABEL(redzone))]	! restore red zone
4058#endif
4059	ret
4060	 restore
4061
4062/*
4063 * Return from kgdb trap.  This is sort of special.
4064 *
4065 * We know that kgdb_trap_glue wrote the window above it, so that we will
4066 * be able to (and are sure to have to) load it up.  We also know that we
4067 * came from kernel land and can assume that the %fp (%i6) we load here
4068 * is proper.  We must also be sure not to lower ipl (it is at splhigh())
4069 * until we have traps disabled, due to the SPARC taking traps at the
4070 * new ipl before noticing that PSR_ET has been turned off.  We are on
4071 * the kgdb stack, so this could be disastrous.
4072 *
4073 * Note that the trapframe argument in %g1 points into the current stack
4074 * frame (current window).  We abandon this window when we move %g1->tf_psr
4075 * into %psr, but we will not have loaded the new %sp yet, so again traps
4076 * must be disabled.
4077 */
4078kgdb_rett:
4079	rd	%psr, %g4		! turn off traps
4080	wr	%g4, PSR_ET, %psr
4081	/* use the three-instruction delay to do something useful */
4082	ld	[%g1], %g2		! pick up new %psr
4083	ld	[%g1 + 12], %g3		! set %y
4084	wr	%g3, 0, %y
4085#ifdef NOTDEF_DEBUG
4086	st	%l6, [%l7 + %lo(_C_LABEL(redzone))] ! and restore red zone
4087#endif
4088	wr	%g0, 0, %wim		! enable window changes
4089	nop; nop; nop
4090	/* now safe to set the new psr (changes CWP, leaves traps disabled) */
4091	wr	%g2, 0, %psr		! set rett psr (including cond codes)
4092	/* 3 instruction delay before we can use the new window */
4093/*1*/	ldd	[%g1 + 24], %g2		! set new %g2, %g3
4094/*2*/	ldd	[%g1 + 32], %g4		! set new %g4, %g5
4095/*3*/	ldd	[%g1 + 40], %g6		! set new %g6, %g7
4096
4097	/* now we can use the new window */
4098	mov	%g1, %l4
4099	ld	[%l4 + 4], %l1		! get new pc
4100	ld	[%l4 + 8], %l2		! get new npc
4101	ld	[%l4 + 20], %g1		! set new %g1
4102
4103	/* set up returnee's out registers, including its %sp */
4104	ldd	[%l4 + 48], %i0
4105	ldd	[%l4 + 56], %i2
4106	ldd	[%l4 + 64], %i4
4107	ldd	[%l4 + 72], %i6
4108
4109	/* load returnee's window, making the window above it be invalid */
4110	restore
4111	restore	%g0, 1, %l1		! move to inval window and set %l1 = 1
4112	rd	%psr, %l0
4113	srl	%l1, %l0, %l1
4114	wr	%l1, 0, %wim		! %wim = 1 << (%psr & 31)
4115	sethi	%hi(CPCB), %l1
4116	LDPTR	[%l1 + %lo(CPCB)], %l1
4117	and	%l0, 31, %l0		! CWP = %psr & 31;
4118!	st	%l0, [%l1 + PCB_WIM]	! cpcb->pcb_wim = CWP;
4119	save	%g0, %g0, %g0		! back to window to reload
4120!	LOADWIN(%sp)
4121	save	%g0, %g0, %g0		! back to trap window
4122	/* note, we have not altered condition codes; safe to just rett */
4123	RETT
4124#endif
4125
4126/*
4127 * syscall_setup() builds a trap frame and calls syscall().
4128 * sun_syscall is same but delivers sun system call number
4129 * XXX	should not have to save&reload ALL the registers just for
4130 *	ptrace...
4131 */
4132syscall_setup:
4133#ifdef TRAPS_USE_IG
4134	wrpr	%g0, PSTATE_KERN|PSTATE_IG, %pstate	! DEBUG
4135#endif
4136	TRAP_SETUP(-CC64FSZ-TF_SIZE)
4137
4138#ifdef DEBUG
4139	rdpr	%tt, %o1	! debug
4140	sth	%o1, [%sp + CC64FSZ + STKB + TF_TT]! debug
4141#endif
4142
4143	! Get back to normal globals
4144#ifdef SUN4V
4145	sethi	%hi(cputyp), %g5
4146	ld	[%g5 + %lo(cputyp)], %g5
4147	cmp	%g5, CPU_SUN4V
4148	bne,pt	%icc, 1f
4149	 nop
4150	NORMAL_GLOBALS_SUN4V
4151	ba	2f
4152	 nop
41531:
4154#endif
4155	NORMAL_GLOBALS_SUN4U
41562:
4157
4158	stx	%g1, [%sp + CC64FSZ + STKB + TF_G + ( 1*8)]
4159	mov	%g1, %o1			! code
4160	rdpr	%tpc, %o2			! (pc)
4161	stx	%g2, [%sp + CC64FSZ + STKB + TF_G + ( 2*8)]
4162	rdpr	%tstate, %g1
4163	stx	%g3, [%sp + CC64FSZ + STKB + TF_G + ( 3*8)]
4164	rdpr	%tnpc, %o3
4165	stx	%g4, [%sp + CC64FSZ + STKB + TF_G + ( 4*8)]
4166	rd	%y, %o4
4167	stx	%g5, [%sp + CC64FSZ + STKB + TF_G + ( 5*8)]
4168	stx	%g6, [%sp + CC64FSZ + STKB + TF_G + ( 6*8)]
4169	wrpr	%g0, 0, %tl			! return to tl=0
4170	stx	%g7, [%sp + CC64FSZ + STKB + TF_G + ( 7*8)]
4171	add	%sp, CC64FSZ + STKB, %o0	! (&tf)
4172
4173	stx	%g1, [%sp + CC64FSZ + STKB + TF_TSTATE]
4174	stx	%o2, [%sp + CC64FSZ + STKB + TF_PC]
4175	stx	%o3, [%sp + CC64FSZ + STKB + TF_NPC]
4176	st	%o4, [%sp + CC64FSZ + STKB + TF_Y]
4177
4178	rdpr	%pil, %g5
4179	stb	%g5, [%sp + CC64FSZ + STKB + TF_PIL]
4180	stb	%g5, [%sp + CC64FSZ + STKB + TF_OLDPIL]
4181
4182	!! In the EMBEDANY memory model %g4 points to the start of the data segment.
4183	!! In our case we need to clear it before calling any C-code
4184	clr	%g4
4185	wr	%g0, ASI_PRIMARY_NOFAULT, %asi	! Restore default ASI
4186
4187	sethi	%hi(CURLWP), %l1
4188	LDPTR	[%l1 + %lo(CURLWP)], %l1
4189	LDPTR	[%l1 + L_PROC], %l1		! now %l1 points to p
4190	LDPTR	[%l1 + P_MD_SYSCALL], %l1
4191	call	%l1
4192	 wrpr	%g0, PSTATE_INTR, %pstate	! turn on interrupts
4193
4194	/* see `lwp_trampoline' for the reason for this label */
4195return_from_syscall:
4196	wrpr	%g0, PSTATE_KERN, %pstate	! Disable interrupts
4197	wrpr	%g0, 0, %tl			! Return to tl==0
4198	b	return_from_trap
4199	 nop
4200	NOTREACHED
4201
4202/*
4203 * interrupt_vector:
4204 *
4205 * Spitfire chips never get level interrupts directly from H/W.
4206 * Instead, all interrupts come in as interrupt_vector traps.
4207 * The interrupt number or handler address is an 11 bit number
4208 * encoded in the first interrupt data word.  Additional words
4209 * are application specific and used primarily for cross-calls.
4210 *
4211 * The interrupt vector handler then needs to identify the
4212 * interrupt source from the interrupt number and arrange to
4213 * invoke the interrupt handler.  This can either be done directly
4214 * from here, or a softint at a particular level can be issued.
4215 *
4216 * To call an interrupt directly and not overflow the trap stack,
4217 * the trap registers should be saved on the stack, registers
4218 * cleaned, trap-level decremented, the handler called, and then
4219 * the process must be reversed.
4220 *
4221 * To simplify life all we do here is issue an appropriate softint.
4222 *
4223 * Note:	It is impossible to identify or change a device's
4224 *		interrupt number until it is probed.  That's the
4225 *		purpose for all the funny interrupt acknowledge
4226 *		code.
4227 *
4228 */
4229
4230/*
4231 * Vectored interrupts:
4232 *
4233 * When an interrupt comes in, interrupt_vector uses the interrupt
4234 * vector number to lookup the appropriate intrhand from the intrlev
4235 * array.  It then looks up the interrupt level from the intrhand
4236 * structure.  It uses the level to index the intrpending array,
4237 * which is 8 slots for each possible interrupt level (so we can
4238 * shift instead of multiply for address calculation).  It hunts for
4239 * any available slot at that level.  Available slots are NULL.
4240 *
4241 * Then interrupt_vector uses the interrupt level in the intrhand
4242 * to issue a softint of the appropriate level.  The softint handler
4243 * figures out what level interrupt it's handling and pulls the first
4244 * intrhand pointer out of the intrpending array for that interrupt
4245 * level, puts a NULL in its place, clears the interrupt generator,
4246 * and invokes the interrupt handler.
4247 */
4248
4249/* intrpending array is now in per-CPU structure. */
4250
4251#ifdef DEBUG
4252#define INTRDEBUG_VECTOR	0x1
4253#define INTRDEBUG_LEVEL		0x2
4254#define INTRDEBUG_FUNC		0x4
4255#define INTRDEBUG_SPUR		0x8
4256	.data
4257	.globl	_C_LABEL(intrdebug)
4258_C_LABEL(intrdebug):	.word 0x0
4259/*
4260 * Note: we use the local label `97' to branch forward to, to skip
4261 * actual debugging code following a `intrdebug' bit test.
4262 */
4263#endif
4264	.text
4265interrupt_vector:
4266#ifdef TRAPSTATS
4267	set	_C_LABEL(kiveccnt), %g1
4268	set	_C_LABEL(iveccnt), %g2
4269	rdpr	%tl, %g3
4270	dec	%g3
4271	movrz	%g3, %g2, %g1
4272	lduw	[%g1], %g2
4273	inc	%g2
4274	stw	%g2, [%g1]
4275#endif
4276	ldxa	[%g0] ASI_IRSR, %g1
4277	mov	IRDR_0H, %g7
4278	ldxa	[%g7] ASI_IRDR, %g7	! Get interrupt number
4279	membar	#Sync
4280
4281	btst	IRSR_BUSY, %g1
4282	bz,pn	%icc, 3f		! spurious interrupt
4283#ifdef MULTIPROCESSOR
4284	 sethi	%hi(KERNBASE), %g1
4285
4286	cmp	%g7, %g1
4287	bl,a,pt	%xcc, Lsoftint_regular	! >= KERNBASE is a fast cross-call
4288	 and	%g7, (MAXINTNUM-1), %g7	! XXX make sun4us work
4289
4290	mov	IRDR_1H, %g2
4291	ldxa	[%g2] ASI_IRDR, %g2	! Get IPI handler argument 1
4292	mov	IRDR_2H, %g3
4293	ldxa	[%g3] ASI_IRDR, %g3	! Get IPI handler argument 2
4294
4295	stxa	%g0, [%g0] ASI_IRSR	! Ack IRQ
4296	membar	#Sync			! Should not be needed due to retry
4297
4298	jmpl	%g7, %g0
4299	 nop
4300#else
4301	and	%g7, (MAXINTNUM-1), %g7	! XXX make sun4us work
4302#endif
4303
4304Lsoftint_regular:
4305	stxa	%g0, [%g0] ASI_IRSR	! Ack IRQ
4306	membar	#Sync			! Should not be needed due to retry
4307	sethi	%hi(_C_LABEL(intrlev)), %g3
4308	sllx	%g7, PTRSHFT, %g5	! Calculate entry number
4309	or	%g3, %lo(_C_LABEL(intrlev)), %g3
4310	LDPTR	[%g3 + %g5], %g5	! We have a pointer to the handler
4311	brz,pn	%g5, 3f			! NULL means it isn't registered yet.  Skip it.
4312	 nop
4313
4314	! increment per-ivec counter
4315	ldx	[%g5 + IH_CNT], %g1
4316	inc	%g1
4317	stx	%g1, [%g5 + IH_CNT]
4318
4319setup_sparcintr:
4320	LDPTR	[%g5+IH_PEND], %g6	! Read pending flag
4321	brnz,pn	%g6, ret_from_intr_vector ! Skip it if it's running
4322	 ldub	[%g5+IH_PIL], %g6	! Read interrupt level
4323	sethi	%hi(CPUINFO_VA+CI_INTRPENDING), %g1
4324	sll	%g6, PTRSHFT, %g3	! Find start of table for this IPL
4325	or	%g1, %lo(CPUINFO_VA+CI_INTRPENDING), %g1
4326	add	%g1, %g3, %g1
43271:
4328	LDPTR	[%g1], %g3		! Load list head
4329	STPTR	%g3, [%g5+IH_PEND]	! Link our intrhand node in
4330	mov	%g5, %g7
4331	CASPTRA	[%g1] ASI_N, %g3, %g7
4332	cmp	%g7, %g3		! Did it work?
4333	bne,pn	CCCR, 1b		! No, try again
4334	 .empty
43352:
4336#ifdef NOT_DEBUG
4337	set	_C_LABEL(intrdebug), %g7
4338	ld	[%g7], %g7
4339	btst	INTRDEBUG_VECTOR, %g7
4340	bz,pt	%icc, 97f
4341	 nop
4342
4343	cmp	%g6, 0xa		! ignore clock interrupts?
4344	bz,pt	%icc, 97f
4345	 nop
4346
4347	STACKFRAME(-CC64FSZ)		! Get a clean register window
4348	LOAD_ASCIZ(%o0,\
4349	    "interrupt_vector: number %lx softint mask %lx pil %lu slot %p\n")
4350	mov	%g2, %o1
4351	rdpr	%pil, %o3
4352	mov	%g1, %o4
4353	GLOBTOLOC
4354	clr	%g4
4355	call	prom_printf
4356	 mov	%g6, %o2
4357	LOCTOGLOB
4358	restore
435997:
4360#endif
4361	mov	1, %g7
4362	sll	%g7, %g6, %g6
4363	wr	%g6, 0, SET_SOFTINT	! Invoke a softint
4364
4365	.global ret_from_intr_vector
4366ret_from_intr_vector:
4367	retry
4368	NOTREACHED
4369
43703:
4371#ifdef NOT_DEBUG	/* always do this */
4372	set	_C_LABEL(intrdebug), %g6
4373	ld	[%g6], %g6
4374	btst	INTRDEBUG_SPUR, %g6
4375	bz,pt	%icc, 97f
4376	 nop
4377#endif
4378#if 1
4379	set	PANICSTACK-STKB, %g1	! Use panic stack temporarily
4380	save	%g1, -CC64FSZ, %sp	! Get a clean register window
4381	LOAD_ASCIZ(%o0, "interrupt_vector: spurious vector %lx at pil %d\n")
4382	mov	%g7, %o1
4383	GLOBTOLOC
4384	clr	%g4
4385	call	prom_printf
4386	 rdpr	%pil, %o2
4387	LOCTOGLOB
4388	restore
438997:
4390#endif
4391	ba,a	ret_from_intr_vector
4392	 nop				! XXX spitfire bug?
4393
4394sun4v_cpu_mondo:
4395! XXX Rework this when a UP kernel works - crash for now
4396	sir
4397	mov	0x3c0, %g1			 ! CPU Mondo Queue Head
4398	ldxa	[%g1] ASI_QUEUE, %g2		 ! fetch index value for head
4399	set	CPUINFO_VA, %g3
4400	ldx	[%g3 + CI_PADDR], %g3
4401	add	%g3, CI_CPUMQ, %g3
4402	ldxa	[%g3] ASI_PHYS_CACHED, %g3	 ! fetch head element
4403	ldxa	[%g3 + %g2] ASI_PHYS_CACHED, %g4 ! fetch func
4404	add	%g2, 8, %g5
4405	ldxa	[%g3 + %g5] ASI_PHYS_CACHED, %g5 ! fetch arg1
4406	add	%g2, 16, %g6
4407	ldxa	[%g3 + %g6] ASI_PHYS_CACHED, %g6 ! fetch arg2
4408	add	%g2, 64, %g2			 ! point to next element in queue
4409	and	%g2, 0x7ff, %g2			 ! modulo queue size 2048 (32*64)
4410	stxa	%g2, [%g1] ASI_QUEUE		 ! update head index
4411	membar	#Sync
4412
4413	mov	%g4, %g2
4414	mov	%g5, %g3
4415	mov	%g6, %g5
4416	jmpl	%g2, %g0
4417	 nop			! No store here!
4418	retry
4419	NOTREACHED
4420
4421sun4v_dev_mondo:
4422	mov	0x3d0, %g1			! Dev Mondo Queue Head
4423	ldxa	[%g1] ASI_QUEUE, %g2		! fetch index value
4424	mov	0x3d8, %g1			! Dev Mondo Queue Tail
4425	ldxa	[%g1] ASI_QUEUE, %g4		! fetch index value
4426	cmp	%g2, %g4			! head = queue?
4427	bne,pt 	%xcc, 2f			! unusually not the case
4428	 nop
4429	retry					! unlikely, ignore interrupt
44302:
4431	set	CPUINFO_VA, %g3			 ! fetch cpuinfo pa
4432	ldx	[%g3 + CI_PADDR], %g3		 ! fetch intstack pa
4433	set	CPUINFO_VA-INTSTACK, %g4	 ! offset to cpuinfo
4434	add	%g4, %g3, %g3			 ! %g3 is now cpuifo
4435	add	%g3, CI_DEVMQ, %g3		 ! calc offset to devmq
4436	ldxa	[%g3] ASI_PHYS_CACHED, %g3	 ! fetch address of devmq
4437	ldxa	[%g3 + %g2] ASI_PHYS_CACHED, %g5 !
4438	add	%g2, 64, %g2			 ! each element is 64 bytes
4439	and	%g2, 0x7ff, %g2			 ! assume 32 elements
4440	mov	0x3d0, %g1			 ! Dev Mondo Queue Head
4441	stxa	%g2, [%g1] ASI_QUEUE		 ! adjust head index value
4442	membar	#Sync
4443
4444	cmp	%g5, MAXINTNUM			! Handle both sun4v legacy (sysino) and cookies.
4445	bgeu,pn	%xcc, 1f			! See UltraSPARC Virtual Machine Specification
4446	 nop					! version 3 chapter 6 (Interrupt model)
4447
4448	sethi	%hi(_C_LABEL(intrlev)), %g3
4449	sllx	%g5, PTRSHFT, %g5	! Calculate entry number
4450	or	%g3, %lo(_C_LABEL(intrlev)), %g3
4451	LDPTR	[%g3 + %g5], %g5	! We have a pointer to the handler
44521:
4453	brnz,pt	%g5, setup_sparcintr	! branch if valid handle
4454	 nop
4455
4456	ba,a	3b			! log if invalid handle
4457	 nop
4458
4459/*
4460 * Ultra1 and Ultra2 CPUs use soft interrupts for everything.  What we do
4461 * on a soft interrupt, is we should check which bits in SOFTINT(%asr22)
4462 * are set, handle those interrupts, then clear them by setting the
4463 * appropriate bits in CLEAR_SOFTINT(%asr21).
4464 *
4465 * We have an array of 8 interrupt vector slots for each of 15 interrupt
4466 * levels.  If a vectored interrupt can be dispatched, the dispatch
4467 * routine will place a pointer to an intrhand structure in one of
4468 * the slots.  The interrupt handler will go through the list to look
4469 * for an interrupt to dispatch.  If it finds one it will pull it off
4470 * the list, free the entry, and call the handler.  The code is like
4471 * this:
4472 *
4473 *	for (i=0; i<8; i++)
4474 *		if (ih = intrpending[intlev][i]) {
4475 *			intrpending[intlev][i] = NULL;
4476 *			if ((*ih->ih_fun)(ih->ih_arg ? ih->ih_arg : &frame))
4477 *				return;
4478 *			strayintr(&frame);
4479 *			return;
4480 *		}
4481 *
4482 * Otherwise we go back to the old style of polled interrupts.
4483 *
4484 * After preliminary setup work, the interrupt is passed to each
4485 * registered handler in turn.  These are expected to return nonzero if
4486 * they took care of the interrupt.  If a handler claims the interrupt,
4487 * we exit (hardware interrupts are latched in the requestor so we'll
4488 * just take another interrupt in the unlikely event of simultaneous
4489 * interrupts from two different devices at the same level).  If we go
4490 * through all the registered handlers and no one claims it, we report a
4491 * stray interrupt.  This is more or less done as:
4492 *
4493 *	for (ih = intrhand[intlev]; ih; ih = ih->ih_next)
4494 *		if ((*ih->ih_fun)(ih->ih_arg ? ih->ih_arg : &frame))
4495 *			return;
4496 *	strayintr(&frame);
4497 *
4498 * Inputs:
4499 *	%l0 = %tstate
4500 *	%l1 = return pc
4501 *	%l2 = return npc
4502 *	%l3 = interrupt level
4503 *	(software interrupt only) %l4 = bits to clear in interrupt register
4504 *
4505 * Internal:
4506 *	%l4, %l5: local variables
4507 *	%l6 = %y
4508 *	%l7 = %g1
4509 *	%g2..%g7 go to stack
4510 *
4511 * An interrupt frame is built in the space for a full trapframe;
4512 * this contains the psr, pc, npc, and interrupt level.
4513 *
4514 * The level of this interrupt is determined by:
4515 *
4516 *       IRQ# = %tt - 0x40
4517 */
4518
4519ENTRY_NOPROFILE(sparc_interrupt)
4520#ifdef TRAPS_USE_IG
4521	! This is for interrupt debugging
4522	wrpr	%g0, PSTATE_KERN|PSTATE_IG, %pstate	! DEBUG
4523#endif
4524	/*
4525	 * If this is a %tick or %stick softint, clear it then call
4526	 * interrupt_vector. Only one of them should be enabled at any given
4527	 * time.
4528	 */
4529	rd	SOFTINT, %g1
4530	set	TICK_INT|STICK_INT, %g5
4531	andcc	%g5, %g1, %g5
4532	bz,pt	%icc, 0f
4533	 sethi	%hi(CPUINFO_VA+CI_TICK_IH), %g3
4534	wr	%g0, %g5, CLEAR_SOFTINT
4535	ba,pt	%icc, setup_sparcintr
4536	 LDPTR	[%g3 + %lo(CPUINFO_VA+CI_TICK_IH)], %g5
45370:
4538
4539#ifdef TRAPSTATS
4540	sethi	%hi(_C_LABEL(kintrcnt)), %g1
4541	sethi	%hi(_C_LABEL(uintrcnt)), %g2
4542	or	%g1, %lo(_C_LABEL(kintrcnt)), %g1
4543	or	%g1, %lo(_C_LABEL(uintrcnt)), %g2
4544	rdpr	%tl, %g3
4545	dec	%g3
4546	movrz	%g3, %g2, %g1
4547	lduw	[%g1], %g2
4548	inc	%g2
4549	stw	%g2, [%g1]
4550	/* See if we're on the interrupt stack already. */
4551	set	EINTSTACK, %g2
4552	set	(EINTSTACK-INTSTACK), %g1
4553	btst	1, %sp
4554	add	%sp, BIAS, %g3
4555	movz	%icc, %sp, %g3
4556	srl	%g3, 0, %g3
4557	sub	%g2, %g3, %g3
4558	cmp	%g3, %g1
4559	bgu	1f
4560	 set	_C_LABEL(intristk), %g1
4561	lduw	[%g1], %g2
4562	inc	%g2
4563	stw	%g2, [%g1]
45641:
4565#endif
4566	INTR_SETUP(-CC64FSZ-TF_SIZE)
4567
4568	! Switch to normal globals so we can save them
4569#ifdef SUN4V
4570	sethi	%hi(cputyp), %g5
4571	ld	[%g5 + %lo(cputyp)], %g5
4572	cmp	%g5, CPU_SUN4V
4573	bne,pt	%icc, 1f
4574	 nop
4575	NORMAL_GLOBALS_SUN4V
4576	! Save the normal globals
4577	stx	%g1, [%sp + CC64FSZ + STKB + TF_G + ( 1*8)]
4578	stx	%g2, [%sp + CC64FSZ + STKB + TF_G + ( 2*8)]
4579	stx	%g3, [%sp + CC64FSZ + STKB + TF_G + ( 3*8)]
4580	stx	%g4, [%sp + CC64FSZ + STKB + TF_G + ( 4*8)]
4581	stx	%g5, [%sp + CC64FSZ + STKB + TF_G + ( 5*8)]
4582	stx	%g6, [%sp + CC64FSZ + STKB + TF_G + ( 6*8)]
4583	stx	%g7, [%sp + CC64FSZ + STKB + TF_G + ( 7*8)]
4584
4585	/*
4586	 * In the EMBEDANY memory model %g4 points to the start of the
4587	 * data segment.  In our case we need to clear it before calling
4588	 * any C-code.
4589	 */
4590	clr	%g4
4591
4592	ba	2f
4593	 nop
45941:
4595#endif
4596	NORMAL_GLOBALS_SUN4U
4597	! Save the normal globals
4598	stx	%g1, [%sp + CC64FSZ + STKB + TF_G + ( 1*8)]
4599	stx	%g2, [%sp + CC64FSZ + STKB + TF_G + ( 2*8)]
4600	stx	%g3, [%sp + CC64FSZ + STKB + TF_G + ( 3*8)]
4601	stx	%g4, [%sp + CC64FSZ + STKB + TF_G + ( 4*8)]
4602	stx	%g5, [%sp + CC64FSZ + STKB + TF_G + ( 5*8)]
4603	stx	%g6, [%sp + CC64FSZ + STKB + TF_G + ( 6*8)]
4604	stx	%g7, [%sp + CC64FSZ + STKB + TF_G + ( 7*8)]
4605
4606	/*
4607	 * In the EMBEDANY memory model %g4 points to the start of the
4608	 * data segment.  In our case we need to clear it before calling
4609	 * any C-code.
4610	 */
4611	clr	%g4
4612
4613	flushw			! Do not remove this insn -- causes interrupt loss
4614
46152:
4616	rd	%y, %l6
4617	INCR64(CPUINFO_VA+CI_NINTR)	! cnt.v_ints++ (clobbers %o0,%o1)
4618	rdpr	%tt, %l5		! Find out our current IPL
4619	rdpr	%tstate, %l0
4620	rdpr	%tpc, %l1
4621	rdpr	%tnpc, %l2
4622	rdpr	%tl, %l3		! Dump our trap frame now we have taken the IRQ
4623	stw	%l6, [%sp + CC64FSZ + STKB + TF_Y]	! Silly, but we need to save this for rft
4624	dec	%l3
4625	wrpr	%g0, %l3, %tl
4626	sth	%l5, [%sp + CC64FSZ + STKB + TF_TT]! debug
4627	stx	%l0, [%sp + CC64FSZ + STKB + TF_TSTATE]	! set up intrframe/clockframe
4628	stx	%l1, [%sp + CC64FSZ + STKB + TF_PC]
4629	btst	TSTATE_PRIV, %l0		! User mode?
4630	stx	%l2, [%sp + CC64FSZ + STKB + TF_NPC]
4631
4632	sub	%l5, 0x40, %l6			! Convert to interrupt level
4633	sethi	%hi(_C_LABEL(intr_evcnts)), %l4
4634	stb	%l6, [%sp + CC64FSZ + STKB + TF_PIL]	! set up intrframe/clockframe
4635	rdpr	%pil, %o1
4636	mulx	%l6, EVC_SIZE, %l3
4637	or	%l4, %lo(_C_LABEL(intr_evcnts)), %l4	! intrcnt[intlev]++;
4638	stb	%o1, [%sp + CC64FSZ + STKB + TF_OLDPIL]	! old %pil
4639	ldx	[%l4 + %l3], %o0
4640	add	%l4, %l3, %l4
4641	clr	%l5			! Zero handled count
4642#ifdef MULTIPROCESSOR
4643	mov	1, %l3			! Ack softint
46441:	add	%o0, 1, %l7
4645	casxa	[%l4] ASI_N, %o0, %l7
4646	cmp	%o0, %l7
4647	bne,a,pn %xcc, 1b		! retry if changed
4648	 mov	%l7, %o0
4649#else
4650	inc	%o0
4651	mov	1, %l3			! Ack softint
4652	stx	%o0, [%l4]
4653#endif
4654	sll	%l3, %l6, %l3		! Generate IRQ mask
4655
4656	wrpr	%l6, %pil
4657
4658#define SOFTINT_INT \
4659	(1<<IPL_SOFTCLOCK|1<<IPL_SOFTBIO|1<<IPL_SOFTNET|1<<IPL_SOFTSERIAL)
4660
4661	! Increment the per-cpu interrupt depth in case of hardintrs
4662	btst	SOFTINT_INT, %l3
4663	bnz,pn	%icc, sparc_intr_retry
4664	 sethi	%hi(CPUINFO_VA+CI_IDEPTH), %l1
4665	ld	[%l1 + %lo(CPUINFO_VA+CI_IDEPTH)], %l2
4666	inc	%l2
4667	st	%l2, [%l1 + %lo(CPUINFO_VA+CI_IDEPTH)]
4668
4669sparc_intr_retry:
4670	wr	%l3, 0, CLEAR_SOFTINT	! (don't clear possible %tick IRQ)
4671	sethi	%hi(CPUINFO_VA+CI_INTRPENDING), %l4
4672	sll	%l6, PTRSHFT, %l2
4673	or	%l4, %lo(CPUINFO_VA+CI_INTRPENDING), %l4
4674	add	%l2, %l4, %l4
4675
46761:
4677	membar	#StoreLoad		! Make sure any failed casxa insns complete
4678	LDPTR	[%l4], %l2		! Check a slot
4679	cmp	%l2, -1
4680	beq,pn	CCCR, intrcmplt		! Empty list?
4681	 mov	-1, %l7
4682	membar	#LoadStore
4683	CASPTRA	[%l4] ASI_N, %l2, %l7	! Grab the entire list
4684	cmp	%l7, %l2
4685	bne,pn	CCCR, 1b
4686	 add	%sp, CC64FSZ+STKB, %o2	! tf = %sp + CC64FSZ + STKB
4687	LDPTR	[%l2 + IH_PEND], %l7
4688	cmp	%l7, -1			! Last slot?
4689	be,pt	CCCR, 3f
4690	 membar	#LoadStore
4691
4692	/*
4693	 * Reverse a pending list since setup_sparcintr/send_softint
4694	 * makes it in a LIFO order.
4695	 */
4696	mov	-1, %o0			! prev = -1
46971:	STPTR	%o0, [%l2 + IH_PEND]	! ih->ih_pending = prev
4698	mov	%l2, %o0		! prev = ih
4699	mov	%l7, %l2		! ih = ih->ih_pending
4700	LDPTR	[%l2 + IH_PEND], %l7
4701	cmp	%l7, -1			! Last slot?
4702	bne,pn	CCCR, 1b
4703	 membar	#LoadStore
4704	ba,pt	CCCR, 3f
4705	 mov	%o0, %l7		! save ih->ih_pending
4706
47072:
4708	add	%sp, CC64FSZ+STKB, %o2	! tf = %sp + CC64FSZ + STKB
4709	LDPTR	[%l2 + IH_PEND], %l7	! save ih->ih_pending
4710	membar	#LoadStore
47113:
4712	STPTR	%g0, [%l2 + IH_PEND]	! Clear pending flag
4713	membar	#Sync
4714	LDPTR	[%l2 + IH_FUN], %o4	! ih->ih_fun
4715	LDPTR	[%l2 + IH_ARG], %o0	! ih->ih_arg
4716
4717#ifdef NOT_DEBUG
4718	set	_C_LABEL(intrdebug), %o3
4719	ld	[%o2], %o3
4720	btst	INTRDEBUG_FUNC, %o3
4721	bz,a,pt	%icc, 97f
4722	 nop
4723
4724	cmp	%l6, 0xa		! ignore clock interrupts?
4725	bz,pt	%icc, 97f
4726	 nop
4727
4728	STACKFRAME(-CC64FSZ)		! Get a clean register window
4729	LOAD_ASCIZ(%o0, "sparc_interrupt: func %p arg %p\n")
4730	mov	%i0, %o2		! arg
4731	GLOBTOLOC
4732	call	prom_printf
4733	 mov	%i4, %o1		! func
4734	LOCTOGLOB
4735	restore
473697:
4737	mov	%l4, %o1
4738#endif
4739
4740	wrpr	%g0, PSTATE_INTR, %pstate	! Reenable interrupts
4741	jmpl	%o4, %o7		! handled = (*ih->ih_fun)(...)
4742	 movrz	%o0, %o2, %o0		! arg = (arg == 0) ? arg : tf
4743	wrpr	%g0, PSTATE_KERN, %pstate	! Disable interrupts
4744	LDPTR	[%l2 + IH_CLR], %l1
4745	membar	#Sync
4746
4747	brz,pn	%l1, 0f
4748	 add	%l5, %o0, %l5
4749	stx	%g0, [%l1]		! Clear intr source
4750	membar	#Sync			! Should not be needed
47510:
4752	LDPTR	[%l2 + IH_ACK], %l1	! ih->ih_ack
4753	brz,pn	%l1, 1f
4754	 nop
4755	jmpl	%l1, %o7		! (*ih->ih_ack)(ih)
4756	 mov	%l2, %o0
47571:
4758	cmp	%l7, -1
4759	bne,pn	CCCR, 2b		! 'Nother?
4760	 mov	%l7, %l2
4761
4762intrcmplt:
4763	/*
4764	 * Re-read SOFTINT to see if any new  pending interrupts
4765	 * at this level.
4766	 */
4767	mov	1, %l3			! Ack softint
4768	rd	SOFTINT, %l7		! %l5 contains #intr handled.
4769	sll	%l3, %l6, %l3		! Generate IRQ mask
4770	btst	%l3, %l7		! leave mask in %l3 for retry code
4771	bnz,pn	%icc, sparc_intr_retry
4772	 mov	1, %l5			! initialize intr count for next run
4773
4774	! Decrement this cpu's interrupt depth in case of hardintrs
4775	btst	SOFTINT_INT, %l3
4776	bnz,pn	%icc, 1f
4777	 sethi	%hi(CPUINFO_VA+CI_IDEPTH), %l4
4778	ld	[%l4 + %lo(CPUINFO_VA+CI_IDEPTH)], %l5
4779	dec	%l5
4780	st	%l5, [%l4 + %lo(CPUINFO_VA+CI_IDEPTH)]
47811:
4782
4783#ifdef NOT_DEBUG
4784	set	_C_LABEL(intrdebug), %o2
4785	ld	[%o2], %o2
4786	btst	INTRDEBUG_FUNC, %o2
4787	bz,a,pt	%icc, 97f
4788	 nop
4789
4790	cmp	%l6, 0xa		! ignore clock interrupts?
4791	bz,pt	%icc, 97f
4792	 nop
4793
4794	STACKFRAME(-CC64FSZ)		! Get a clean register window
4795	LOAD_ASCIZ(%o0, "sparc_interrupt:  done\n")
4796	GLOBTOLOC
4797	call	prom_printf
4798	 nop
4799	LOCTOGLOB
4800	restore
480197:
4802#endif
4803
4804	ldub	[%sp + CC64FSZ + STKB + TF_OLDPIL], %l3	! restore old %pil
4805	wrpr	%l3, 0, %pil
4806
4807	b	return_from_trap
4808	 ldx	[%sp + CC64FSZ + STKB + TF_TSTATE], %g1	! Load this for return_from_trap
4809
4810#ifdef notyet
4811/*
4812 * Level 12 (ZS serial) interrupt.  Handle it quickly, schedule a
4813 * software interrupt, and get out.  Do the software interrupt directly
4814 * if we would just take it on the way out.
4815 *
4816 * Input:
4817 *	%l0 = %psr
4818 *	%l1 = return pc
4819 *	%l2 = return npc
4820 * Internal:
4821 *	%l3 = zs device
4822 *	%l4, %l5 = temporary
4823 *	%l6 = rr3 (or temporary data) + 0x100 => need soft int
4824 *	%l7 = zs soft status
4825 */
4826zshard:
4827#endif /* notyet */
4828
4829	.globl	return_from_trap, rft_kernel, rft_user
4830	.globl	softtrap, slowtrap
4831
4832/*
4833 * Various return-from-trap routines (see return_from_trap).
4834 */
4835
4836/*
4837 * Return from trap.
4838 * registers are:
4839 *
4840 *	[%sp + CC64FSZ + STKB] => trap frame
4841 *      %g1 => tstate from trap frame
4842 *
4843 * We must load all global, out, and trap registers from the trap frame.
4844 *
4845 * If returning to kernel, we should be at the proper trap level because
4846 * we don't touch %tl.
4847 *
4848 * When returning to user mode, the trap level does not matter, as it
4849 * will be set explicitly.
4850 *
4851 * If we are returning to user code, we must:
4852 *  1.  Check for register windows in the pcb that belong on the stack.
4853 *	If there are any, reload them
4854 */
4855return_from_trap:
4856#ifdef DEBUG
4857	!! Make sure we don't have pc == npc == 0 or we suck.
4858	ldx	[%sp + CC64FSZ + STKB + TF_PC], %g2
4859	ldx	[%sp + CC64FSZ + STKB + TF_NPC], %g3
4860	orcc	%g2, %g3, %g0
4861	tz	%icc, 1
4862#endif
4863
4864	!!
4865	!! We'll make sure we flush our pcb here, rather than later.
4866	!!
4867!	ldx	[%sp + CC64FSZ + STKB + TF_TSTATE], %g1	! already passed in, no need to reload
4868	btst	TSTATE_PRIV, %g1			! returning to userland?
4869
4870	!!
4871	!! Let all pending interrupts drain before returning to userland
4872	!!
4873	bnz,pn	%icc, 1f				! Returning to userland?
4874	 nop
4875	ENABLE_INTERRUPTS %g5
4876	wrpr	%g0, %g0, %pil				! Lower IPL
48771:
4878	!! Make sure we have no IRQs
4879	DISABLE_INTERRUPTS %g5
4880
4881#ifdef SUN4V
4882	sethi	%hi(cputyp), %g5
4883	ld	[%g5 + %lo(cputyp)], %g5
4884	cmp	%g5, CPU_SUN4V
4885	bne,pt	%icc, 1f
4886	 nop
4887	!! Make sure we have normal globals
4888	NORMAL_GLOBALS_SUN4V
4889	/* Restore normal globals */
4890	ldx	[%sp + CC64FSZ + STKB + TF_G + (1*8)], %g1
4891	ldx	[%sp + CC64FSZ + STKB + TF_G + (2*8)], %g2
4892	ldx	[%sp + CC64FSZ + STKB + TF_G + (3*8)], %g3
4893	ldx	[%sp + CC64FSZ + STKB + TF_G + (4*8)], %g4
4894	ldx	[%sp + CC64FSZ + STKB + TF_G + (5*8)], %g5
4895	ldx	[%sp + CC64FSZ + STKB + TF_G + (6*8)], %g6
4896	ldx	[%sp + CC64FSZ + STKB + TF_G + (7*8)], %g7
4897	/* Switch to alternate globals */
4898	ALTERNATE_GLOBALS_SUN4V
4899	ba	2f
4900	 nop
49011:
4902#endif
4903	!! Make sure we have normal globals
4904	NORMAL_GLOBALS_SUN4U
4905	/* Restore normal globals */
4906	ldx	[%sp + CC64FSZ + STKB + TF_G + (1*8)], %g1
4907	ldx	[%sp + CC64FSZ + STKB + TF_G + (2*8)], %g2
4908	ldx	[%sp + CC64FSZ + STKB + TF_G + (3*8)], %g3
4909	ldx	[%sp + CC64FSZ + STKB + TF_G + (4*8)], %g4
4910	ldx	[%sp + CC64FSZ + STKB + TF_G + (5*8)], %g5
4911	ldx	[%sp + CC64FSZ + STKB + TF_G + (6*8)], %g6
4912	ldx	[%sp + CC64FSZ + STKB + TF_G + (7*8)], %g7
4913	/* Switch to alternate globals */
4914#ifdef TRAPS_USE_IG
4915	wrpr	%g0, PSTATE_KERN|PSTATE_IG, %pstate	! DEBUG
4916#else
4917	ALTERNATE_GLOBALS_SUN4U
4918#endif
49192:
4920
4921	/* Load outs */
4922	ldx	[%sp + CC64FSZ + STKB + TF_O + (0*8)], %i0
4923	ldx	[%sp + CC64FSZ + STKB + TF_O + (1*8)], %i1
4924	ldx	[%sp + CC64FSZ + STKB + TF_O + (2*8)], %i2
4925	ldx	[%sp + CC64FSZ + STKB + TF_O + (3*8)], %i3
4926	ldx	[%sp + CC64FSZ + STKB + TF_O + (4*8)], %i4
4927	ldx	[%sp + CC64FSZ + STKB + TF_O + (5*8)], %i5
4928	ldx	[%sp + CC64FSZ + STKB + TF_O + (6*8)], %i6
4929	ldx	[%sp + CC64FSZ + STKB + TF_O + (7*8)], %i7
4930	/* Now load trap registers into alternate globals */
4931	ld	[%sp + CC64FSZ + STKB + TF_Y], %g4
4932	ldx	[%sp + CC64FSZ + STKB + TF_TSTATE], %g1		! load new values
4933	wr	%g4, 0, %y
4934	ldx	[%sp + CC64FSZ + STKB + TF_PC], %g2
4935	ldx	[%sp + CC64FSZ + STKB + TF_NPC], %g3
4936
4937#ifdef NOTDEF_DEBUG
4938	ldub	[%sp + CC64FSZ + STKB + TF_PIL], %g5		! restore %pil
4939	wrpr	%g5, %pil				! DEBUG
4940#endif
4941
4942	/* Returning to user mode or kernel mode? */
4943	btst	TSTATE_PRIV, %g1		! returning to userland?
4944	bz,pt	%icc, rft_user
4945	 sethi	%hi(CPUINFO_VA+CI_WANT_AST), %g7	! first instr of rft_user
4946
4947/*
4948 * Return from trap, to kernel.
4949 *
4950 * We will assume, for the moment, that all kernel traps are properly stacked
4951 * in the trap registers, so all we have to do is insert the (possibly modified)
4952 * register values into the trap registers then do a retry.
4953 *
4954 */
4955rft_kernel:
4956	rdpr	%tl, %g4			! Grab a set of trap registers
4957	inc	%g4
4958	wrpr	%g4, %g0, %tl
4959	wrpr	%g3, 0, %tnpc
4960	wrpr	%g2, 0, %tpc
4961	wrpr	%g1, 0, %tstate
4962
4963	rdpr	%canrestore, %g2
4964	brnz	%g2, 1f
4965	 nop
4966
4967	wr	%g0, ASI_NUCLEUS, %asi
4968	rdpr	%cwp, %g1
4969	dec	%g1
4970	wrpr	%g1, %cwp
4971#ifdef _LP64
4972	FILL	ldxa, %sp+BIAS, 8, %asi
4973#else
4974	FILL	lda, %sp, 4, %asi
4975#endif
4976	restored
4977	inc	%g1
4978	wrpr	%g1, %cwp
49791:
4980	restore
4981	rdpr	%tstate, %g1			! Since we may have trapped our regs may be toast
4982	rdpr	%cwp, %g2
4983	andn	%g1, CWP, %g1
4984	wrpr	%g1, %g2, %tstate		! Put %cwp in %tstate
4985	CLRTT
4986#ifdef TRAPSTATS
4987	rdpr	%tl, %g2
4988	set	_C_LABEL(rftkcnt), %g1
4989	sllx	%g2, 2, %g2
4990	add	%g1, %g2, %g1
4991	lduw	[%g1], %g2
4992	inc	%g2
4993	stw	%g2, [%g1]
4994#endif
4995#if	0
4996	wrpr	%g0, 0, %cleanwin	! DEBUG
4997#endif
4998#if defined(DDB) && defined(MULTIPROCESSOR)
4999	set	sparc64_ipi_pause_trap_point, %g1
5000	rdpr	%tpc, %g2
5001	cmp	%g1, %g2
5002	bne,pt	%icc, 0f
5003	 nop
5004	done
50050:
5006#endif
5007	retry
5008	NOTREACHED
5009/*
5010 * Return from trap, to user.  Checks for scheduling trap (`ast') first;
5011 * will re-enter trap() if set.  Note that we may have to switch from
5012 * the interrupt stack to the kernel stack in this case.
5013 *	%g1 = %tstate
5014 *	%g2 = return %pc
5015 *	%g3 = return %npc
5016 * If returning to a valid window, just set psr and return.
5017 */
5018	.data
5019rft_wcnt:	.word 0
5020	.text
5021
5022rft_user:
5023!	sethi	%hi(CPUINFO_VA+CI_WANT_AST), %g7	! (done above)
5024	lduw	[%g7 + %lo(CPUINFO_VA+CI_WANT_AST)], %g7! want AST trap?
5025	brnz,pn	%g7, softtrap			! yes, re-enter trap with type T_AST
5026	 mov	T_AST, %g4
5027
5028#ifdef NOTDEF_DEBUG
5029	sethi	%hi(CPCB), %g4
5030	LDPTR	[%g4 + %lo(CPCB)], %g4
5031	ldub	[%g4 + PCB_NSAVED], %g4		! nsaved
5032	brz,pt	%g4, 2f		! Only print if nsaved <> 0
5033	 nop
5034
5035	set	1f, %o0
5036	mov	%g4, %o1
5037	mov	%g2, %o2			! pc
5038	wr	%g0, ASI_DMMU, %asi		! restore the user context
5039	ldxa	[CTX_SECONDARY] %asi, %o3	! ctx
5040	GLOBTOLOC
5041	mov	%g3, %o5
5042	call	printf
5043	 mov	%i6, %o4			! sp
5044!	wrpr	%g0, PSTATE_INTR, %pstate		! Allow IRQ service
5045!	wrpr	%g0, PSTATE_KERN, %pstate		! DenyIRQ service
5046	LOCTOGLOB
50471:
5048	.data
5049	.asciz	"rft_user: nsaved=%x pc=%d ctx=%x sp=%x npc=%p\n"
5050	_ALIGN
5051	.text
5052#endif
5053
5054	/*
5055	 * NB: only need to do this after a cache miss
5056	 */
5057#ifdef TRAPSTATS
5058	set	_C_LABEL(rftucnt), %g6
5059	lduw	[%g6], %g7
5060	inc	%g7
5061	stw	%g7, [%g6]
5062#endif
5063	/*
5064	 * Now check to see if any regs are saved in the pcb and restore them.
5065	 *
5066	 * Here we need to undo the damage caused by switching to a kernel
5067	 * stack.
5068	 *
5069	 * We will use alternate globals %g4..%g7 because %g1..%g3 are used
5070	 * by the data fault trap handlers and we don't want possible conflict.
5071	 */
5072
5073	sethi	%hi(CPCB), %g6
5074	rdpr	%otherwin, %g7			! restore register window controls
5075#ifdef DEBUG
5076	rdpr	%canrestore, %g5		! DEBUG
5077	tst	%g5				! DEBUG
5078	tnz	%icc, 1; nop			! DEBUG
5079!	mov	%g0, %g5			! There should be *NO* %canrestore
5080	add	%g7, %g5, %g7			! DEBUG
5081#endif
5082	wrpr	%g0, %g7, %canrestore
5083	LDPTR	[%g6 + %lo(CPCB)], %g6
5084	wrpr	%g0, 0, %otherwin
5085
5086	ldub	[%g6 + PCB_NSAVED], %g7		! Any saved reg windows?
5087	wrpr	%g0, WSTATE_USER, %wstate	! Need to know where our sp points
5088
5089#ifdef DEBUG
5090	set	rft_wcnt, %g4	! Keep track of all the windows we restored
5091	stw	%g7, [%g4]
5092#endif
5093
5094	brz,pt	%g7, 5f				! No saved reg wins
5095	 nop
5096	dec	%g7				! We can do this now or later.  Move to last entry
5097
5098#ifdef DEBUG
5099	rdpr	%canrestore, %g4			! DEBUG Make sure we've restored everything
5100	brnz,a,pn	%g4, 0f				! DEBUG
5101	 sir						! DEBUG we should NOT have any usable windows here
51020:							! DEBUG
5103	wrpr	%g0, 5, %tl
5104#endif
5105	rdpr	%otherwin, %g4
5106	sll	%g7, 7, %g5			! calculate ptr into rw64 array 8*16 == 128 or 7 bits
5107	brz,pt	%g4, 6f				! We should not have any user windows left
5108	 add	%g5, %g6, %g5
5109
5110	set	1f, %o0
5111	mov	%g7, %o1
5112	mov	%g4, %o2
5113	call	printf
5114	 wrpr	%g0, PSTATE_KERN, %pstate
5115	set	2f, %o0
5116	call	panic
5117	 nop
5118	NOTREACHED
5119	.data
51201:	.asciz	"pcb_nsaved=%x and otherwin=%x\n"
51212:	.asciz	"rft_user\n"
5122	_ALIGN
5123	.text
51246:
51253:
5126	restored					! Load in the window
5127	restore						! This should not trap!
5128	ldx	[%g5 + PCB_RW + ( 0*8)], %l0		! Load the window from the pcb
5129	ldx	[%g5 + PCB_RW + ( 1*8)], %l1
5130	ldx	[%g5 + PCB_RW + ( 2*8)], %l2
5131	ldx	[%g5 + PCB_RW + ( 3*8)], %l3
5132	ldx	[%g5 + PCB_RW + ( 4*8)], %l4
5133	ldx	[%g5 + PCB_RW + ( 5*8)], %l5
5134	ldx	[%g5 + PCB_RW + ( 6*8)], %l6
5135	ldx	[%g5 + PCB_RW + ( 7*8)], %l7
5136
5137	ldx	[%g5 + PCB_RW + ( 8*8)], %i0
5138	ldx	[%g5 + PCB_RW + ( 9*8)], %i1
5139	ldx	[%g5 + PCB_RW + (10*8)], %i2
5140	ldx	[%g5 + PCB_RW + (11*8)], %i3
5141	ldx	[%g5 + PCB_RW + (12*8)], %i4
5142	ldx	[%g5 + PCB_RW + (13*8)], %i5
5143	ldx	[%g5 + PCB_RW + (14*8)], %i6
5144	ldx	[%g5 + PCB_RW + (15*8)], %i7
5145
5146#ifdef DEBUG
5147	stx	%g0, [%g5 + PCB_RW + (14*8)]		! DEBUG mark that we've saved this one
5148#endif
5149
5150	cmp	%g5, %g6
5151	bgu,pt	%xcc, 3b				! Next one?
5152	 dec	8*16, %g5
5153
5154	stb	%g0, [%g6 + PCB_NSAVED]			! Clear them out so we won't do this again
5155	GET_MAXCWP %g5
5156	add	%g5, %g7, %g4
5157	dec	1, %g5					! NWINDOWS-1-1
5158	wrpr	%g5, 0, %cansave
5159	wrpr	%g0, 0, %canrestore			! Make sure we have no freeloaders XXX
5160	wrpr	%g0, WSTATE_USER, %wstate		! Save things to user space
5161	mov	%g7, %g5				! We already did one restore
51624:
5163	rdpr	%canrestore, %g4
5164	inc	%g4
5165	deccc	%g5
5166	wrpr	%g4, 0, %cleanwin			! Make *sure* we don't trap to cleanwin
5167	bge,a,pt	%xcc, 4b				! return to starting regwin
5168	 save	%g0, %g0, %g0				! This may force a datafault
5169
5170#ifdef DEBUG
5171	wrpr	%g0, 0, %tl
5172#endif
5173#ifdef TRAPSTATS
5174	set	_C_LABEL(rftuld), %g5
5175	lduw	[%g5], %g4
5176	inc	%g4
5177	stw	%g4, [%g5]
5178#endif
5179	!!
5180	!! We can't take any save faults in here 'cause they will never be serviced
5181	!!
5182
5183#ifdef DEBUG
5184	sethi	%hi(CPCB), %g5
5185	LDPTR	[%g5 + %lo(CPCB)], %g5
5186	ldub	[%g5 + PCB_NSAVED], %g5		! Any saved reg windows?
5187	tst	%g5
5188	tnz	%icc, 1; nop			! Debugger if we still have saved windows
5189	bne,a	rft_user			! Try starting over again
5190	 sethi	%hi(CPUINFO_VA+CI_WANT_AST), %g7
5191#endif
5192	/*
5193	 * Set up our return trapframe so we can recover if we trap from here
5194	 * on in.
5195	 */
5196	wrpr	%g0, 1, %tl			! Set up the trap state
5197	wrpr	%g2, 0, %tpc
5198	wrpr	%g3, 0, %tnpc
5199	ba,pt	%icc, 6f
5200	 wrpr	%g1, %g0, %tstate
5201
52025:
5203	/*
5204	 * Set up our return trapframe so we can recover if we trap from here
5205	 * on in.
5206	 */
5207	wrpr	%g0, 1, %tl			! Set up the trap state
5208	wrpr	%g2, 0, %tpc
5209	wrpr	%g3, 0, %tnpc
5210	wrpr	%g1, %g0, %tstate
5211
5212	/*
5213	 * The restore instruction further down may cause the trap level
5214	 * to exceed the maximum trap level on sun4v, so a manual fill
5215	 * may be necessary.
5216	*/
5217
5218#ifdef SUN4V
5219	sethi	%hi(cputyp), %g5
5220	ld	[%g5 + %lo(cputyp)], %g5
5221	cmp	%g5, CPU_SUN4V
5222	bne,pt	%icc, 1f
5223	 nop
5224
5225	! Only manual fill if the restore instruction will cause a fill trap
5226	rdpr	%canrestore, %g5
5227	brnz	%g5, 1f
5228	 nop
5229
5230	! Do a manual fill
5231	wr	%g0, ASI_AIUS, %asi
5232	rdpr	%cwp, %g4
5233	dec	%g4
5234	wrpr	%g4, 0, %cwp
5235rft_user_fault_start:
5236	FILL	ldxa, %sp+BIAS, 8, %asi
5237rft_user_fault_end:
5238	restored
5239	inc	%g4
5240	wrpr	%g4, 0, %cwp
52411:
5242#endif
5243	restore
52446:
5245	rdpr	%canrestore, %g5
5246	wrpr	%g5, 0, %cleanwin			! Force cleanup of kernel windows
5247
5248#ifdef NOTDEF_DEBUG
5249	ldx	[%g6 + CC64FSZ + STKB + TF_L + (0*8)], %g5! DEBUG -- get proper value for %l0
5250	cmp	%l0, %g5
5251	be,a,pt %icc, 1f
5252	 nop
5253!	sir			! WATCHDOG
5254	set	badregs, %g1	! Save the suspect regs
5255	stw	%l0, [%g1+(4*0)]
5256	stw	%l1, [%g1+(4*1)]
5257	stw	%l2, [%g1+(4*2)]
5258	stw	%l3, [%g1+(4*3)]
5259	stw	%l4, [%g1+(4*4)]
5260	stw	%l5, [%g1+(4*5)]
5261	stw	%l6, [%g1+(4*6)]
5262	stw	%l7, [%g1+(4*7)]
5263	stw	%i0, [%g1+(4*8)+(4*0)]
5264	stw	%i1, [%g1+(4*8)+(4*1)]
5265	stw	%i2, [%g1+(4*8)+(4*2)]
5266	stw	%i3, [%g1+(4*8)+(4*3)]
5267	stw	%i4, [%g1+(4*8)+(4*4)]
5268	stw	%i5, [%g1+(4*8)+(4*5)]
5269	stw	%i6, [%g1+(4*8)+(4*6)]
5270	stw	%i7, [%g1+(4*8)+(4*7)]
5271	save
5272	inc	%g7
5273	wrpr	%g7, 0, %otherwin
5274	wrpr	%g0, 0, %canrestore
5275	wrpr	%g0, WSTATE_KERN, %wstate	! Need to know where our sp points
5276	set	rft_wcnt, %g4	! Restore nsaved before trapping
5277	sethi	%hi(CPCB), %g6
5278	LDPTR	[%g6 + %lo(CPCB)], %g6
5279	lduw	[%g4], %g4
5280	stb	%g4, [%g6 + PCB_NSAVED]
5281	ta	1
5282	sir
5283	.data
5284badregs:
5285	.space	16*4
5286	.text
52871:
5288#endif
5289
5290	rdpr	%tstate, %g1
5291	rdpr	%cwp, %g7			! Find our cur window
5292	andn	%g1, CWP, %g1			! Clear it from %tstate
5293	wrpr	%g1, %g7, %tstate		! Set %tstate with %cwp
5294	mov	CTX_SECONDARY, %g1		! Restore the user context
5295	GET_MMU_CONTEXTID %g4, %g1, %g3
5296	mov	CTX_PRIMARY, %g2
5297	SET_MMU_CONTEXTID %g4, %g2, %g3
5298	sethi	%hi(KERNBASE), %g7		! Should not be needed due to retry
5299	membar	#Sync				! Should not be needed due to retry
5300	flush	%g7				! Should not be needed due to retry
5301
5302	CLRTT
5303#ifdef TRAPSTATS
5304	set	_C_LABEL(rftudone), %g1
5305	lduw	[%g1], %g2
5306	inc	%g2
5307	stw	%g2, [%g1]
5308#endif
5309#ifdef DEBUG
5310	sethi	%hi(CPCB), %g5
5311	LDPTR	[%g5 + %lo(CPCB)], %g5
5312	ldub	[%g5 + PCB_NSAVED], %g5		! Any saved reg windows?
5313	tst	%g5
5314	tnz	%icc, 1; nop			! Debugger if we still have saved windows!
5315#endif
5316	wrpr	%g0, 0, %pil			! Enable all interrupts
5317	retry
5318
5319! exported end marker for kernel gdb
5320	.globl	_C_LABEL(endtrapcode)
5321_C_LABEL(endtrapcode):
5322
5323/*
5324 * Kernel entry point.
5325 *
5326 * The contract between bootloader and kernel is:
5327 *
5328 * %o0		OpenFirmware entry point, to keep Sun's updaters happy
5329 * %o1		Address of boot information vector (see bootinfo.h)
5330 * %o2		Length of the vector, in bytes
5331 * %o3		OpenFirmware entry point, to mimic Sun bootloader behavior
5332 * %o4		OpenFirmware, to meet earlier NetBSD kernels expectations
5333 */
5334	.align	8
5335start:
5336dostart:
5337	/*
5338	 * Startup.
5339	 *
5340	 * The Sun FCODE bootloader is nice and loads us where we want
5341	 * to be.  We have a full set of mappings already set up for us.
5342	 *
5343	 * I think we end up having an entire 16M allocated to us.
5344	 *
5345	 * We enter with the prom entry vector in %o0, dvec in %o1,
5346	 * and the bootops vector in %o2.
5347	 *
5348	 * All we need to do is:
5349	 *
5350	 *	1:	Save the prom vector
5351	 *
5352	 *	2:	Create a decent stack for ourselves
5353	 *
5354	 *	3:	Install the permanent 4MB kernel mapping
5355	 *
5356	 *	4:	Call the C language initialization code
5357	 *
5358	 */
5359
5360	/*
5361	 * Set the psr into a known state:
5362	 * Set supervisor mode, interrupt level >= 13, traps enabled
5363	 */
5364	wrpr	%g0, 13, %pil
5365	wrpr	%g0, PSTATE_INTR|PSTATE_PEF, %pstate
5366	wr	%g0, FPRS_FEF, %fprs		! Turn on FPU
5367
5368	/*
5369	 * Step 2: Set up a v8-like stack if we need to
5370	 */
5371
5372#ifdef _LP64
5373	btst	1, %sp
5374	bnz,pt	%icc, 0f
5375	 nop
5376	add	%sp, -BIAS, %sp
5377#else
5378	btst	1, %sp
5379	bz,pt	%icc, 0f
5380	 nop
5381	add	%sp, BIAS, %sp
5382#endif
53830:
5384
5385	call	_C_LABEL(bootstrap)
5386	 clr	%g4				! Clear data segment pointer
5387
5388/*
5389 * Initialize the boot CPU.  Basically:
5390 *
5391 *	Locate the cpu_info structure for this CPU.
5392 *	Establish a locked mapping for interrupt stack.
5393 *	Switch to the initial stack.
5394 *	Call the routine passed in in cpu_info->ci_spinup
5395 */
5396
5397#ifdef NO_VCACHE
5398#define	SUN4U_TTE_DATABITS	SUN4U_TTE_L|SUN4U_TTE_CP|SUN4U_TTE_P|SUN4U_TTE_W
5399#else
5400#define	SUN4U_TTE_DATABITS	SUN4U_TTE_L|SUN4U_TTE_CP|SUN4U_TTE_CV|SUN4U_TTE_P|SUN4U_TTE_W
5401#endif
5402
5403
5404ENTRY_NOPROFILE(cpu_initialize)	/* for cosmetic reasons - nicer backtrace */
5405
5406	/* Cache the cputyp in %l6 for later use below */
5407	sethi	%hi(cputyp), %l6
5408	ld	[%l6 + %lo(cputyp)], %l6
5409
5410	/*
5411	 * Step 5: is no more.
5412	 */
5413
5414	/*
5415	 * Step 6: hunt through cpus list and find the one that matches our cpuid
5416	 */
5417
5418	call	_C_LABEL(cpu_myid)	! Retrieve cpuid in %o0
5419	 mov	%g0, %o0
5420
5421	sethi	%hi(_C_LABEL(cpus)), %l1
5422	LDPTR	[%l1 + %lo(_C_LABEL(cpus))], %l1
54230:
5424	ld	[%l1 + CI_CPUID], %l3		! Load CPUID
5425	cmp	%l3, %o0			! Does it match?
5426	bne,a,pt	%icc, 0b		! no
5427	 LDPTR	[%l1 + CI_NEXT], %l1		! Load next cpu_info pointer
5428
5429	/*
5430	 * Get pointer to our cpu_info struct
5431	 */
5432	mov	%l1, %l7			! save cpu_info pointer
5433	ldx	[%l1 + CI_PADDR], %l1		! Load the interrupt stack's PA
5434#ifdef SUN4V
5435	cmp	%l6, CPU_SUN4V
5436	bne,pt	%icc, 3f
5437	 nop
5438
5439	/* sun4v */
5440	call	_C_LABEL(pmap_setup_intstack_sun4v)	! Call nice C function for mapping INTSTACK
5441	 mov	%l1, %o0
5442	ba	4f
5443	 nop
54443:
5445#endif
5446	/* sun4u */
5447	sethi	%hi(0xa0000000), %l2		! V=1|SZ=01|NFO=0|IE=0
5448	sllx	%l2, 32, %l2			! Shift it into place
5449
5450	mov	-1, %l3				! Create a nice mask
5451	sllx	%l3, 43, %l4			! Mask off high bits
5452	or	%l4, 0xfff, %l4			! We can just load this in 12 (of 13) bits
5453
5454	andn	%l1, %l4, %l1			! Mask the phys page number
5455
5456	or	%l2, %l1, %l1			! Now take care of the high bits
5457	or	%l1, SUN4U_TTE_DATABITS, %l2	! And low bits:	L=1|CP=1|CV=?|E=0|P=1|W=1|G=0
5458
5459	!!
5460	!!  Now, map in the interrupt stack as context==0
5461	!!
5462	set	TLB_TAG_ACCESS, %l5
5463	set	INTSTACK, %l0
5464	stxa	%l0, [%l5] ASI_DMMU		! Make DMMU point to it
5465	stxa	%l2, [%g0] ASI_DMMU_DATA_IN	! Store it
5466	membar	#Sync
54674:
5468
5469	!! Setup kernel stack (we rely on curlwp on this cpu
5470	!! being lwp0 here and its uarea is mapped special
5471	!! and already accessible here)
5472	flushw
5473	LDPTR	[%l7 + CI_CPCB], %l0		! load PCB/uarea pointer
5474	set	2*USPACE - TF_SIZE - CC64FSZ, %l1
5475 	add	%l1, %l0, %l0
5476#ifdef _LP64
5477	andn	%l0, 0x0f, %l0			! Needs to be 16-byte aligned
5478	sub	%l0, BIAS, %l0			! and biased
5479#endif
5480	mov	%l0, %sp
5481	flushw
5482
5483#ifdef DEBUG
5484	set	_C_LABEL(pmapdebug), %o1
5485	ld	[%o1], %o1
5486	sethi	%hi(0x40000), %o2
5487	btst	%o2, %o1
5488	bz	0f
5489
5490	set	1f, %o0		! Debug printf
5491	call	_C_LABEL(prom_printf)
5492	 nop
5493	.data
54941:
5495	.asciz	"Setting trap base...\n"
5496	_ALIGN
5497	.text
54980:
5499#endif
5500	/*
5501	 * Step 7: change the trap base register, and install our TSB pointers
5502	 */
5503
5504	/*
5505	 * install our TSB pointers
5506	 */
5507
5508#ifdef SUN4V
5509	cmp	%l6, CPU_SUN4V
5510	bne,pt	%icc, 5f
5511	 nop
5512
5513	/* sun4v */
5514	LDPTR	[%l7 + CI_TSB_DESC], %o0
5515	call	_C_LABEL(pmap_setup_tsb_sun4v)
5516	 nop
5517	ba	1f
5518	 nop
55195:
5520#endif
5521	/* sun4u */
5522	sethi	%hi(_C_LABEL(tsbsize)), %l2
5523	sethi	%hi(0x1fff), %l3
5524	sethi	%hi(TSB), %l4
5525	LDPTR	[%l7 + CI_TSB_DMMU], %l0
5526	LDPTR	[%l7 + CI_TSB_IMMU], %l1
5527	ld	[%l2 + %lo(_C_LABEL(tsbsize))], %l2
5528	or	%l3, %lo(0x1fff), %l3
5529	or	%l4, %lo(TSB), %l4
5530
5531	andn	%l0, %l3, %l0			! Mask off size and split bits
5532	or	%l0, %l2, %l0			! Make a TSB pointer
5533	stxa	%l0, [%l4] ASI_DMMU		! Install data TSB pointer
5534
5535	andn	%l1, %l3, %l1			! Mask off size and split bits
5536	or	%l1, %l2, %l1			! Make a TSB pointer
5537	stxa	%l1, [%l4] ASI_IMMU		! Install instruction TSB pointer
5538	membar	#Sync
5539	set	1f, %l1
5540	flush	%l1
55411:
5542
5543	/* set trap table */
5544#ifdef SUN4V
5545	cmp	%l6, CPU_SUN4V
5546	bne,pt	%icc, 6f
5547	 nop
5548	/* sun4v */
5549	set	_C_LABEL(trapbase_sun4v), %l1
5550	GET_MMFSA %o1
5551	call	_C_LABEL(prom_set_trap_table_sun4v)	! Now we should be running 100% from our handlers
5552	 mov	%l1, %o0
5553
5554	ba	7f
5555	 nop
55566:
5557#endif
5558	/* sun4u */
5559	set	_C_LABEL(trapbase), %l1
5560	call	_C_LABEL(prom_set_trap_table_sun4u)	! Now we should be running 100% from our handlers
5561	 mov	%l1, %o0
55627:
5563	wrpr	%l1, 0, %tba			! Make sure the PROM didn't foul up.
5564
5565	/*
5566	 * Switch to the kernel mode and run away.
5567	 */
5568	wrpr	%g0, WSTATE_KERN, %wstate
5569
5570#ifdef DEBUG
5571	wrpr	%g0, 1, %tl			! Debug -- start at tl==3 so we'll watchdog
5572	wrpr	%g0, 0x1ff, %tt			! Debug -- clear out unused trap regs
5573	wrpr	%g0, 0, %tpc
5574	wrpr	%g0, 0, %tnpc
5575	wrpr	%g0, 0, %tstate
5576	wrpr	%g0, 0, %tl
5577#endif
5578
5579#ifdef DEBUG
5580	set	_C_LABEL(pmapdebug), %o1
5581	ld	[%o1], %o1
5582	sethi	%hi(0x40000), %o2
5583	btst	%o2, %o1
5584	bz	0f
5585
5586	LDPTR	[%l7 + CI_SPINUP], %o1
5587	set	1f, %o0		! Debug printf
5588	call	_C_LABEL(prom_printf)
5589	 mov	%sp, %o2
5590
5591	.data
55921:
5593	.asciz	"Calling startup routine %p with stack at %p...\n"
5594	_ALIGN
5595	.text
55960:
5597#endif
5598	/*
5599	 * Call our startup routine.
5600	 */
5601
5602	LDPTR	[%l7 + CI_SPINUP], %o1
5603
5604	call	%o1				! Call routine
5605	 clr	%o0				! our frame arg is ignored
5606
5607	set	1f, %o0				! Main should never come back here
5608	call	_C_LABEL(panic)
5609	 nop
5610	.data
56111:
5612	.asciz	"main() returned\n"
5613	_ALIGN
5614	.text
5615
5616	.align 8
5617ENTRY(get_romtba)
5618	retl
5619	 rdpr	%tba, %o0
5620
5621ENTRY(setcputyp)
5622	sethi	%hi(cputyp), %o1	! Trash %o1 assuming this is ok
5623	st	%o0, [%o1 + %lo(cputyp)]
5624	retl
5625	 nop
5626
5627#ifdef MULTIPROCESSOR
5628	/*
5629	 * cpu_mp_startup is called with:
5630	 *
5631	 *	%g2 = cpu_args
5632	 */
5633ENTRY(cpu_mp_startup)
5634	mov	1, %o0
5635	sllx	%o0, 63, %o0
5636	wr	%o0, TICK_CMPR	! XXXXXXX clear and disable %tick_cmpr for now
5637	wrpr    %g0, 0, %cleanwin
5638	wrpr	%g0, 0, %tl			! Make sure we're not in NUCLEUS mode
5639	wrpr	%g0, WSTATE_KERN, %wstate
5640	wrpr	%g0, PSTATE_KERN, %pstate
5641	flushw
5642
5643	/* Cache the cputyp in %l6 for later use below */
5644	sethi	%hi(cputyp), %l6
5645	ld	[%l6 + %lo(cputyp)], %l6
5646
5647	/*
5648	 * Get pointer to our cpu_info struct
5649	 */
5650	ldx	[%g2 + CBA_CPUINFO], %l1	! Load the interrupt stack's PA
5651
5652#ifdef SUN4V
5653	cmp	%l6, CPU_SUN4V
5654	bne,pt	%icc, 3f
5655	 nop
5656
5657	/* sun4v */
5658
5659	sethi	%hi(0x80000000), %l2		! V=1|NFO=0|SW=0
5660	sllx	%l2, 32, %l2			! Shift it into place
5661	mov	-1, %l3				! Create a nice mask
5662	sllx	%l3, 56, %l4			! Mask off high 8 bits
5663	or	%l4, 0xfff, %l4			! We can just load this in 12 (of 13) bits
5664	andn	%l1, %l4, %l1			! Mask the phys page number into RA
5665	or	%l2, %l1, %l1			! Now take care of the 8 high bits V|NFO|SW
5666	or	%l1, 0x0741, %l2		! And low 13 bits IE=0|E=0|CP=1|CV=1|P=1|
5667						!		  X=0|W=1|SW=00|SZ=0001
5668
5669	/*
5670	 *  Now, map in the interrupt stack & cpu_info as context==0
5671	 */
5672
5673	set	INTSTACK, %o0			! vaddr
5674	clr	%o1				! reserved
5675	mov	%l2, %o2			! tte
5676	mov	MAP_DTLB, %o3			! flags
5677	mov	FT_MMU_MAP_PERM_ADDR, %o5	! hv fast trap function
5678	ta	ST_FAST_TRAP
5679	cmp	%o0, 0
5680	be,pt	%icc, 5f
5681	 nop
5682	sir					! crash if mapping fails
56835:
5684
5685	/*
5686	 * Set 0 as primary context XXX
5687	 */
5688
5689	mov	CTX_PRIMARY, %o0
5690	SET_MMU_CONTEXTID_SUN4V %g0, %o0
5691
5692	ba	4f
5693	 nop
56943:
5695#endif
5696
5697	/* sun4u */
5698
5699	sethi	%hi(0xa0000000), %l2		! V=1|SZ=01|NFO=0|IE=0
5700	sllx	%l2, 32, %l2			! Shift it into place
5701	mov	-1, %l3				! Create a nice mask
5702	sllx	%l3, 43, %l4			! Mask off high bits
5703	or	%l4, 0xfff, %l4			! We can just load this in 12 (of 13) bits
5704	andn	%l1, %l4, %l1			! Mask the phys page number
5705	or	%l2, %l1, %l1			! Now take care of the high bits
5706	or	%l1, SUN4U_TTE_DATABITS, %l2	! And low bits:	L=1|CP=1|CV=?|E=0|P=1|W=1|G=0
5707
5708	/*
5709	 *  Now, map in the interrupt stack & cpu_info as context==0
5710	 */
5711
5712	set	TLB_TAG_ACCESS, %l5
5713	set	INTSTACK, %l0
5714	stxa	%l0, [%l5] ASI_DMMU		! Make DMMU point to it
5715	stxa	%l2, [%g0] ASI_DMMU_DATA_IN	! Store it
5716
5717	/*
5718	 * Set 0 as primary context XXX
5719	 */
5720
5721	mov	CTX_PRIMARY, %o0
5722	SET_MMU_CONTEXTID_SUN4U %g0, %o0
5723
57244:
5725	membar	#Sync
5726
5727	/*
5728	 * Temporarily use the interrupt stack
5729	 */
5730#ifdef _LP64
5731	set	((EINTSTACK - CC64FSZ - TF_SIZE)) & ~0x0f - BIAS, %sp
5732#else
5733	set	EINTSTACK - CC64FSZ - TF_SIZE, %sp
5734#endif
5735	set	1, %fp
5736	clr	%i7
5737
5738#ifdef SUN4V
5739	cmp	%l6, CPU_SUN4V
5740	bne,pt	%icc, 2f
5741	 nop
5742
5743	/* sun4v */
5744
5745	/*
5746	 * install our TSB pointers
5747	 */
5748
5749	set	CPUINFO_VA, %o0
5750	LDPTR	[%o0 + CI_TSB_DESC], %o0
5751	call	_C_LABEL(pmap_setup_tsb_sun4v)
5752	 nop
5753
5754	/* set trap table */
5755
5756	set	_C_LABEL(trapbase_sun4v), %l1
5757	GET_MMFSA %o1
5758	call	_C_LABEL(prom_set_trap_table_sun4v)
5759	 mov	%l1, %o0
5760
5761	! Now we should be running 100% from our handlers
5762	ba	3f
5763	 nop
57642:
5765#endif
5766	/* sun4u */
5767
5768	/*
5769	 * install our TSB pointers
5770	 */
5771
5772	sethi	%hi(CPUINFO_VA+CI_TSB_DMMU), %l0
5773	sethi	%hi(CPUINFO_VA+CI_TSB_IMMU), %l1
5774	sethi	%hi(_C_LABEL(tsbsize)), %l2
5775	sethi	%hi(0x1fff), %l3
5776	sethi	%hi(TSB), %l4
5777	LDPTR	[%l0 + %lo(CPUINFO_VA+CI_TSB_DMMU)], %l0
5778	LDPTR	[%l1 + %lo(CPUINFO_VA+CI_TSB_IMMU)], %l1
5779	ld	[%l2 + %lo(_C_LABEL(tsbsize))], %l2
5780	or	%l3, %lo(0x1fff), %l3
5781	or	%l4, %lo(TSB), %l4
5782
5783	andn	%l0, %l3, %l0			! Mask off size and split bits
5784	or	%l0, %l2, %l0			! Make a TSB pointer
5785	stxa	%l0, [%l4] ASI_DMMU		! Install data TSB pointer
5786	membar	#Sync
5787
5788	andn	%l1, %l3, %l1			! Mask off size and split bits
5789	or	%l1, %l2, %l1			! Make a TSB pointer
5790	stxa	%l1, [%l4] ASI_IMMU		! Install instruction TSB pointer
5791	membar	#Sync
5792	set	1f, %o0
5793	flush	%o0
57941:
5795
5796	/* set trap table */
5797
5798	set	_C_LABEL(trapbase), %l1
5799	call	_C_LABEL(prom_set_trap_table_sun4u)
5800	 mov	%l1, %o0
58013:
5802	wrpr	%l1, 0, %tba			! Make sure the PROM didn't
5803						! foul up.
5804	/*
5805	 * Use this CPUs idlelewp's uarea stack
5806	 */
5807	sethi	%hi(CPUINFO_VA+CI_IDLELWP), %l0
5808	LDPTR	[%l0 + %lo(CPUINFO_VA+CI_IDLELWP)], %l0
5809	set	USPACE - TF_SIZE - CC64FSZ, %l1
5810	LDPTR	[%l0 + L_PCB], %l0
5811	add	%l0, %l1, %l0
5812#ifdef _LP64
5813	andn	%l0, 0x0f, %l0			! Needs to be 16-byte aligned
5814	sub	%l0, BIAS, %l0			! and biased
5815#endif
5816	mov	%l0, %sp
5817	flushw
5818
5819	/*
5820	 * Switch to the kernel mode and run away.
5821	 */
5822	wrpr	%g0, 13, %pil
5823	wrpr	%g0, PSTATE_INTR|PSTATE_PEF, %pstate
5824	wr	%g0, FPRS_FEF, %fprs			! Turn on FPU
5825
5826	call	_C_LABEL(cpu_hatch)
5827	 clr %g4
5828
5829	b	_C_LABEL(idle_loop)
5830	 clr	%o0
5831
5832	NOTREACHED
5833
5834	.globl cpu_mp_startup_end
5835cpu_mp_startup_end:
5836#endif
5837
5838/*
5839 * openfirmware(cell* param);
5840 *
5841 * OpenFirmware entry point
5842 *
5843 * If we're running in 32-bit mode we need to convert to a 64-bit stack
5844 * and 64-bit cells.  The cells we'll allocate off the stack for simplicity.
5845 */
5846	.align 8
5847ENTRY(openfirmware)
5848	sethi	%hi(romp), %o4
5849	andcc	%sp, 1, %g0
5850	bz,pt	%icc, 1f
5851	 LDPTR	[%o4+%lo(romp)], %o4		! v9 stack, just load the addr and callit
5852	save	%sp, -CC64FSZ, %sp
5853	rdpr	%pil, %i2
5854	mov	PIL_HIGH, %i3
5855	cmp	%i3, %i2
5856	movle	%icc, %i2, %i3
5857	wrpr	%g0, %i3, %pil
5858	mov	%i0, %o0
5859	mov	%g1, %l1
5860	mov	%g2, %l2
5861	mov	%g3, %l3
5862	mov	%g4, %l4
5863	mov	%g5, %l5
5864	mov	%g6, %l6
5865	mov	%g7, %l7
5866	rdpr	%pstate, %l0
5867	jmpl	%i4, %o7
5868#if !defined(_LP64)
5869	 wrpr	%g0, PSTATE_PROM, %pstate
5870#else
5871	 wrpr	%g0, PSTATE_PROM|PSTATE_IE, %pstate
5872#endif
5873	wrpr	%l0, %g0, %pstate
5874	mov	%l1, %g1
5875	mov	%l2, %g2
5876	mov	%l3, %g3
5877	mov	%l4, %g4
5878	mov	%l5, %g5
5879	mov	%l6, %g6
5880	mov	%l7, %g7
5881	wrpr	%i2, 0, %pil
5882	ret
5883	 restore	%o0, %g0, %o0
5884
58851:	! v8 -- need to screw with stack & params
5886#ifdef NOTDEF_DEBUG
5887	mov	%o7, %o5
5888	call	globreg_check
5889	 nop
5890	mov	%o5, %o7
5891#endif
5892	save	%sp, -CC64FSZ, %sp		! Get a new 64-bit stack frame
5893	add	%sp, -BIAS, %sp
5894	rdpr	%pstate, %l0
5895	srl	%sp, 0, %sp
5896	rdpr	%pil, %i2	! s = splx(level)
5897	mov	%i0, %o0
5898	mov	PIL_HIGH, %i3
5899	mov	%g1, %l1
5900	mov	%g2, %l2
5901	cmp	%i3, %i2
5902	mov	%g3, %l3
5903	mov	%g4, %l4
5904	mov	%g5, %l5
5905	movle	%icc, %i2, %i3
5906	mov	%g6, %l6
5907	mov	%g7, %l7
5908	wrpr	%i3, %g0, %pil
5909	jmpl	%i4, %o7
5910	! Enable 64-bit addresses for the prom
5911#if defined(_LP64)
5912	 wrpr	%g0, PSTATE_PROM, %pstate
5913#else
5914	 wrpr	%g0, PSTATE_PROM|PSTATE_IE, %pstate
5915#endif
5916	wrpr	%l0, 0, %pstate
5917	wrpr	%i2, 0, %pil
5918	mov	%l1, %g1
5919	mov	%l2, %g2
5920	mov	%l3, %g3
5921	mov	%l4, %g4
5922	mov	%l5, %g5
5923	mov	%l6, %g6
5924	mov	%l7, %g7
5925	ret
5926	 restore	%o0, %g0, %o0
5927
5928/*
5929 * void ofw_exit(cell_t args[])
5930 */
5931ENTRY(openfirmware_exit)
5932	STACKFRAME(-CC64FSZ)
5933	flushw					! Flush register windows
5934
5935	wrpr	%g0, PIL_HIGH, %pil		! Disable interrupts
5936	sethi	%hi(romtba), %l5
5937	LDPTR	[%l5 + %lo(romtba)], %l5
5938	wrpr	%l5, 0, %tba			! restore the ofw trap table
5939
5940	/* Arrange locked kernel stack as PROM stack */
5941	set	EINTSTACK  - CC64FSZ, %l5
5942
5943	andn	%l5, 0x0f, %l5			! Needs to be 16-byte aligned
5944	sub	%l5, BIAS, %l5			! and biased
5945	mov	%l5, %sp
5946	flushw
5947
5948	sethi	%hi(romp), %l6
5949	LDPTR	[%l6 + %lo(romp)], %l6
5950
5951	mov     CTX_PRIMARY, %l3		! set context 0
5952	stxa    %g0, [%l3] ASI_DMMU
5953	membar	#Sync
5954
5955	wrpr	%g0, PSTATE_PROM, %pstate	! Disable interrupts
5956						! and enable 64-bit addresses
5957	wrpr	%g0, 0, %tl			! force trap level 0
5958	call	%l6
5959	 mov	%i0, %o0
5960	NOTREACHED
5961
5962/*
5963 * sp_tlb_flush_pte_us(vaddr_t va, int ctx)
5964 * sp_tlb_flush_pte_usiii(vaddr_t va, int ctx)
5965 *
5966 * Flush tte from both IMMU and DMMU.
5967 *
5968 * This uses %o0-%o5
5969 */
5970	.align 8
5971ENTRY(sp_tlb_flush_pte_us)
5972#ifdef DEBUG
5973	set	pmapdebug, %o3
5974	lduw	[%o3], %o3
5975!	movrz	%o1, -1, %o3				! Print on either pmapdebug & PDB_DEMAP or ctx == 0
5976	btst	0x0020, %o3
5977	bz,pt	%icc, 2f
5978	 nop
5979	save	%sp, -CC64FSZ, %sp
5980	set	1f, %o0
5981	mov	%i1, %o1
5982	andn	%i0, 0xfff, %o3
5983	or	%o3, 0x010, %o3
5984	call	_C_LABEL(printf)
5985	 mov	%i0, %o2
5986	restore
5987	.data
59881:
5989	.asciz	"sp_tlb_flush_pte_us:	demap ctx=%x va=%08x res=%x\n"
5990	_ALIGN
5991	.text
59922:
5993#endif
5994#ifdef MULTIPROCESSOR
5995	rdpr	%pstate, %o3
5996	andn	%o3, PSTATE_IE, %o4			! disable interrupts
5997	wrpr	%o4, 0, %pstate
5998#endif
5999	srlx	%o0, PG_SHIFT4U, %o0			! drop unused va bits
6000	mov	CTX_SECONDARY, %o2
6001	sllx	%o0, PG_SHIFT4U, %o0
6002	ldxa	[%o2] ASI_DMMU, %o5			! Save secondary context
6003	sethi	%hi(KERNBASE), %o4
6004	membar	#LoadStore
6005	stxa	%o1, [%o2] ASI_DMMU			! Insert context to demap
6006	membar	#Sync
6007	or	%o0, DEMAP_PAGE_SECONDARY, %o0		! Demap page from secondary context only
6008	stxa	%o0, [%o0] ASI_DMMU_DEMAP		! Do the demap
6009	stxa	%o0, [%o0] ASI_IMMU_DEMAP		! to both TLBs
6010#ifdef TLB_FLUSH_LOWVA
6011	srl	%o0, 0, %o0				! and make sure it's both 32- and 64-bit entries
6012	stxa	%o0, [%o0] ASI_DMMU_DEMAP		! Do the demap
6013	stxa	%o0, [%o0] ASI_IMMU_DEMAP		! Do the demap
6014#endif
6015	flush	%o4
6016	stxa	%o5, [%o2] ASI_DMMU			! Restore secondary context
6017	membar	#Sync
6018	retl
6019#ifdef MULTIPROCESSOR
6020	 wrpr	%o3, %pstate				! restore interrupts
6021#else
6022	 nop
6023#endif
6024
6025ENTRY(sp_tlb_flush_pte_usiii)
6026#ifdef DEBUG
6027	set	pmapdebug, %o3
6028	lduw	[%o3], %o3
6029!	movrz	%o1, -1, %o3				! Print on either pmapdebug & PDB_DEMAP or ctx == 0
6030	btst	0x0020, %o3
6031	bz,pt	%icc, 2f
6032	 nop
6033	save	%sp, -CC64FSZ, %sp
6034	set	1f, %o0
6035	mov	%i1, %o1
6036	andn	%i0, 0xfff, %o3
6037	or	%o3, 0x010, %o3
6038	call	_C_LABEL(printf)
6039	 mov	%i0, %o2
6040	restore
6041	.data
60421:
6043	.asciz	"sp_tlb_flush_pte_usiii:	demap ctx=%x va=%08x res=%x\n"
6044	_ALIGN
6045	.text
60462:
6047#endif
6048	! %o0 = VA [in]
6049	! %o1 = ctx value [in] / KERNBASE
6050	! %o2 = CTX_PRIMARY
6051	! %o3 = saved %tl
6052	! %o4 = saved %pstate
6053	! %o5 = saved primary ctx
6054
6055	! Need this for UP as well
6056	rdpr	%pstate, %o4
6057	andn	%o4, PSTATE_IE, %o3			! disable interrupts
6058	wrpr	%o3, 0, %pstate
6059
6060	!!
6061	!! Cheetahs do not support flushing the IMMU from secondary context
6062	!!
6063	rdpr	%tl, %o3
6064	mov	CTX_PRIMARY, %o2
6065	brnz,pt	%o3, 1f
6066	 andn	%o0, 0xfff, %o0				! drop unused va bits
6067	wrpr	%g0, 1, %tl				! Make sure we're NUCLEUS
60681:
6069	ldxa	[%o2] ASI_DMMU, %o5			! Save primary context
6070	membar	#LoadStore
6071	stxa	%o1, [%o2] ASI_DMMU			! Insert context to demap
6072	sethi	%hi(KERNBASE), %o1
6073	membar	#Sync
6074	or	%o0, DEMAP_PAGE_PRIMARY, %o0
6075	stxa	%o0, [%o0] ASI_DMMU_DEMAP		! Do the demap
6076	membar	#Sync
6077	stxa	%o0, [%o0] ASI_IMMU_DEMAP		! to both TLBs
6078	membar	#Sync
6079#ifdef TLB_FLUSH_LOWVA
6080	srl	%o0, 0, %o0				! and make sure it's both 32- and 64-bit entries
6081	stxa	%o0, [%o0] ASI_DMMU_DEMAP		! Do the demap
6082	membar	#Sync
6083	stxa	%o0, [%o0] ASI_IMMU_DEMAP		! Do the demap
6084	membar	#Sync
6085#endif
6086	flush	%o1
6087	stxa	%o5, [%o2] ASI_DMMU			! Restore primary context
6088	membar	#Sync
6089	brnz,pt	%o3, 1f
6090	 flush	%o1
6091	wrpr	%g0, %o3, %tl				! Return to kernel mode.
60921:
6093	retl
6094	 wrpr	%o4, %pstate				! restore interrupts
6095
6096
6097/*
6098 * sp_tlb_flush_all_us(void)
6099 * sp_tlb_flush_all_usiii(void)
6100 *
6101 * Flush all user TLB entries from both IMMU and DMMU.
6102 * We have both UltraSPARC I+II, and UltraSPARC >=III versions.
6103 */
6104	.align 8
6105ENTRY(sp_tlb_flush_all_us)
6106	rdpr	%pstate, %o3
6107	andn	%o3, PSTATE_IE, %o4			! disable interrupts
6108	wrpr	%o4, 0, %pstate
6109	set	((TLB_SIZE_SPITFIRE-1) * 8), %o0
6110	set	CTX_SECONDARY, %o4
6111	ldxa	[%o4] ASI_DMMU, %o4			! save secondary context
6112	set	CTX_MASK, %o5
6113	membar	#Sync
6114
6115	! %o0 = loop counter
6116	! %o1 = ctx value
6117	! %o2 = TLB tag value
6118	! %o3 = saved %pstate
6119	! %o4 = saved primary ctx
6120	! %o5 = CTX_MASK
6121	! %xx = saved %tl
6122
61230:
6124	ldxa	[%o0] ASI_DMMU_TLB_TAG, %o2		! fetch the TLB tag
6125	andcc	%o2, %o5, %o1				! context 0?
6126	bz,pt	%xcc, 1f				! if so, skip
6127	 mov	CTX_SECONDARY, %o2
6128
6129	stxa	%o1, [%o2] ASI_DMMU			! set the context
6130	set	DEMAP_CTX_SECONDARY, %o2
6131	membar	#Sync
6132	stxa	%o2, [%o2] ASI_DMMU_DEMAP		! do the demap
6133	membar	#Sync
6134
61351:
6136	dec	8, %o0
6137	brgz,pt %o0, 0b					! loop over all entries
6138	 nop
6139
6140/*
6141 * now do the IMMU
6142 */
6143
6144	set	((TLB_SIZE_SPITFIRE-1) * 8), %o0
6145
61460:
6147	ldxa	[%o0] ASI_IMMU_TLB_TAG, %o2		! fetch the TLB tag
6148	andcc	%o2, %o5, %o1				! context 0?
6149	bz,pt	%xcc, 1f				! if so, skip
6150	 mov	CTX_SECONDARY, %o2
6151
6152	stxa	%o1, [%o2] ASI_DMMU			! set the context
6153	set	DEMAP_CTX_SECONDARY, %o2
6154	membar	#Sync
6155	stxa	%o2, [%o2] ASI_IMMU_DEMAP		! do the demap
6156	membar	#Sync
6157
61581:
6159	dec	8, %o0
6160	brgz,pt %o0, 0b					! loop over all entries
6161	 nop
6162
6163	set	CTX_SECONDARY, %o2
6164	stxa	%o4, [%o2] ASI_DMMU			! restore secondary ctx
6165	sethi	%hi(KERNBASE), %o4
6166	membar	#Sync
6167	flush	%o4
6168	retl
6169	 wrpr	%o3, %pstate
6170
6171	.align 8
6172ENTRY(sp_tlb_flush_all_usiii)
6173	rdpr	%tl, %o5
6174	brnz,pt	%o5, 1f
6175	 set	DEMAP_ALL, %o2
6176	wrpr	1, %tl
61771:
6178	rdpr	%pstate, %o3
6179	andn	%o3, PSTATE_IE, %o4			! disable interrupts
6180	wrpr	%o4, 0, %pstate
6181
6182	stxa	%o2, [%o2] ASI_IMMU_DEMAP
6183	membar	#Sync
6184	stxa	%o2, [%o2] ASI_DMMU_DEMAP
6185
6186	sethi	%hi(KERNBASE), %o4
6187	membar	#Sync
6188	flush	%o4
6189
6190	wrpr	%o5, %tl
6191	retl
6192	 wrpr	%o3, %pstate
6193
6194/*
6195 * sp_blast_dcache(int dcache_size, int dcache_line_size)
6196 * sp_blast_dcache_disabled(int dcache_size, int dcache_line_size)
6197 *
6198 * Clear out all of D$ regardless of contents.  The latter one also
6199 * disables the D$ while doing so.
6200 */
6201	.align 8
6202ENTRY(sp_blast_dcache)
6203/*
6204 * We turn off interrupts for the duration to prevent RED exceptions.
6205 */
6206#ifdef PROF
6207	save	%sp, -CC64FSZ, %sp
6208#endif
6209
6210	rdpr	%pstate, %o3
6211	sub	%o0, %o1, %o0
6212	andn	%o3, PSTATE_IE, %o4			! Turn off PSTATE_IE bit
6213	wrpr	%o4, 0, %pstate
62141:
6215	stxa	%g0, [%o0] ASI_DCACHE_TAG
6216	membar	#Sync
6217	brnz,pt	%o0, 1b
6218	 sub	%o0, %o1, %o0
6219
6220	sethi	%hi(KERNBASE), %o2
6221	flush	%o2
6222	membar	#Sync
6223#ifdef PROF
6224	wrpr	%o3, %pstate
6225	ret
6226	 restore
6227#else
6228	retl
6229	 wrpr	%o3, %pstate
6230#endif
6231
6232	.align 8
6233ENTRY(sp_blast_dcache_disabled)
6234/*
6235 * We turn off interrupts for the duration to prevent RED exceptions.
6236 */
6237#ifdef PROF
6238	save	%sp, -CC64FSZ, %sp
6239#endif
6240
6241	rdpr	%pstate, %o3
6242	sub	%o0, %o1, %o0
6243	andn	%o3, PSTATE_IE, %o4			! Turn off PSTATE_IE bit
6244	wrpr	%o4, 0, %pstate
6245
6246	ldxa    [%g0] ASI_MCCR, %o5
6247	andn	%o5, MCCR_DCACHE_EN, %o4		! Turn off the D$
6248	stxa	%o4, [%g0] ASI_MCCR
6249	flush 	%g0
6250
62511:
6252	stxa	%g0, [%o0] ASI_DCACHE_TAG
6253	membar	#Sync
6254	brnz,pt	%o0, 1b
6255	 sub	%o0, %o1, %o0
6256
6257	sethi	%hi(KERNBASE), %o2
6258	flush	%o2
6259	membar	#Sync
6260
6261	stxa	%o5, [%g0] ASI_MCCR			! Restore the D$
6262	flush 	%g0
6263#ifdef PROF
6264	wrpr	%o3, %pstate
6265	ret
6266	 restore
6267#else
6268	retl
6269	 wrpr	%o3, %pstate
6270#endif
6271
6272#ifdef MULTIPROCESSOR
6273/*
6274 * void sparc64_ipi_blast_dcache(int dcache_size, int dcache_line_size)
6275 *
6276 * Clear out all of D$ regardless of contents
6277 *
6278 * On entry:
6279 *	%g2 = dcache_size
6280 *	%g3 = dcache_line_size
6281 */
6282	.align 8
6283ENTRY(sparc64_ipi_blast_dcache)
6284	sub	%g2, %g3, %g2
62851:
6286	stxa	%g0, [%g2] ASI_DCACHE_TAG
6287	membar	#Sync
6288	brnz,pt	%g2, 1b
6289	 sub	%g2, %g3, %g2
6290
6291	sethi	%hi(KERNBASE), %g5
6292	flush	%g5
6293	membar	#Sync
6294
6295	ba,a	ret_from_intr_vector
6296	 nop
6297#endif /* MULTIPROCESSOR */
6298
6299/*
6300 * blast_icache_us()
6301 * blast_icache_usiii()
6302 *
6303 * Clear out all of I$ regardless of contents
6304 * Does not modify %o0
6305 *
6306 * We turn off interrupts for the duration to prevent RED exceptions.
6307 * For the Cheetah version, we also have to to turn off the I$ during this as
6308 * ASI_ICACHE_TAG accesses interfere with coherency.
6309 */
6310	.align 8
6311ENTRY(blast_icache_us)
6312	rdpr	%pstate, %o3
6313	sethi	%hi(icache_size), %o1
6314	ld	[%o1 + %lo(icache_size)], %o1
6315	sethi	%hi(icache_line_size), %o2
6316	ld	[%o2 + %lo(icache_line_size)], %o2
6317	sub	%o1, %o2, %o1
6318	andn	%o3, PSTATE_IE, %o4			! Turn off PSTATE_IE bit
6319	wrpr	%o4, 0, %pstate
63201:
6321	stxa	%g0, [%o1] ASI_ICACHE_TAG
6322	brnz,pt	%o1, 1b
6323	 sub	%o1, %o2, %o1
6324	sethi	%hi(KERNBASE), %o5
6325	flush	%o5
6326	membar	#Sync
6327	retl
6328	 wrpr	%o3, %pstate
6329
6330	.align 8
6331ENTRY(blast_icache_usiii)
6332	rdpr	%pstate, %o3
6333	sethi	%hi(icache_size), %o1
6334	ld	[%o1 + %lo(icache_size)], %o1
6335	sethi	%hi(icache_line_size), %o2
6336	ld	[%o2 + %lo(icache_line_size)], %o2
6337	sub	%o1, %o2, %o1
6338	andn	%o3, PSTATE_IE, %o4			! Turn off PSTATE_IE bit
6339	wrpr	%o4, 0, %pstate
6340	ldxa    [%g0] ASI_MCCR, %o5
6341	andn	%o5, MCCR_ICACHE_EN, %o4		! Turn off the I$
6342	stxa	%o4, [%g0] ASI_MCCR
6343	flush 	%g0
63441:
6345	stxa	%g0, [%o1] ASI_ICACHE_TAG
6346	membar	#Sync
6347	brnz,pt	%o1, 1b
6348	 sub	%o1, %o2, %o1
6349	stxa	%o5, [%g0] ASI_MCCR			! Restore the I$
6350	flush 	%g0
6351	retl
6352	 wrpr	%o3, %pstate
6353
6354/*
6355 * dcache_flush_page_us(paddr_t pa)
6356 * dcache_flush_page_usiii(paddr_t pa)
6357 *
6358 * Clear one page from D$.
6359 *
6360 */
6361	.align 8
6362ENTRY(dcache_flush_page_us)
6363#ifndef _LP64
6364	COMBINE(%o0, %o1, %o0)
6365#endif
6366	mov	-1, %o1		! Generate mask for tag: bits [29..2]
6367	srlx	%o0, 13-2, %o2	! Tag is PA bits <40:13> in bits <29:2>
6368	clr	%o4
6369	srl	%o1, 2, %o1	! Now we have bits <29:0> set
6370	set	(2*NBPG), %o5
6371	ba,pt	%icc, 1f
6372	 andn	%o1, 3, %o1	! Now we have bits <29:2> set
6373
6374	.align 8
63751:
6376	ldxa	[%o4] ASI_DCACHE_TAG, %o3
6377	mov	%o4, %o0
6378	deccc	32, %o5
6379	bl,pn	%icc, 2f
6380	 inc	32, %o4
6381
6382	xor	%o3, %o2, %o3
6383	andcc	%o3, %o1, %g0
6384	bne,pt	%xcc, 1b
6385	 membar	#LoadStore
6386
6387	stxa	%g0, [%o0] ASI_DCACHE_TAG
6388	ba,pt	%icc, 1b
6389	 membar	#StoreLoad
63902:
6391
6392	sethi	%hi(KERNBASE), %o5
6393	flush	%o5
6394	retl
6395	 membar	#Sync
6396
6397	.align 8
6398ENTRY(dcache_flush_page_usiii)
6399#ifndef _LP64
6400	COMBINE(%o0, %o1, %o0)
6401#endif
6402	set	NBPG, %o1
6403	sethi	%hi(dcache_line_size), %o2
6404	add	%o0, %o1, %o1	! end address
6405	ld	[%o2 + %lo(dcache_line_size)], %o2
6406
64071:
6408	stxa	%g0, [%o0] ASI_DCACHE_INVALIDATE
6409	add	%o0, %o2, %o0
6410	cmp	%o0, %o1
6411	bl,pt	%xcc, 1b
6412	 nop
6413
6414	sethi	%hi(KERNBASE), %o5
6415	flush	%o5
6416	retl
6417	 membar	#Sync
6418
6419/*
6420 *	cache_flush_phys_us(paddr_t, psize_t, int);
6421 *	cache_flush_phys_usiii(paddr_t, psize_t, int);
6422 *
6423 *	Clear a set of paddrs from the D$, I$ and if param3 is
6424 *	non-zero, E$.  (E$ is not supported yet).
6425 */
6426
6427	.align 8
6428ENTRY(cache_flush_phys_us)
6429#ifndef _LP64
6430	COMBINE(%o0, %o1, %o0)
6431	COMBINE(%o2, %o3, %o1)
6432	mov	%o4, %o2
6433#endif
6434#ifdef DEBUG
6435	tst	%o2		! Want to clear E$?
6436	tnz	1		! Error!
6437#endif
6438	add	%o0, %o1, %o1	! End PA
6439	dec	%o1
6440
6441	!!
6442	!! Both D$ and I$ tags match pa bits 42-13, but
6443	!! they are shifted different amounts.  So we'll
6444	!! generate a mask for bits 40-13.
6445	!!
6446
6447	mov	-1, %o2		! Generate mask for tag: bits [40..13]
6448	srl	%o2, 5, %o2	! 32-5 = [27..0]
6449	sllx	%o2, 13, %o2	! 27+13 = [40..13]
6450
6451	and	%o2, %o0, %o0	! Mask away uninteresting bits
6452	and	%o2, %o1, %o1	! (probably not necessary)
6453
6454	set	(2*NBPG), %o5
6455	clr	%o4
64561:
6457	ldxa	[%o4] ASI_DCACHE_TAG, %o3
6458	sllx	%o3, 40-29, %o3	! Shift D$ tag into place
6459	and	%o3, %o2, %o3	! Mask out trash
6460
6461	cmp	%o0, %o3
6462	blt,pt	%xcc, 2f	! Too low
6463	 cmp	%o1, %o3
6464	bgt,pt	%xcc, 2f	! Too high
6465	 nop
6466
6467	membar	#LoadStore
6468	stxa	%g0, [%o4] ASI_DCACHE_TAG ! Just right
6469	membar	#Sync
64702:
6471	ldda	[%o4] ASI_ICACHE_TAG, %g0	! Tag goes in %g1
6472	sllx	%g1, 40-35, %g1			! Shift I$ tag into place
6473	and	%g1, %o2, %g1			! Mask out trash
6474	cmp	%o0, %g1
6475	blt,pt	%xcc, 3f
6476	 cmp	%o1, %g1
6477	bgt,pt	%xcc, 3f
6478	 nop
6479	stxa	%g0, [%o4] ASI_ICACHE_TAG
64803:
6481	membar	#StoreLoad
6482	dec	32, %o5
6483	brgz,pt	%o5, 1b
6484	 inc	32, %o4
6485
6486	sethi	%hi(KERNBASE), %o5
6487	flush	%o5
6488	retl
6489	 membar	#Sync
6490
6491	.align 8
6492ENTRY(cache_flush_phys_usiii)
6493#ifndef _LP64
6494	COMBINE(%o0, %o1, %o0)
6495	COMBINE(%o2, %o3, %o1)
6496	mov	%o4, %o2
6497#endif
6498#ifdef DEBUG
6499	tst	%o2		! Want to clear E$?
6500	tnz	1		! Error!
6501#endif
6502	add	%o0, %o1, %o1	! End PA
6503	sethi	%hi(dcache_line_size), %o3
6504	ld	[%o3 + %lo(dcache_line_size)], %o3
6505	sethi	%hi(KERNBASE), %o5
65061:
6507	stxa	%g0, [%o0] ASI_DCACHE_INVALIDATE
6508	add	%o0, %o3, %o0
6509	cmp	%o0, %o1
6510	bl,pt	%xcc, 1b
6511	 nop
6512
6513	/* don't need to flush the I$ on cheetah */
6514
6515	flush	%o5
6516	retl
6517	 membar	#Sync
6518
6519#ifdef COMPAT_16
6520#ifdef _LP64
6521/*
6522 * XXXXX Still needs lotsa cleanup after sendsig is complete and offsets are known
6523 *
6524 * The following code is copied to the top of the user stack when each
6525 * process is exec'ed, and signals are `trampolined' off it.
6526 *
6527 * When this code is run, the stack looks like:
6528 *	[%sp]			128 bytes to which registers can be dumped
6529 *	[%sp + 128]		signal number (goes in %o0)
6530 *	[%sp + 128 + 4]		signal code (goes in %o1)
6531 *	[%sp + 128 + 8]		first word of saved state (sigcontext)
6532 *	    .
6533 *	    .
6534 *	    .
6535 *	[%sp + NNN]	last word of saved state
6536 * (followed by previous stack contents or top of signal stack).
6537 * The address of the function to call is in %g1; the old %g1 and %o0
6538 * have already been saved in the sigcontext.  We are running in a clean
6539 * window, all previous windows now being saved to the stack.
6540 *
6541 * Note that [%sp + 128 + 8] == %sp + 128 + 16.  The copy at %sp+128+8
6542 * will eventually be removed, with a hole left in its place, if things
6543 * work out.
6544 */
6545ENTRY_NOPROFILE(sigcode)
6546	/*
6547	 * XXX  the `save' and `restore' below are unnecessary: should
6548	 *	replace with simple arithmetic on %sp
6549	 *
6550	 * Make room on the stack for 64 %f registers + %fsr.  This comes
6551	 * out to 64*4+8 or 264 bytes, but this must be aligned to a multiple
6552	 * of 64, or 320 bytes.
6553	 */
6554	save	%sp, -CC64FSZ - 320, %sp
6555	mov	%g2, %l2		! save globals in %l registers
6556	mov	%g3, %l3
6557	mov	%g4, %l4
6558	mov	%g5, %l5
6559	mov	%g6, %l6
6560	mov	%g7, %l7
6561	/*
6562	 * Saving the fpu registers is expensive, so do it iff it is
6563	 * enabled and dirty.
6564	 */
6565	rd	%fprs, %l0
6566	btst	FPRS_DL|FPRS_DU, %l0	! All clean?
6567	bz,pt	%icc, 2f
6568	 btst	FPRS_DL, %l0		! test dl
6569	bz,pt	%icc, 1f
6570	 btst	FPRS_DU, %l0		! test du
6571
6572	! fpu is enabled, oh well
6573	stx	%fsr, [%sp + CC64FSZ + BIAS + 0]
6574	add	%sp, BIAS+CC64FSZ+BLOCK_SIZE, %l0	! Generate a pointer so we can
6575	andn	%l0, BLOCK_ALIGN, %l0	! do a block store
6576	stda	%f0, [%l0] ASI_BLK_P
6577	inc	BLOCK_SIZE, %l0
6578	stda	%f16, [%l0] ASI_BLK_P
65791:
6580	bz,pt	%icc, 2f
6581	 add	%sp, BIAS+CC64FSZ+BLOCK_SIZE, %l0	! Generate a pointer so we can
6582	andn	%l0, BLOCK_ALIGN, %l0	! do a block store
6583	add	%l0, 2*BLOCK_SIZE, %l0	! and skip what we already stored
6584	stda	%f32, [%l0] ASI_BLK_P
6585	inc	BLOCK_SIZE, %l0
6586	stda	%f48, [%l0] ASI_BLK_P
65872:
6588	membar	#Sync
6589	rd	%fprs, %l0		! reload fprs copy, for checking after
6590	rd	%y, %l1			! in any case, save %y
6591	lduw	[%fp + BIAS + 128], %o0	! sig
6592	lduw	[%fp + BIAS + 128 + 4], %o1	! code
6593	call	%g1			! (*sa->sa_handler)(sig,code,scp)
6594	 add	%fp, BIAS + 128 + 8, %o2	! scp
6595	wr	%l1, %g0, %y		! in any case, restore %y
6596
6597	/*
6598	 * Now that the handler has returned, re-establish all the state
6599	 * we just saved above, then do a sigreturn.
6600	 */
6601	btst	FPRS_DL|FPRS_DU, %l0	! All clean?
6602	bz,pt	%icc, 2f
6603	 btst	FPRS_DL, %l0		! test dl
6604	bz,pt	%icc, 1f
6605	 btst	FPRS_DU, %l0		! test du
6606
6607	ldx	[%sp + CC64FSZ + BIAS + 0], %fsr
6608	add	%sp, BIAS+CC64FSZ+BLOCK_SIZE, %l0	! Generate a pointer so we can
6609	andn	%l0, BLOCK_ALIGN, %l0	! do a block load
6610	ldda	[%l0] ASI_BLK_P, %f0
6611	inc	BLOCK_SIZE, %l0
6612	ldda	[%l0] ASI_BLK_P, %f16
66131:
6614	bz,pt	%icc, 2f
6615	 nop
6616	add	%sp, BIAS+CC64FSZ+BLOCK_SIZE, %l0	! Generate a pointer so we can
6617	andn	%l0, BLOCK_ALIGN, %l0	! do a block load
6618	inc	2*BLOCK_SIZE, %l0	! and skip what we already loaded
6619	ldda	[%l0] ASI_BLK_P, %f32
6620	inc	BLOCK_SIZE, %l0
6621	ldda	[%l0] ASI_BLK_P, %f48
66222:
6623	mov	%l2, %g2
6624	mov	%l3, %g3
6625	mov	%l4, %g4
6626	mov	%l5, %g5
6627	mov	%l6, %g6
6628	mov	%l7, %g7
6629	membar	#Sync
6630
6631	restore	%g0, SYS_compat_16___sigreturn14, %g1 ! get registers back & set syscall #
6632	add	%sp, BIAS + 128 + 8, %o0! compute scp
6633!	andn	%o0, 0x0f, %o0
6634	t	ST_SYSCALL		! sigreturn(scp)
6635	! sigreturn does not return unless it fails
6636	mov	SYS_exit, %g1		! exit(errno)
6637	t	ST_SYSCALL
6638	/* NOTREACHED */
6639
6640	.globl	_C_LABEL(esigcode)
6641_C_LABEL(esigcode):
6642#endif
6643
6644#if !defined(_LP64)
6645
6646#define SIGCODE_NAME		sigcode
6647#define ESIGCODE_NAME		esigcode
6648#define SIGRETURN_NAME		SYS_compat_16___sigreturn14
6649#define EXIT_NAME		SYS_exit
6650
6651#include "sigcode32.s"
6652
6653#endif
6654#endif
6655
6656/*
6657 * getfp() - get stack frame pointer
6658 */
6659ENTRY(getfp)
6660	retl
6661	 mov %fp, %o0
6662
6663/*
6664 * Call optional cpu_idle handler if provided
6665 */
6666ENTRY(cpu_idle)
6667	set	CPUINFO_VA, %o0
6668	LDPTR	[%o0 + CI_IDLESPIN], %o1
6669	tst	%o1
6670	bz	1f
6671	 nop
6672	jmp	%o1
6673	 nop
66741:
6675	retl
6676	nop
6677
6678/*
6679 * cpu_switchto() switches to an lwp to run and runs it, saving the
6680 * current one away.
6681 *
6682 * struct lwp * cpu_switchto(struct lwp *current, struct lwp *next)
6683 * Switch to the specified next LWP
6684 * Arguments:
6685 *	i0	'struct lwp *' of the current LWP
6686 *	i1	'struct lwp *' of the LWP to switch to
6687 *	i2	'bool' of the flag returning to a softint LWP or not
6688 * Returns:
6689 *	the old lwp switched away from
6690 */
6691ENTRY(cpu_switchto)
6692	save	%sp, -CC64FSZ, %sp
6693	/*
6694	 * REGISTER USAGE AT THIS POINT:
6695	 *	%l1 = newpcb
6696	 *	%l3 = new trapframe
6697	 *	%l4 = new l->l_proc
6698	 *	%l5 = pcb of oldlwp
6699	 *	%l6 = %hi(CPCB)
6700	 *	%l7 = %hi(CURLWP)
6701	 *	%i0 = oldlwp
6702	 *	%i1 = lwp
6703	 *	%i2 = returning
6704	 *	%o0 = tmp 1
6705	 *	%o1 = tmp 2
6706	 *	%o2 = tmp 3
6707	 *	%o3 = tmp 4
6708	 */
6709
6710	flushw				! save all register windows except this one
6711	wrpr	%g0, PSTATE_KERN, %pstate	! make sure we're on normal globals
6712						! with traps turned off
6713
6714	sethi	%hi(CPCB), %l6
6715
6716	rdpr	%pstate, %o1			! oldpstate = %pstate;
6717	LDPTR	[%i0 + L_PCB], %l5
6718
6719	stx	%i7, [%l5 + PCB_PC]
6720	stx	%i6, [%l5 + PCB_SP]
6721	sth	%o1, [%l5 + PCB_PSTATE]
6722
6723	rdpr	%cwp, %o2		! Useless
6724	stb	%o2, [%l5 + PCB_CWP]
6725
6726	sethi	%hi(CURLWP), %l7
6727
6728	LDPTR   [%i1 + L_PCB], %l1	! newpcb = l->l_pcb;
6729
6730	/*
6731	 * Load the new lwp.  To load, we must change stacks and
6732	 * alter cpcb and the window control registers, hence we must
6733	 * keep interrupts disabled.
6734	 *
6735	 * Issue barriers to coordinate mutex_exit on this CPU with
6736	 * mutex_vector_enter on another CPU.
6737	 *
6738	 * 1. Any prior mutex_exit by oldlwp must be visible to other
6739	 *    CPUs before we set ci_curlwp := newlwp on this one,
6740	 *    requiring a store-before-store barrier.
6741	 *
6742	 * 2. ci_curlwp := newlwp must be visible on all other CPUs
6743	 *    before any subsequent mutex_exit by newlwp can even test
6744	 *    whether there might be waiters, requiring a
6745	 *    store-before-load barrier.
6746	 *
6747	 * See kern_mutex.c for details -- this is necessary for
6748	 * adaptive mutexes to detect whether the lwp is on the CPU in
6749	 * order to safely block without requiring atomic r/m/w in
6750	 * mutex_exit.
6751	 */
6752
6753	membar	#StoreStore
6754	STPTR	%i1, [%l7 + %lo(CURLWP)]	! curlwp = l;
6755	membar	#StoreLoad
6756	STPTR	%l1, [%l6 + %lo(CPCB)]		! cpcb = newpcb;
6757
6758	ldx	[%l1 + PCB_SP], %i6
6759	ldx	[%l1 + PCB_PC], %i7
6760
6761	wrpr	%g0, 0, %otherwin	! These two insns should be redundant
6762	wrpr	%g0, 0, %canrestore
6763	GET_MAXCWP %o3
6764	wrpr	%g0, %o3, %cleanwin
6765	dec	1, %o3			! CANSAVE + CANRESTORE + OTHERWIN = MAXCWP - 1
6766	/* Skip the rest if returning to a interrupted LWP. */
6767	brnz,pn	%i2, Lsw_noras
6768	 wrpr	%o3, %cansave
6769
6770	/* finally, enable traps */
6771	wrpr	%g0, PSTATE_INTR, %pstate
6772
6773	!flushw
6774	!membar #Sync
6775
6776	/*
6777	 * Check for restartable atomic sequences (RAS)
6778	 */
6779	LDPTR	[%i1 + L_PROC], %l4		! now %l4 points to p
6780	mov	%l4, %o0		! p is first arg to ras_lookup
6781	LDPTR	[%o0 + P_RASLIST], %o1	! any RAS in p?
6782	brz,pt	%o1, Lsw_noras		! no, skip RAS check
6783	 LDPTR	[%i1 + L_TF], %l3	! pointer to trap frame
6784	call	_C_LABEL(ras_lookup)
6785	 ldx	[%l3 + TF_PC], %o1
6786	cmp	%o0, -1
6787	be,pt	CCCR, Lsw_noras
6788	 add	%o0, 4, %o1
6789	stx	%o0, [%l3 + TF_PC]	! store rewound %pc
6790	stx	%o1, [%l3 + TF_NPC]	! and %npc
6791
6792Lsw_noras:
6793
6794	/*
6795	 * We are resuming the process that was running at the
6796	 * call to switch().  Just set psr ipl and return.
6797	 */
6798!	wrpr	%g0, 0, %cleanwin	! DEBUG
6799	clr	%g4		! This needs to point to the base of the data segment
6800	wr	%g0, ASI_PRIMARY_NOFAULT, %asi		! Restore default ASI
6801	!wrpr	%g0, PSTATE_INTR, %pstate
6802	ret
6803	 restore %i0, %g0, %o0				! return old curlwp
6804
6805#ifdef __HAVE_FAST_SOFTINTS
6806/*
6807 * Switch to the LWP assigned to handle interrupts from the given
6808 * source.  We borrow the VM context from the interrupted LWP.
6809 *
6810 * int softint_fastintr(void *l)
6811 *
6812 * Arguments:
6813 *	i0	softint lwp
6814 */
6815ENTRY(softint_fastintr)
6816	save	%sp, -CC64FSZ, %sp
6817	set	CPUINFO_VA, %l0			! l0 = curcpu()
6818	rdpr	%pil, %l7			! l7 = splhigh()
6819	wrpr	%g0, PIL_HIGH, %pil
6820	LDPTR	[%l0 + CI_EINTSTACK], %l6	! l6 = ci_eintstack
6821	add	%sp, -CC64FSZ, %l2		! ci_eintstack = sp - CC64FSZ
6822	STPTR	%l2, [%l0 + CI_EINTSTACK]	! save intstack for nested intr
6823
6824	mov	%i0, %o0			! o0/i0 = softint lwp
6825	mov	%l7, %o1			! o1/i1 = ipl
6826	save	%sp, -CC64FSZ, %sp		! make one more register window
6827	flushw					! and save all
6828
6829	sethi	%hi(CURLWP), %l7
6830	sethi	%hi(CPCB), %l6
6831	LDPTR	[%l7 + %lo(CURLWP)], %l0	! l0 = interrupted lwp (curlwp)
6832
6833	/* save interrupted lwp/pcb info */
6834	sethi	%hi(softint_fastintr_ret - 8), %o0	! trampoline function
6835	LDPTR	[%l0 + L_PCB], %l5		! l5 = interrupted pcb
6836	or	%o0, %lo(softint_fastintr_ret - 8), %o0
6837	stx	%i6, [%l5 + PCB_SP]
6838	stx	%o0, [%l5 + PCB_PC]
6839	rdpr	%pstate, %o1
6840	rdpr	%cwp, %o2
6841	sth	%o1, [%l5 + PCB_PSTATE]
6842	stb	%o2, [%l5 + PCB_CWP]
6843
6844	/* switch to softint lwp */
6845	sethi	%hi(USPACE - TF_SIZE - CC64FSZ - STKB), %o3
6846	LDPTR	[%i0 + L_PCB], %l1		! l1 = softint pcb
6847	or	%o3, %lo(USPACE - TF_SIZE - CC64FSZ - STKB), %o3
6848	membar	#StoreStore		/* for mutex_enter; see cpu_switchto */
6849	STPTR	%i0, [%l7 + %lo(CURLWP)]
6850	/*
6851	 * No need for barrier after ci->ci_curlwp = softlwp -- when we
6852	 * enter a softint lwp, it can't be holding any mutexes, so it
6853	 * can't release any until after it has acquired them, so we
6854	 * need not participate in the protocol with mutex_vector_enter
6855	 * barriers here.
6856	 */
6857	add	%l1, %o3, %i6
6858	STPTR	%l1, [%l6 + %lo(CPCB)]
6859	stx	%i6, [%l1 + PCB_SP]
6860	add	%i6, -CC64FSZ, %sp		! new stack
6861
6862	/* now switched, then invoke MI dispatcher */
6863	mov	%i1, %o1
6864	call	_C_LABEL(softint_dispatch)
6865	 mov	%l0, %o0
6866
6867	/* switch back to interrupted lwp */
6868	ldx	[%l5 + PCB_SP], %i6
6869	membar	#StoreStore		/* for mutex_enter; see cpu_switchto */
6870	STPTR	%l0, [%l7 + %lo(CURLWP)]
6871	membar	#StoreLoad		/* for mutex_enter; see cpu_switchto */
6872	STPTR	%l5, [%l6 + %lo(CPCB)]
6873
6874	restore					! rewind register window
6875
6876	STPTR	%l6, [%l0 + CI_EINTSTACK]	! restore ci_eintstack
6877	wrpr	%g0, %l7, %pil			! restore ipl
6878	ret
6879	 restore	%g0, 1, %o0
6880
6881/*
6882 * Trampoline function that gets returned to by cpu_switchto() when
6883 * an interrupt handler blocks.
6884 *
6885 * Arguments:
6886 *	o0	old lwp from cpu_switchto()
6887 *
6888 * from softint_fastintr():
6889 *	l0	CPUINFO_VA
6890 *	l6	saved ci_eintstack
6891 *	l7	saved ipl
6892 */
6893softint_fastintr_ret:
6894	/* re-adjust after mi_switch() */
6895	ld	[%l0 + CI_MTX_COUNT], %o1
6896	inc	%o1				! ci_mtx_count++
6897	st	%o1, [%l0 + CI_MTX_COUNT]
6898
6899	STPTR	%l6, [%l0 + CI_EINTSTACK]	! restore ci_eintstack
6900	wrpr	%g0, %l7, %pil			! restore ipl
6901	ret
6902	 restore	%g0, 1, %o0
6903
6904#endif /* __HAVE_FAST_SOFTINTS */
6905
6906/*
6907 * Snapshot the current process so that stack frames are up to date.
6908 * Only used just before a crash dump.
6909 */
6910ENTRY(snapshot)
6911	rdpr	%pstate, %o1		! save psr
6912	stx	%o7, [%o0 + PCB_PC]	! save pc
6913	stx	%o6, [%o0 + PCB_SP]	! save sp
6914	rdpr	%pil, %o2
6915	sth	%o1, [%o0 + PCB_PSTATE]
6916	rdpr	%cwp, %o3
6917	stb	%o2, [%o0 + PCB_PIL]
6918	stb	%o3, [%o0 + PCB_CWP]
6919
6920	flushw
6921	save	%sp, -CC64FSZ, %sp
6922	flushw
6923	ret
6924	 restore
6925
6926/*
6927 * cpu_lwp_fork() arranges for lwp_trampoline() to run when the
6928 * nascent lwp is selected by switch().
6929 *
6930 * The switch frame will contain pointer to struct lwp of this lwp in
6931 * %l2, a pointer to the function to call in %l0, and an argument to
6932 * pass to it in %l1 (we abuse the callee-saved registers).
6933 *
6934 * We enter lwp_trampoline as if we are "returning" from
6935 * cpu_switchto(), so %o0 contains previous lwp (the one we are
6936 * switching from) that we pass to lwp_startup().
6937 *
6938 * If the function *(%l0) returns, we arrange for an immediate return
6939 * to user mode.  This happens in two known cases: after execve(2) of
6940 * init, and when returning a child to user mode after a fork(2).
6941 *
6942 * If were setting up a kernel thread, the function *(%l0) will not
6943 * return.
6944 */
6945ENTRY(lwp_trampoline)
6946	/*
6947	 * Note: cpu_lwp_fork() has set up a stack frame for us to run
6948	 * in, so we can call other functions from here without using
6949	 * `save ... restore'.
6950	 */
6951
6952	! newlwp in %l2, oldlwp in %o0
6953	call    lwp_startup
6954	 mov    %l2, %o1
6955
6956	call	%l0			! re-use current frame
6957	 mov	%l1, %o0
6958
6959	/*
6960	 * Here we finish up as in syscall, but simplified.
6961	 */
6962	b	return_from_trap
6963	 nop
6964
6965/*
6966 * pmap_zero_page_phys(pa)
6967 *
6968 * Zero one page physically addressed
6969 *
6970 * Block load/store ASIs do not exist for physical addresses,
6971 * so we won't use them.
6972 *
6973 * We will execute a flush at the end to sync the I$.
6974 *
6975 * This version expects to have the dcache_flush_page_all(pa)
6976 * to have been called before calling into here.
6977 */
6978ENTRY(pmap_zero_page_phys)
6979#ifndef _LP64
6980	COMBINE(%o0, %o1, %o0)
6981#endif
6982#ifdef DEBUG
6983	set	pmapdebug, %o4
6984	ld	[%o4], %o4
6985	btst	0x80, %o4	! PDB_COPY
6986	bz,pt	%icc, 3f
6987	 nop
6988	save	%sp, -CC64FSZ, %sp
6989	set	2f, %o0
6990	call	printf
6991	 mov	%i0, %o1
6992!	ta	1; nop
6993	restore
6994	.data
69952:	.asciz	"pmap_zero_page(%p)\n"
6996	_ALIGN
6997	.text
69983:
6999#endif
7000	set	NBPG, %o2		! Loop count
7001	wr	%g0, ASI_PHYS_CACHED, %asi
70021:
7003	/* Unroll the loop 8 times */
7004	stxa	%g0, [%o0 + 0x00] %asi
7005	deccc	0x40, %o2
7006	stxa	%g0, [%o0 + 0x08] %asi
7007	stxa	%g0, [%o0 + 0x10] %asi
7008	stxa	%g0, [%o0 + 0x18] %asi
7009	stxa	%g0, [%o0 + 0x20] %asi
7010	stxa	%g0, [%o0 + 0x28] %asi
7011	stxa	%g0, [%o0 + 0x30] %asi
7012	stxa	%g0, [%o0 + 0x38] %asi
7013	bg,pt	%icc, 1b
7014	 inc	0x40, %o0
7015
7016	sethi	%hi(KERNBASE), %o3
7017	flush	%o3
7018	retl
7019	 wr	%g0, ASI_PRIMARY_NOFAULT, %asi	! Make C code happy
7020
7021/*
7022 * pmap_copy_page_phys(paddr_t src, paddr_t dst)
7023 *
7024 * Copy one page physically addressed
7025 * We need to use a global reg for ldxa/stxa
7026 * so the top 32-bits cannot be lost if we take
7027 * a trap and need to save our stack frame to a
7028 * 32-bit stack.  We will unroll the loop by 4 to
7029 * improve performance.
7030 *
7031 * This version expects to have the dcache_flush_page_all(pa)
7032 * to have been called before calling into here.
7033 *
7034 */
7035ENTRY(pmap_copy_page_phys)
7036#ifndef _LP64
7037	COMBINE(%o0, %o1, %o0)
7038	COMBINE(%o2, %o3, %o1)
7039#endif
7040#ifdef DEBUG
7041	set	pmapdebug, %o4
7042	ld	[%o4], %o4
7043	btst	0x80, %o4	! PDB_COPY
7044	bz,pt	%icc, 3f
7045	 nop
7046	save	%sp, -CC64FSZ, %sp
7047	mov	%i0, %o1
7048	set	2f, %o0
7049	call	printf
7050	 mov	%i1, %o2
7051!	ta	1; nop
7052	restore
7053	.data
70542:	.asciz	"pmap_copy_page(%p,%p)\n"
7055	_ALIGN
7056	.text
70573:
7058#endif
7059#if 1
7060	set	NBPG, %o2
7061	wr	%g0, ASI_PHYS_CACHED, %asi
70621:
7063	ldxa	[%o0 + 0x00] %asi, %g1
7064	ldxa	[%o0 + 0x08] %asi, %o3
7065	ldxa	[%o0 + 0x10] %asi, %o4
7066	ldxa	[%o0 + 0x18] %asi, %o5
7067	inc	0x20, %o0
7068	deccc	0x20, %o2
7069	stxa	%g1, [%o1 + 0x00] %asi
7070	stxa	%o3, [%o1 + 0x08] %asi
7071	stxa	%o4, [%o1 + 0x10] %asi
7072	stxa	%o5, [%o1 + 0x18] %asi
7073	bg,pt	%icc, 1b		! We don't care about pages >4GB
7074	 inc	0x20, %o1
7075	retl
7076	 wr	%g0, ASI_PRIMARY_NOFAULT, %asi
7077#else
7078	set	NBPG, %o3
7079	add	%o3, %o0, %o3
7080	mov	%g1, %o4		! Save g1
70811:
7082	ldxa	[%o0] ASI_PHYS_CACHED, %g1
7083	inc	8, %o0
7084	cmp	%o0, %o3
7085	stxa	%g1, [%o1] ASI_PHYS_CACHED
7086	bl,pt	%icc, 1b		! We don't care about pages >4GB
7087	 inc	8, %o1
7088	retl
7089	 mov	%o4, %g1		! Restore g1
7090#endif
7091
7092/*
7093 * extern int64_t pseg_get_real(struct pmap *pm, vaddr_t addr);
7094 *
7095 * Return TTE at addr in pmap.  Uses physical addressing only.
7096 * pmap->pm_physaddr must by the physical address of pm_segs
7097 *
7098 */
7099ENTRY(pseg_get_real)
7100!	flushw			! Make sure we don't have stack probs & lose hibits of %o
7101#ifndef _LP64
7102	clruw	%o1					! Zero extend
7103#endif
7104	ldx	[%o0 + PM_PHYS], %o2			! pmap->pm_segs
7105
7106	srax	%o1, HOLESHIFT, %o3			! Check for valid address
7107	brz,pt	%o3, 0f					! Should be zero or -1
7108	 inc	%o3					! Make -1 -> 0
7109	brnz,pn	%o3, 1f					! Error! In hole!
71100:
7111	srlx	%o1, STSHIFT, %o3
7112	and	%o3, STMASK, %o3			! Index into pm_segs
7113	sll	%o3, 3, %o3
7114	add	%o2, %o3, %o2
7115	DLFLUSH(%o2,%o3)
7116	ldxa	[%o2] ASI_PHYS_CACHED, %o2		! Load page directory pointer
7117	DLFLUSH2(%o3)
7118
7119	srlx	%o1, PDSHIFT, %o3
7120	and	%o3, PDMASK, %o3
7121	sll	%o3, 3, %o3
7122	brz,pn	%o2, 1f					! NULL entry? check somewhere else
7123	 add	%o2, %o3, %o2
7124	DLFLUSH(%o2,%o3)
7125	ldxa	[%o2] ASI_PHYS_CACHED, %o2		! Load page table pointer
7126	DLFLUSH2(%o3)
7127
7128	srlx	%o1, PTSHIFT, %o3			! Convert to ptab offset
7129	and	%o3, PTMASK, %o3
7130	sll	%o3, 3, %o3
7131	brz,pn	%o2, 1f					! NULL entry? check somewhere else
7132	 add	%o2, %o3, %o2
7133	DLFLUSH(%o2,%o3)
7134	ldxa	[%o2] ASI_PHYS_CACHED, %o0
7135	DLFLUSH2(%o3)
7136	brgez,pn %o0, 1f				! Entry invalid?  Punt
7137	 btst	1, %sp
7138	bz,pn	%icc, 0f				! 64-bit mode?
7139	 nop
7140	retl						! Yes, return full value
7141	 nop
71420:
7143#if 1
7144	srl	%o0, 0, %o1
7145	retl						! No, generate a %o0:%o1 double
7146	 srlx	%o0, 32, %o0
7147#else
7148	DLFLUSH(%o2,%o3)
7149	ldda	[%o2] ASI_PHYS_CACHED, %o0
7150	DLFLUSH2(%o3)
7151	retl						! No, generate a %o0:%o1 double
7152	 nop
7153#endif
71541:
7155#ifndef _LP64
7156	clr	%o1
7157#endif
7158	retl
7159	 clr	%o0
7160
7161/*
7162 * In 32-bit mode:
7163 *
7164 * extern int pseg_set_real(struct pmap* %o0, vaddr_t addr %o1,
7165 *			    int64_t tte %o2:%o3, paddr_t spare %o4:%o5);
7166 *
7167 * In 64-bit mode:
7168 *
7169 * extern int pseg_set_real(struct pmap* %o0, vaddr_t addr %o1,
7170 *			    int64_t tte %o2, paddr_t spare %o3);
7171 *
7172 * Set a pseg entry to a particular TTE value.  Return values are:
7173 *
7174 *	-2	addr in hole
7175 *	0	success	(spare was not used if given)
7176 *	1	failure	(spare was not given, but one is needed)
7177 *	2	success	(spare was given, used for L2)
7178 *	3	failure	(spare was given, used for L2, another is needed for L3)
7179 *	4	success	(spare was given, used for L3)
7180 *
7181 *	rv == 0	success, spare not used if one was given
7182 *	rv & 4	spare was used for L3
7183 *	rv & 2	spare was used for L2
7184 *	rv & 1	failure, spare is needed
7185 *
7186 * (NB: nobody in pmap checks for the virtual hole, so the system will hang.)
7187 * The way to call this is:  first just call it without a spare page.
7188 * If that fails, allocate a page and try again, passing the paddr of the
7189 * new page as the spare.
7190 * If spare is non-zero it is assumed to be the address of a zeroed physical
7191 * page that can be used to generate a directory table or page table if needed.
7192 *
7193 * We keep track of valid (A_TLB_V bit set) and wired (A_TLB_TSB_LOCK bit set)
7194 * mappings that are set here. We check both bits on the new data entered
7195 * and increment counts, as well as decrementing counts if the bits are set
7196 * in the value replaced by this call.
7197 * The counters are 32 bit or 64 bit wide, depending on the kernel type we are
7198 * running!
7199 */
7200ENTRY(pseg_set_real)
7201#ifndef _LP64
7202	clruw	%o1					! Zero extend
7203	COMBINE(%o2, %o3, %o2)
7204	COMBINE(%o4, %o5, %o3)
7205#endif
7206	!!
7207	!! However we managed to get here we now have:
7208	!!
7209	!! %o0 = *pmap
7210	!! %o1 = addr
7211	!! %o2 = tte
7212	!! %o3 = paddr of spare page
7213	!!
7214	srax	%o1, HOLESHIFT, %o4			! Check for valid address
7215	brz,pt	%o4, 0f					! Should be zero or -1
7216	 inc	%o4					! Make -1 -> 0
7217	brz,pt	%o4, 0f
7218	 nop
7219#ifdef DEBUG
7220	ta	1					! Break into debugger
7221#endif
7222	retl
7223	 mov -2, %o0					! Error -- in hole!
7224
72250:
7226	ldx	[%o0 + PM_PHYS], %o4			! pmap->pm_segs
7227	clr	%g1
7228	srlx	%o1, STSHIFT, %o5
7229	and	%o5, STMASK, %o5
7230	sll	%o5, 3, %o5
7231	add	%o4, %o5, %o4
72320:
7233	DLFLUSH(%o4,%g5)
7234	ldxa	[%o4] ASI_PHYS_CACHED, %o5		! Load page directory pointer
7235	DLFLUSH2(%g5)
7236
7237	brnz,a,pt %o5, 0f				! Null pointer?
7238	 mov	%o5, %o4
7239	brz,pn	%o3, 9f					! Have a spare?
7240	 mov	%o3, %o5
7241	casxa	[%o4] ASI_PHYS_CACHED, %g0, %o5
7242	brnz,pn	%o5, 0b					! Something changed?
7243	DLFLUSH(%o4, %o5)
7244	mov	%o3, %o4
7245	mov	2, %g1					! record spare used for L2
7246	clr	%o3					! and not available for L3
72470:
7248	srlx	%o1, PDSHIFT, %o5
7249	and	%o5, PDMASK, %o5
7250	sll	%o5, 3, %o5
7251	add	%o4, %o5, %o4
72520:
7253	DLFLUSH(%o4,%g5)
7254	ldxa	[%o4] ASI_PHYS_CACHED, %o5		! Load table directory pointer
7255	DLFLUSH2(%g5)
7256
7257	brnz,a,pt %o5, 0f				! Null pointer?
7258	 mov	%o5, %o4
7259	brz,pn	%o3, 9f					! Have a spare?
7260	 mov	%o3, %o5
7261	casxa	[%o4] ASI_PHYS_CACHED, %g0, %o5
7262	brnz,pn	%o5, 0b					! Something changed?
7263	DLFLUSH(%o4, %o4)
7264	mov	%o3, %o4
7265	mov	4, %g1					! record spare used for L3
72660:
7267	srlx	%o1, PTSHIFT, %o5			! Convert to ptab offset
7268	and	%o5, PTMASK, %o5
7269	sll	%o5, 3, %o5
7270	add	%o5, %o4, %o4
7271
7272	DLFLUSH(%o4,%g5)
7273	ldxa	[%o4] ASI_PHYS_CACHED, %o5		! save old value in %o5
7274	stxa	%o2, [%o4] ASI_PHYS_CACHED		! Easier than shift+or
7275	DLFLUSH2(%g5)
7276
7277	!! at this point we have:
7278	!!  %g1 = return value
7279	!!  %o0 = struct pmap * (where the counts are)
7280	!!  %o2 = new TTE
7281	!!  %o5 = old TTE
7282
7283	!! see if stats needs an update
7284#ifdef SUN4V
7285	sethi	%hi(cputyp), %g5
7286	ld	[%g5 + %lo(cputyp)], %g5
7287	cmp	%g5, CPU_SUN4V
7288	bne,pt	%icc, 0f
7289	 nop
7290	sethi	%hh(SUN4V_TLB_TSB_LOCK), %g5
7291	sllx	%g5, 32, %g5
7292	ba	1f
7293	 nop
72940:
7295#endif
7296	set	SUN4U_TLB_TSB_LOCK, %g5
72971:
7298	xor	%o2, %o5, %o3			! %o3 - what changed
7299
7300	brgez,pn %o3, 5f			! has resident changed? (we predict it has)
7301	 btst	%g5, %o3			! has wired changed?
7302
7303	LDPTR	[%o0 + PM_RESIDENT], %o1	! gonna update resident count
7304	brlz	%o2, 0f
7305	 mov	1, %o4
7306	neg	%o4				! new is not resident -> decrement
73070:	add	%o1, %o4, %o1
7308	STPTR	%o1, [%o0 + PM_RESIDENT]
7309	btst	%g5, %o3			! has wired changed?
73105:	bz,pt	%xcc, 8f			! we predict it's not
7311	 btst	%g5, %o2			! don't waste delay slot, check if new one is wired
7312	LDPTR	[%o0 + PM_WIRED], %o1		! gonna update wired count
7313	bnz,pt	%xcc, 0f			! if wired changes, we predict it increments
7314	 mov	1, %o4
7315	neg	%o4				! new is not wired -> decrement
73160:	add	%o1, %o4, %o1
7317	STPTR	%o1, [%o0 + PM_WIRED]
73188:	retl
7319	 mov	%g1, %o0			! return %g1
7320
73219:	retl
7322	 or	%g1, 1, %o0			! spare needed, return flags + 1
7323
7324
7325/*
7326 * clearfpstate()
7327 *
7328 * Drops the current fpu state, without saving it.
7329 */
7330ENTRY(clearfpstate)
7331	rdpr	%pstate, %o1		! enable FPU
7332	wr	%g0, FPRS_FEF, %fprs
7333	or	%o1, PSTATE_PEF, %o1
7334	retl
7335	 wrpr	%o1, 0, %pstate
7336
7337/*
7338 * savefpstate(f) struct fpstate *f;
7339 *
7340 * Store the current FPU state.
7341 *
7342 * Since the kernel may need to use the FPU and we have problems atomically
7343 * testing and enabling the FPU, we leave here with the FPRS_FEF bit set.
7344 * Normally this should be turned on in loadfpstate().
7345 */
7346 /* XXXXXXXXXX  Assume caller created a proper stack frame */
7347ENTRY(savefpstate)
7348!	flushw			! Make sure we don't have stack probs & lose hibits of %o
7349	rdpr	%pstate, %o1		! enable FP before we begin
7350	rd	%fprs, %o5
7351	wr	%g0, FPRS_FEF, %fprs
7352	or	%o1, PSTATE_PEF, %o1
7353	wrpr	%o1, 0, %pstate
7354
7355	stx	%fsr, [%o0 + FS_FSR]	! f->fs_fsr = getfsr();
7356	rd	%gsr, %o4		! Save %gsr
7357	st	%o4, [%o0 + FS_GSR]
7358
7359	add	%o0, FS_REGS, %o2
7360#ifdef DIAGNOSTIC
7361	btst	BLOCK_ALIGN, %o2	! Needs to be re-executed
7362	bnz,pn	%icc, 6f		! Check alignment
7363#endif
7364	 st	%g0, [%o0 + FS_QSIZE]	! f->fs_qsize = 0;
7365	btst	FPRS_DL|FPRS_DU, %o5	! Both FPU halves clean?
7366	bz,pt	%icc, 5f		! Then skip it
7367
7368	 btst	FPRS_DL, %o5		! Lower FPU clean?
7369	membar	#Sync
7370	bz,a,pt	%icc, 1f		! Then skip it, but upper FPU not clean
7371	 add	%o2, 2*BLOCK_SIZE, %o2	! Skip a block
7372
7373	stda	%f0, [%o2] ASI_BLK_P	! f->fs_f0 = etc;
7374	inc	BLOCK_SIZE, %o2
7375	stda	%f16, [%o2] ASI_BLK_P
7376
7377	btst	FPRS_DU, %o5		! Upper FPU clean?
7378	bz,pt	%icc, 2f		! Then skip it
7379	 inc	BLOCK_SIZE, %o2
73801:
7381	stda	%f32, [%o2] ASI_BLK_P
7382	inc	BLOCK_SIZE, %o2
7383	stda	%f48, [%o2] ASI_BLK_P
73842:
7385	membar	#Sync			! Finish operation so we can
73865:
7387	retl
7388	 wr	%g0, FPRS_FEF, %fprs	! Mark FPU clean
7389
7390#ifdef DIAGNOSTIC
7391	!!
7392	!! Damn thing is *NOT* aligned on a 64-byte boundary
7393	!!
73946:
7395	wr	%g0, FPRS_FEF, %fprs
7396	! XXX -- we should panic instead of silently entering debugger
7397	ta	1
7398	retl
7399	 nop
7400#endif
7401
7402/*
7403 * Load FPU state.
7404 */
7405 /* XXXXXXXXXX  Should test to see if we only need to do a partial restore */
7406ENTRY(loadfpstate)
7407	flushw			! Make sure we don't have stack probs & lose hibits of %o
7408	rdpr	%pstate, %o1		! enable FP before we begin
7409	ld	[%o0 + FS_GSR], %o4	! Restore %gsr
7410	set	PSTATE_PEF, %o2
7411	wr	%g0, FPRS_FEF, %fprs
7412	or	%o1, %o2, %o1
7413	wrpr	%o1, 0, %pstate
7414	ldx	[%o0 + FS_FSR], %fsr	! setfsr(f->fs_fsr);
7415	add	%o0, FS_REGS, %o3	! This is zero...
7416#ifdef DIAGNOSTIC
7417	btst	BLOCK_ALIGN, %o3
7418	bne,pn	%icc, 1f	! Only use block loads on aligned blocks
7419#endif
7420	 wr	%o4, %g0, %gsr
7421	membar	#Sync
7422	ldda	[%o3] ASI_BLK_P, %f0
7423	inc	BLOCK_SIZE, %o3
7424	ldda	[%o3] ASI_BLK_P, %f16
7425	inc	BLOCK_SIZE, %o3
7426	ldda	[%o3] ASI_BLK_P, %f32
7427	inc	BLOCK_SIZE, %o3
7428	ldda	[%o3] ASI_BLK_P, %f48
7429	membar	#Sync			! Make sure loads are complete
7430	retl
7431	 wr	%g0, FPRS_FEF, %fprs	! Clear dirty bits
7432
7433#ifdef DIAGNOSTIC
7434	!!
7435	!! Damn thing is *NOT* aligned on a 64-byte boundary
7436	!!
74371:
7438	wr	%g0, FPRS_FEF, %fprs	! Clear dirty bits
7439	! XXX -- we should panic instead of silently entering debugger
7440	ta	1
7441	retl
7442	 nop
7443#endif
7444
7445/*
7446 * ienab_bis(bis) int bis;
7447 * ienab_bic(bic) int bic;
7448 *
7449 * Set and clear bits in the interrupt register.
7450 */
7451
7452/*
7453 * sun4u has separate asr's for clearing/setting the interrupt mask.
7454 */
7455ENTRY(ienab_bis)
7456	retl
7457	 wr	%o0, 0, SET_SOFTINT	! SET_SOFTINT
7458
7459ENTRY(ienab_bic)
7460	retl
7461	 wr	%o0, 0, CLEAR_SOFTINT	! CLEAR_SOFTINT
7462
7463/*
7464 * send_softint(cpu, level, intrhand)
7465 *
7466 * Send a softint with an intrhand pointer so we can cause a vectored
7467 * interrupt instead of a polled interrupt.  This does pretty much the same
7468 * as interrupt_vector.  If cpu is -1 then send it to this CPU, if it's -2
7469 * send it to any CPU, otherwise send it to a particular CPU.
7470 *
7471 * XXXX Dispatching to different CPUs is not implemented yet.
7472 */
7473ENTRY(send_softint)
7474	rdpr	%pstate, %g1
7475	andn	%g1, PSTATE_IE, %g2	! clear PSTATE.IE
7476	wrpr	%g2, 0, %pstate
7477
7478	sethi	%hi(CPUINFO_VA+CI_INTRPENDING), %o3
7479	LDPTR	[%o2 + IH_PEND], %o5
7480	or	%o3, %lo(CPUINFO_VA+CI_INTRPENDING), %o3
7481	brnz	%o5, 1f
7482	 sll	%o1, PTRSHFT, %o5	! Find start of table for this IPL
7483	add	%o3, %o5, %o3
74842:
7485	LDPTR	[%o3], %o5		! Load list head
7486	STPTR	%o5, [%o2+IH_PEND]	! Link our intrhand node in
7487	mov	%o2, %o4
7488	CASPTRA	[%o3] ASI_N, %o5, %o4
7489	cmp	%o4, %o5		! Did it work?
7490	bne,pn	CCCR, 2b		! No, try again
7491	 .empty
7492
7493	mov	1, %o4			! Change from level to bitmask
7494	sllx	%o4, %o1, %o4
7495	wr	%o4, 0, SET_SOFTINT	! SET_SOFTINT
74961:
7497	retl
7498	 wrpr	%g1, 0, %pstate		! restore PSTATE.IE
7499
7500
7501#define MICROPERSEC	(1000000)
7502
7503/*
7504 * delay function
7505 *
7506 * void delay(N)  -- delay N microseconds
7507 *
7508 * Register usage: %o0 = "N" number of usecs to go (counts down to zero)
7509 *		   %o1 = "timerblurb" (stays constant)
7510 *		   %o2 = counter for 1 usec (counts down from %o1 to zero)
7511 *
7512 *
7513 *	ci_cpu_clockrate should be tuned during CPU probe to the CPU
7514 *	clockrate in Hz
7515 *
7516 */
7517ENTRY(delay)			! %o0 = n
7518#if 1
7519	rdpr	%tick, %o1					! Take timer snapshot
7520	sethi	%hi(CPUINFO_VA + CI_CLOCKRATE), %o2
7521	sethi	%hi(MICROPERSEC), %o3
7522	ldx	[%o2 + %lo(CPUINFO_VA + CI_CLOCKRATE + 8)], %o4	! Get scale factor
7523	brnz,pt	%o4, 0f
7524	 or	%o3, %lo(MICROPERSEC), %o3
7525
7526	!! Calculate ticks/usec
7527	ldx	[%o2 + %lo(CPUINFO_VA + CI_CLOCKRATE)], %o4	! No, we need to calculate it
7528	udivx	%o4, %o3, %o4
7529	stx	%o4, [%o2 + %lo(CPUINFO_VA + CI_CLOCKRATE + 8)]	! Save it so we don't need to divide again
75300:
7531
7532	mulx	%o0, %o4, %o0					! Convert usec -> ticks
7533	rdpr	%tick, %o2					! Top of next itr
75341:
7535	sub	%o2, %o1, %o3					! How many ticks have gone by?
7536	sub	%o0, %o3, %o4					! Decrement count by that much
7537	movrgz	%o3, %o4, %o0					! But only if we're decrementing
7538	mov	%o2, %o1					! Remember last tick
7539	brgz,pt	%o0, 1b						! Done?
7540	 rdpr	%tick, %o2					! Get new tick
7541
7542	retl
7543	 nop
7544#else
7545/* This code only works if %tick does not wrap */
7546	rdpr	%tick, %g1					! Take timer snapshot
7547	sethi	%hi(CPUINFO_VA + CI_CLOCKRATE), %g2
7548	sethi	%hi(MICROPERSEC), %o2
7549	ldx	[%g2 + %lo(CPUINFO_VA + CI_CLOCKRATE)], %g2	! Get scale factor
7550	or	%o2, %lo(MICROPERSEC), %o2
7551!	sethi	%hi(_C_LABEL(timerblurb), %o5			! This is if we plan to tune the clock
7552!	ld	[%o5 + %lo(_C_LABEL(timerblurb))], %o5		!  with respect to the counter/timer
7553	mulx	%o0, %g2, %g2					! Scale it: (usec * Hz) / 1 x 10^6 = ticks
7554	udivx	%g2, %o2, %g2
7555	add	%g1, %g2, %g2
7556!	add	%o5, %g2, %g2			5, %g2, %g2					! But this gets complicated
7557	rdpr	%tick, %g1					! Top of next itr
7558	mov	%g1, %g1	! Erratum 50
75591:
7560	cmp	%g1, %g2
7561	bl,a,pn %xcc, 1b					! Done?
7562	 rdpr	%tick, %g1
7563
7564	retl
7565	 nop
7566#endif
7567	/*
7568	 * If something's wrong with the standard setup do this stupid loop
7569	 * calibrated for a 143MHz processor.
7570	 */
7571Lstupid_delay:
7572	set	142857143/MICROPERSEC, %o1
7573Lstupid_loop:
7574	brnz,pt	%o1, Lstupid_loop
7575	 dec	%o1
7576	brnz,pt	%o0, Lstupid_delay
7577	 dec	%o0
7578	retl
7579	 nop
7580
7581/*
7582 * next_tick(long increment)
7583 *
7584 * Sets the %tick_cmpr register to fire off in `increment' machine
7585 * cycles in the future.  Also handles %tick wraparound.  In 32-bit
7586 * mode we're limited to a 32-bit increment.
7587 */
7588ENTRY(next_tick)
7589	rd	TICK_CMPR, %o2
7590	rdpr	%tick, %o1
7591
7592	mov	1, %o3		! Mask off high bits of these registers
7593	sllx	%o3, 63, %o3
7594	andn	%o1, %o3, %o1
7595	andn	%o2, %o3, %o2
7596	cmp	%o1, %o2	! Did we wrap?  (tick < tick_cmpr)
7597	bgt,pt	%icc, 1f
7598	 add	%o1, 1000, %o1	! Need some slack so we don't lose intrs.
7599
7600	/*
7601	 * Handle the unlikely case of %tick wrapping.
7602	 *
7603	 * This should only happen every 10 years or more.
7604	 *
7605	 * We need to increment the time base by the size of %tick in
7606	 * microseconds.  This will require some divides and multiplies
7607	 * which can take time.  So we re-read %tick.
7608	 *
7609	 */
7610
7611	/* XXXXX NOT IMPLEMENTED */
7612
7613
7614
76151:
7616	add	%o2, %o0, %o2
7617	andn	%o2, %o3, %o4
7618	brlz,pn	%o4, Ltick_ovflw
7619	 cmp	%o2, %o1	! Has this tick passed?
7620	blt,pn	%xcc, 1b	! Yes
7621	 nop
7622
7623#ifdef BB_ERRATA_1
7624	ba,a	2f
7625	 nop
7626#else
7627	retl
7628	 wr	%o2, TICK_CMPR
7629#endif
7630
7631Ltick_ovflw:
7632/*
7633 * When we get here tick_cmpr has wrapped, but we don't know if %tick
7634 * has wrapped.  If bit 62 is set then we have not wrapped and we can
7635 * use the current value of %o4 as %tick.  Otherwise we need to return
7636 * to our loop with %o4 as %tick_cmpr (%o2).
7637 */
7638	srlx	%o3, 1, %o5
7639	btst	%o5, %o1
7640	bz,pn	%xcc, 1b
7641	 mov	%o4, %o2
7642#ifdef BB_ERRATA_1
7643	ba,a	2f
7644	 nop
7645	.align	64
76462:	wr	%o2, TICK_CMPR
7647	rd	TICK_CMPR, %g0
7648	retl
7649	 nop
7650#else
7651	retl
7652	 wr	%o2, TICK_CMPR
7653#endif
7654
7655/*
7656 * next_stick(long increment)
7657 *
7658 * Sets the %stick_cmpr register to fire off in `increment' machine
7659 * cycles in the future.  Also handles %stick wraparound.  In 32-bit
7660 * mode we're limited to a 32-bit increment.
7661 */
7662ENTRY(next_stick)
7663	rd	STICK_CMPR, %o2
7664	rd	STICK, %o1
7665
7666	mov	1, %o3		! Mask off high bits of these registers
7667	sllx	%o3, 63, %o3
7668	andn	%o1, %o3, %o1
7669	andn	%o2, %o3, %o2
7670	cmp	%o1, %o2	! Did we wrap?  (stick < stick_cmpr)
7671	bgt,pt	%xcc, 1f
7672	 add	%o1, 1000, %o1	! Need some slack so we don't lose intrs.
7673
7674	/*
7675	 * Handle the unlikely case of %stick wrapping.
7676	 *
7677	 * This should only happen every 10 years or more.
7678	 *
7679	 * We need to increment the time base by the size of %stick in
7680	 * microseconds.  This will require some divides and multiplies
7681	 * which can take time.  So we re-read %stick.
7682	 *
7683	 */
7684
7685	/* XXXXX NOT IMPLEMENTED */
7686
7687
7688
76891:
7690	add	%o2, %o0, %o2
7691	andn	%o2, %o3, %o4
7692	brlz,pn	%o4, Lstick_ovflw
7693	 cmp	%o2, %o1	! Has this stick passed?
7694	blt,pn	%xcc, 1b	! Yes
7695	 nop
7696	retl
7697	 wr	%o2, STICK_CMPR
7698
7699Lstick_ovflw:
7700/*
7701 * When we get here tick_cmpr has wrapped, but we don't know if %stick
7702 * has wrapped.  If bit 62 is set then we have not wrapped and we can
7703 * use the current value of %o4 as %stick.  Otherwise we need to return
7704 * to our loop with %o4 as %stick_cmpr (%o2).
7705 */
7706	srlx	%o3, 1, %o5
7707	btst	%o5, %o1
7708	bz,pn	%xcc, 1b
7709	 mov	%o4, %o2
7710	retl
7711	 wr	%o2, STICK_CMPR
7712
7713/*
7714 * next_stick_init()
7715 *
7716 * Sets the %stick_cmpr register to the value retrieved from %stick so
7717 * next_stick() does not spend too much time in the function when called
7718 * for the first time.
7719 * This has been observed on (at least) a SPARC-T5 (sun4v) system where
7720 * the %stick_cmpr ends up being less than the %stick value and then
7721 * the stickitr() interrupt is never triggered.
7722 */
7723ENTRY(next_stick_init)
7724	rd	STICK, %o0
7725	mov	1, %o1		! Mask off high bits of the register
7726	sllx	%o1, 63, %o1
7727	andn	%o0, %o1, %o0
7728	retl
7729	 wr	%o0, STICK_CMPR
7730
7731ENTRY(setjmp)
7732	save	%sp, -CC64FSZ, %sp	! Need a frame to return to.
7733	flushw
7734	stx	%fp, [%i0+0]	! 64-bit stack pointer
7735	stx	%i7, [%i0+8]	! 64-bit return pc
7736	ret
7737	 restore	%g0, 0, %o0
7738
7739	.data
7740Lpanic_ljmp:
7741	.asciz	"longjmp botch"
7742	_ALIGN
7743	.text
7744
7745ENTRY(longjmp)
7746	save	%sp, -CC64FSZ, %sp	! prepare to restore to (old) frame
7747	flushw
7748	mov	1, %i2
7749	ldx	[%i0+0], %fp	! get return stack
7750	movrz	%i1, %i1, %i2	! compute v ? v : 1
7751	ldx	[%i0+8], %i7	! get rpc
7752	ret
7753	 restore	%i2, 0, %o0
7754
7755#if defined(DDB) || defined(KGDB)
7756	/*
7757	 * Debug stuff.  Dump the trap registers into buffer & set tl=0.
7758	 *
7759	 *  %o0 = *ts
7760	 */
7761ENTRY(savetstate)
7762	mov	%o0, %o1
7763	rdpr	%tl, %o0
7764	brz	%o0, 2f
7765	 mov	%o0, %o2
77661:
7767	rdpr	%tstate, %o3
7768	stx	%o3, [%o1]
7769	deccc	%o2
7770	inc	8, %o1
7771	rdpr	%tpc, %o4
7772	stx	%o4, [%o1]
7773	inc	8, %o1
7774	rdpr	%tnpc, %o5
7775	stx	%o5, [%o1]
7776	inc	8, %o1
7777	rdpr	%tt, %o4
7778	stx	%o4, [%o1]
7779	inc	8, %o1
7780	bnz	1b
7781	 wrpr	%o2, 0, %tl
77822:
7783	retl
7784	 nop
7785
7786	/*
7787	 * Debug stuff.  Restore trap registers from buffer.
7788	 *
7789	 *  %o0 = %tl
7790	 *  %o1 = *ts
7791	 *
7792	 * Maybe this should be re-written to increment tl instead of decrementing.
7793	 */
7794ENTRY(restoretstate)
7795	flushw			! Make sure we don't have stack probs & lose hibits of %o
7796	brz,pn	%o0, 2f
7797	 mov	%o0, %o2
7798	wrpr	%o0, 0, %tl
77991:
7800	ldx	[%o1], %o3
7801	deccc	%o2
7802	inc	8, %o1
7803	wrpr	%o3, 0, %tstate
7804	ldx	[%o1], %o4
7805	inc	8, %o1
7806	wrpr	%o4, 0, %tpc
7807	ldx	[%o1], %o5
7808	inc	8, %o1
7809	wrpr	%o5, 0, %tnpc
7810	ldx	[%o1], %o4
7811	inc	8, %o1
7812	wrpr	%o4, 0, %tt
7813	bnz	1b
7814	 wrpr	%o2, 0, %tl
78152:
7816	retl
7817	 wrpr	%o0, 0, %tl
7818
7819	/*
7820	 * Switch to context in abs(%o0)
7821	 */
7822ENTRY(switchtoctx_us)
7823	set	DEMAP_CTX_SECONDARY, %o3
7824	stxa	%o3, [%o3] ASI_DMMU_DEMAP
7825	mov	CTX_SECONDARY, %o4
7826	stxa	%o3, [%o3] ASI_IMMU_DEMAP
7827	membar	#Sync
7828	stxa	%o0, [%o4] ASI_DMMU		! Maybe we should invalid
7829	sethi	%hi(KERNBASE), %o2
7830	membar	#Sync
7831	flush	%o2
7832	retl
7833	 nop
7834
7835ENTRY(switchtoctx_usiii)
7836	mov	CTX_SECONDARY, %o4
7837	ldxa	[%o4] ASI_DMMU, %o2		! Load secondary context
7838	mov	CTX_PRIMARY, %o5
7839	ldxa	[%o5] ASI_DMMU, %o1		! Save primary context
7840	membar	#LoadStore
7841	stxa	%o2, [%o5] ASI_DMMU		! Insert secondary for demap
7842	membar	#Sync
7843	set	DEMAP_CTX_PRIMARY, %o3
7844	stxa	%o3, [%o3] ASI_DMMU_DEMAP
7845	membar	#Sync
7846	stxa	%o0, [%o4] ASI_DMMU		! Maybe we should invalid
7847	membar	#Sync
7848	stxa	%o1, [%o5] ASI_DMMU		! Restore primary context
7849	sethi	%hi(KERNBASE), %o2
7850	membar	#Sync
7851	flush	%o2
7852	retl
7853	 nop
7854
7855#ifndef _LP64
7856	/*
7857	 * Convert to 32-bit stack then call OF_sym2val()
7858	 */
7859ENTRY(OF_sym2val32)
7860	save	%sp, -CC64FSZ, %sp
7861	btst	7, %i0
7862	bnz,pn	%icc, 1f
7863	 add	%sp, BIAS, %o1
7864	btst	1, %sp
7865	movnz	%icc, %o1, %sp
7866	call	_C_LABEL(OF_sym2val)
7867	 mov	%i0, %o0
78681:
7869	ret
7870	 restore	%o0, 0, %o0
7871
7872	/*
7873	 * Convert to 32-bit stack then call OF_val2sym()
7874	 */
7875ENTRY(OF_val2sym32)
7876	save	%sp, -CC64FSZ, %sp
7877	btst	7, %i0
7878	bnz,pn	%icc, 1f
7879	 add	%sp, BIAS, %o1
7880	btst	1, %sp
7881	movnz	%icc, %o1, %sp
7882	call	_C_LABEL(OF_val2sym)
7883	 mov	%i0, %o0
78841:
7885	ret
7886	 restore	%o0, 0, %o0
7887#endif /* _LP64 */
7888#endif /* DDB */
7889
7890
7891#if defined(MULTIPROCESSOR)
7892/*
7893 * IPI target function to setup a C compatible environment and call a MI function.
7894 *
7895 * On entry:
7896 *	We are on one of the alternate set of globals
7897 *	%g2 = function to call
7898 *	%g3 = single argument to called function
7899 */
7900ENTRY(sparc64_ipi_ccall)
7901#ifdef TRAPS_USE_IG
7902	wrpr	%g0, PSTATE_KERN|PSTATE_IG, %pstate	! DEBUG
7903#endif
7904	TRAP_SETUP(-CC64FSZ-TF_SIZE)
7905
7906#ifdef DEBUG
7907	rdpr	%tt, %o1	! debug
7908	sth	%o1, [%sp + CC64FSZ + STKB + TF_TT]! debug
7909#endif
7910	mov	%g3, %o0			! save argument of function to call
7911	mov	%g2, %o5			! save function pointer
7912
7913	wrpr	%g0, PSTATE_KERN, %pstate	! Get back to normal globals
7914	stx	%g1, [%sp + CC64FSZ + STKB + TF_G + ( 1*8)]
7915	rdpr	%tpc, %o2			! (pc)
7916	stx	%g2, [%sp + CC64FSZ + STKB + TF_G + ( 2*8)]
7917	rdpr	%tstate, %g1
7918	stx	%g3, [%sp + CC64FSZ + STKB + TF_G + ( 3*8)]
7919	rdpr	%tnpc, %o3
7920	stx	%g4, [%sp + CC64FSZ + STKB + TF_G + ( 4*8)]
7921	rd	%y, %o4
7922	stx	%g5, [%sp + CC64FSZ + STKB + TF_G + ( 5*8)]
7923	stx	%g6, [%sp + CC64FSZ + STKB + TF_G + ( 6*8)]
7924	stx	%g7, [%sp + CC64FSZ + STKB + TF_G + ( 7*8)]
7925
7926	stx	%g1, [%sp + CC64FSZ + STKB + TF_TSTATE]
7927	stx	%o2, [%sp + CC64FSZ + STKB + TF_PC]
7928	stx	%o3, [%sp + CC64FSZ + STKB + TF_NPC]
7929	st	%o4, [%sp + CC64FSZ + STKB + TF_Y]
7930
7931	rdpr	%pil, %g5
7932	stb	%g5, [%sp + CC64FSZ + STKB + TF_PIL]
7933	stb	%g5, [%sp + CC64FSZ + STKB + TF_OLDPIL]
7934
7935	rdpr	%tl, %g7
7936	dec	%g7
7937	movrlz	%g7, %g0, %g7
7938	wrpr	%g0, %g7, %tl
7939	!! In the EMBEDANY memory model %g4 points to the start of the data segment.
7940	!! In our case we need to clear it before calling any C-code
7941	clr	%g4
7942	wr	%g0, ASI_NUCLEUS, %asi			! default kernel ASI
7943
7944	call %o5					! call function
7945	 nop
7946
7947	b	return_from_trap			! and return from IPI
7948	 ldx	[%sp + CC64FSZ + STKB + TF_TSTATE], %g1	! Load this for return_from_trap
7949
7950#endif
7951
7952
7953	.data
7954	_ALIGN
7955#if NKSYMS || defined(DDB) || defined(MODULAR)
7956	.globl	_C_LABEL(esym)
7957_C_LABEL(esym):
7958	POINTER	0
7959	.globl	_C_LABEL(ssym)
7960_C_LABEL(ssym):
7961	POINTER	0
7962#endif
7963	.comm	_C_LABEL(promvec), PTRSZ
7964
7965#ifdef DEBUG
7966	.comm	_C_LABEL(trapdebug), 4
7967	.comm	_C_LABEL(pmapdebug), 4
7968#endif
7969