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 #pragma ident "%Z%%M% %I% %E% SMI"
27
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 */
34
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)
50
51 #include <sys/thread.h>
52 #include <sys/time.h>
53
54 #else /* lint */
55
56 #include "assym.h"
57
58
59 !
60 ! REGOFF must add up to allow double word access to r_tstate.
61 ! PCB_WBUF must also be aligned.
62 !
63 #if (REGOFF & 7) != 0
64 #error "struct regs not aligned"
65 #endif
66
67 /*
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).
75 */
157 * show in which TRACE_PTR the assertion failure happened.
158 */
159 .align 8
160 trap_freeze_pc:
161 .nword 0
162 #endif /* TRAPTRACE */
163
164 .align 4
165 .seg ".text"
166
167 #ifdef NOPROM
168 .global availmem
169 availmem:
170 .word 0
171 #endif /* NOPROM */
172
173 .align 8
174 _local_p1275cis:
175 .nword 0
176
177 #endif /* lint */
178
179 #if defined(lint)
180
181 void
182 _start(void)
183 {}
184
185 #else /* lint */
186
187 .seg ".data"
188
189 .global nwindows, nwin_minus_one, winmask
190 nwindows:
191 .word 8
192 nwin_minus_one:
193 .word 7
194 winmask:
195 .word 8
196
197 .global afsrbuf
198 afsrbuf:
199 .word 0,0,0,0
200
201 /*
202 * System initialization
203 *
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
339 #endif
340
341 !
342 ! Now call main. We will return as process 1 (init).
343 !
344 call main
345 nop
346
347 !
348 ! Main should never return.
349 !
350 set .mainretmsg, %o0
351 call panic
352 nop
353 SET_SIZE(_start)
354
355 .mainretmsg:
356 .asciz "main returned"
357 .align 4
358
359 #endif /* lint */
360
361
362 /*
363 * Generic system trap handler.
364 *
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.
369 *
370 * Entry Conditions:
371 * %pstate am:0 priv:1 ie:0
372 * globals are either ag or ig (not mg!)
373 *
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
380 *
381 * Register Usage:
382 * %l0, %l1 temps
383 * %l3 saved %g1
384 * %l6 curthread for user traps, %pil for priv traps
385 * %l7 regs
386 *
387 * Called function prototype variants:
388 *
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])
395 */
396
397 #if defined(lint)
398
399 void
400 sys_trap(void)
401 {}
402
403 #else /* lint */
404
405 ENTRY_NP(sys_trap)
406 !
407 ! force tl=1, update %cwp, branch to correct handler
408 !
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
415
416 ALTENTRY(user_trap)
417 !
418 ! user trap
419 !
420 ! make all windows clean for kernel
421 ! buy a window using the current thread's stack
422 !
423 sethi %hi(nwin_minus_one), %g5
424 ld [%g5 + %lo(nwin_minus_one)], %g5
858 !
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
867 !
868 ! set %tstate to the correct %cwp
869 ! retry resumes prom execution
870 !
871 rdpr %cwp, %g1
872 wrpr %g1, %g7, %tstate
873 retry
874 /* NOTREACHED */
875 SET_SIZE(priv_rtt)
876 SET_SIZE(ktl0)
877
878 #endif /* lint */
879
880 #ifndef lint
881
882 #ifdef DEBUG
883 .seg ".data"
884 .align 4
885
886 .global bad_g4_called
887 bad_g4_called:
888 .word 0
889
890 sys_trap_wrong_pil:
891 .asciz "sys_trap: %g4(%d) is lower than %pil(%d)"
892 .align 4
893 .seg ".text"
894
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 */
903
904 /*
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.
908 */
909 #if defined(lint)
910
911 void
912 sys_tl1_panic(void)
913 {}
914
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 */
923
924 /*
925 * Turn on or off bits in the auxiliary i/o register.
926 *
927 * set_auxioreg(bit, flag)
928 * int bit; bit mask in aux i/o reg
929 * int flag; 0 = off, otherwise on
930 *
931 * This is intrinsicly ugly but is used by the floppy driver. It is also
932 * used to turn on/off the led.
933 */
934
935 #if defined(lint)
936
937 /* ARGSUSED */
938 void
939 set_auxioreg(int bit, int flag)
940 {}
941
942 #else /* lint */
943
944 .seg ".data"
945 .align 4
946 auxio_panic:
947 .asciz "set_auxioreg: interrupts already disabled on entry"
948 .align 4
949 .seg ".text"
950
951 ENTRY_NP(set_auxioreg)
952 /*
953 * o0 = bit mask
954 * o1 = flag: 0 = off, otherwise on
955 *
956 * disable interrupts while updating auxioreg
957 */
958 rdpr %pstate, %o2
959 #ifdef DEBUG
960 andcc %o2, PSTATE_IE, %g0 /* if interrupts already */
961 bnz,a,pt %icc, 1f /* disabled, panic */
962 nop
963 sethi %hi(auxio_panic), %o0
964 call panic
965 or %o0, %lo(auxio_panic), %o0
966 1:
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 */
976 2:
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)
982
983 #endif /* lint */
984
985 /*
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.
990 */
991
992 #if defined(lint)
993
994 void
995 flush_windows(void)
996 {}
997
998 #else /* lint */
999
1000 ENTRY_NP(flush_windows)
1001 retl
1002 flushw
1003 SET_SIZE(flush_windows)
1004
1005 #endif /* lint */
1006
1007 #if defined(lint)
1008
1009 void
1010 debug_flush_windows(void)
1011 {}
1012
1013 #else /* lint */
1014
1015 ENTRY_NP(debug_flush_windows)
1016 set nwindows, %g1
1017 ld [%g1], %g1
1018 mov %g1, %g2
1019
1020 1:
1021 save %sp, -WINDOWSIZE, %sp
1022 brnz %g2, 1b
1023 dec %g2
1024
1025 mov %g1, %g2
1026 2:
1027 restore
1028 brnz %g2, 2b
1029 dec %g2
1030
1031 retl
1032 nop
1033
1034 SET_SIZE(debug_flush_windows)
1035
1036 #endif /* lint */
1037
1038 /*
1039 * flush user windows to memory.
1040 */
1041
1042 #if defined(lint)
1043
1044 void
1045 flush_user_windows(void)
1046 {}
1047
1048 #else /* lint */
1049
1050 ENTRY_NP(flush_user_windows)
1051 rdpr %otherwin, %g1
1052 brz %g1, 3f
1053 clr %g2
1054 1:
1055 save %sp, -WINDOWSIZE, %sp
1056 rdpr %otherwin, %g1
1057 brnz %g1, 1b
1058 add %g2, 1, %g2
1059 2:
1060 sub %g2, 1, %g2 ! restore back to orig window
1061 brnz %g2, 2b
1062 restore
1063 3:
1064 retl
1065 nop
1066 SET_SIZE(flush_user_windows)
1067
1068 #endif /* lint */
1069
1070 /*
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.
1075 */
1076
1077 #if defined(lint)
1078
1079 void
1080 trash_user_windows(void)
1081 {}
1082
1083 #else /* lint */
1084
1085 ENTRY_NP(trash_user_windows)
1086 rdpr %otherwin, %g1
1087 brz %g1, 3f ! no user windows?
1088 ldn [THREAD_REG + T_STACK], %g5
1089
1090 !
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.
1095 !
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
1104 3:
1105 retl
1106 clr [%g5 + MPCB_WBCNT] ! zero window buffer cnt
1107 SET_SIZE(trash_user_windows)
1108
1109
1110 #endif /* lint */
1111
1112 /*
1113 * Setup g7 via the CPU data structure.
1114 */
1115 #if defined(lint)
1116
1117 struct scb *
1118 set_tbr(struct scb *s)
1119 { return (s); }
1120
1121 #else /* lint */
1122
1123 ENTRY_NP(set_tbr)
1124 retl
1125 ta 72 ! no tbr, stop simulation
1126 SET_SIZE(set_tbr)
1127
1128 #endif /* lint */
1129
1130
1131 #if defined(lint)
1132 /*
1133 * These need to be defined somewhere to lint and there is no "hicore.s"...
1134 */
1135 char etext[1], end[1];
1136 #endif /* lint*/
1137
1138 #if defined (lint)
1139
1140 /* ARGSUSED */
1141 void
1142 ptl1_panic(u_int reason)
1143 {}
1144
1145 #else /* lint */
1146
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
1166
1401 CPU_ADDR(%l0, %l1) ! %l0 = cpu[cpuid]
1402 add %l0, CPU_PTL1, %l1 ! %l1 = &CPU->mcpu.ptl1_state
1403 !
1404 ! prepare to call panic()
1405 !
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
1411 !
1412 ! enable limited interrupts
1413 !
1414 wrpr %g0, CLOCK_LEVEL, %pil
1415 wrpr %g0, PSTATE_KERN, %pstate
1416 !
1417 ba,pt %xcc, ptl1_panic_handler
1418 mov %l1, %o0
1419 /*NOTREACHED*/
1420 SET_SIZE(ptl1_panic)
1421 #endif /* lint */
1422
1423 #ifdef PTL1_PANIC_DEBUG
1424 #if defined (lint)
1425 /*
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.
1431 */
1432
1433 /* ARGSUSED */
1434 void
1435 ptl1_recurse(int count_threshold, int trap_threshold)
1436 {}
1437
1438 #else /* lint */
1439
1440 ENTRY_NP(ptl1_recurse)
1441 save %sp, -SA(MINFRAME), %sp
1442
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
1447
1448 /*
1449 * Initialize Out Registers to Known Values
1450 */
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
1484
1485 brz,pn %i1, ptl1_recurse_trap ! if trpp_count == 0) {
1486 nop ! trap to ptl1_panic
1487 !
1488 brz,pn %i0, ptl1_recure_exit ! if(depth_count == 0) {
1489 nop ! skip recursive call
1490 ! }
1491 ptl1_recurse_call:
1492 call ptl1_recurse
1493 nop
1494
1495 ptl1_recure_exit:
1496 ret
1497 restore
1498
1499 ptl1_recurse_trap:
1500 ta PTL1_DEBUG_TRAP; ! Trap Always to ptl1_panic()
1501 nop ! NOTREACHED
1502 SET_SIZE(ptl1_recurse)
1503
1504 #endif /* lint */
1505
1506 #if defined (lint)
1507
1508 /* ARGSUSED */
1509 void
1510 ptl1_panic_xt(int arg1, int arg2)
1511 {}
1512
1513 #else /* lint */
1514 /*
1515 * Asm function to handle a cross trap to call ptl1_panic()
1516 */
1517 ENTRY_NP(ptl1_panic_xt)
1518 ba ptl1_panic
1519 mov PTL1_BAD_DEBUG, %g1
1520 SET_SIZE(ptl1_panic_xt)
1521
1522 #endif /* lint */
1523
1524 #endif /* PTL1_PANIC_DEBUG */
1525
1526 #ifdef TRAPTRACE
1527 #if defined (lint)
1528
1529 void
1530 trace_ptr_panic(void)
1531 {
1532 }
1533
1534 #else /* lint */
1535
1536 ENTRY_NP(trace_ptr_panic)
1537 !
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.
1541 !
1542 mov 1, %g3
1543 sethi %hi(trap_freeze), %g2
1544 st %g3, [%g2 + %lo(trap_freeze)]
1545 !
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.
1549 !
1550 set trap_freeze_pc, %g2
1551 casn [%g2], %g0, %g1
1552
1553 ba ptl1_panic
1554 mov PTL1_BAD_TRACE_PTR, %g1
1555 SET_SIZE(trace_ptr_panic)
1556
1557 #endif /* lint */
1558 #endif /* TRAPTRACE */
1559
1560 #if defined (lint)
1561 /*
1562 * set_kcontextreg() sets PCONTEXT to kctx
1563 * if PCONTEXT==kctx, do nothing
1564 * if N_pgsz0|N_pgsz1 differ, do demap all first
1565 */
1566
1567 /* ARGSUSED */
1568 void
1569 set_kcontextreg()
1570 {
1571 }
1572
1573 #else /* lint */
1574
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
1579 nop
1580 SET_SIZE(set_kcontextreg)
1581
1582 #endif /* lint */
1583
1584
1585 /*
1586 * The interface for a 32-bit client program that takes over the TBA
1587 * calling the 64-bit romvec OBP.
1588 */
1589
1590 #if defined(lint)
1591
1592 /* ARGSUSED */
1593 int
1594 client_handler(void *cif_handler, void *arg_array)
1595 { return 0; }
1596
1597 #else /* lint */
1598
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
1607
1608 !
1609 ! switch to PCONTEXT=0
1610 !
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
1616 nop
1617 rdpr %pstate, %l4 ! disable interrupts
1618 andn %l4, PSTATE_IE, %o2
1647 ldx [%o3 + %lo(kcontextreg)], %o3
1648 brz %o3, 1f
1649 nop
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 */
1663
1664 1: ret ! Return result ...
1665 restore %o0, %g0, %o0 ! delay; result in %o0
1666 SET_SIZE(client_handler)
1667
1668 #endif /* lint */
1669
|
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 */
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
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
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
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 ENTRY_NP(ptl1_recurse)
1301 save %sp, -SA(MINFRAME), %sp
1302
1303 set ptl1_recurse_call, %o7
1304 cmp %o7, %i7 ! if ptl1_recurse is called
1305 be,pt %icc, 0f ! by itself, then skip
1306 nop ! register initialization
1307
1308 /*
1309 * Initialize Out Registers to Known Values
1310 */
1311 set 0x01000, %l0 ! %i0 is the ...
1312 ! recursion_depth_count
1313 sub %i0, 1, %o0;
1314 sub %i1, 1, %o1;
1315 add %l0, %o0, %o2;
1316 add %l0, %o2, %o3;
1317 add %l0, %o3, %o4;
1318 add %l0, %o4, %o5;
1319 ba,a 1f
1344
1345 brz,pn %i1, ptl1_recurse_trap ! if trpp_count == 0) {
1346 nop ! trap to ptl1_panic
1347 !
1348 brz,pn %i0, ptl1_recure_exit ! if(depth_count == 0) {
1349 nop ! skip recursive call
1350 ! }
1351 ptl1_recurse_call:
1352 call ptl1_recurse
1353 nop
1354
1355 ptl1_recure_exit:
1356 ret
1357 restore
1358
1359 ptl1_recurse_trap:
1360 ta PTL1_DEBUG_TRAP; ! Trap Always to ptl1_panic()
1361 nop ! NOTREACHED
1362 SET_SIZE(ptl1_recurse)
1363
1364 /*
1365 * Asm function to handle a cross trap to call ptl1_panic()
1366 */
1367 ENTRY_NP(ptl1_panic_xt)
1368 ba ptl1_panic
1369 mov PTL1_BAD_DEBUG, %g1
1370 SET_SIZE(ptl1_panic_xt)
1371
1372 #endif /* PTL1_PANIC_DEBUG */
1373
1374 #ifdef TRAPTRACE
1375
1376 ENTRY_NP(trace_ptr_panic)
1377 !
1378 ! freeze the trap trace to disable the assertions. Otherwise,
1379 ! ptl1_panic is likely to be repeatedly called from there.
1380 ! %g2 and %g3 are used as scratch registers in ptl1_panic.
1381 !
1382 mov 1, %g3
1383 sethi %hi(trap_freeze), %g2
1384 st %g3, [%g2 + %lo(trap_freeze)]
1385 !
1386 ! %g1 contains the %pc address where an assertion was failed.
1387 ! save it in trap_freeze_pc for a debugging hint if there is
1388 ! no value saved in it.
1389 !
1390 set trap_freeze_pc, %g2
1391 casn [%g2], %g0, %g1
1392
1393 ba ptl1_panic
1394 mov PTL1_BAD_TRACE_PTR, %g1
1395 SET_SIZE(trace_ptr_panic)
1396
1397 #endif /* TRAPTRACE */
1398
1399 ENTRY_NP(set_kcontextreg)
1400 ! SET_KCONTEXTREG(reg0, reg1, reg2, reg3, reg4, label1, label2, label3)
1401 SET_KCONTEXTREG(%o0, %o1, %o2, %o3, %o4, l1, l2, l3)
1402 retl
1403 nop
1404 SET_SIZE(set_kcontextreg)
1405
1406
1407 /*
1408 * The interface for a 32-bit client program that takes over the TBA
1409 * calling the 64-bit romvec OBP.
1410 */
1411
1412 ENTRY(client_handler)
1413 save %sp, -SA64(MINFRAME64), %sp ! 32 bit frame, 64 bit sized
1414 sethi %hi(tba_taken_over), %l2
1415 ld [%l2+%lo(tba_taken_over)], %l3
1416 brz %l3, 1f ! is the tba_taken_over = 1 ?
1417 rdpr %wstate, %l5 ! save %wstate
1418 andn %l5, WSTATE_MASK, %l6
1419 wrpr %l6, WSTATE_KMIX, %wstate
1420
1421 !
1422 ! switch to PCONTEXT=0
1423 !
1424 #ifndef _OPL
1425 mov MMU_PCONTEXT, %o2
1426 ldxa [%o2]ASI_DMMU, %o2
1427 srlx %o2, CTXREG_NEXT_SHIFT, %o2
1428 brz,pt %o2, 1f ! nucleus pgsz is 0, no problem
1429 nop
1430 rdpr %pstate, %l4 ! disable interrupts
1431 andn %l4, PSTATE_IE, %o2
1460 ldx [%o3 + %lo(kcontextreg)], %o3
1461 brz %o3, 1f
1462 nop
1463 rdpr %pstate, %l4 ! disable interrupts
1464 andn %l4, PSTATE_IE, %o2
1465 wrpr %g0, %o2, %pstate
1466 mov DEMAP_ALL_TYPE, %o2
1467 stxa %g0, [%o2]ASI_DTLB_DEMAP
1468 stxa %g0, [%o2]ASI_ITLB_DEMAP
1469 mov MMU_PCONTEXT, %o2
1470 stxa %o3, [%o2]ASI_DMMU
1471 membar #Sync
1472 sethi %hi(FLUSH_ADDR), %o2
1473 flush %o2 ! flush required by immu
1474 wrpr %g0, %l4, %pstate ! restore interrupt state
1475 #endif /* _OPL */
1476
1477 1: ret ! Return result ...
1478 restore %o0, %g0, %o0 ! delay; result in %o0
1479 SET_SIZE(client_handler)
1480
|