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]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
29 #include <sys/types.h>
30 #include <sys/t_lock.h>
31 #include <sys/promif.h>
32 #include <sys/prom_isa.h>
35 #include <sys/asm_linkage.h>
36 #include <sys/intreg.h>
37 #include <sys/ivintr.h>
39 #include <sys/machpcb.h>
40 #include <sys/machtrap.h>
41 #include <sys/machlock.h>
42 #include <sys/fdreg.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>
51 #include <sys/thread.h>
60 ! REGOFF must
add up to allow double word access to r_tstate.
61 ! PCB_WBUF must also
be aligned.
64 #error "struct regs not aligned"
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).
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
110 .type t0stack, #object
112 .skip T0STKSZ ! thread 0 stack
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.
125 .size cpu0, CPU_ALLOC_SIZE
128 .align PTR24_ALIGN ! alignment for mutex.
131 .skip THREAD_SIZE ! thread 0
132 .size t0, THREAD_SIZE
135 .global trap_trace_ctl
137 .global trap_trace_bufsize
139 .global trap_freeze_pc
143 .word TRAP_TSIZE ! default trap buffer size
149 .skip NCPU * TRAPTR_SIZE ! NCPU control headers
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.
162 #endif /* TRAPTRACE */
189 .global nwindows, nwin_minus_one, winmask
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
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;
216 * the bootops vector is in the third argument (%o1)
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
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
244 ! call krtld to link the world together
249 CLEARTICKNPT
! allow user rdtick
251 ! Get maxwin from
%ver
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
)]
262 sethi
%hi
(nwindows
), %g2
263 st %g1
, [%g2
+ %lo
(nwindows
)]
267 sethi
%hi
(winmask
), %g4
268 st %g2
, [%g4
+ %lo
(winmask
)]
271 ! save
a pointer to obp
's tba for later use by kmdb
278 ! copy obp's breakpoint
trap entry to obp_bpt
281 set T_SOFTWARE_TRAP | ST_MON_BREAKPOINT
, %g2
299 ! Initialize thread
0's stack.
301 set t0stacktop, %g1 ! setup kernel stack pointer
302 sub %g1, SA(KFPUSIZE+GSR_SIZE), %g2
305 sub %o1, SA(MPCBSIZE) + STACK_BIAS, %sp
308 ! Initialize global thread register.
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.
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
332 ! Call mlsetup with address of prototype user registers.
335 add %sp
, REGOFF
+ STACK_BIAS
, %o0
337 #if (REGOFF != MPCB_REGS)
338 #error "hole in struct machpcb between frame and regs?"
342 ! Now call main. We will return as process
1 (init
).
348 ! Main should never return.
356 .asciz "main returned"
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.
371 * %pstate am:0 priv:1 ie:0
372 * globals are either ag or ig (not mg!)
375 * %g1 pc of trap handler
376 * %g2, %g3 args for handler
377 * %g4 desired %pil (-1 means current %pil)
384 * %l6 curthread for user traps, %pil for priv traps
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])
407 ! force tl
=1, update
%cwp
, branch to correct handler
411 btst TSTATE_PRIV
, %g5
412 and %g5
, TSTATE_CWP
, %g6
413 bnz
,pn
%xcc
, priv_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
427 ldn [%g5 + CPU_THREAD], %g5
428 ldn [%g5 + T_STACK], %g6
429 sub %g6, STACK_BIAS, %g6
432 ! set window registers so that current windows are "other" windows
434 rdpr %canrestore, %l0
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
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
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
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
483 stn %l0, [%l7 + PC_OFF]
484 stn %l1, [%l7 + nPC_OFF]
485 stx %l2, [%l7 + TSTATE_OFF]
493 ! ASSERT(%g4 >= %pil).
498 nop ! yes, nop; to avoid anull
499 set bad_g4_called, %l3
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
512 ! set trap regs to execute in kernel at %g6
513 ! done resumes execution there
518 wrpr %l1, %l0, %tstate
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 */
534 ba,a,pt %xcc, have_win
540 ! buy a window on the current stack
542 ! is the trap PC in the range allocated to Open Firmware?
544 set OFW_END_ADDR, %g6
548 set OFW_START_ADDR, %g6
550 bgeu,pn %xcc, prom_trap
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
562 ! primary context is of kernel.
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.
575 srlx %g5, VER_MAXTL_SHIFT, %g5
576 and %g5, VER_MAXTL_MASK, %g5 ! %g5 = MAXTL
579 mov PTL1_BAD_CTX, %g1
580 ba,a,pt %xcc, ptl1_panic
587 wrpr %g0, PSTATE_KERN, %pstate ! enable ints
588 jmpl %l3, %o7 ! call trap handler
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
606 ld [%sp + STACK_BIAS + MPCB_WBCNT], %l3
608 ! call trap to do ast processing
610 wrpr %g0, %l4, %pil ! pil = cpu_base_spl
614 ba,a,pt %xcc, user_rtt
619 ! call restore_wbuf to push wbuf windows to stack
621 wrpr %g0, %l4, %pil ! pil = cpu_base_spl
625 ba,a,pt %xcc, user_rtt
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
636 wrpr %l1, PSTATE_IE, %pstate
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
643 ! set %pil from cpu_base_spl
647 ! raise tl (now using nucleus context)
651 ! switch "other" windows back to "normal" windows.
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.
683 .global rtt_ctx_start
688 ldn [%l7 + PC_OFF], %g3
689 ldn [%l7 + nPC_OFF], %g2
690 ldx [%l7 + TSTATE_OFF], %l0
691 andn %l0, TSTATE_CWP, %g7
696 ! Restore to window we originally trapped in.
697 ! First attempt to restore from the watchpoint saved register window
701 clrn [%g6 + STACK_BIAS + MPCB_RSP0]
704 clrn [%g6 + STACK_BIAS + MPCB_RSP0]
705 ! test for user return window in pcb
706 ldn [%g6 + STACK_BIAS + MPCB_RSP0], %g1
709 clrn [%g6 + STACK_BIAS + MPCB_RSP0]
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
718 clrn [%g6 + STACK_BIAS + MPCB_RSP1]
719 ldn [%g6 + STACK_BIAS + MPCB_RSP1], %g1
722 clrn [%g6 + STACK_BIAS + MPCB_RSP1]
725 RESTORE_V9WINDOW(%g6 + STACK_BIAS + MPCB_RWIN1)
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
739 wrpr %g1, %g7, %tstate
751 ldn [%g5 + CPU_THREAD], THREAD_REG
752 wrpr %g0, PSTATE_KERN, %pstate ! enable ints
753 jmpl %l3, %o7 ! call trap handler
758 TRACE_RTT(TT_SYS_RTT_PROM, %l0, %l1, %l2, %l3)
759 #endif /* TRAPTRACE */
760 ba,pt %xcc, common_rtt
767 SAVE_OUTS(%l7) ! for the call bug workaround
768 wrpr %g0, PSTATE_KERN, %pstate ! enable ints
769 jmpl %l3, %o7 ! call trap handler
774 TRACE_RTT(TT_SYS_RTT_PRIV, %l0, %l1, %l2, %l3)
775 #endif /* TRAPTRACE */
781 ! Check for a kernel preemption request
783 ldn [THREAD_REG + T_CPU], %l0
784 ldub [%l0 + CPU_KPRUNRUN], %l0
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.
..
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
812 cmp %l0
, mutex_owner_running_critical_size
815 stn
%l1
, [%l7
+ PC_OFF
] ! restart mutex_owner_running
()
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
829 cmp %l0
, mutex_exit_critical_size
830 bgeu
,pt
%xcc
, common_rtt
832 stn
%l1
, [%l7
+ PC_OFF
] ! restart mutex_exit
()
834 stn
%l1
, [%l7
+ nPC_OFF
]
838 ! restore globals
and outs
841 wrpr
%l1
, PSTATE_IE
, %pstate
843 ! switch to alternate globals
844 wrpr
%l1
, PSTATE_IE | PSTATE_AG
, %pstate
847 ! set
%pil from max
(old pil
, cpu_base_spl
)
849 ldn
[%l0
+ T_CPU
], %l0
850 ld [%l0
+ CPU_BASE_SPL
], %l0
857 ! restore to window we originally trapped in
860 ldn
[%l7
+ PC_OFF
], %g1
861 ldn
[%l7
+ nPC_OFF
], %g2
862 ldx [%l7
+ TSTATE_OFF
], %l0
863 andn
%l0
, TSTATE_CWP
, %g7
868 ! set
%tstate to the correct
%cwp
869 ! retry resumes prom execution
872 wrpr
%g1
, %g7
, %tstate
886 .global bad_g4_called
891 .asciz "sys_trap: %g4(%d) is lower than %pil(%d)"
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.
916 ENTRY_NP
(sys_tl1_panic
)
921 SET_SIZE
(sys_tl1_panic
)
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.
939 set_auxioreg
(int bit
, int flag
)
947 .asciz "set_auxioreg: interrupts already disabled on entry"
951 ENTRY_NP
(set_auxioreg
)
954 * o1 = flag: 0 = off, otherwise on
956 * disable interrupts while updating auxioreg
960 andcc
%o2
, PSTATE_IE
, %g0
/* if interrupts already */
961 bnz
,a,pt
%icc
, 1f
/* disabled, panic */
963 sethi
%hi
(auxio_panic
), %o0
965 or %o0
, %lo
(auxio_panic
), %o0
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 */
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 */
980 wrpr
%g0
, %o2
, %pstate
/* enable interrupt */
981 SET_SIZE
(set_auxioreg
)
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.
1000 ENTRY_NP
(flush_windows
)
1003 SET_SIZE
(flush_windows
)
1010 debug_flush_windows
(void
)
1015 ENTRY_NP
(debug_flush_windows
)
1021 save
%sp
, -WINDOWSIZE
, %sp
1034 SET_SIZE
(debug_flush_windows
)
1039 * flush user windows to memory.
1045 flush_user_windows
(void
)
1050 ENTRY_NP
(flush_user_windows
)
1055 save
%sp
, -WINDOWSIZE
, %sp
1060 sub %g2
, 1, %g2
! restore back to orig window
1066 SET_SIZE
(flush_user_windows
)
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
1080 trash_user_windows
(void
)
1085 ENTRY_NP
(trash_user_windows
)
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
1097 wrpr %g2, PSTATE_IE, %pstate
1099 rdpr %otherwin, %g1 ! re-read in case of interrupt
1101 wrpr %g0, 0, %otherwin
1102 wrpr %g0, %g3, %cansave
1103 wrpr %g0, %g2, %pstate
1106 clr [%g5 + MPCB_WBCNT] ! zero window buffer cnt
1107 SET_SIZE(trash_user_windows)
1113 * Setup g7 via the CPU data structure.
1118 set_tbr(struct scb *s)
1125 ta 72 ! no tbr, stop simulation
1133 * These need to be defined somewhere to lint and there is no "hicore.s"...
1135 char etext[1], end[1];
1142 ptl1_panic(u_int reason)
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; \
1172 wrpr scr, %cansave; \
1173 wrpr %g0, %canrestore; \
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
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
1213 ! For FJ OPL processors (IMPL values < SPITFIRE_IMPL), DC flushing
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
1225 0: stxa %g0, [%g2] ASI_DC_TAG
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
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]
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
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 ! !
1274 stwa %g5, [%g4 + PTL1_TT] %asi ! !
1275 rdpr %tstate, %g5 ! !
1276 stxa %g5, [%g4 + PTL1_TSTATE] %asi ! !
1278 stxa %g5, [%g4 + PTL1_TPC] %asi ! !
1280 stxa %g5, [%g4 + PTL1_TNPC] %asi ! !
1281 add %g4, PTL1_TRAP_REGS_INCR, %g4 ! !
1283 bnz,a,pt %icc, 0b ! if(trap_level != 0) --+ !
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.
1292 stba %g1, [%g3 + PTL1_PIL] %asi
1294 stha %g1, [%g3 + PTL1_PSTATE] %asi
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
1303 2: stxa %g1, [%g3 + PTL1_TICK] %asi
1306 ! MMU registers because ptl1_panic may be called from
1307 ! the MMU trap handlers.
1310 ldxa [%g1]ASI_DMMU, %g4
1311 stxa %g4, [%g3 + PTL1_DMMU_SFAR]%asi
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.
1327 stba %g1, [%g3 + PTL1_CWP] %asi
1329 stba %g1, [%g3 + PTL1_WSTATE] %asi
1331 stba %g1, [%g3 + PTL1_OTHERWIN] %asi
1333 stba %g1, [%g3 + PTL1_CLEANWIN] %asi
1335 stba %g1, [%g3 + PTL1_CANSAVE] %asi
1336 rdpr %canrestore, %g1
1337 stba %g1, [%g3 + PTL1_CANRESTORE] %asi
1339 PTL1_RESET_RWINDOWS(%g1)
1342 add %g3, PTL1_RWINDOW, %g4 ! %g4 = &ptl1_rwindow[0];
1344 3: PTL1_SAVE_WINDOW(%g4) ! <-------------+
1350 cmp %g1, %g2 ! saturation check
1352 PTL1_NEXT_WINDOW(%g4) ! ------+
1355 ! most crucial CPU state was saved.
1356 ! Proceed to go back to TL = 0.
1360 wrpr %g0, PIL_MAX, %pil
1362 PTL1_RESET_RWINDOWS(%g1)
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.
1374 sethi %hi(kcontextreg), %g4
1375 ldx [%g4 + %lo(kcontextreg)], %g4
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
1386 stxa %g4, [%g2]ASI_MMU_CTX
1388 stxa %g0, [%g2]ASI_MMU_CTX
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
1412 ! enable limited interrupts
1414 wrpr %g0, CLOCK_LEVEL, %pil
1415 wrpr %g0, PSTATE_KERN, %pstate
1417 ba,pt %xcc, ptl1_panic_handler
1420 SET_SIZE(ptl1_panic)
1423 #ifdef PTL1_PANIC_DEBUG
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.
1435 ptl1_recurse
(int count_threshold
, int trap_threshold
)
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
1462 0: /* Outs = Ins - 1 */
1470 /* Locals = Ins + 1 */
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
1500 ta PTL1_DEBUG_TRAP;
! Trap Always to ptl1_panic
()
1502 SET_SIZE
(ptl1_recurse
)
1510 ptl1_panic_xt
(int arg1
, int arg2
)
1515 * Asm function to handle a cross trap to call ptl1_panic()
1517 ENTRY_NP
(ptl1_panic_xt
)
1519 mov PTL1_BAD_DEBUG
, %g1
1520 SET_SIZE
(ptl1_panic_xt
)
1524 #endif /* PTL1_PANIC_DEBUG */
1530 trace_ptr_panic
(void
)
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.
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
1554 mov PTL1_BAD_TRACE_PTR
, %g1
1555 SET_SIZE
(trace_ptr_panic
)
1558 #endif /* TRAPTRACE */
1562 * set_kcontextreg() sets PCONTEXT to kctx
1563 * if PCONTEXT==kctx, do nothing
1564 * if N_pgsz0|N_pgsz1 differ, do demap all first
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
)
1580 SET_SIZE
(set_kcontextreg
)
1586 * The interface for a 32-bit client program that takes over the TBA
1587 * calling the 64-bit romvec OBP.
1594 client_handler
(void
*cif_handler
, void
*arg_array
)
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
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
1626 sethi
%hi
(FLUSH_ADDR
), %o2
1627 flush
%o2
! flush required by immu
1628 wrpr
%g0
, %l4
, %pstate
! restore interrupt state
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
1646 sethi
%hi
(kcontextreg
), %o3
1647 ldx [%o3
+ %lo
(kcontextreg
)], %o3
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
1659 sethi
%hi
(FLUSH_ADDR
), %o2
1660 flush
%o2
! flush required by immu
1661 wrpr
%g0
, %l4
, %pstate
! restore interrupt state
1664 1: ret
! Return result
...
1665 restore
%o0
, %g0
, %o0
! delay; result in
%o0
1666 SET_SIZE
(client_handler
)