8354 sync regcomp(3C) with upstream (fix make catalog)
[unleashed/tickless.git] / usr / src / uts / sun4u / ml / mach_locore.s
blob4447483f2605d1a70fdeac7a2f93edaac3935b81
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
28 #if defined(lint)
29 #include <sys/types.h>
30 #include <sys/t_lock.h>
31 #include <sys/promif.h>
32 #include <sys/prom_isa.h>
33 #endif /* lint */
35 #include <sys/asm_linkage.h>
36 #include <sys/intreg.h>
37 #include <sys/ivintr.h>
38 #include <sys/mmu.h>
39 #include <sys/machpcb.h>
40 #include <sys/machtrap.h>
41 #include <sys/machlock.h>
42 #include <sys/fdreg.h>
43 #include <sys/vis.h>
44 #include <sys/traptrace.h>
45 #include <sys/panic.h>
46 #include <sys/machasi.h>
47 #include <sys/clock.h>
48 #include <vm/hat_sfmmu.h>
49 #if defined(lint)
51 #include <sys/thread.h>
52 #include <sys/time.h>
54 #else /* lint */
56 #include "assym.h"
60 ! REGOFF must add up to allow double word access to r_tstate.
61 ! PCB_WBUF must also be aligned.
63 #if (REGOFF & 7) != 0
64 #error "struct regs not aligned"
65 #endif
68 * Absolute external symbols.
69 * On the sun4u we put the panic buffer in the third and fourth pages.
70 * We set things up so that the first 2 pages of KERNELBASE is illegal
71 * to act as a redzone during copyin/copyout type operations. One of
72 * the reasons the panic buffer is allocated in low memory to
73 * prevent being overwritten during booting operations (besides
74 * the fact that it is small enough to share pages with others).
77 .seg ".data"
78 .global panicbuf
80 PROM = 0xFFE00000 ! address of prom virtual area
81 panicbuf = SYSBASE32 + PAGESIZE ! address of panic buffer
83 .type panicbuf, #object
84 .size panicbuf, PANICBUFSIZE
87 * Absolute external symbol - intr_vec_table.
89 * With new bus structures supporting a larger number of interrupt
90 * numbers, the interrupt vector table, intr_vec_table[] has been
91 * moved out of kernel nucleus and allocated after panicbuf.
93 .global intr_vec_table
95 intr_vec_table = SYSBASE32 + PAGESIZE + PANICBUFSIZE ! address of interrupt table
97 .type intr_vec_table, #object
98 .size intr_vec_table, MAXIVNUM * CPTRSIZE + MAX_RSVD_IV * IV_SIZE + MAX_RSVD_IVX * (IV_SIZE + CPTRSIZE * (NCPU - 1))
101 * The thread 0 stack. This must be the first thing in the data
102 * segment (other than an sccs string) so that we don't stomp
103 * on anything important if the stack overflows. We get a
104 * red zone below this stack for free when the kernel text is
105 * write protected.
108 .global t0stack
109 .align 16
110 .type t0stack, #object
111 t0stack:
112 .skip T0STKSZ ! thread 0 stack
113 t0stacktop:
114 .size t0stack, T0STKSZ
117 * cpu0 and its ptl1_panic stack. The cpu structure must be allocated
118 * on a single page for ptl1_panic's physical address accesses.
120 .global cpu0
121 .align MMU_PAGESIZE
122 cpu0:
123 .type cpu0, #object
124 .skip CPU_ALLOC_SIZE
125 .size cpu0, CPU_ALLOC_SIZE
127 .global t0
128 .align PTR24_ALIGN ! alignment for mutex.
129 .type t0, #object
131 .skip THREAD_SIZE ! thread 0
132 .size t0, THREAD_SIZE
134 #ifdef TRAPTRACE
135 .global trap_trace_ctl
136 .global trap_tr0
137 .global trap_trace_bufsize
138 .global trap_freeze
139 .global trap_freeze_pc
141 .align 4
142 trap_trace_bufsize:
143 .word TRAP_TSIZE ! default trap buffer size
144 trap_freeze:
145 .word 0
147 .align 64
148 trap_trace_ctl:
149 .skip NCPU * TRAPTR_SIZE ! NCPU control headers
151 .align 16
152 trap_tr0:
153 .skip TRAP_TSIZE ! one buffer for the boot cpu
156 * When an assertion in TRACE_PTR was failed, %pc is saved in trap_freeze_pc to
157 * show in which TRACE_PTR the assertion failure happened.
159 .align 8
160 trap_freeze_pc:
161 .nword 0
162 #endif /* TRAPTRACE */
164 .align 4
165 .seg ".text"
167 #ifdef NOPROM
168 .global availmem
169 availmem:
170 .word 0
171 #endif /* NOPROM */
173 .align 8
174 _local_p1275cis:
175 .nword 0
177 #endif /* lint */
179 #if defined(lint)
181 void
182 _start(void)
185 #else /* lint */
187 .seg ".data"
189 .global nwindows, nwin_minus_one, winmask
190 nwindows:
191 .word 8
192 nwin_minus_one:
193 .word 7
194 winmask:
195 .word 8
197 .global afsrbuf
198 afsrbuf:
199 .word 0,0,0,0
202 * System initialization
204 * Our contract with the boot prom specifies that the MMU is on and the
205 * first 16 meg of memory is mapped with a level-1 pte. We are called
206 * with p1275cis ptr in %o0 and kdi_dvec in %o1; we start execution
207 * directly from physical memory, so we need to get up into our proper
208 * addresses quickly: all code before we do this must be position
209 * independent.
211 * NB: Above is not true for boot/stick kernel, the only thing mapped is
212 * the text+data+bss. The kernel is loaded directly into KERNELBASE.
214 * entry, the romvec pointer (romp) is the first argument;
215 * i.e., %o0.
216 * the bootops vector is in the third argument (%o1)
218 * Our tasks are:
219 * save parameters
220 * construct mappings for KERNELBASE (not needed for boot/stick kernel)
221 * hop up into high memory (not needed for boot/stick kernel)
222 * initialize stack pointer
223 * initialize trap base register
224 * initialize window invalid mask
225 * initialize psr (with traps enabled)
226 * figure out all the module type stuff
227 * tear down the 1-1 mappings
228 * dive into main()
230 ENTRY_NP(_start)
232 ! Stash away our arguments in memory.
234 sethi %hi(_local_p1275cis), %g1
235 stn %o4, [%g1 + %lo(_local_p1275cis)]
238 ! Initialize CPU state registers
240 wrpr %g0, PSTATE_KERN, %pstate
241 wr %g0, %g0, %fprs
244 ! call krtld to link the world together
246 call kobj_start
247 mov %o4, %o0
249 CLEARTICKNPT ! allow user rdtick
251 ! Get maxwin from %ver
253 rdpr %ver, %g1
254 and %g1, VER_MAXWIN, %g1
257 ! Stuff some memory cells related to numbers of windows.
259 sethi %hi(nwin_minus_one), %g2
260 st %g1, [%g2 + %lo(nwin_minus_one)]
261 inc %g1
262 sethi %hi(nwindows), %g2
263 st %g1, [%g2 + %lo(nwindows)]
264 dec %g1
265 mov -2, %g2
266 sll %g2, %g1, %g2
267 sethi %hi(winmask), %g4
268 st %g2, [%g4 + %lo(winmask)]
271 ! save a pointer to obp's tba for later use by kmdb
273 rdpr %tba, %g1
274 set boot_tba, %g2
275 stx %g1, [%g2]
278 ! copy obp's breakpoint trap entry to obp_bpt
280 rdpr %tba, %g1
281 set T_SOFTWARE_TRAP | ST_MON_BREAKPOINT, %g2
282 sll %g2, 5, %g2
283 or %g1, %g2, %g1
284 set obp_bpt, %g2
285 ldx [%g1], %g3
286 stx %g3, [%g2]
287 flush %g2
288 ldx [%g1 + 8], %g3
289 stx %g3, [%g2 + 8]
290 flush %g2 + 8
291 ldx [%g1 + 16], %g3
292 stx %g3, [%g2 + 16]
293 flush %g2 + 16
294 ldx [%g1 + 24], %g3
295 stx %g3, [%g2 + 24]
296 flush %g2 + 24
299 ! Initialize thread 0's stack.
301 set t0stacktop, %g1 ! setup kernel stack pointer
302 sub %g1, SA(KFPUSIZE+GSR_SIZE), %g2
303 and %g2, 0x3f, %g3
304 sub %g2, %g3, %o1
305 sub %o1, SA(MPCBSIZE) + STACK_BIAS, %sp
308 ! Initialize global thread register.
310 set t0, THREAD_REG
313 ! Fill in enough of the cpu structure so that
314 ! the wbuf management code works. Make sure the
315 ! boot cpu is inserted in cpu[] based on cpuid.
317 CPU_INDEX(%g2, %g1)
318 sll %g2, CPTRSHIFT, %g2 ! convert cpuid to cpu[] offset
319 set cpu0, %o0 ! &cpu0
320 set cpu, %g1 ! &cpu[]
321 stn %o0, [%g1 + %g2] ! cpu[cpuid] = &cpu0
323 stn %o0, [THREAD_REG + T_CPU] ! threadp()->t_cpu = cpu[cpuid]
324 stn THREAD_REG, [%o0 + CPU_THREAD] ! cpu[cpuid]->cpu_thread = threadp()
327 ! We do NOT need to bzero our BSS...boot has already done it for us.
328 ! Just need to reference edata so that we don't break /dev/ksyms
329 set edata, %g0
332 ! Call mlsetup with address of prototype user registers.
334 call mlsetup
335 add %sp, REGOFF + STACK_BIAS, %o0
337 #if (REGOFF != MPCB_REGS)
338 #error "hole in struct machpcb between frame and regs?"
339 #endif
342 ! Now call main. We will return as process 1 (init).
344 call main
348 ! Main should never return.
350 set .mainretmsg, %o0
351 call panic
353 SET_SIZE(_start)
355 .mainretmsg:
356 .asciz "main returned"
357 .align 4
359 #endif /* lint */
363 * Generic system trap handler.
365 * Some kernel trap handlers save themselves from buying a window by
366 * borrowing some of sys_trap's unused locals. %l0 thru %l3 may be used
367 * for this purpose, as user_rtt and priv_rtt do not depend on them.
368 * %l4 thru %l7 should NOT be used this way.
370 * Entry Conditions:
371 * %pstate am:0 priv:1 ie:0
372 * globals are either ag or ig (not mg!)
374 * Register Inputs:
375 * %g1 pc of trap handler
376 * %g2, %g3 args for handler
377 * %g4 desired %pil (-1 means current %pil)
378 * %g5, %g6 destroyed
379 * %g7 saved
381 * Register Usage:
382 * %l0, %l1 temps
383 * %l3 saved %g1
384 * %l6 curthread for user traps, %pil for priv traps
385 * %l7 regs
387 * Called function prototype variants:
389 * func(struct regs *rp);
390 * func(struct regs *rp, uintptr_t arg1 [%g2], uintptr_t arg2 [%g3])
391 * func(struct regs *rp, uintptr_t arg1 [%g2],
392 * uint32_t arg2 [%g3.l], uint32_t arg3 [%g3.h])
393 * func(struct regs *rp, uint32_t arg1 [%g2.l],
394 * uint32_t arg2 [%g3.l], uint32_t arg3 [%g3.h], uint32_t [%g2.h])
397 #if defined(lint)
399 void
400 sys_trap(void)
403 #else /* lint */
405 ENTRY_NP(sys_trap)
407 ! force tl=1, update %cwp, branch to correct handler
409 wrpr %g0, 1, %tl
410 rdpr %tstate, %g5
411 btst TSTATE_PRIV, %g5
412 and %g5, TSTATE_CWP, %g6
413 bnz,pn %xcc, priv_trap
414 wrpr %g0, %g6, %cwp
416 ALTENTRY(user_trap)
418 ! user trap
420 ! make all windows clean for kernel
421 ! buy a window using the current thread's stack
423 sethi %hi(nwin_minus_one), %g5
424 ld [%g5 + %lo(nwin_minus_one)], %g5
425 wrpr %g0, %g5, %cleanwin
426 CPU_ADDR(%g5, %g6)
427 ldn [%g5 + CPU_THREAD], %g5
428 ldn [%g5 + T_STACK], %g6
429 sub %g6, STACK_BIAS, %g6
430 save %g6, 0, %sp
432 ! set window registers so that current windows are "other" windows
434 rdpr %canrestore, %l0
435 rdpr %wstate, %l1
436 wrpr %g0, 0, %canrestore
437 sllx %l1, WSTATE_SHIFT, %l1
438 wrpr %l1, WSTATE_K64, %wstate
439 wrpr %g0, %l0, %otherwin
441 ! set pcontext to run kernel
443 sethi %hi(kcontextreg), %l0
444 ldx [%l0 + %lo(kcontextreg)], %l0
445 mov MMU_PCONTEXT, %l1 ! if kcontextreg==PCONTEXT, do nothing
446 ldxa [%l1]ASI_MMU_CTX, %l2
447 xor %l0, %l2, %l2
448 srlx %l2, CTXREG_NEXT_SHIFT, %l2
449 brz %l2, 2f ! if N_pgsz0/1 changed, need demap
450 sethi %hi(FLUSH_ADDR), %l3
451 mov DEMAP_ALL_TYPE, %l2
452 stxa %g0, [%l2]ASI_DTLB_DEMAP
453 stxa %g0, [%l2]ASI_ITLB_DEMAP
455 stxa %l0, [%l1]ASI_MMU_CTX
456 flush %l3 ! flush required by immu
459 set utl0, %g6 ! bounce to utl0
460 have_win:
461 SYSTRAP_TRACE(%o1, %o2, %o3)
465 ! at this point we have a new window we can play in,
466 ! and %g6 is the label we want done to bounce to
468 ! save needed current globals
470 mov %g1, %l3 ! pc
471 mov %g2, %o1 ! arg #1
472 mov %g3, %o2 ! arg #2
473 srlx %g3, 32, %o3 ! pseudo arg #3
474 srlx %g2, 32, %o4 ! pseudo arg #4
475 mov %g5, %l6 ! curthread if user trap, %pil if priv trap
477 ! save trap state on stack
479 add %sp, REGOFF + STACK_BIAS, %l7
480 rdpr %tpc, %l0
481 rdpr %tnpc, %l1
482 rdpr %tstate, %l2
483 stn %l0, [%l7 + PC_OFF]
484 stn %l1, [%l7 + nPC_OFF]
485 stx %l2, [%l7 + TSTATE_OFF]
487 ! setup pil
489 brlz,pt %g4, 1f
491 #ifdef DEBUG
493 ! ASSERT(%g4 >= %pil).
495 rdpr %pil, %l0
496 cmp %g4, %l0
497 bge,pt %xcc, 0f
498 nop ! yes, nop; to avoid anull
499 set bad_g4_called, %l3
500 mov 1, %o1
501 st %o1, [%l3]
502 set bad_g4, %l3 ! pc
503 set sys_trap_wrong_pil, %o1 ! arg #1
504 mov %g4, %o2 ! arg #2
505 ba 1f ! stay at the current %pil
506 mov %l0, %o3 ! arg #3
508 #endif /* DEBUG */
509 wrpr %g0, %g4, %pil
512 ! set trap regs to execute in kernel at %g6
513 ! done resumes execution there
515 wrpr %g0, %g6, %tnpc
516 rdpr %cwp, %l0
517 set TSTATE_KERN, %l1
518 wrpr %l1, %l0, %tstate
519 done
520 /* NOTREACHED */
521 SET_SIZE(user_trap)
522 SET_SIZE(sys_trap)
525 ENTRY_NP(prom_trap)
527 ! prom trap switches the stack to 32-bit
528 ! if we took a trap from a 64-bit window
529 ! Then buys a window on the current stack.
531 save %sp, -SA64(REGOFF + REGSIZE), %sp
532 /* 32 bit frame, 64 bit sized */
533 set ptl0, %g6
534 ba,a,pt %xcc, have_win
535 SET_SIZE(prom_trap)
537 ENTRY_NP(priv_trap)
539 ! kernel trap
540 ! buy a window on the current stack
542 ! is the trap PC in the range allocated to Open Firmware?
543 rdpr %tpc, %g5
544 set OFW_END_ADDR, %g6
545 cmp %g5, %g6
546 bgu,a,pn %xcc, 1f
547 rdpr %pil, %g5
548 set OFW_START_ADDR, %g6
549 cmp %g5, %g6
550 bgeu,pn %xcc, prom_trap
551 rdpr %pil, %g5
554 ! check if the primary context is of kernel.
556 mov MMU_PCONTEXT, %g6
557 ldxa [%g6]ASI_MMU_CTX, %g5
558 sllx %g5, CTXREG_CTX_SHIFT, %g5 ! keep just the ctx bits
559 brnz,pn %g5, 2f ! assumes KCONTEXT == 0
560 rdpr %pil, %g5
562 ! primary context is of kernel.
564 set ktl0, %g6
565 save %sp, -SA(REGOFF + REGSIZE), %sp
566 ba,a,pt %xcc, have_win
569 ! primary context is of user. caller of sys_trap()
570 ! or priv_trap() did not set kernel context. raise
571 ! trap level to MAXTL-1 so that ptl1_panic() prints
572 ! out all levels of trap data.
574 rdpr %ver, %g5
575 srlx %g5, VER_MAXTL_SHIFT, %g5
576 and %g5, VER_MAXTL_MASK, %g5 ! %g5 = MAXTL
577 sub %g5, 1, %g5
578 wrpr %g0, %g5, %tl
579 mov PTL1_BAD_CTX, %g1
580 ba,a,pt %xcc, ptl1_panic
581 SET_SIZE(priv_trap)
583 ENTRY_NP(utl0)
584 SAVE_GLOBALS(%l7)
585 SAVE_OUTS(%l7)
586 mov %l6, THREAD_REG
587 wrpr %g0, PSTATE_KERN, %pstate ! enable ints
588 jmpl %l3, %o7 ! call trap handler
589 mov %l7, %o0
591 ALTENTRY(user_rtt)
593 ! Register inputs
594 ! %l7 - regs
596 ! disable interrupts and check for ASTs and wbuf restores
597 ! keep cpu_base_spl in %l4 and THREAD_REG in %l6 (needed
598 ! in wbuf.s when globals have already been restored).
600 wrpr %g0, PIL_MAX, %pil
601 ldn [THREAD_REG + T_CPU], %l0
602 ld [%l0 + CPU_BASE_SPL], %l4
604 ldub [THREAD_REG + T_ASTFLAG], %l2
605 brz,pt %l2, 1f
606 ld [%sp + STACK_BIAS + MPCB_WBCNT], %l3
608 ! call trap to do ast processing
610 wrpr %g0, %l4, %pil ! pil = cpu_base_spl
611 mov %l7, %o0
612 call trap
613 mov T_AST, %o2
614 ba,a,pt %xcc, user_rtt
616 brz,pt %l3, 2f
617 mov THREAD_REG, %l6
619 ! call restore_wbuf to push wbuf windows to stack
621 wrpr %g0, %l4, %pil ! pil = cpu_base_spl
622 mov %l7, %o0
623 call trap
624 mov T_FLUSH_PCB, %o2
625 ba,a,pt %xcc, user_rtt
627 #ifdef TRAPTRACE
628 TRACE_RTT(TT_SYS_RTT_USER, %l0, %l1, %l2, %l3)
629 #endif /* TRAPTRACE */
630 ld [%sp + STACK_BIAS + MPCB_WSTATE], %l3 ! get wstate
633 ! restore user globals and outs
635 rdpr %pstate, %l1
636 wrpr %l1, PSTATE_IE, %pstate
637 RESTORE_GLOBALS(%l7)
638 ! switch to alternate globals, saving THREAD_REG in %l6
639 wrpr %l1, PSTATE_IE | PSTATE_AG, %pstate
640 mov %sp, %g6 ! remember the mpcb pointer in %g6
641 RESTORE_OUTS(%l7)
643 ! set %pil from cpu_base_spl
645 wrpr %g0, %l4, %pil
647 ! raise tl (now using nucleus context)
649 wrpr %g0, 1, %tl
651 ! switch "other" windows back to "normal" windows.
652 rdpr %otherwin, %g1
653 wrpr %g0, 0, %otherwin
654 add %l3, WSTATE_CLEAN_OFFSET, %l3 ! convert to "clean" wstate
655 wrpr %g0, %l3, %wstate
656 wrpr %g0, %g1, %canrestore
658 ! set pcontext to scontext for user execution
659 mov MMU_SCONTEXT, %g3
660 ldxa [%g3]ASI_MMU_CTX, %g2
662 mov MMU_PCONTEXT, %g3
663 ldxa [%g3]ASI_MMU_CTX, %g4 ! need N_pgsz0/1 bits
664 srlx %g4, CTXREG_NEXT_SHIFT, %g4
665 sllx %g4, CTXREG_NEXT_SHIFT, %g4
666 or %g4, %g2, %g2 ! Or in Nuc pgsz bits
668 sethi %hi(FLUSH_ADDR), %g4
669 stxa %g2, [%g3]ASI_MMU_CTX
670 flush %g4 ! flush required by immu
672 ! Within the code segment [rtt_ctx_start - rtt_ctx_end],
673 ! PCONTEXT is set to run user code. If a trap happens in this
674 ! window, and the trap needs to be handled at TL=0, the handler
675 ! must make sure to set PCONTEXT to run kernel. A convenience
676 ! macro, RESET_USER_RTT_REGS(scr1, scr2, label) is available to
677 ! TL>1 handlers for this purpose.
679 ! %g1 = %canrestore
680 ! %l7 = regs
681 ! %g6 = mpcb
683 .global rtt_ctx_start
684 rtt_ctx_start:
686 ! setup trap regs
688 ldn [%l7 + PC_OFF], %g3
689 ldn [%l7 + nPC_OFF], %g2
690 ldx [%l7 + TSTATE_OFF], %l0
691 andn %l0, TSTATE_CWP, %g7
692 wrpr %g3, %tpc
693 wrpr %g2, %tnpc
696 ! Restore to window we originally trapped in.
697 ! First attempt to restore from the watchpoint saved register window
699 tst %g1
700 bne,a 1f
701 clrn [%g6 + STACK_BIAS + MPCB_RSP0]
702 tst %fp
703 be,a 1f
704 clrn [%g6 + STACK_BIAS + MPCB_RSP0]
705 ! test for user return window in pcb
706 ldn [%g6 + STACK_BIAS + MPCB_RSP0], %g1
707 cmp %fp, %g1
708 bne 1f
709 clrn [%g6 + STACK_BIAS + MPCB_RSP0]
710 restored
711 restore
712 ! restore from user return window
713 RESTORE_V9WINDOW(%g6 + STACK_BIAS + MPCB_RWIN0)
715 ! Attempt to restore from the scond watchpoint saved register window
716 tst %fp
717 be,a 2f
718 clrn [%g6 + STACK_BIAS + MPCB_RSP1]
719 ldn [%g6 + STACK_BIAS + MPCB_RSP1], %g1
720 cmp %fp, %g1
721 bne 2f
722 clrn [%g6 + STACK_BIAS + MPCB_RSP1]
723 restored
724 restore
725 RESTORE_V9WINDOW(%g6 + STACK_BIAS + MPCB_RWIN1)
726 save
727 b,a 2f
729 restore ! should not trap
732 ! set %cleanwin to %canrestore
733 ! set %tstate to the correct %cwp
734 ! retry resumes user execution
736 rdpr %canrestore, %g1
737 wrpr %g0, %g1, %cleanwin
738 rdpr %cwp, %g1
739 wrpr %g1, %g7, %tstate
740 retry
741 .global rtt_ctx_end
742 rtt_ctx_end:
743 /* NOTREACHED */
744 SET_SIZE(user_rtt)
745 SET_SIZE(utl0)
747 ENTRY_NP(ptl0)
748 SAVE_GLOBALS(%l7)
749 SAVE_OUTS(%l7)
750 CPU_ADDR(%g5, %g6)
751 ldn [%g5 + CPU_THREAD], THREAD_REG
752 wrpr %g0, PSTATE_KERN, %pstate ! enable ints
753 jmpl %l3, %o7 ! call trap handler
754 mov %l7, %o0
756 ALTENTRY(prom_rtt)
757 #ifdef TRAPTRACE
758 TRACE_RTT(TT_SYS_RTT_PROM, %l0, %l1, %l2, %l3)
759 #endif /* TRAPTRACE */
760 ba,pt %xcc, common_rtt
761 mov THREAD_REG, %l0
762 SET_SIZE(prom_rtt)
763 SET_SIZE(ptl0)
765 ENTRY_NP(ktl0)
766 SAVE_GLOBALS(%l7)
767 SAVE_OUTS(%l7) ! for the call bug workaround
768 wrpr %g0, PSTATE_KERN, %pstate ! enable ints
769 jmpl %l3, %o7 ! call trap handler
770 mov %l7, %o0
772 ALTENTRY(priv_rtt)
773 #ifdef TRAPTRACE
774 TRACE_RTT(TT_SYS_RTT_PRIV, %l0, %l1, %l2, %l3)
775 #endif /* TRAPTRACE */
777 ! Register inputs
778 ! %l7 - regs
779 ! %l6 - trap %pil
781 ! Check for a kernel preemption request
783 ldn [THREAD_REG + T_CPU], %l0
784 ldub [%l0 + CPU_KPRUNRUN], %l0
785 brz,pt %l0, 1f
789 ! Attempt to preempt
791 ldstub [THREAD_REG + T_PREEMPT_LK], %l0 ! load preempt lock
792 brnz,pn %l0, 1f ! can't call kpreempt if this thread is
793 nop ! already in it...
795 call kpreempt
796 mov %l6, %o0 ! pass original interrupt level
798 stub %g0, [THREAD_REG + T_PREEMPT_LK] ! nuke the lock
800 rdpr %pil, %o0 ! compare old pil level
801 cmp %l6, %o0 ! with current pil level
802 movg %xcc, %o0, %l6 ! if current is lower, drop old pil
805 ! If we interrupted the mutex_owner_running() critical region we
806 ! must reset the PC and nPC back to the beginning to prevent missed
807 ! wakeups. See the comments in mutex_owner_running() for details.
809 ldn [%l7 + PC_OFF], %l0
810 set mutex_owner_running_critical_start, %l1
811 sub %l0, %l1, %l0
812 cmp %l0, mutex_owner_running_critical_size
813 bgeu,pt %xcc, 2f
814 mov THREAD_REG, %l0
815 stn %l1, [%l7 + PC_OFF] ! restart mutex_owner_running()
816 add %l1, 4, %l1
817 ba,pt %xcc, common_rtt
818 stn %l1, [%l7 + nPC_OFF]
822 ! If we interrupted the mutex_exit() critical region we must reset
823 ! the PC and nPC back to the beginning to prevent missed wakeups.
824 ! See the comments in mutex_exit() for details.
826 ldn [%l7 + PC_OFF], %l0
827 set mutex_exit_critical_start, %l1
828 sub %l0, %l1, %l0
829 cmp %l0, mutex_exit_critical_size
830 bgeu,pt %xcc, common_rtt
831 mov THREAD_REG, %l0
832 stn %l1, [%l7 + PC_OFF] ! restart mutex_exit()
833 add %l1, 4, %l1
834 stn %l1, [%l7 + nPC_OFF]
836 common_rtt:
838 ! restore globals and outs
840 rdpr %pstate, %l1
841 wrpr %l1, PSTATE_IE, %pstate
842 RESTORE_GLOBALS(%l7)
843 ! switch to alternate globals
844 wrpr %l1, PSTATE_IE | PSTATE_AG, %pstate
845 RESTORE_OUTS(%l7)
847 ! set %pil from max(old pil, cpu_base_spl)
849 ldn [%l0 + T_CPU], %l0
850 ld [%l0 + CPU_BASE_SPL], %l0
851 cmp %l6, %l0
852 movg %xcc, %l6, %l0
853 wrpr %g0, %l0, %pil
855 ! raise tl
856 ! setup trap regs
857 ! restore to window we originally trapped in
859 wrpr %g0, 1, %tl
860 ldn [%l7 + PC_OFF], %g1
861 ldn [%l7 + nPC_OFF], %g2
862 ldx [%l7 + TSTATE_OFF], %l0
863 andn %l0, TSTATE_CWP, %g7
864 wrpr %g1, %tpc
865 wrpr %g2, %tnpc
866 restore
868 ! set %tstate to the correct %cwp
869 ! retry resumes prom execution
871 rdpr %cwp, %g1
872 wrpr %g1, %g7, %tstate
873 retry
874 /* NOTREACHED */
875 SET_SIZE(priv_rtt)
876 SET_SIZE(ktl0)
878 #endif /* lint */
880 #ifndef lint
882 #ifdef DEBUG
883 .seg ".data"
884 .align 4
886 .global bad_g4_called
887 bad_g4_called:
888 .word 0
890 sys_trap_wrong_pil:
891 .asciz "sys_trap: %g4(%d) is lower than %pil(%d)"
892 .align 4
893 .seg ".text"
895 ENTRY_NP(bad_g4)
896 mov %o1, %o0
897 mov %o2, %o1
898 call panic
899 mov %o3, %o2
900 SET_SIZE(bad_g4)
901 #endif /* DEBUG */
902 #endif /* lint */
905 * sys_tl1_panic can be called by traps at tl1 which
906 * really want to panic, but need the rearrangement of
907 * the args as provided by this wrapper routine.
909 #if defined(lint)
911 void
912 sys_tl1_panic(void)
915 #else /* lint */
916 ENTRY_NP(sys_tl1_panic)
917 mov %o1, %o0
918 mov %o2, %o1
919 call panic
920 mov %o3, %o2
921 SET_SIZE(sys_tl1_panic)
922 #endif /* lint */
925 * Turn on or off bits in the auxiliary i/o register.
927 * set_auxioreg(bit, flag)
928 * int bit; bit mask in aux i/o reg
929 * int flag; 0 = off, otherwise on
931 * This is intrinsicly ugly but is used by the floppy driver. It is also
932 * used to turn on/off the led.
935 #if defined(lint)
937 /* ARGSUSED */
938 void
939 set_auxioreg(int bit, int flag)
942 #else /* lint */
944 .seg ".data"
945 .align 4
946 auxio_panic:
947 .asciz "set_auxioreg: interrupts already disabled on entry"
948 .align 4
949 .seg ".text"
951 ENTRY_NP(set_auxioreg)
953 * o0 = bit mask
954 * o1 = flag: 0 = off, otherwise on
956 * disable interrupts while updating auxioreg
958 rdpr %pstate, %o2
959 #ifdef DEBUG
960 andcc %o2, PSTATE_IE, %g0 /* if interrupts already */
961 bnz,a,pt %icc, 1f /* disabled, panic */
963 sethi %hi(auxio_panic), %o0
964 call panic
965 or %o0, %lo(auxio_panic), %o0
967 #endif /* DEBUG */
968 wrpr %o2, PSTATE_IE, %pstate /* disable interrupts */
969 sethi %hi(v_auxio_addr), %o3
970 ldn [%o3 + %lo(v_auxio_addr)], %o4
971 ldub [%o4], %g1 /* read aux i/o register */
972 tst %o1
973 bnz,a 2f
974 bset %o0, %g1 /* on */
975 bclr %o0, %g1 /* off */
977 or %g1, AUX_MBO, %g1 /* Must Be Ones */
978 stb %g1, [%o4] /* write aux i/o register */
979 retl
980 wrpr %g0, %o2, %pstate /* enable interrupt */
981 SET_SIZE(set_auxioreg)
983 #endif /* lint */
986 * Flush all windows to memory, except for the one we entered in.
987 * We do this by doing NWINDOW-2 saves then the same number of restores.
988 * This leaves the WIM immediately before window entered in.
989 * This is used for context switching.
992 #if defined(lint)
994 void
995 flush_windows(void)
998 #else /* lint */
1000 ENTRY_NP(flush_windows)
1001 retl
1002 flushw
1003 SET_SIZE(flush_windows)
1005 #endif /* lint */
1007 #if defined(lint)
1009 void
1010 debug_flush_windows(void)
1013 #else /* lint */
1015 ENTRY_NP(debug_flush_windows)
1016 set nwindows, %g1
1017 ld [%g1], %g1
1018 mov %g1, %g2
1021 save %sp, -WINDOWSIZE, %sp
1022 brnz %g2, 1b
1023 dec %g2
1025 mov %g1, %g2
1027 restore
1028 brnz %g2, 2b
1029 dec %g2
1031 retl
1034 SET_SIZE(debug_flush_windows)
1036 #endif /* lint */
1039 * flush user windows to memory.
1042 #if defined(lint)
1044 void
1045 flush_user_windows(void)
1048 #else /* lint */
1050 ENTRY_NP(flush_user_windows)
1051 rdpr %otherwin, %g1
1052 brz %g1, 3f
1053 clr %g2
1055 save %sp, -WINDOWSIZE, %sp
1056 rdpr %otherwin, %g1
1057 brnz %g1, 1b
1058 add %g2, 1, %g2
1060 sub %g2, 1, %g2 ! restore back to orig window
1061 brnz %g2, 2b
1062 restore
1064 retl
1066 SET_SIZE(flush_user_windows)
1068 #endif /* lint */
1071 * Throw out any user windows in the register file.
1072 * Used by setregs (exec) to clean out old user.
1073 * Used by sigcleanup to remove extraneous windows when returning from a
1074 * signal.
1077 #if defined(lint)
1079 void
1080 trash_user_windows(void)
1083 #else /* lint */
1085 ENTRY_NP(trash_user_windows)
1086 rdpr %otherwin, %g1
1087 brz %g1, 3f ! no user windows?
1088 ldn [THREAD_REG + T_STACK], %g5
1091 ! There are old user windows in the register file. We disable ints
1092 ! and increment cansave so that we don't overflow on these windows.
1093 ! Also, this sets up a nice underflow when first returning to the
1094 ! new user.
1096 rdpr %pstate, %g2
1097 wrpr %g2, PSTATE_IE, %pstate
1098 rdpr %cansave, %g3
1099 rdpr %otherwin, %g1 ! re-read in case of interrupt
1100 add %g3, %g1, %g3
1101 wrpr %g0, 0, %otherwin
1102 wrpr %g0, %g3, %cansave
1103 wrpr %g0, %g2, %pstate
1105 retl
1106 clr [%g5 + MPCB_WBCNT] ! zero window buffer cnt
1107 SET_SIZE(trash_user_windows)
1110 #endif /* lint */
1113 * Setup g7 via the CPU data structure.
1115 #if defined(lint)
1117 struct scb *
1118 set_tbr(struct scb *s)
1119 { return (s); }
1121 #else /* lint */
1123 ENTRY_NP(set_tbr)
1124 retl
1125 ta 72 ! no tbr, stop simulation
1126 SET_SIZE(set_tbr)
1128 #endif /* lint */
1131 #if defined(lint)
1133 * These need to be defined somewhere to lint and there is no "hicore.s"...
1135 char etext[1], end[1];
1136 #endif /* lint*/
1138 #if defined (lint)
1140 /* ARGSUSED */
1141 void
1142 ptl1_panic(u_int reason)
1145 #else /* lint */
1147 #define PTL1_SAVE_WINDOW(RP) \
1148 stxa %l0, [RP + RW64_LOCAL + (0 * RW64_LOCAL_INCR)] %asi; \
1149 stxa %l1, [RP + RW64_LOCAL + (1 * RW64_LOCAL_INCR)] %asi; \
1150 stxa %l2, [RP + RW64_LOCAL + (2 * RW64_LOCAL_INCR)] %asi; \
1151 stxa %l3, [RP + RW64_LOCAL + (3 * RW64_LOCAL_INCR)] %asi; \
1152 stxa %l4, [RP + RW64_LOCAL + (4 * RW64_LOCAL_INCR)] %asi; \
1153 stxa %l5, [RP + RW64_LOCAL + (5 * RW64_LOCAL_INCR)] %asi; \
1154 stxa %l6, [RP + RW64_LOCAL + (6 * RW64_LOCAL_INCR)] %asi; \
1155 stxa %l7, [RP + RW64_LOCAL + (7 * RW64_LOCAL_INCR)] %asi; \
1156 stxa %i0, [RP + RW64_IN + (0 * RW64_IN_INCR)] %asi; \
1157 stxa %i1, [RP + RW64_IN + (1 * RW64_IN_INCR)] %asi; \
1158 stxa %i2, [RP + RW64_IN + (2 * RW64_IN_INCR)] %asi; \
1159 stxa %i3, [RP + RW64_IN + (3 * RW64_IN_INCR)] %asi; \
1160 stxa %i4, [RP + RW64_IN + (4 * RW64_IN_INCR)] %asi; \
1161 stxa %i5, [RP + RW64_IN + (5 * RW64_IN_INCR)] %asi; \
1162 stxa %i6, [RP + RW64_IN + (6 * RW64_IN_INCR)] %asi; \
1163 stxa %i7, [RP + RW64_IN + (7 * RW64_IN_INCR)] %asi
1164 #define PTL1_NEXT_WINDOW(scr) \
1165 add scr, RWIN64SIZE, scr
1167 #define PTL1_RESET_RWINDOWS(scr) \
1168 sethi %hi(nwin_minus_one), scr; \
1169 ld [scr + %lo(nwin_minus_one)], scr; \
1170 wrpr scr, %cleanwin; \
1171 dec scr; \
1172 wrpr scr, %cansave; \
1173 wrpr %g0, %canrestore; \
1174 wrpr %g0, %otherwin
1176 #define PTL1_DCACHE_LINE_SIZE 4 /* small enough for all CPUs */
1179 * ptl1_panic is called when the kernel detects that it is in an invalid state
1180 * and the trap level is greater than 0. ptl1_panic is responsible to save the
1181 * current CPU state, to restore the CPU state to normal, and to call panic.
1182 * The CPU state must be saved reliably without causing traps. ptl1_panic saves
1183 * it in the ptl1_state structure, which is a member of the machcpu structure.
1184 * In order to access the ptl1_state structure without causing traps, physical
1185 * addresses are used so that we can avoid MMU miss traps. The restriction of
1186 * physical memory accesses is that the ptl1_state structure must be on a single
1187 * physical page. This is because (1) a single physical address for each
1188 * ptl1_state structure is needed and (2) it simplifies physical address
1189 * calculation for each member of the structure.
1190 * ptl1_panic is a likely spot for stack overflows to wind up; thus, the current
1191 * stack may not be usable. In order to call panic reliably in such a state,
1192 * each CPU needs a dedicated ptl1 panic stack.
1193 * CPU_ALLOC_SIZE, which is defined to be MMU_PAGESIZE, is used to allocate the
1194 * cpu structure and a ptl1 panic stack. They are put together on the same page
1195 * for memory space efficiency. The low address part is used for the cpu
1196 * structure, and the high address part is for a ptl1 panic stack.
1197 * The cpu_pa array holds the physical addresses of the allocated cpu structures,
1198 * as the cpu array holds their virtual addresses.
1200 * %g1 reason to be called
1201 * %g2 broken
1202 * %g3 broken
1204 ENTRY_NP(ptl1_panic)
1206 ! flush D$ first, so that stale data will not be accessed later.
1207 ! Data written via ASI_MEM bypasses D$. If D$ contains data at the same
1208 ! address, where data was written via ASI_MEM, a load from that address
1209 ! using a virtual address and the default ASI still takes the old data.
1210 ! Flushing D$ erases old data in D$, so that it will not be loaded.
1211 ! Since we can afford only 2 registers (%g2 and %g3) for this job, we
1212 ! flush entire D$.
1213 ! For FJ OPL processors (IMPL values < SPITFIRE_IMPL), DC flushing
1214 ! is not needed.
1216 GET_CPU_IMPL(%g2)
1217 cmp %g2, SPITFIRE_IMPL
1218 blt,pn %icc, 1f ! Skip flushing for OPL processors
1220 sethi %hi(dcache_size), %g2
1221 ld [%g2 + %lo(dcache_size)], %g2
1222 sethi %hi(dcache_linesize), %g3
1223 ld [%g3 + %lo(dcache_linesize)], %g3
1224 sub %g2, %g3, %g2
1225 0: stxa %g0, [%g2] ASI_DC_TAG
1226 membar #Sync
1227 brnz,pt %g2, 0b
1228 sub %g2, %g3, %g2
1231 ! increment the entry counter.
1232 ! save CPU state if this is the first entry.
1234 CPU_PADDR(%g2, %g3);
1235 add %g2, CPU_PTL1, %g2 ! pstate = &CPU->mcpu.ptl1_state
1236 wr %g0, ASI_MEM, %asi ! physical address access
1238 ! pstate->ptl1_entry_count++
1240 lduwa [%g2 + PTL1_ENTRY_COUNT] %asi, %g3
1241 add %g3, 1, %g3
1242 stuwa %g3, [%g2 + PTL1_ENTRY_COUNT] %asi
1244 ! CPU state saving is skipped from the 2nd entry to ptl1_panic since we
1245 ! do not want to clobber the state from the original failure. panic()
1246 ! is responsible for handling multiple or recursive panics.
1248 cmp %g3, 2 ! if (ptl1_entry_count >= 2)
1249 bge,pn %icc, state_saved ! goto state_saved
1250 add %g2, PTL1_REGS, %g3 ! %g3 = &pstate->ptl1_regs[0]
1252 ! save CPU state
1254 save_cpu_state:
1255 ! save current global registers
1256 ! so that all them become available for use
1258 stxa %g1, [%g3 + PTL1_G1] %asi
1259 stxa %g2, [%g3 + PTL1_G2] %asi
1260 stxa %g3, [%g3 + PTL1_G3] %asi
1261 stxa %g4, [%g3 + PTL1_G4] %asi
1262 stxa %g5, [%g3 + PTL1_G5] %asi
1263 stxa %g6, [%g3 + PTL1_G6] %asi
1264 stxa %g7, [%g3 + PTL1_G7] %asi
1266 ! %tl, %tt, %tstate, %tpc, %tnpc for each TL
1268 rdpr %tl, %g1
1269 brz %g1, 1f ! if(trap_level == 0) -------+
1270 add %g3, PTL1_TRAP_REGS, %g4 ! %g4 = &ptl1_trap_regs[0]; !
1271 0: ! -----------<----------+ !
1272 stwa %g1, [%g4 + PTL1_TL] %asi ! !
1273 rdpr %tt, %g5 ! !
1274 stwa %g5, [%g4 + PTL1_TT] %asi ! !
1275 rdpr %tstate, %g5 ! !
1276 stxa %g5, [%g4 + PTL1_TSTATE] %asi ! !
1277 rdpr %tpc, %g5 ! !
1278 stxa %g5, [%g4 + PTL1_TPC] %asi ! !
1279 rdpr %tnpc, %g5 ! !
1280 stxa %g5, [%g4 + PTL1_TNPC] %asi ! !
1281 add %g4, PTL1_TRAP_REGS_INCR, %g4 ! !
1282 deccc %g1 ! !
1283 bnz,a,pt %icc, 0b ! if(trap_level != 0) --+ !
1284 wrpr %g1, %tl !
1285 1: ! ----------<----------------+
1287 ! %pstate, %pil, SOFTINT, (S)TICK
1288 ! Pending interrupts is also cleared in order to avoid a recursive call
1289 ! to ptl1_panic in case the interrupt handler causes a panic.
1291 rdpr %pil, %g1
1292 stba %g1, [%g3 + PTL1_PIL] %asi
1293 rdpr %pstate, %g1
1294 stha %g1, [%g3 + PTL1_PSTATE] %asi
1295 rd SOFTINT, %g1
1296 sta %g1, [%g3 + PTL1_SOFTINT] %asi
1297 wr %g1, CLEAR_SOFTINT
1298 sethi %hi(traptrace_use_stick), %g1
1299 ld [%g1 + %lo(traptrace_use_stick)], %g1
1300 brz,a,pn %g1, 2f
1301 rdpr %tick, %g1
1302 rd STICK, %g1
1303 2: stxa %g1, [%g3 + PTL1_TICK] %asi
1306 ! MMU registers because ptl1_panic may be called from
1307 ! the MMU trap handlers.
1309 mov MMU_SFAR, %g1
1310 ldxa [%g1]ASI_DMMU, %g4
1311 stxa %g4, [%g3 + PTL1_DMMU_SFAR]%asi
1312 mov MMU_SFSR, %g1
1313 ldxa [%g1]ASI_DMMU, %g4
1314 stxa %g4, [%g3 + PTL1_DMMU_SFSR]%asi
1315 ldxa [%g1]ASI_IMMU, %g4
1316 stxa %g4, [%g3 + PTL1_IMMU_SFSR]%asi
1317 mov MMU_TAG_ACCESS, %g1
1318 ldxa [%g1]ASI_DMMU, %g4
1319 stxa %g4, [%g3 + PTL1_DMMU_TAG_ACCESS]%asi
1320 ldxa [%g1]ASI_IMMU, %g4
1321 stxa %g4, [%g3 + PTL1_IMMU_TAG_ACCESS]%asi
1324 ! Save register window state and register windows.
1326 rdpr %cwp, %g1
1327 stba %g1, [%g3 + PTL1_CWP] %asi
1328 rdpr %wstate, %g1
1329 stba %g1, [%g3 + PTL1_WSTATE] %asi
1330 rdpr %otherwin, %g1
1331 stba %g1, [%g3 + PTL1_OTHERWIN] %asi
1332 rdpr %cleanwin, %g1
1333 stba %g1, [%g3 + PTL1_CLEANWIN] %asi
1334 rdpr %cansave, %g1
1335 stba %g1, [%g3 + PTL1_CANSAVE] %asi
1336 rdpr %canrestore, %g1
1337 stba %g1, [%g3 + PTL1_CANRESTORE] %asi
1339 PTL1_RESET_RWINDOWS(%g1)
1340 clr %g1
1341 wrpr %g1, %cwp
1342 add %g3, PTL1_RWINDOW, %g4 ! %g4 = &ptl1_rwindow[0];
1344 3: PTL1_SAVE_WINDOW(%g4) ! <-------------+
1345 inc %g1 !
1346 cmp %g1, MAXWIN !
1347 bgeu,pn %icc, 5f !
1348 wrpr %g1, %cwp !
1349 rdpr %cwp, %g2 !
1350 cmp %g1, %g2 ! saturation check
1351 be,pt %icc, 3b !
1352 PTL1_NEXT_WINDOW(%g4) ! ------+
1355 ! most crucial CPU state was saved.
1356 ! Proceed to go back to TL = 0.
1358 state_saved:
1359 wrpr %g0, 1, %tl
1360 wrpr %g0, PIL_MAX, %pil
1362 PTL1_RESET_RWINDOWS(%g1)
1363 wrpr %g0, %cwp
1364 wrpr %g0, %cleanwin
1365 wrpr %g0, WSTATE_KERN, %wstate
1367 ! Set pcontext to run kernel.
1369 ! For OPL, load kcontexreg instead of clearing primary
1370 ! context register. This is to avoid changing nucleus page
1371 ! size bits after boot initialization.
1373 #ifdef _OPL
1374 sethi %hi(kcontextreg), %g4
1375 ldx [%g4 + %lo(kcontextreg)], %g4
1376 #endif /* _OPL */
1378 set DEMAP_ALL_TYPE, %g1
1379 sethi %hi(FLUSH_ADDR), %g3
1380 set MMU_PCONTEXT, %g2
1382 stxa %g0, [%g1]ASI_DTLB_DEMAP
1383 stxa %g0, [%g1]ASI_ITLB_DEMAP
1385 #ifdef _OPL
1386 stxa %g4, [%g2]ASI_MMU_CTX
1387 #else /* _OPL */
1388 stxa %g0, [%g2]ASI_MMU_CTX
1389 #endif /* _OPL */
1391 flush %g3
1393 rdpr %cwp, %g1
1394 set TSTATE_KERN, %g3
1395 wrpr %g3, %g1, %tstate
1396 set ptl1_panic_tl0, %g3
1397 wrpr %g0, %g3, %tnpc
1398 done ! go to -->-+ TL:1
1400 ptl1_panic_tl0: ! ----<-----+ TL:0
1401 CPU_ADDR(%l0, %l1) ! %l0 = cpu[cpuid]
1402 add %l0, CPU_PTL1, %l1 ! %l1 = &CPU->mcpu.ptl1_state
1404 ! prepare to call panic()
1406 ldn [%l0 + CPU_THREAD], THREAD_REG ! restore %g7
1407 ldn [%l1 + PTL1_STKTOP], %l2 ! %sp = ptl1_stktop
1408 sub %l2, SA(MINFRAME) + STACK_BIAS, %sp
1409 clr %fp ! no frame below this window
1410 clr %i7
1412 ! enable limited interrupts
1414 wrpr %g0, CLOCK_LEVEL, %pil
1415 wrpr %g0, PSTATE_KERN, %pstate
1417 ba,pt %xcc, ptl1_panic_handler
1418 mov %l1, %o0
1419 /*NOTREACHED*/
1420 SET_SIZE(ptl1_panic)
1421 #endif /* lint */
1423 #ifdef PTL1_PANIC_DEBUG
1424 #if defined (lint)
1426 * ptl1_recurse() calls itself a number of times to either set up a known
1427 * stack or to cause a kernel stack overflow. It decrements the arguments
1428 * on each recursion.
1429 * It's called by #ifdef PTL1_PANIC_DEBUG code in startup.c to set the
1430 * registers to a known state to facilitate debugging.
1433 /* ARGSUSED */
1434 void
1435 ptl1_recurse(int count_threshold, int trap_threshold)
1438 #else /* lint */
1440 ENTRY_NP(ptl1_recurse)
1441 save %sp, -SA(MINFRAME), %sp
1443 set ptl1_recurse_call, %o7
1444 cmp %o7, %i7 ! if ptl1_recurse is called
1445 be,pt %icc, 0f ! by itself, then skip
1446 nop ! register initialization
1449 * Initialize Out Registers to Known Values
1451 set 0x01000, %l0 ! %i0 is the ...
1452 ! recursion_depth_count
1453 sub %i0, 1, %o0;
1454 sub %i1, 1, %o1;
1455 add %l0, %o0, %o2;
1456 add %l0, %o2, %o3;
1457 add %l0, %o3, %o4;
1458 add %l0, %o4, %o5;
1459 ba,a 1f
1462 0: /* Outs = Ins - 1 */
1463 sub %i0, 1, %o0;
1464 sub %i1, 1, %o1;
1465 sub %i2, 1, %o2;
1466 sub %i3, 1, %o3;
1467 sub %i4, 1, %o4;
1468 sub %i5, 1, %o5;
1470 /* Locals = Ins + 1 */
1471 1: add %i0, 1, %l0;
1472 add %i1, 1, %l1;
1473 add %i2, 1, %l2;
1474 add %i3, 1, %l3;
1475 add %i4, 1, %l4;
1476 add %i5, 1, %l5;
1478 set 0x0100000, %g5
1479 add %g5, %g0, %g1
1480 add %g5, %g1, %g2
1481 add %g5, %g2, %g3
1482 add %g5, %g3, %g4
1483 add %g5, %g4, %g5
1485 brz,pn %i1, ptl1_recurse_trap ! if trpp_count == 0) {
1486 nop ! trap to ptl1_panic
1488 brz,pn %i0, ptl1_recure_exit ! if(depth_count == 0) {
1489 nop ! skip recursive call
1491 ptl1_recurse_call:
1492 call ptl1_recurse
1495 ptl1_recure_exit:
1497 restore
1499 ptl1_recurse_trap:
1500 ta PTL1_DEBUG_TRAP; ! Trap Always to ptl1_panic()
1501 nop ! NOTREACHED
1502 SET_SIZE(ptl1_recurse)
1504 #endif /* lint */
1506 #if defined (lint)
1508 /* ARGSUSED */
1509 void
1510 ptl1_panic_xt(int arg1, int arg2)
1513 #else /* lint */
1515 * Asm function to handle a cross trap to call ptl1_panic()
1517 ENTRY_NP(ptl1_panic_xt)
1518 ba ptl1_panic
1519 mov PTL1_BAD_DEBUG, %g1
1520 SET_SIZE(ptl1_panic_xt)
1522 #endif /* lint */
1524 #endif /* PTL1_PANIC_DEBUG */
1526 #ifdef TRAPTRACE
1527 #if defined (lint)
1529 void
1530 trace_ptr_panic(void)
1534 #else /* lint */
1536 ENTRY_NP(trace_ptr_panic)
1538 ! freeze the trap trace to disable the assertions. Otherwise,
1539 ! ptl1_panic is likely to be repeatedly called from there.
1540 ! %g2 and %g3 are used as scratch registers in ptl1_panic.
1542 mov 1, %g3
1543 sethi %hi(trap_freeze), %g2
1544 st %g3, [%g2 + %lo(trap_freeze)]
1546 ! %g1 contains the %pc address where an assertion was failed.
1547 ! save it in trap_freeze_pc for a debugging hint if there is
1548 ! no value saved in it.
1550 set trap_freeze_pc, %g2
1551 casn [%g2], %g0, %g1
1553 ba ptl1_panic
1554 mov PTL1_BAD_TRACE_PTR, %g1
1555 SET_SIZE(trace_ptr_panic)
1557 #endif /* lint */
1558 #endif /* TRAPTRACE */
1560 #if defined (lint)
1562 * set_kcontextreg() sets PCONTEXT to kctx
1563 * if PCONTEXT==kctx, do nothing
1564 * if N_pgsz0|N_pgsz1 differ, do demap all first
1567 /* ARGSUSED */
1568 void
1569 set_kcontextreg()
1573 #else /* lint */
1575 ENTRY_NP(set_kcontextreg)
1576 ! SET_KCONTEXTREG(reg0, reg1, reg2, reg3, reg4, label1, label2, label3)
1577 SET_KCONTEXTREG(%o0, %o1, %o2, %o3, %o4, l1, l2, l3)
1578 retl
1580 SET_SIZE(set_kcontextreg)
1582 #endif /* lint */
1586 * The interface for a 32-bit client program that takes over the TBA
1587 * calling the 64-bit romvec OBP.
1590 #if defined(lint)
1592 /* ARGSUSED */
1594 client_handler(void *cif_handler, void *arg_array)
1595 { return 0; }
1597 #else /* lint */
1599 ENTRY(client_handler)
1600 save %sp, -SA64(MINFRAME64), %sp ! 32 bit frame, 64 bit sized
1601 sethi %hi(tba_taken_over), %l2
1602 ld [%l2+%lo(tba_taken_over)], %l3
1603 brz %l3, 1f ! is the tba_taken_over = 1 ?
1604 rdpr %wstate, %l5 ! save %wstate
1605 andn %l5, WSTATE_MASK, %l6
1606 wrpr %l6, WSTATE_KMIX, %wstate
1609 ! switch to PCONTEXT=0
1611 #ifndef _OPL
1612 mov MMU_PCONTEXT, %o2
1613 ldxa [%o2]ASI_DMMU, %o2
1614 srlx %o2, CTXREG_NEXT_SHIFT, %o2
1615 brz,pt %o2, 1f ! nucleus pgsz is 0, no problem
1617 rdpr %pstate, %l4 ! disable interrupts
1618 andn %l4, PSTATE_IE, %o2
1619 wrpr %g0, %o2, %pstate
1620 mov DEMAP_ALL_TYPE, %o2 ! set PCONTEXT=0
1621 stxa %g0, [%o2]ASI_DTLB_DEMAP
1622 stxa %g0, [%o2]ASI_ITLB_DEMAP
1623 mov MMU_PCONTEXT, %o2
1624 stxa %g0, [%o2]ASI_DMMU
1625 membar #Sync
1626 sethi %hi(FLUSH_ADDR), %o2
1627 flush %o2 ! flush required by immu
1628 wrpr %g0, %l4, %pstate ! restore interrupt state
1629 #endif /* _OPL */
1631 1: mov %i1, %o0
1632 rdpr %pstate, %l4 ! Get the present pstate value
1633 andn %l4, PSTATE_AM, %l6
1634 wrpr %l6, 0, %pstate ! Set PSTATE_AM = 0
1635 jmpl %i0, %o7 ! Call cif handler
1637 wrpr %l4, 0, %pstate ! restore pstate
1638 brz %l3, 1f ! is the tba_taken_over = 1
1640 wrpr %g0, %l5, %wstate ! restore wstate
1643 ! switch to PCONTEXT=kcontexreg
1645 #ifndef _OPL
1646 sethi %hi(kcontextreg), %o3
1647 ldx [%o3 + %lo(kcontextreg)], %o3
1648 brz %o3, 1f
1650 rdpr %pstate, %l4 ! disable interrupts
1651 andn %l4, PSTATE_IE, %o2
1652 wrpr %g0, %o2, %pstate
1653 mov DEMAP_ALL_TYPE, %o2
1654 stxa %g0, [%o2]ASI_DTLB_DEMAP
1655 stxa %g0, [%o2]ASI_ITLB_DEMAP
1656 mov MMU_PCONTEXT, %o2
1657 stxa %o3, [%o2]ASI_DMMU
1658 membar #Sync
1659 sethi %hi(FLUSH_ADDR), %o2
1660 flush %o2 ! flush required by immu
1661 wrpr %g0, %l4, %pstate ! restore interrupt state
1662 #endif /* _OPL */
1664 1: ret ! Return result ...
1665 restore %o0, %g0, %o0 ! delay; result in %o0
1666 SET_SIZE(client_handler)
1668 #endif /* lint */