xref: /illumos-gate/usr/src/uts/sun4/os/cpu_states.c (revision fbd1c0dae6f4a2ccc2ce0527c7f19d3dd5ea90b8)
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 2007 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 #include <sys/reboot.h>
29 #include <sys/systm.h>
30 #include <sys/archsystm.h>
31 #include <sys/machsystm.h>
32 #include <sys/promif.h>
33 #include <sys/promimpl.h>
34 #include <sys/prom_plat.h>
35 #include <sys/cpu_sgnblk_defs.h>
36 #include <sys/ivintr.h>
37 #include <sys/kdi.h>
38 #include <sys/kdi_machimpl.h>
39 #include <sys/callb.h>
40 #include <sys/wdt.h>
41 
42 #ifdef	TRAPTRACE
43 #include <sys/traptrace.h>
44 #endif /* TRAPTRACE */
45 
46 #ifdef C2_AUDIT
47 extern void audit_enterprom();
48 extern void audit_exitprom();
49 #endif /* C2_AUDIT */
50 
51 /*
52  * Platforms that use CPU signatures need to set cpu_sgn_func
53  * to point to a platform specific function.  This needs to
54  * be done in set_platform_defaults() within the platmod.
55  */
56 void (*cpu_sgn_func)(ushort_t, uchar_t, uchar_t, int) = NULL;
57 
58 /*
59  * abort_seq_handler required by sysctrl.
60  */
61 void debug_enter(char *);
62 void (*abort_seq_handler)(char *) = debug_enter;
63 
64 /*
65  * Platform tunable to disable the h/w watchdog timer.
66  */
67 extern void clear_watchdog_on_exit(void);
68 
69 /*
70  * On sun4u platform, abort_sequence_enter() can be called at high PIL
71  * and we can't afford to acquire any adaptive mutex or use any
72  * condition variables as we are not allowed to sleep while running
73  * on interrupt stack. We work around this problem by posting a level
74  * 10 soft interrupt and then invoking the "abort_seq_handler" within
75  * that soft interrupt context.
76  *
77  * This has the side effect of not allowing us to drop into debugger
78  * when the kernel is stuck at high PIL (PIL > 10).  It's better to
79  * be able to break into a hung system even if it means crashing the
80  * system.  If a user presses L1-A more than once within a 15 seconds
81  * window, and the previous L1-A soft interrupt is still pending, then
82  * we directly invoke the abort_sequence_enter.
83  *
84  * Since the "msg" argument passed to abort_sequence_enter can refer
85  * to a message anywhere in memory, including stack, it's copied into
86  * abort_seq_msgbuf buffer for processing by the soft interrupt.
87  */
88 
89 #define	ABORT_SEQ_MSGBUFSZ	256
90 #define	FORCE_ABORT_SEQ_INTERVAL ((hrtime_t)15 * NANOSEC)
91 
92 static kmutex_t	abort_seq_lock;
93 static uint64_t	abort_seq_inum;		/* abort seq softintr # */
94 static hrtime_t	abort_seq_tstamp;	/* hrtime of last abort seq */
95 static size_t	abort_seq_msglen;	/* abort seq message length */
96 static char	abort_seq_msgbuf[ABORT_SEQ_MSGBUFSZ];
97 
98 /*ARGSUSED0*/
99 static uint_t
100 abort_seq_softintr(caddr_t arg)
101 {
102 	char	*msg;
103 	char	msgbuf[ABORT_SEQ_MSGBUFSZ];
104 
105 	mutex_enter(&abort_seq_lock);
106 	if (abort_enable != 0 && abort_seq_tstamp != 0LL) {
107 		if (abort_seq_msglen > 0) {
108 			bcopy(abort_seq_msgbuf, msgbuf, abort_seq_msglen);
109 			msg = msgbuf;
110 		} else
111 			msg = NULL;
112 		abort_seq_tstamp = 0LL;
113 		mutex_exit(&abort_seq_lock);
114 #ifdef C2_AUDIT
115 		if (audit_active)
116 			audit_enterprom(1);
117 #endif /* C2_AUDIT */
118 		(*abort_seq_handler)(msg);
119 #ifdef C2_AUDIT
120 		if (audit_active)
121 			audit_exitprom(1);
122 #endif /* C2_AUDIT */
123 	} else {
124 		mutex_exit(&abort_seq_lock);
125 #ifdef C2_AUDIT
126 		if (audit_active)
127 			audit_enterprom(0);
128 #endif /* C2_AUDIT */
129 	}
130 	return (1);
131 }
132 
133 void
134 abort_sequence_init(void)
135 {
136 	mutex_init(&abort_seq_lock, NULL, MUTEX_SPIN, (void *)PIL_12);
137 	abort_seq_tstamp = 0LL;
138 	if (abort_seq_inum == 0)
139 		abort_seq_inum = add_softintr(LOCK_LEVEL,
140 		    (softintrfunc)abort_seq_softintr, NULL, SOFTINT_ST);
141 }
142 
143 /*
144  *	Machine dependent abort sequence handling
145  */
146 void
147 abort_sequence_enter(char *msg)
148 {
149 	int		s, on_intr;
150 	size_t		msglen;
151 	hrtime_t	tstamp;
152 
153 	if (abort_enable != 0) {
154 		s = splhi();
155 		on_intr = CPU_ON_INTR(CPU) || (spltoipl(s) > LOCK_LEVEL);
156 		splx(s);
157 
158 		tstamp = gethrtime();
159 		mutex_enter(&abort_seq_lock);
160 
161 		/*
162 		 * If we are on an interrupt stack and/or running at
163 		 * PIL > LOCK_LEVEL, then we post a softint and invoke
164 		 * abort_seq_handler from there as we can't afford to
165 		 * acquire any adaptive mutex here. However, if we
166 		 * already have a pending softint, which was posted
167 		 * within FORCE_ABORT_SEQ_INTERVAL duration, then we
168 		 * bypass softint approach as our softint may be blocked
169 		 * and the user really wants to drop into the debugger.
170 		 */
171 		if (on_intr && abort_seq_inum != 0 &&
172 		    (abort_seq_tstamp == 0LL || tstamp >
173 		    (abort_seq_tstamp + FORCE_ABORT_SEQ_INTERVAL))) {
174 			abort_seq_tstamp = tstamp;
175 			if (msg != NULL) {
176 				msglen = strlen(msg);
177 				if (msglen >= ABORT_SEQ_MSGBUFSZ)
178 					msglen = ABORT_SEQ_MSGBUFSZ - 1;
179 				bcopy(msg, abort_seq_msgbuf, msglen);
180 				abort_seq_msgbuf[msglen] = '\0';
181 				abort_seq_msglen = msglen + 1;
182 			} else
183 				abort_seq_msglen = 0;
184 			mutex_exit(&abort_seq_lock);
185 			setsoftint(abort_seq_inum);
186 		} else {
187 			/*
188 			 * Ignore any pending abort sequence softint
189 			 * as we are invoking the abort_seq_handler
190 			 * here.
191 			 */
192 			abort_seq_tstamp = 0LL;
193 			mutex_exit(&abort_seq_lock);
194 #ifdef C2_AUDIT
195 		if (!on_intr && audit_active)
196 			audit_enterprom(1);
197 #endif /* C2_AUDIT */
198 			(*abort_seq_handler)(msg);
199 #ifdef C2_AUDIT
200 		if (!on_intr && audit_active)
201 			audit_exitprom(1);
202 #endif /* C2_AUDIT */
203 		}
204 	} else {
205 #ifdef C2_AUDIT
206 		if (audit_active)
207 			audit_enterprom(0);
208 #endif /* C2_AUDIT */
209 	}
210 }
211 
212 /*
213  * Enter debugger.  Called when the user types L1-A or break or whenever
214  * code wants to enter the debugger and possibly resume later.
215  * If the debugger isn't present, enter the PROM monitor.
216  *
217  * If console is a framebuffer which is powered off, it will be powered up
218  * before jumping to the debugger.  If we are called above lock level, a
219  * softint is triggered to reenter this code and allow the fb to be powered
220  * up as in the less than lock level case.  If this code is entered at greater
221  * than lock level and the fb is not already powered up, the msg argument
222  * will not be displayed.
223  */
224 void
225 debug_enter(char *msg)
226 {
227 	label_t old_pcb;
228 	int s;
229 	extern void pm_cfb_powerup(void);
230 	extern void pm_cfb_rele(void);
231 	extern void pm_cfb_trigger(void);
232 	extern int pm_cfb_check_and_hold(void);
233 
234 	/*
235 	 * For platforms that use CPU signatures, update the signature
236 	 * to indicate that we are entering the debugger if we are in
237 	 * the middle of a panic flow.
238 	 */
239 	if (panicstr)
240 		CPU_SIGNATURE(OS_SIG, SIGST_EXIT, SIGSUBST_DEBUG, -1);
241 
242 	if (!panicstr)
243 		(void) callb_execute_class(CB_CL_ENTER_DEBUGGER, 0);
244 
245 	if (pm_cfb_check_and_hold())
246 		if (getpil() > LOCK_LEVEL) {
247 			pm_cfb_trigger();
248 			return;
249 		} else
250 			pm_cfb_powerup();
251 	if (msg)
252 		prom_printf("%s\n", msg);
253 
254 	clear_watchdog_on_exit();
255 
256 	if ((s = getpil()) < ipltospl(12))
257 		s = splzs();
258 
259 	old_pcb = curthread->t_pcb;
260 	(void) setjmp(&curthread->t_pcb);
261 
262 	if (boothowto & RB_DEBUG)
263 		kmdb_enter();
264 	else
265 		prom_enter_mon();
266 
267 	restore_watchdog_on_entry();
268 
269 	curthread->t_pcb = old_pcb;
270 	splx(s);
271 	pm_cfb_rele();
272 
273 	if (!panicstr)
274 		(void) callb_execute_class(CB_CL_ENTER_DEBUGGER, 1);
275 
276 	if (panicstr)
277 		CPU_SIGNATURE(OS_SIG, SIGST_EXIT, SIGSUBST_PANIC_CONT, -1);
278 }
279 
280 /*
281  * Halt the machine and return to the monitor
282  */
283 void
284 halt(char *s)
285 {
286 	flush_windows();
287 	stop_other_cpus();		/* send stop signal to other CPUs */
288 
289 	if (s)
290 		prom_printf("(%s) ", s);
291 
292 	/*
293 	 * For Platforms that use CPU signatures, we
294 	 * need to set the signature block to OS and
295 	 * the state to exiting for all the processors.
296 	 */
297 	CPU_SIGNATURE(OS_SIG, SIGST_EXIT, SIGSUBST_HALT, -1);
298 	prom_exit_to_mon();
299 	/*NOTREACHED*/
300 }
301 
302 /*
303  * Halt the machine and power off the system.
304  */
305 void
306 power_down(const char *s)
307 {
308 	flush_windows();
309 	stop_other_cpus();		/* send stop signal to other CPUs */
310 
311 	if (s != NULL)
312 		prom_printf("(%s) ", s);
313 
314 	/*
315 	 * For platforms that use CPU signatures, we need to set up the
316 	 * signature blocks to indicate that we have an environmental
317 	 * interrupt request to power down, and then exit to the prom monitor.
318 	 */
319 	CPU_SIGNATURE(OS_SIG, SIGST_EXIT, SIGSUBST_ENVIRON, -1);
320 	prom_power_off();
321 	/*
322 	 * If here is reached, for some reason prom's power-off command failed.
323 	 * Prom should have already printed out error messages. Exit to
324 	 * firmware.
325 	 */
326 	prom_exit_to_mon();
327 	/*NOTREACHED*/
328 }
329 
330 void
331 do_shutdown(void)
332 {
333 	proc_t *initpp;
334 
335 	/*
336 	 * If we're still booting and init(1) isn't set up yet, simply halt.
337 	 */
338 	mutex_enter(&pidlock);
339 	initpp = prfind(P_INITPID);
340 	mutex_exit(&pidlock);
341 	if (initpp == NULL) {
342 		extern void halt(char *);
343 		prom_power_off();
344 		halt("Power off the System");	/* just in case */
345 	}
346 
347 	/*
348 	 * else, graceful shutdown with inittab and all getting involved
349 	 */
350 	psignal(initpp, SIGPWR);
351 }
352