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
65 PROM = 0xFFE00000 ! address of prom virtual area
66 panicbuf = 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
80 intr_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
96 t0stack:
97 .skip T0STKSZ ! thread 0 stack
98 t0stacktop:
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
107 cpu0:
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
115 t0:
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
127 trap_trace_bufsize:
128 .word TRAP_TSIZE ! default trap buffer size
129 trap_freeze:
130 .word 0
131
132 .align 64
133 trap_trace_ctl:
134 .skip NCPU * TRAPTR_SIZE ! NCPU control headers
135
136 .align 16
137 trap_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
145 trap_freeze_pc:
146 .nword 0
147 #endif /* TRAPTRACE */
148
149 .align 4
150 .seg ".text"
151
152 #ifdef NOPROM
153 .global availmem
154 availmem:
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
165 nwindows:
166 .word 8
167 nwin_minus_one:
168 .word 7
169 winmask:
170 .word 8
171
172 .global afsrbuf
173 afsrbuf:
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
419 2:
420 stxa %l0, [%l1]ASI_MMU_CTX
421 flush %l3 ! flush required by immu
422 1:
423
424 set utl0, %g6 ! bounce to utl0
425 have_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
472 0:
473 #endif /* DEBUG */
474 wrpr %g0, %g4, %pil
475 1:
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
517 1:
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
532 2:
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
580 1:
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
591 2:
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
649 rtt_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
693 1:
694 restore ! should not trap
695 2:
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
707 rtt_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
768 1:
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
785 2:
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
801 common_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
848 bad_g4_called:
849 .word 0
850
851 sys_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
889 auxio_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
909 1:
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 */
919 2:
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
943 1:
944 save %sp, -WINDOWSIZE, %sp
945 brnz %g2, 1b
946 dec %g2
947
948 mov %g1, %g2
949 2:
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
967 1:
968 save %sp, -WINDOWSIZE, %sp
969 rdpr %otherwin, %g1
970 brnz %g1, 1b
971 add %g2, 1, %g2
972 2:
973 sub %g2, 1, %g2 ! restore back to orig window
974 brnz %g2, 2b
975 restore
976 3:
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
1007 3:
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
1101 0: stxa %g0, [%g2] ASI_DC_TAG
1102 membar #Sync
1103 brnz,pt %g2, 0b
1104 sub %g2, %g3, %g2
1105 1:
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 !
1130 save_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]; !
1147 0: ! -----------<----------+ !
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 !
1161 1: ! ----------<----------------+
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
1179 2: 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
1220 3: 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) ! ------+
1229 5:
1230 !
1231 ! most crucial CPU state was saved.
1232 ! Proceed to go back to TL = 0.
1233 !
1234 state_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 !
1276 ptl1_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
1329 0: /* 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 */
1338 1: 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 ! }
1358 ptl1_recurse_call:
1359 call ptl1_recurse
1360 nop
1361
1362 ptl1_recure_exit:
1363 ret
1364 restore
1365
1366 ptl1_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
1454 1: 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
1487 1: ret ! Return result ...
1488 restore %o0, %g0, %o0 ! delay; result in %o0
1489 SET_SIZE(client_handler)
1490