xref: /illumos-gate/usr/src/uts/sun4u/ml/mach_locore.S (revision 55fea89d)
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26#include <sys/asm_linkage.h>
27#include <sys/intreg.h>
28#include <sys/ivintr.h>
29#include <sys/mmu.h>
30#include <sys/machpcb.h>
31#include <sys/machtrap.h>
32#include <sys/machlock.h>
33#include <sys/fdreg.h>
34#include <sys/vis.h>
35#include <sys/traptrace.h>
36#include <sys/panic.h>
37#include <sys/machasi.h>
38#include <sys/clock.h>
39#include <vm/hat_sfmmu.h>
40
41#include "assym.h"
42
43
44!
45! REGOFF must add up to allow double word access to r_tstate.
46! PCB_WBUF must also be aligned.
47!
48#if (REGOFF & 7) != 0
49#error "struct regs not aligned"
50#endif
51
52/*
53 * Absolute external symbols.
54 * On the sun4u we put the panic buffer in the third and fourth pages.
55 * We set things up so that the first 2 pages of KERNELBASE is illegal
56 * to act as a redzone during copyin/copyout type operations. One of
57 * the reasons the panic buffer is allocated in low memory to
58 * prevent being overwritten during booting operations (besides
59 * the fact that it is small enough to share pages with others).
60 */
61
62	.seg	".data"
63	.global	panicbuf
64
65PROM	= 0xFFE00000			! address of prom virtual area
66panicbuf = SYSBASE32 + PAGESIZE		! address of panic buffer
67
68	.type	panicbuf, #object
69	.size	panicbuf, PANICBUFSIZE
70
71/*
72 * Absolute external symbol - intr_vec_table.
73 *
74 * With new bus structures supporting a larger number of interrupt
75 * numbers, the interrupt vector table, intr_vec_table[] has been
76 * moved out of kernel nucleus and allocated after panicbuf.
77 */
78	.global intr_vec_table
79
80intr_vec_table = SYSBASE32 + PAGESIZE + PANICBUFSIZE ! address of interrupt table
81
82	.type	intr_vec_table, #object
83	.size	intr_vec_table, MAXIVNUM * CPTRSIZE + MAX_RSVD_IV * IV_SIZE + MAX_RSVD_IVX * (IV_SIZE + CPTRSIZE * (NCPU - 1))
84
85/*
86 * The thread 0 stack. This must be the first thing in the data
87 * segment (other than an sccs string) so that we don't stomp
88 * on anything important if the stack overflows. We get a
89 * red zone below this stack for free when the kernel text is
90 * write protected.
91 */
92
93	.global	t0stack
94	.align	16
95	.type	t0stack, #object
96t0stack:
97	.skip	T0STKSZ			! thread 0 stack
98t0stacktop:
99	.size	t0stack, T0STKSZ
100
101/*
102 * cpu0 and its ptl1_panic stack.  The cpu structure must be allocated
103 * on a single page for ptl1_panic's physical address accesses.
104 */
105	.global	cpu0
106	.align	MMU_PAGESIZE
107cpu0:
108	.type	cpu0, #object
109	.skip	CPU_ALLOC_SIZE
110	.size	cpu0, CPU_ALLOC_SIZE
111
112	.global t0
113	.align	PTR24_ALIGN		! alignment for mutex.
114	.type	t0, #object
115t0:
116	.skip	THREAD_SIZE		! thread 0
117	.size	t0, THREAD_SIZE
118
119#ifdef	TRAPTRACE
120	.global	trap_trace_ctl
121	.global	trap_tr0
122	.global trap_trace_bufsize
123	.global	trap_freeze
124	.global	trap_freeze_pc
125
126	.align	4
127trap_trace_bufsize:
128	.word	TRAP_TSIZE		! default trap buffer size
129trap_freeze:
130	.word	0
131
132	.align	64
133trap_trace_ctl:
134	.skip	NCPU * TRAPTR_SIZE	! NCPU control headers
135
136	.align	16
137trap_tr0:
138	.skip	TRAP_TSIZE		! one buffer for the boot cpu
139
140/*
141 * When an assertion in TRACE_PTR was failed, %pc is saved in trap_freeze_pc to
142 * show in which TRACE_PTR the assertion failure happened.
143 */
144	.align	8
145trap_freeze_pc:
146	.nword	0
147#endif	/* TRAPTRACE */
148
149	.align 4
150	.seg	".text"
151
152#ifdef	NOPROM
153	.global availmem
154availmem:
155	.word	0
156#endif	/* NOPROM */
157
158	.align	8
159_local_p1275cis:
160	.nword	0
161
162	.seg	".data"
163
164	.global nwindows, nwin_minus_one, winmask
165nwindows:
166	.word   8
167nwin_minus_one:
168	.word   7
169winmask:
170	.word	8
171
172	.global	afsrbuf
173afsrbuf:
174	.word	0,0,0,0
175
176/*
177 * System initialization
178 *
179 * Our contract with the boot prom specifies that the MMU is on and the
180 * first 16 meg of memory is mapped with a level-1 pte.  We are called
181 * with p1275cis ptr in %o0 and kdi_dvec in %o1; we start execution
182 * directly from physical memory, so we need to get up into our proper
183 * addresses quickly: all code before we do this must be position
184 * independent.
185 *
186 * NB: Above is not true for boot/stick kernel, the only thing mapped is
187 * the text+data+bss. The kernel is loaded directly into KERNELBASE.
188 *
189 * 	entry, the romvec pointer (romp) is the first argument;
190 * 	  i.e., %o0.
191 * 	the bootops vector is in the third argument (%o1)
192 *
193 * Our tasks are:
194 * 	save parameters
195 * 	construct mappings for KERNELBASE (not needed for boot/stick kernel)
196 * 	hop up into high memory           (not needed for boot/stick kernel)
197 * 	initialize stack pointer
198 * 	initialize trap base register
199 * 	initialize window invalid mask
200 * 	initialize psr (with traps enabled)
201 * 	figure out all the module type stuff
202 * 	tear down the 1-1 mappings
203 * 	dive into main()
204 */
205	ENTRY_NP(_start)
206	!
207	! Stash away our arguments in memory.
208	!
209	sethi	%hi(_local_p1275cis), %g1
210	stn	%o4, [%g1 + %lo(_local_p1275cis)]
211
212	!
213	! Initialize CPU state registers
214	!
215	wrpr	%g0, PSTATE_KERN, %pstate
216	wr	%g0, %g0, %fprs
217
218	!
219	! call krtld to link the world together
220	!
221	call	kobj_start
222	mov	%o4, %o0
223
224	CLEARTICKNPT			! allow user rdtick
225	!
226	! Get maxwin from %ver
227	!
228	rdpr	%ver, %g1
229	and	%g1, VER_MAXWIN, %g1
230
231	!
232	! Stuff some memory cells related to numbers of windows.
233	!
234	sethi	%hi(nwin_minus_one), %g2
235	st	%g1, [%g2 + %lo(nwin_minus_one)]
236	inc	%g1
237	sethi	%hi(nwindows), %g2
238	st	%g1, [%g2 + %lo(nwindows)]
239	dec	%g1
240	mov	-2, %g2
241	sll	%g2, %g1, %g2
242	sethi	%hi(winmask), %g4
243	st	%g2, [%g4 + %lo(winmask)]
244
245	!
246	! save a pointer to obp's tba for later use by kmdb
247	!
248	rdpr	%tba, %g1
249	set	boot_tba, %g2
250	stx	%g1, [%g2]
251
252	!
253	! copy obp's breakpoint trap entry to obp_bpt
254	!
255	rdpr	%tba, %g1
256	set	T_SOFTWARE_TRAP | ST_MON_BREAKPOINT, %g2
257	sll	%g2, 5, %g2
258	or	%g1, %g2, %g1
259	set	obp_bpt, %g2
260	ldx	[%g1], %g3
261	stx	%g3, [%g2]
262	flush	%g2
263	ldx	[%g1 + 8], %g3
264	stx	%g3, [%g2 + 8]
265	flush	%g2 + 8
266	ldx	[%g1 + 16], %g3
267	stx	%g3, [%g2 + 16]
268	flush	%g2 + 16
269	ldx	[%g1 + 24], %g3
270	stx	%g3, [%g2 + 24]
271	flush	%g2 + 24
272
273	!
274	! Initialize thread 0's stack.
275	!
276	set	t0stacktop, %g1		! setup kernel stack pointer
277	sub	%g1, SA(KFPUSIZE+GSR_SIZE), %g2
278	and	%g2, 0x3f, %g3
279	sub	%g2, %g3, %o1
280	sub	%o1, SA(MPCBSIZE) + STACK_BIAS, %sp
281
282	!
283	! Initialize global thread register.
284	!
285	set	t0, THREAD_REG
286
287	!
288	! Fill in enough of the cpu structure so that
289	! the wbuf management code works. Make sure the
290	! boot cpu is inserted in cpu[] based on cpuid.
291	!
292	CPU_INDEX(%g2, %g1)
293	sll	%g2, CPTRSHIFT, %g2		! convert cpuid to cpu[] offset
294	set	cpu0, %o0			! &cpu0
295	set	cpu, %g1			! &cpu[]
296	stn	%o0, [%g1 + %g2]		! cpu[cpuid] = &cpu0
297
298	stn	%o0, [THREAD_REG + T_CPU]	! threadp()->t_cpu = cpu[cpuid]
299	stn	THREAD_REG, [%o0 + CPU_THREAD]	! cpu[cpuid]->cpu_thread = threadp()
300
301
302	!  We do NOT need to bzero our BSS...boot has already done it for us.
303	!  Just need to reference edata so that we don't break /dev/ksyms
304	set	edata, %g0
305
306	!
307	! Call mlsetup with address of prototype user registers.
308	!
309	call	mlsetup
310	add	%sp, REGOFF + STACK_BIAS, %o0
311
312#if (REGOFF != MPCB_REGS)
313#error "hole in struct machpcb between frame and regs?"
314#endif
315
316	!
317	! Now call main.  We will return as process 1 (init).
318	!
319	call	main
320	nop
321
322	!
323	! Main should never return.
324	!
325	set	.mainretmsg, %o0
326	call	panic
327	nop
328	SET_SIZE(_start)
329
330.mainretmsg:
331	.asciz	"main returned"
332	.align	4
333
334
335/*
336 * Generic system trap handler.
337 *
338 * Some kernel trap handlers save themselves from buying a window by
339 * borrowing some of sys_trap's unused locals. %l0 thru %l3 may be used
340 * for this purpose, as user_rtt and priv_rtt do not depend on them.
341 * %l4 thru %l7 should NOT be used this way.
342 *
343 * Entry Conditions:
344 * 	%pstate		am:0 priv:1 ie:0
345 * 			globals are either ag or ig (not mg!)
346 *
347 * Register Inputs:
348 * 	%g1		pc of trap handler
349 * 	%g2, %g3	args for handler
350 * 	%g4		desired %pil (-1 means current %pil)
351 * 	%g5, %g6	destroyed
352 * 	%g7		saved
353 *
354 * Register Usage:
355 * 	%l0, %l1	temps
356 * 	%l3		saved %g1
357 * 	%l6		curthread for user traps, %pil for priv traps
358 * 	%l7		regs
359 *
360 * Called function prototype variants:
361 *
362 *	func(struct regs *rp);
363 * 	func(struct regs *rp, uintptr_t arg1 [%g2], uintptr_t arg2 [%g3])
364 *	func(struct regs *rp, uintptr_t arg1 [%g2],
365 *	    uint32_t arg2 [%g3.l], uint32_t arg3 [%g3.h])
366 *	func(struct regs *rp, uint32_t arg1 [%g2.l],
367 *	    uint32_t arg2 [%g3.l], uint32_t arg3 [%g3.h], uint32_t [%g2.h])
368 */
369
370	ENTRY_NP(sys_trap)
371	!
372	! force tl=1, update %cwp, branch to correct handler
373	!
374	wrpr	%g0, 1, %tl
375	rdpr	%tstate, %g5
376	btst	TSTATE_PRIV, %g5
377	and	%g5, TSTATE_CWP, %g6
378	bnz,pn	%xcc, priv_trap
379	wrpr	%g0, %g6, %cwp
380
381	ALTENTRY(user_trap)
382	!
383	! user trap
384	!
385	! make all windows clean for kernel
386	! buy a window using the current thread's stack
387	!
388	sethi	%hi(nwin_minus_one), %g5
389	ld	[%g5 + %lo(nwin_minus_one)], %g5
390	wrpr	%g0, %g5, %cleanwin
391	CPU_ADDR(%g5, %g6)
392	ldn	[%g5 + CPU_THREAD], %g5
393	ldn	[%g5 + T_STACK], %g6
394	sub	%g6, STACK_BIAS, %g6
395	save	%g6, 0, %sp
396	!
397	! set window registers so that current windows are "other" windows
398	!
399	rdpr	%canrestore, %l0
400	rdpr	%wstate, %l1
401	wrpr	%g0, 0, %canrestore
402	sllx	%l1, WSTATE_SHIFT, %l1
403	wrpr	%l1, WSTATE_K64, %wstate
404	wrpr	%g0, %l0, %otherwin
405	!
406	! set pcontext to run kernel
407	!
408	sethi	%hi(kcontextreg), %l0
409	ldx     [%l0 + %lo(kcontextreg)], %l0
410	mov	MMU_PCONTEXT, %l1	! if kcontextreg==PCONTEXT, do nothing
411	ldxa	[%l1]ASI_MMU_CTX, %l2
412	xor	%l0, %l2, %l2
413	srlx	%l2, CTXREG_NEXT_SHIFT, %l2
414	brz	%l2, 2f			! if N_pgsz0/1 changed, need demap
415	sethi	%hi(FLUSH_ADDR), %l3
416	mov	DEMAP_ALL_TYPE, %l2
417	stxa	%g0, [%l2]ASI_DTLB_DEMAP
418	stxa	%g0, [%l2]ASI_ITLB_DEMAP
4192:
420	stxa	%l0, [%l1]ASI_MMU_CTX
421	flush	%l3			! flush required by immu
4221:
423
424	set	utl0, %g6		! bounce to utl0
425have_win:
426	SYSTRAP_TRACE(%o1, %o2, %o3)
427
428
429	!
430	! at this point we have a new window we can play in,
431	! and %g6 is the label we want done to bounce to
432	!
433	! save needed current globals
434	!
435	mov	%g1, %l3	! pc
436	mov	%g2, %o1	! arg #1
437	mov	%g3, %o2	! arg #2
438	srlx	%g3, 32, %o3	! pseudo arg #3
439	srlx	%g2, 32, %o4	! pseudo arg #4
440	mov	%g5, %l6	! curthread if user trap, %pil if priv trap
441	!
442	! save trap state on stack
443	!
444	add	%sp, REGOFF + STACK_BIAS, %l7
445	rdpr	%tpc, %l0
446	rdpr	%tnpc, %l1
447	rdpr	%tstate, %l2
448	stn	%l0, [%l7 + PC_OFF]
449	stn	%l1, [%l7 + nPC_OFF]
450	stx	%l2, [%l7 + TSTATE_OFF]
451	!
452	! setup pil
453	!
454	brlz,pt		%g4, 1f
455	nop
456#ifdef DEBUG
457	!
458	! ASSERT(%g4 >= %pil).
459	!
460	rdpr	%pil, %l0
461	cmp	%g4, %l0
462	bge,pt	%xcc, 0f
463	nop				! yes, nop; to avoid anull
464	set	bad_g4_called, %l3
465	mov	1, %o1
466	st	%o1, [%l3]
467	set	bad_g4, %l3		! pc
468	set	sys_trap_wrong_pil, %o1	! arg #1
469	mov	%g4, %o2		! arg #2
470	ba	1f			! stay at the current %pil
471	mov	%l0, %o3		! arg #3
4720:
473#endif /* DEBUG */
474	wrpr		%g0, %g4, %pil
4751:
476	!
477	! set trap regs to execute in kernel at %g6
478	! done resumes execution there
479	!
480	wrpr	%g0, %g6, %tnpc
481	rdpr	%cwp, %l0
482	set	TSTATE_KERN, %l1
483	wrpr	%l1, %l0, %tstate
484	done
485	/* NOTREACHED */
486	SET_SIZE(user_trap)
487	SET_SIZE(sys_trap)
488
489
490	ENTRY_NP(prom_trap)
491	!
492	! prom trap switches the stack to 32-bit
493	! if we took a trap from a 64-bit window
494	! Then buys a window on the current stack.
495	!
496	save	%sp, -SA64(REGOFF + REGSIZE), %sp
497					/* 32 bit frame, 64 bit sized */
498	set	ptl0, %g6
499	ba,a,pt	%xcc, have_win
500	SET_SIZE(prom_trap)
501
502	ENTRY_NP(priv_trap)
503	!
504	! kernel trap
505	! buy a window on the current stack
506	!
507	! is the trap PC in the range allocated to Open Firmware?
508	rdpr	%tpc, %g5
509	set	OFW_END_ADDR, %g6
510	cmp	%g5, %g6
511	bgu,a,pn %xcc, 1f
512	  rdpr	%pil, %g5
513	set	OFW_START_ADDR, %g6
514	cmp	%g5, %g6
515	bgeu,pn	%xcc, prom_trap
516	  rdpr	%pil, %g5
5171:
518	!
519	! check if the primary context is of kernel.
520	!
521	mov     MMU_PCONTEXT, %g6
522	ldxa    [%g6]ASI_MMU_CTX, %g5
523	sllx    %g5, CTXREG_CTX_SHIFT, %g5      ! keep just the ctx bits
524	brnz,pn %g5, 2f				! assumes KCONTEXT == 0
525	  rdpr  %pil, %g5
526	!
527	! primary context is of kernel.
528	!
529        set     ktl0, %g6
530        save    %sp, -SA(REGOFF + REGSIZE), %sp
531        ba,a,pt %xcc, have_win
5322:
533	!
534	! primary context is of user. caller of sys_trap()
535	! or priv_trap() did not set kernel context. raise
536	! trap level to MAXTL-1 so that ptl1_panic() prints
537	! out all levels of trap data.
538	!
539	rdpr	%ver, %g5
540	srlx	%g5, VER_MAXTL_SHIFT, %g5
541	and	%g5, VER_MAXTL_MASK, %g5	! %g5 = MAXTL
542	sub	%g5, 1, %g5
543	wrpr	%g0, %g5, %tl
544	mov	PTL1_BAD_CTX, %g1
545	ba,a,pt	%xcc, ptl1_panic
546	SET_SIZE(priv_trap)
547
548	ENTRY_NP(utl0)
549	SAVE_GLOBALS(%l7)
550	SAVE_OUTS(%l7)
551	mov	%l6, THREAD_REG
552	wrpr	%g0, PSTATE_KERN, %pstate	! enable ints
553	jmpl	%l3, %o7			! call trap handler
554	mov	%l7, %o0
555	!
556	ALTENTRY(user_rtt)
557	!
558	! Register inputs
559	!	%l7 - regs
560	!
561	! disable interrupts and check for ASTs and wbuf restores
562	! keep cpu_base_spl in %l4 and THREAD_REG in %l6 (needed
563	! in wbuf.s when globals have already been restored).
564	!
565	wrpr	%g0, PIL_MAX, %pil
566	ldn	[THREAD_REG + T_CPU], %l0
567	ld	[%l0 + CPU_BASE_SPL], %l4
568
569	ldub	[THREAD_REG + T_ASTFLAG], %l2
570	brz,pt	%l2, 1f
571	ld	[%sp + STACK_BIAS + MPCB_WBCNT], %l3
572	!
573	! call trap to do ast processing
574	!
575	wrpr	%g0, %l4, %pil			! pil = cpu_base_spl
576	mov	%l7, %o0
577	call	trap
578	  mov	T_AST, %o2
579	ba,a,pt	%xcc, user_rtt
5801:
581	brz,pt	%l3, 2f
582	mov	THREAD_REG, %l6
583	!
584	! call restore_wbuf to push wbuf windows to stack
585	!
586	wrpr	%g0, %l4, %pil			! pil = cpu_base_spl
587	mov	%l7, %o0
588	call	trap
589	  mov	T_FLUSH_PCB, %o2
590	ba,a,pt	%xcc, user_rtt
5912:
592#ifdef TRAPTRACE
593	TRACE_RTT(TT_SYS_RTT_USER, %l0, %l1, %l2, %l3)
594#endif /* TRAPTRACE */
595	ld	[%sp + STACK_BIAS + MPCB_WSTATE], %l3	! get wstate
596
597	!
598	! restore user globals and outs
599	!
600	rdpr	%pstate, %l1
601	wrpr	%l1, PSTATE_IE, %pstate
602	RESTORE_GLOBALS(%l7)
603	! switch to alternate globals, saving THREAD_REG in %l6
604	wrpr	%l1, PSTATE_IE | PSTATE_AG, %pstate
605	mov	%sp, %g6	! remember the mpcb pointer in %g6
606	RESTORE_OUTS(%l7)
607	!
608	! set %pil from cpu_base_spl
609	!
610	wrpr	%g0, %l4, %pil
611	!
612	! raise tl (now using nucleus context)
613	!
614	wrpr	%g0, 1, %tl
615
616	! switch "other" windows back to "normal" windows.
617	rdpr	%otherwin, %g1
618	wrpr	%g0, 0, %otherwin
619	add	%l3, WSTATE_CLEAN_OFFSET, %l3	! convert to "clean" wstate
620	wrpr	%g0, %l3, %wstate
621	wrpr	%g0, %g1, %canrestore
622
623	! set pcontext to scontext for user execution
624	mov	MMU_SCONTEXT, %g3
625	ldxa	[%g3]ASI_MMU_CTX, %g2
626
627	mov	MMU_PCONTEXT, %g3
628	ldxa    [%g3]ASI_MMU_CTX, %g4		! need N_pgsz0/1 bits
629        srlx    %g4, CTXREG_NEXT_SHIFT, %g4
630        sllx    %g4, CTXREG_NEXT_SHIFT, %g4
631        or      %g4, %g2, %g2                   ! Or in Nuc pgsz bits
632
633	sethi	%hi(FLUSH_ADDR), %g4
634	stxa	%g2, [%g3]ASI_MMU_CTX
635	flush	%g4				! flush required by immu
636	!
637	! Within the code segment [rtt_ctx_start - rtt_ctx_end],
638	! PCONTEXT is set to run user code. If a trap happens in this
639	! window, and the trap needs to be handled at TL=0, the handler
640	! must make sure to set PCONTEXT to run kernel. A convenience
641	! macro, RESET_USER_RTT_REGS(scr1, scr2, label) is available to
642	! TL>1 handlers for this purpose.
643	!
644	! %g1 = %canrestore
645	! %l7 = regs
646	! %g6 = mpcb
647	!
648	.global	rtt_ctx_start
649rtt_ctx_start:
650	!
651	! setup trap regs
652	!
653	ldn	[%l7 + PC_OFF], %g3
654	ldn	[%l7 + nPC_OFF], %g2
655	ldx	[%l7 + TSTATE_OFF], %l0
656	andn	%l0, TSTATE_CWP, %g7
657	wrpr	%g3, %tpc
658	wrpr	%g2, %tnpc
659
660	!
661	! Restore to window we originally trapped in.
662	! First attempt to restore from the watchpoint saved register window
663	!
664	tst	%g1
665	bne,a	1f
666	  clrn	[%g6 + STACK_BIAS + MPCB_RSP0]
667	tst	%fp
668	be,a	1f
669	  clrn	[%g6 + STACK_BIAS + MPCB_RSP0]
670	! test for user return window in pcb
671	ldn	[%g6 + STACK_BIAS + MPCB_RSP0], %g1
672	cmp	%fp, %g1
673	bne	1f
674	  clrn	[%g6 + STACK_BIAS + MPCB_RSP0]
675	restored
676	restore
677	! restore from user return window
678	RESTORE_V9WINDOW(%g6 + STACK_BIAS + MPCB_RWIN0)
679	!
680	! Attempt to restore from the scond watchpoint saved register window
681	tst	%fp
682	be,a	2f
683	  clrn	[%g6 + STACK_BIAS + MPCB_RSP1]
684	ldn	[%g6 + STACK_BIAS + MPCB_RSP1], %g1
685	cmp	%fp, %g1
686	bne	2f
687	  clrn	[%g6 + STACK_BIAS + MPCB_RSP1]
688	restored
689	restore
690	RESTORE_V9WINDOW(%g6 + STACK_BIAS + MPCB_RWIN1)
691	save
692	b,a	2f
6931:
694	restore				! should not trap
6952:
696	!
697	! set %cleanwin to %canrestore
698	! set %tstate to the correct %cwp
699	! retry resumes user execution
700	!
701	rdpr	%canrestore, %g1
702	wrpr	%g0, %g1, %cleanwin
703	rdpr	%cwp, %g1
704	wrpr	%g1, %g7, %tstate
705	retry
706	.global	rtt_ctx_end
707rtt_ctx_end:
708	/* NOTREACHED */
709	SET_SIZE(user_rtt)
710	SET_SIZE(utl0)
711
712	ENTRY_NP(ptl0)
713	SAVE_GLOBALS(%l7)
714	SAVE_OUTS(%l7)
715	CPU_ADDR(%g5, %g6)
716	ldn	[%g5 + CPU_THREAD], THREAD_REG
717	wrpr	%g0, PSTATE_KERN, %pstate	! enable ints
718	jmpl	%l3, %o7			! call trap handler
719	mov	%l7, %o0
720	!
721	ALTENTRY(prom_rtt)
722#ifdef TRAPTRACE
723	TRACE_RTT(TT_SYS_RTT_PROM, %l0, %l1, %l2, %l3)
724#endif /* TRAPTRACE */
725	ba,pt	%xcc, common_rtt
726	mov	THREAD_REG, %l0
727	SET_SIZE(prom_rtt)
728	SET_SIZE(ptl0)
729
730	ENTRY_NP(ktl0)
731	SAVE_GLOBALS(%l7)
732	SAVE_OUTS(%l7)				! for the call bug workaround
733	wrpr	%g0, PSTATE_KERN, %pstate	! enable ints
734	jmpl	%l3, %o7			! call trap handler
735	mov	%l7, %o0
736	!
737	ALTENTRY(priv_rtt)
738#ifdef TRAPTRACE
739	TRACE_RTT(TT_SYS_RTT_PRIV, %l0, %l1, %l2, %l3)
740#endif /* TRAPTRACE */
741	!
742	! Register inputs
743	!	%l7 - regs
744	!	%l6 - trap %pil
745	!
746	! Check for a kernel preemption request
747	!
748	ldn	[THREAD_REG + T_CPU], %l0
749	ldub	[%l0 + CPU_KPRUNRUN], %l0
750	brz,pt	%l0, 1f
751	nop
752
753	!
754	! Attempt to preempt
755	!
756	ldstub	[THREAD_REG + T_PREEMPT_LK], %l0	! load preempt lock
757	brnz,pn	%l0, 1f			! can't call kpreempt if this thread is
758	nop				!   already in it...
759
760	call	kpreempt
761	mov	%l6, %o0		! pass original interrupt level
762
763	stub	%g0, [THREAD_REG + T_PREEMPT_LK]	! nuke the lock
764
765	rdpr	%pil, %o0		! compare old pil level
766	cmp	%l6, %o0		!   with current pil level
767	movg	%xcc, %o0, %l6		! if current is lower, drop old pil
7681:
769	!
770	! If we interrupted the mutex_owner_running() critical region we
771	! must reset the PC and nPC back to the beginning to prevent missed
772	! wakeups. See the comments in mutex_owner_running() for details.
773	!
774	ldn	[%l7 + PC_OFF], %l0
775	set	mutex_owner_running_critical_start, %l1
776	sub	%l0, %l1, %l0
777	cmp	%l0, mutex_owner_running_critical_size
778	bgeu,pt	%xcc, 2f
779	mov	THREAD_REG, %l0
780	stn	%l1, [%l7 + PC_OFF]	! restart mutex_owner_running()
781	add	%l1, 4, %l1
782	ba,pt	%xcc, common_rtt
783	stn	%l1, [%l7 + nPC_OFF]
784
7852:
786	!
787	! If we interrupted the mutex_exit() critical region we must reset
788	! the PC and nPC back to the beginning to prevent missed wakeups.
789	! See the comments in mutex_exit() for details.
790	!
791	ldn	[%l7 + PC_OFF], %l0
792	set	mutex_exit_critical_start, %l1
793	sub	%l0, %l1, %l0
794	cmp	%l0, mutex_exit_critical_size
795	bgeu,pt	%xcc, common_rtt
796	mov	THREAD_REG, %l0
797	stn	%l1, [%l7 + PC_OFF]	! restart mutex_exit()
798	add	%l1, 4, %l1
799	stn	%l1, [%l7 + nPC_OFF]
800
801common_rtt:
802	!
803	! restore globals and outs
804	!
805	rdpr	%pstate, %l1
806	wrpr	%l1, PSTATE_IE, %pstate
807	RESTORE_GLOBALS(%l7)
808	! switch to alternate globals
809	wrpr	%l1, PSTATE_IE | PSTATE_AG, %pstate
810	RESTORE_OUTS(%l7)
811	!
812	! set %pil from max(old pil, cpu_base_spl)
813	!
814	ldn	[%l0 + T_CPU], %l0
815	ld	[%l0 + CPU_BASE_SPL], %l0
816	cmp	%l6, %l0
817	movg	%xcc, %l6, %l0
818	wrpr	%g0, %l0, %pil
819	!
820	! raise tl
821	! setup trap regs
822	! restore to window we originally trapped in
823	!
824	wrpr	%g0, 1, %tl
825	ldn	[%l7 + PC_OFF], %g1
826	ldn	[%l7 + nPC_OFF], %g2
827	ldx	[%l7 + TSTATE_OFF], %l0
828	andn	%l0, TSTATE_CWP, %g7
829	wrpr	%g1, %tpc
830	wrpr	%g2, %tnpc
831	restore
832	!
833	! set %tstate to the correct %cwp
834	! retry resumes prom execution
835	!
836	rdpr	%cwp, %g1
837	wrpr	%g1, %g7, %tstate
838	retry
839	/* NOTREACHED */
840	SET_SIZE(priv_rtt)
841	SET_SIZE(ktl0)
842
843#ifdef DEBUG
844	.seg	".data"
845	.align	4
846
847	.global bad_g4_called
848bad_g4_called:
849	.word	0
850
851sys_trap_wrong_pil:
852	.asciz	"sys_trap: %g4(%d) is lower than %pil(%d)"
853	.align	4
854	.seg	".text"
855
856	ENTRY_NP(bad_g4)
857	mov	%o1, %o0
858	mov	%o2, %o1
859	call	panic
860	mov	%o3, %o2
861	SET_SIZE(bad_g4)
862#endif /* DEBUG */
863
864/*
865 * sys_tl1_panic can be called by traps at tl1 which
866 * really want to panic, but need the rearrangement of
867 * the args as provided by this wrapper routine.
868 */
869	ENTRY_NP(sys_tl1_panic)
870	mov	%o1, %o0
871	mov	%o2, %o1
872	call	panic
873	mov	%o3, %o2
874	SET_SIZE(sys_tl1_panic)
875
876/*
877 * Turn on or off bits in the auxiliary i/o register.
878 *
879 * set_auxioreg(bit, flag)
880 *	int bit;		bit mask in aux i/o reg
881 *	int flag;		0 = off, otherwise on
882 *
883 * This is intrinsicly ugly but is used by the floppy driver.  It is also
884 * used to turn on/off the led.
885 */
886
887	.seg	".data"
888	.align	4
889auxio_panic:
890	.asciz	"set_auxioreg: interrupts already disabled on entry"
891	.align	4
892	.seg	".text"
893
894	ENTRY_NP(set_auxioreg)
895	/*
896	 * o0 = bit mask
897	 * o1 = flag: 0 = off, otherwise on
898	 *
899	 * disable interrupts while updating auxioreg
900	 */
901	rdpr	%pstate, %o2
902#ifdef	DEBUG
903	andcc	%o2, PSTATE_IE, %g0	/* if interrupts already */
904	bnz,a,pt %icc, 1f		/* disabled, panic */
905	  nop
906	sethi	%hi(auxio_panic), %o0
907	call	panic
908	  or	%o0, %lo(auxio_panic), %o0
9091:
910#endif /* DEBUG */
911	wrpr	%o2, PSTATE_IE, %pstate		/* disable interrupts */
912	sethi	%hi(v_auxio_addr), %o3
913	ldn	[%o3 + %lo(v_auxio_addr)], %o4
914	ldub	[%o4], %g1			/* read aux i/o register */
915	tst	%o1
916	bnz,a	2f
917	 bset	%o0, %g1		/* on */
918	bclr	%o0, %g1		/* off */
9192:
920	or	%g1, AUX_MBO, %g1	/* Must Be Ones */
921	stb	%g1, [%o4]		/* write aux i/o register */
922	retl
923	 wrpr	%g0, %o2, %pstate	/* enable interrupt */
924	SET_SIZE(set_auxioreg)
925
926/*
927 * Flush all windows to memory, except for the one we entered in.
928 * We do this by doing NWINDOW-2 saves then the same number of restores.
929 * This leaves the WIM immediately before window entered in.
930 * This is used for context switching.
931 */
932
933	ENTRY_NP(flush_windows)
934	retl
935	flushw
936	SET_SIZE(flush_windows)
937
938	ENTRY_NP(debug_flush_windows)
939	set	nwindows, %g1
940	ld	[%g1], %g1
941	mov	%g1, %g2
942
9431:
944	save	%sp, -WINDOWSIZE, %sp
945	brnz	%g2, 1b
946	dec	%g2
947
948	mov	%g1, %g2
9492:
950	restore
951	brnz	%g2, 2b
952	dec	%g2
953
954	retl
955	nop
956
957	SET_SIZE(debug_flush_windows)
958
959/*
960 * flush user windows to memory.
961 */
962
963	ENTRY_NP(flush_user_windows)
964	rdpr	%otherwin, %g1
965	brz	%g1, 3f
966	clr	%g2
9671:
968	save	%sp, -WINDOWSIZE, %sp
969	rdpr	%otherwin, %g1
970	brnz	%g1, 1b
971	add	%g2, 1, %g2
9722:
973	sub	%g2, 1, %g2		! restore back to orig window
974	brnz	%g2, 2b
975	restore
9763:
977	retl
978	nop
979	SET_SIZE(flush_user_windows)
980
981/*
982 * Throw out any user windows in the register file.
983 * Used by setregs (exec) to clean out old user.
984 * Used by sigcleanup to remove extraneous windows when returning from a
985 * signal.
986 */
987
988	ENTRY_NP(trash_user_windows)
989	rdpr	%otherwin, %g1
990	brz	%g1, 3f			! no user windows?
991	ldn	[THREAD_REG + T_STACK], %g5
992
993	!
994	! There are old user windows in the register file. We disable ints
995	! and increment cansave so that we don't overflow on these windows.
996	! Also, this sets up a nice underflow when first returning to the
997	! new user.
998	!
999	rdpr	%pstate, %g2
1000	wrpr	%g2, PSTATE_IE, %pstate
1001	rdpr	%cansave, %g3
1002	rdpr	%otherwin, %g1		! re-read in case of interrupt
1003	add	%g3, %g1, %g3
1004	wrpr	%g0, 0, %otherwin
1005	wrpr	%g0, %g3, %cansave
1006	wrpr	%g0, %g2, %pstate
10073:
1008	retl
1009 	clr     [%g5 + MPCB_WBCNT]       ! zero window buffer cnt
1010	SET_SIZE(trash_user_windows)
1011
1012
1013/*
1014 * Setup g7 via the CPU data structure.
1015 */
1016
1017	ENTRY_NP(set_tbr)
1018	retl
1019	ta	72		! no tbr, stop simulation
1020	SET_SIZE(set_tbr)
1021
1022
1023#define	PTL1_SAVE_WINDOW(RP)						\
1024	stxa	%l0, [RP + RW64_LOCAL + (0 * RW64_LOCAL_INCR)] %asi;	\
1025	stxa	%l1, [RP + RW64_LOCAL + (1 * RW64_LOCAL_INCR)] %asi;	\
1026	stxa	%l2, [RP + RW64_LOCAL + (2 * RW64_LOCAL_INCR)] %asi;	\
1027	stxa	%l3, [RP + RW64_LOCAL + (3 * RW64_LOCAL_INCR)] %asi;	\
1028	stxa	%l4, [RP + RW64_LOCAL + (4 * RW64_LOCAL_INCR)] %asi;	\
1029	stxa	%l5, [RP + RW64_LOCAL + (5 * RW64_LOCAL_INCR)] %asi;	\
1030	stxa	%l6, [RP + RW64_LOCAL + (6 * RW64_LOCAL_INCR)] %asi;	\
1031	stxa	%l7, [RP + RW64_LOCAL + (7 * RW64_LOCAL_INCR)] %asi;	\
1032	stxa	%i0, [RP + RW64_IN + (0 * RW64_IN_INCR)] %asi;		\
1033	stxa	%i1, [RP + RW64_IN + (1 * RW64_IN_INCR)] %asi;		\
1034	stxa	%i2, [RP + RW64_IN + (2 * RW64_IN_INCR)] %asi;		\
1035	stxa	%i3, [RP + RW64_IN + (3 * RW64_IN_INCR)] %asi;		\
1036	stxa	%i4, [RP + RW64_IN + (4 * RW64_IN_INCR)] %asi;		\
1037	stxa	%i5, [RP + RW64_IN + (5 * RW64_IN_INCR)] %asi;		\
1038	stxa	%i6, [RP + RW64_IN + (6 * RW64_IN_INCR)] %asi;		\
1039	stxa	%i7, [RP + RW64_IN + (7 * RW64_IN_INCR)] %asi
1040#define	PTL1_NEXT_WINDOW(scr)	\
1041	add	scr, RWIN64SIZE, scr
1042
1043#define	PTL1_RESET_RWINDOWS(scr)			\
1044	sethi	%hi(nwin_minus_one), scr;		\
1045	ld	[scr + %lo(nwin_minus_one)], scr;	\
1046	wrpr	scr, %cleanwin;				\
1047	dec	scr;					\
1048	wrpr	scr, %cansave;				\
1049	wrpr	%g0, %canrestore;			\
1050	wrpr	%g0, %otherwin
1051
1052#define	PTL1_DCACHE_LINE_SIZE	4	/* small enough for all CPUs */
1053
1054/*
1055 * ptl1_panic is called when the kernel detects that it is in an invalid state
1056 * and the trap level is greater than 0.  ptl1_panic is responsible to save the
1057 * current CPU state, to restore the CPU state to normal, and to call panic.
1058 * The CPU state must be saved reliably without causing traps.  ptl1_panic saves
1059 * it in the ptl1_state structure, which is a member of the machcpu structure.
1060 * In order to access the ptl1_state structure without causing traps, physical
1061 * addresses are used so that we can avoid MMU miss traps.  The restriction of
1062 * physical memory accesses is that the ptl1_state structure must be on a single
1063 * physical page.  This is because (1) a single physical address for each
1064 * ptl1_state structure is needed and (2) it simplifies physical address
1065 * calculation for each member of the structure.
1066 * ptl1_panic is a likely spot for stack overflows to wind up; thus, the current
1067 * stack may not be usable.  In order to call panic reliably in such a state,
1068 * each CPU needs a dedicated ptl1 panic stack.
1069 * CPU_ALLOC_SIZE, which is defined to be MMU_PAGESIZE, is used to allocate the
1070 * cpu structure and a ptl1 panic stack.  They are put together on the same page
1071 * for memory space efficiency.  The low address part is used for the cpu
1072 * structure, and the high address part is for a ptl1 panic stack.
1073 * The cpu_pa array holds the physical addresses of the allocated cpu structures,
1074 * as the cpu array holds their virtual addresses.
1075 *
1076 * %g1 reason to be called
1077 * %g2 broken
1078 * %g3 broken
1079 */
1080	ENTRY_NP(ptl1_panic)
1081	!
1082	! flush D$ first, so that stale data will not be accessed later.
1083	! Data written via ASI_MEM bypasses D$.  If D$ contains data at the same
1084	! address, where data was written via ASI_MEM, a load from that address
1085	! using a virtual address and the default ASI still takes the old data.
1086	! Flushing D$ erases old data in D$, so that it will not be loaded.
1087	! Since we can afford only 2 registers (%g2 and %g3) for this job, we
1088	! flush entire D$.
1089	! For FJ OPL processors (IMPL values < SPITFIRE_IMPL), DC flushing
1090	! is not needed.
1091	!
1092	GET_CPU_IMPL(%g2)
1093	cmp	%g2, SPITFIRE_IMPL
1094	blt,pn	%icc, 1f		! Skip flushing for OPL processors
1095	 nop
1096	sethi	%hi(dcache_size), %g2
1097	ld	[%g2 + %lo(dcache_size)], %g2
1098	sethi	%hi(dcache_linesize), %g3
1099	ld	[%g3 + %lo(dcache_linesize)], %g3
1100	sub	%g2, %g3, %g2
11010:	stxa	%g0, [%g2] ASI_DC_TAG
1102	membar	#Sync
1103	brnz,pt	%g2, 0b
1104	  sub	%g2, %g3, %g2
11051:
1106	!
1107	! increment the entry counter.
1108	! save CPU state if this is the first entry.
1109	!
1110	CPU_PADDR(%g2, %g3);
1111	add	%g2, CPU_PTL1, %g2		! pstate = &CPU->mcpu.ptl1_state
1112	wr	%g0, ASI_MEM, %asi		! physical address access
1113	!
1114	! pstate->ptl1_entry_count++
1115	!
1116	lduwa	[%g2 + PTL1_ENTRY_COUNT] %asi, %g3
1117	add	%g3, 1, %g3
1118	stuwa	%g3, [%g2 + PTL1_ENTRY_COUNT] %asi
1119	!
1120	! CPU state saving is skipped from the 2nd entry to ptl1_panic since we
1121	! do not want to clobber the state from the original failure.  panic()
1122	! is responsible for handling multiple or recursive panics.
1123	!
1124	cmp	%g3, 2				! if (ptl1_entry_count >= 2)
1125	bge,pn	%icc, state_saved		!	goto state_saved
1126	  add	%g2, PTL1_REGS, %g3		! %g3 = &pstate->ptl1_regs[0]
1127	!
1128	! save CPU state
1129	!
1130save_cpu_state:
1131	! save current global registers
1132	! so that all them become available for use
1133	!
1134	stxa	%g1, [%g3 + PTL1_G1] %asi
1135	stxa	%g2, [%g3 + PTL1_G2] %asi
1136	stxa	%g3, [%g3 + PTL1_G3] %asi
1137	stxa	%g4, [%g3 + PTL1_G4] %asi
1138	stxa	%g5, [%g3 + PTL1_G5] %asi
1139	stxa	%g6, [%g3 + PTL1_G6] %asi
1140	stxa	%g7, [%g3 + PTL1_G7] %asi
1141	!
1142	! %tl, %tt, %tstate, %tpc, %tnpc for each TL
1143	!
1144	rdpr	%tl, %g1
1145	brz	%g1, 1f				! if(trap_level == 0) -------+
1146	add	%g3, PTL1_TRAP_REGS, %g4	! %g4 = &ptl1_trap_regs[0];  !
11470:						! -----------<----------+    !
1148	stwa	%g1, [%g4 + PTL1_TL] %asi				!    !
1149	rdpr	%tt, %g5						!    !
1150	stwa	%g5, [%g4 + PTL1_TT] %asi				!    !
1151	rdpr	%tstate, %g5						!    !
1152	stxa	%g5, [%g4 + PTL1_TSTATE] %asi				!    !
1153	rdpr	%tpc, %g5						!    !
1154	stxa	%g5, [%g4 + PTL1_TPC] %asi				!    !
1155	rdpr	%tnpc, %g5						!    !
1156	stxa	%g5, [%g4 + PTL1_TNPC] %asi				!    !
1157	add	%g4, PTL1_TRAP_REGS_INCR, %g4				!    !
1158	deccc	%g1							!    !
1159	bnz,a,pt %icc, 0b			! if(trap_level != 0) --+    !
1160	  wrpr	%g1, %tl						     !
11611:						! ----------<----------------+
1162	!
1163	! %pstate, %pil, SOFTINT, (S)TICK
1164	! Pending interrupts is also cleared in order to avoid a recursive call
1165	! to ptl1_panic in case the interrupt handler causes a panic.
1166	!
1167	rdpr	%pil, %g1
1168	stba	%g1, [%g3 + PTL1_PIL] %asi
1169	rdpr	%pstate, %g1
1170	stha	%g1, [%g3 + PTL1_PSTATE] %asi
1171	rd	SOFTINT, %g1
1172	sta	%g1, [%g3 + PTL1_SOFTINT] %asi
1173	wr	%g1, CLEAR_SOFTINT
1174	sethi   %hi(traptrace_use_stick), %g1
1175	ld      [%g1 + %lo(traptrace_use_stick)], %g1
1176	brz,a,pn %g1, 2f
1177	  rdpr	%tick, %g1
1178	rd	STICK, %g1
11792:	stxa	%g1, [%g3 + PTL1_TICK] %asi
1180
1181	!
1182	! MMU registers because ptl1_panic may be called from
1183	! the MMU trap handlers.
1184	!
1185	mov     MMU_SFAR, %g1
1186	ldxa    [%g1]ASI_DMMU, %g4
1187	stxa	%g4, [%g3 + PTL1_DMMU_SFAR]%asi
1188	mov     MMU_SFSR, %g1
1189	ldxa    [%g1]ASI_DMMU, %g4
1190	stxa	%g4, [%g3 + PTL1_DMMU_SFSR]%asi
1191	ldxa    [%g1]ASI_IMMU, %g4
1192	stxa	%g4, [%g3 + PTL1_IMMU_SFSR]%asi
1193	mov     MMU_TAG_ACCESS, %g1
1194	ldxa    [%g1]ASI_DMMU, %g4
1195	stxa	%g4, [%g3 + PTL1_DMMU_TAG_ACCESS]%asi
1196	ldxa    [%g1]ASI_IMMU, %g4
1197	stxa	%g4, [%g3 + PTL1_IMMU_TAG_ACCESS]%asi
1198
1199	!
1200	! Save register window state and register windows.
1201	!
1202	rdpr	%cwp, %g1
1203	stba	%g1, [%g3 + PTL1_CWP] %asi
1204	rdpr	%wstate, %g1
1205	stba	%g1, [%g3 + PTL1_WSTATE] %asi
1206	rdpr	%otherwin, %g1
1207	stba	%g1, [%g3 + PTL1_OTHERWIN] %asi
1208	rdpr	%cleanwin, %g1
1209	stba	%g1, [%g3 + PTL1_CLEANWIN] %asi
1210	rdpr	%cansave, %g1
1211	stba	%g1, [%g3 + PTL1_CANSAVE] %asi
1212	rdpr	%canrestore, %g1
1213	stba	%g1, [%g3 + PTL1_CANRESTORE] %asi
1214
1215	PTL1_RESET_RWINDOWS(%g1)
1216	clr	%g1
1217	wrpr	%g1, %cwp
1218	add	%g3, PTL1_RWINDOW, %g4		! %g4 = &ptl1_rwindow[0];
1219
12203:	PTL1_SAVE_WINDOW(%g4)	! <-------------+
1221	inc	%g1				!
1222	cmp	%g1, MAXWIN			!
1223	bgeu,pn	%icc, 5f			!
1224	wrpr	%g1, %cwp			!
1225	rdpr	%cwp, %g2			!
1226	cmp	%g1, %g2			! saturation check
1227	be,pt	%icc, 3b			!
1228	  PTL1_NEXT_WINDOW(%g4)		! ------+
12295:
1230	!
1231	! most crucial CPU state was saved.
1232	! Proceed to go back to TL = 0.
1233	!
1234state_saved:
1235	wrpr	%g0, 1, %tl
1236	wrpr	%g0, PIL_MAX, %pil
1237	!
1238	PTL1_RESET_RWINDOWS(%g1)
1239	wrpr	%g0, %cwp
1240	wrpr	%g0, %cleanwin
1241	wrpr	%g0, WSTATE_KERN, %wstate
1242	!
1243	! Set pcontext to run kernel.
1244	!
1245	! For OPL, load kcontexreg instead of clearing primary
1246	! context register.  This is to avoid changing nucleus page
1247	! size bits after boot initialization.
1248	!
1249#ifdef _OPL
1250	sethi	%hi(kcontextreg), %g4
1251	ldx	[%g4 + %lo(kcontextreg)], %g4
1252#endif /* _OPL */
1253
1254	set	DEMAP_ALL_TYPE, %g1
1255	sethi	%hi(FLUSH_ADDR), %g3
1256	set	MMU_PCONTEXT, %g2
1257
1258	stxa	%g0, [%g1]ASI_DTLB_DEMAP
1259	stxa	%g0, [%g1]ASI_ITLB_DEMAP
1260
1261#ifdef _OPL
1262	stxa	%g4, [%g2]ASI_MMU_CTX
1263#else /* _OPL */
1264	stxa	%g0, [%g2]ASI_MMU_CTX
1265#endif /* _OPL */
1266
1267	flush	%g3
1268
1269	rdpr	%cwp, %g1
1270	set	TSTATE_KERN, %g3
1271	wrpr	%g3, %g1, %tstate
1272	set	ptl1_panic_tl0, %g3
1273	wrpr	%g0, %g3, %tnpc
1274	done					! go to -->-+	TL:1
1275							    !
1276ptl1_panic_tl0:					! ----<-----+	TL:0
1277	CPU_ADDR(%l0, %l1)			! %l0 = cpu[cpuid]
1278	add	%l0, CPU_PTL1, %l1		! %l1 = &CPU->mcpu.ptl1_state
1279	!
1280	! prepare to call panic()
1281	!
1282	ldn	[%l0 + CPU_THREAD], THREAD_REG	! restore %g7
1283	ldn	[%l1 + PTL1_STKTOP], %l2	! %sp = ptl1_stktop
1284	sub	%l2, SA(MINFRAME) + STACK_BIAS, %sp
1285	clr	%fp				! no frame below this window
1286	clr	%i7
1287	!
1288	! enable limited interrupts
1289	!
1290	wrpr	%g0, CLOCK_LEVEL, %pil
1291	wrpr	%g0, PSTATE_KERN, %pstate
1292	!
1293	ba,pt	%xcc, ptl1_panic_handler
1294	  mov	%l1, %o0
1295	/*NOTREACHED*/
1296	SET_SIZE(ptl1_panic)
1297
1298#ifdef	PTL1_PANIC_DEBUG
1299
1300/*
1301 * ptl1_recurse() calls itself a number of times to either set up a known
1302 * stack or to cause a kernel stack overflow. It decrements the arguments
1303 * on each recursion.
1304 * It's called by #ifdef PTL1_PANIC_DEBUG code in startup.c to set the
1305 * registers to a known state to facilitate debugging.
1306 */
1307	ENTRY_NP(ptl1_recurse)
1308	save    %sp, -SA(MINFRAME), %sp
1309
1310	set 	ptl1_recurse_call, %o7
1311	cmp	%o7, %i7			! if ptl1_recurse is called
1312	be,pt  %icc, 0f				! by itself, then skip
1313	  nop					! register initialization
1314
1315	/*
1316	 * Initialize Out Registers to Known Values
1317	 */
1318	set	0x01000, %l0			! %i0 is the ...
1319						! recursion_depth_count
1320	sub	%i0, 1, %o0;
1321	sub 	%i1, 1, %o1;
1322	add	%l0, %o0, %o2;
1323	add	%l0, %o2, %o3;
1324	add	%l0, %o3, %o4;
1325	add	%l0, %o4, %o5;
1326	ba,a	1f
1327	  nop
1328
13290:	/* Outs = Ins - 1 */
1330	sub	%i0, 1, %o0;
1331	sub	%i1, 1, %o1;
1332	sub	%i2, 1, %o2;
1333	sub	%i3, 1, %o3;
1334	sub	%i4, 1, %o4;
1335	sub	%i5, 1, %o5;
1336
1337	/* Locals = Ins + 1 */
13381:	add	%i0, 1, %l0;
1339	add	%i1, 1, %l1;
1340	add	%i2, 1, %l2;
1341	add	%i3, 1, %l3;
1342	add	%i4, 1, %l4;
1343	add	%i5, 1, %l5;
1344
1345	set     0x0100000, %g5
1346	add	%g5, %g0, %g1
1347	add	%g5, %g1, %g2
1348	add	%g5, %g2, %g3
1349	add	%g5, %g3, %g4
1350	add	%g5, %g4, %g5
1351
1352	brz,pn %i1, ptl1_recurse_trap		! if trpp_count == 0) {
1353	  nop					!    trap to ptl1_panic
1354						!
1355	brz,pn %i0, ptl1_recure_exit		! if(depth_count == 0) {
1356	  nop					!    skip recursive call
1357						! }
1358ptl1_recurse_call:
1359	call	ptl1_recurse
1360	  nop
1361
1362ptl1_recure_exit:
1363	ret
1364	restore
1365
1366ptl1_recurse_trap:
1367	ta	PTL1_DEBUG_TRAP; 		! Trap Always to ptl1_panic()
1368	  nop 					! NOTREACHED
1369        SET_SIZE(ptl1_recurse)
1370
1371	/*
1372	 * Asm function to handle a cross trap to call ptl1_panic()
1373	 */
1374	ENTRY_NP(ptl1_panic_xt)
1375	ba	ptl1_panic
1376	  mov	PTL1_BAD_DEBUG, %g1
1377        SET_SIZE(ptl1_panic_xt)
1378
1379#endif	/* PTL1_PANIC_DEBUG */
1380
1381#ifdef	TRAPTRACE
1382
1383	ENTRY_NP(trace_ptr_panic)
1384	!
1385	! freeze the trap trace to disable the assertions.  Otherwise,
1386	! ptl1_panic is likely to be repeatedly called from there.
1387	! %g2 and %g3 are used as scratch registers in ptl1_panic.
1388	!
1389	mov	1, %g3
1390	sethi	%hi(trap_freeze), %g2
1391	st	%g3, [%g2 + %lo(trap_freeze)]
1392	!
1393	! %g1 contains the %pc address where an assertion was failed.
1394	! save it in trap_freeze_pc for a debugging hint if there is
1395	! no value saved in it.
1396	!
1397	set	trap_freeze_pc, %g2
1398	casn	[%g2], %g0, %g1
1399
1400	ba	ptl1_panic
1401	mov	PTL1_BAD_TRACE_PTR, %g1
1402	SET_SIZE(trace_ptr_panic)
1403
1404#endif	/* TRAPTRACE */
1405/*
1406 * set_kcontextreg() sets PCONTEXT to kctx
1407 * if PCONTEXT==kctx, do nothing
1408 * if N_pgsz0|N_pgsz1 differ, do demap all first
1409 */
1410        ENTRY_NP(set_kcontextreg)
1411	! SET_KCONTEXTREG(reg0, reg1, reg2, reg3, reg4, label1, label2, label3)
1412	SET_KCONTEXTREG(%o0, %o1, %o2, %o3, %o4, l1, l2, l3)
1413	retl
1414        nop
1415	SET_SIZE(set_kcontextreg)
1416
1417/*
1418 * The interface for a 32-bit client program that takes over the TBA
1419 * calling the 64-bit romvec OBP.
1420 */
1421
1422	ENTRY(client_handler)
1423	save	%sp, -SA64(MINFRAME64), %sp	! 32 bit frame, 64 bit sized
1424	sethi	%hi(tba_taken_over), %l2
1425	ld	[%l2+%lo(tba_taken_over)], %l3
1426	brz	%l3, 1f				! is the tba_taken_over = 1 ?
1427	rdpr	%wstate, %l5			! save %wstate
1428	andn	%l5, WSTATE_MASK, %l6
1429	wrpr	%l6, WSTATE_KMIX, %wstate
1430
1431	!
1432	! switch to PCONTEXT=0
1433	!
1434#ifndef _OPL
1435	mov	MMU_PCONTEXT, %o2
1436	ldxa	[%o2]ASI_DMMU, %o2
1437	srlx	%o2, CTXREG_NEXT_SHIFT, %o2
1438	brz,pt	%o2, 1f				! nucleus pgsz is 0, no problem
1439	  nop
1440	rdpr	%pstate, %l4			! disable interrupts
1441	andn	%l4, PSTATE_IE, %o2
1442	wrpr	%g0, %o2, %pstate
1443	mov	DEMAP_ALL_TYPE, %o2		! set PCONTEXT=0
1444	stxa	%g0, [%o2]ASI_DTLB_DEMAP
1445	stxa	%g0, [%o2]ASI_ITLB_DEMAP
1446	mov	MMU_PCONTEXT, %o2
1447	stxa	%g0, [%o2]ASI_DMMU
1448        membar  #Sync
1449	sethi	%hi(FLUSH_ADDR), %o2
1450	flush	%o2				! flush required by immu
1451	wrpr	%g0, %l4, %pstate		! restore interrupt state
1452#endif /* _OPL */
1453
14541:	mov	%i1, %o0
1455	rdpr	%pstate, %l4			! Get the present pstate value
1456	andn	%l4, PSTATE_AM, %l6
1457	wrpr	%l6, 0, %pstate			! Set PSTATE_AM = 0
1458	jmpl	%i0, %o7			! Call cif handler
1459	nop
1460	wrpr	%l4, 0, %pstate			! restore pstate
1461	brz	%l3, 1f				! is the tba_taken_over = 1
1462	  nop
1463	wrpr	%g0, %l5, %wstate		! restore wstate
1464
1465	!
1466	! switch to PCONTEXT=kcontexreg
1467	!
1468#ifndef _OPL
1469	sethi	%hi(kcontextreg), %o3
1470	ldx     [%o3 + %lo(kcontextreg)], %o3
1471	brz	%o3, 1f
1472	  nop
1473	rdpr	%pstate, %l4			! disable interrupts
1474	andn	%l4, PSTATE_IE, %o2
1475	wrpr	%g0, %o2, %pstate
1476	mov	DEMAP_ALL_TYPE, %o2
1477	stxa	%g0, [%o2]ASI_DTLB_DEMAP
1478	stxa	%g0, [%o2]ASI_ITLB_DEMAP
1479	mov	MMU_PCONTEXT, %o2
1480	stxa	%o3, [%o2]ASI_DMMU
1481        membar  #Sync
1482	sethi	%hi(FLUSH_ADDR), %o2
1483	flush	%o2				! flush required by immu
1484	wrpr	%g0, %l4, %pstate		! restore interrupt state
1485#endif /* _OPL */
1486
14871:	ret					! Return result ...
1488	restore	%o0, %g0, %o0			! delay; result in %o0
1489	SET_SIZE(client_handler)
1490
1491