xref: /illumos-gate/usr/src/uts/i86pc/os/machdep.c (revision 65a89a64c60f3061bbe2381edaacc81660af9a95)
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 /*
23  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/types.h>
30 #include <sys/t_lock.h>
31 #include <sys/param.h>
32 #include <sys/sysmacros.h>
33 #include <sys/signal.h>
34 #include <sys/systm.h>
35 #include <sys/user.h>
36 #include <sys/mman.h>
37 #include <sys/vm.h>
38 
39 #include <sys/disp.h>
40 #include <sys/class.h>
41 
42 #include <sys/proc.h>
43 #include <sys/buf.h>
44 #include <sys/kmem.h>
45 
46 #include <sys/reboot.h>
47 #include <sys/uadmin.h>
48 #include <sys/callb.h>
49 
50 #include <sys/cred.h>
51 #include <sys/vnode.h>
52 #include <sys/file.h>
53 
54 #include <sys/procfs.h>
55 #include <sys/acct.h>
56 
57 #include <sys/vfs.h>
58 #include <sys/dnlc.h>
59 #include <sys/var.h>
60 #include <sys/cmn_err.h>
61 #include <sys/utsname.h>
62 #include <sys/debug.h>
63 #include <sys/kdi_impl.h>
64 
65 #include <sys/dumphdr.h>
66 #include <sys/bootconf.h>
67 #include <sys/varargs.h>
68 #include <sys/promif.h>
69 #include <sys/modctl.h>
70 
71 #include <sys/consdev.h>
72 #include <sys/frame.h>
73 
74 #include <sys/sunddi.h>
75 #include <sys/ddidmareq.h>
76 #include <sys/psw.h>
77 #include <sys/regset.h>
78 #include <sys/privregs.h>
79 #include <sys/clock.h>
80 #include <sys/tss.h>
81 #include <sys/cpu.h>
82 #include <sys/stack.h>
83 #include <sys/trap.h>
84 #include <sys/pic.h>
85 #include <sys/mmu.h>
86 #include <vm/hat.h>
87 #include <vm/anon.h>
88 #include <vm/as.h>
89 #include <vm/page.h>
90 #include <vm/seg.h>
91 #include <vm/seg_kmem.h>
92 #include <vm/seg_map.h>
93 #include <vm/seg_vn.h>
94 #include <vm/seg_kp.h>
95 #include <vm/hat_i86.h>
96 #include <sys/swap.h>
97 #include <sys/thread.h>
98 #include <sys/sysconf.h>
99 #include <sys/vm_machparam.h>
100 #include <sys/archsystm.h>
101 #include <sys/machsystm.h>
102 #include <sys/machlock.h>
103 #include <sys/x_call.h>
104 #include <sys/instance.h>
105 
106 #include <sys/time.h>
107 #include <sys/smp_impldefs.h>
108 #include <sys/psm_types.h>
109 #include <sys/atomic.h>
110 #include <sys/panic.h>
111 #include <sys/cpuvar.h>
112 #include <sys/dtrace.h>
113 #include <sys/bl.h>
114 #include <sys/nvpair.h>
115 #include <sys/x86_archext.h>
116 #include <sys/pool_pset.h>
117 #include <sys/autoconf.h>
118 #include <sys/kdi.h>
119 
120 #ifdef	TRAPTRACE
121 #include <sys/traptrace.h>
122 #endif	/* TRAPTRACE */
123 
124 #ifdef C2_AUDIT
125 extern void audit_enterprom(int);
126 extern void audit_exitprom(int);
127 #endif
128 
129 /*
130  * The panicbuf array is used to record messages and state:
131  */
132 char panicbuf[PANICBUFSIZE];
133 
134 /*
135  * maxphys - used during physio
136  * klustsize - used for klustering by swapfs and specfs
137  */
138 int maxphys = 56 * 1024;    /* XXX See vm_subr.c - max b_count in physio */
139 int klustsize = 56 * 1024;
140 
141 caddr_t	p0_va;		/* Virtual address for accessing physical page 0 */
142 
143 /*
144  * defined here, though unused on x86,
145  * to make kstat_fr.c happy.
146  */
147 int vac;
148 
149 void stop_other_cpus();
150 void debug_enter(char *);
151 
152 int	procset = 1;
153 
154 extern void pm_cfb_check_and_powerup(void);
155 extern void pm_cfb_rele(void);
156 
157 /*
158  * Machine dependent code to reboot.
159  * "mdep" is interpreted as a character pointer; if non-null, it is a pointer
160  * to a string to be used as the argument string when rebooting.
161  *
162  * "invoke_cb" is a boolean. It is set to true when mdboot() can safely
163  * invoke CB_CL_MDBOOT callbacks before shutting the system down, i.e. when
164  * we are in a normal shutdown sequence (interrupts are not blocked, the
165  * system is not panic'ing or being suspended).
166  */
167 /*ARGSUSED*/
168 void
169 mdboot(int cmd, int fcn, char *mdep, boolean_t invoke_cb)
170 {
171 	extern void mtrr_resync(void);
172 
173 	if (!panicstr) {
174 		kpreempt_disable();
175 		affinity_set(CPU_CURRENT);
176 	}
177 
178 	/*
179 	 * XXX - rconsvp is set to NULL to ensure that output messages
180 	 * are sent to the underlying "hardware" device using the
181 	 * monitor's printf routine since we are in the process of
182 	 * either rebooting or halting the machine.
183 	 */
184 	rconsvp = NULL;
185 
186 	/*
187 	 * Print the reboot message now, before pausing other cpus.
188 	 * There is a race condition in the printing support that
189 	 * can deadlock multiprocessor machines.
190 	 */
191 	if (!(fcn == AD_HALT || fcn == AD_POWEROFF))
192 		prom_printf("rebooting...\n");
193 
194 	/*
195 	 * We can't bring up the console from above lock level, so do it now
196 	 */
197 	pm_cfb_check_and_powerup();
198 
199 	/* make sure there are no more changes to the device tree */
200 	devtree_freeze();
201 
202 	if (invoke_cb)
203 		(void) callb_execute_class(CB_CL_MDBOOT, NULL);
204 
205 	page_retire_hunt(page_retire_mdboot_cb);
206 
207 	/*
208 	 * stop other cpus and raise our priority.  since there is only
209 	 * one active cpu after this, and our priority will be too high
210 	 * for us to be preempted, we're essentially single threaded
211 	 * from here on out.
212 	 */
213 	(void) spl6();
214 	if (!panicstr) {
215 		mutex_enter(&cpu_lock);
216 		pause_cpus(NULL);
217 		mutex_exit(&cpu_lock);
218 	}
219 
220 	/*
221 	 * try and reset leaf devices.  reset_leaves() should only
222 	 * be called when there are no other threads that could be
223 	 * accessing devices
224 	 */
225 	reset_leaves();
226 
227 	(void) spl8();
228 	(*psm_shutdownf)(cmd, fcn);
229 
230 	mtrr_resync();
231 
232 	if (fcn == AD_HALT || fcn == AD_POWEROFF)
233 		halt((char *)NULL);
234 	else
235 		prom_reboot("");
236 	/*NOTREACHED*/
237 }
238 
239 /* mdpreboot - may be called prior to mdboot while root fs still mounted */
240 /*ARGSUSED*/
241 void
242 mdpreboot(int cmd, int fcn, char *mdep)
243 {
244 	(*psm_preshutdownf)(cmd, fcn);
245 }
246 
247 void
248 idle_other_cpus()
249 {
250 	int cpuid = CPU->cpu_id;
251 	cpuset_t xcset;
252 
253 	ASSERT(cpuid < NCPU);
254 	CPUSET_ALL_BUT(xcset, cpuid);
255 	xc_capture_cpus(xcset);
256 }
257 
258 void
259 resume_other_cpus()
260 {
261 	ASSERT(CPU->cpu_id < NCPU);
262 
263 	xc_release_cpus();
264 }
265 
266 extern void	mp_halt(char *);
267 
268 void
269 stop_other_cpus()
270 {
271 	int cpuid = CPU->cpu_id;
272 	cpuset_t xcset;
273 
274 	ASSERT(cpuid < NCPU);
275 
276 	/*
277 	 * xc_trycall will attempt to make all other CPUs execute mp_halt,
278 	 * and will return immediately regardless of whether or not it was
279 	 * able to make them do it.
280 	 */
281 	CPUSET_ALL_BUT(xcset, cpuid);
282 	xc_trycall(NULL, NULL, NULL, xcset, (int (*)())mp_halt);
283 }
284 
285 /*
286  *	Machine dependent abort sequence handling
287  */
288 void
289 abort_sequence_enter(char *msg)
290 {
291 	if (abort_enable == 0) {
292 #ifdef C2_AUDIT
293 		if (audit_active)
294 			audit_enterprom(0);
295 #endif /* C2_AUDIT */
296 		return;
297 	}
298 #ifdef C2_AUDIT
299 	if (audit_active)
300 		audit_enterprom(1);
301 #endif /* C2_AUDIT */
302 	debug_enter(msg);
303 #ifdef C2_AUDIT
304 	if (audit_active)
305 		audit_exitprom(1);
306 #endif /* C2_AUDIT */
307 }
308 
309 /*
310  * Enter debugger.  Called when the user types ctrl-alt-d or whenever
311  * code wants to enter the debugger and possibly resume later.
312  */
313 void
314 debug_enter(
315 	char	*msg)		/* message to print, possibly NULL */
316 {
317 	if (dtrace_debugger_init != NULL)
318 		(*dtrace_debugger_init)();
319 
320 	if (msg)
321 		prom_printf("%s\n", msg);
322 
323 	if (boothowto & RB_DEBUG)
324 		kdi_dvec_enter();
325 
326 	if (dtrace_debugger_fini != NULL)
327 		(*dtrace_debugger_fini)();
328 }
329 
330 void
331 reset(void)
332 {
333 	ushort_t *bios_memchk;
334 
335 	/*
336 	 * Can't use psm_map_phys before the hat is initialized.
337 	 */
338 	if (khat_running) {
339 		bios_memchk = (ushort_t *)psm_map_phys(0x472,
340 		    sizeof (ushort_t), PROT_READ | PROT_WRITE);
341 		if (bios_memchk)
342 			*bios_memchk = 0x1234;	/* bios memory check disable */
343 	}
344 
345 	pc_reset();
346 	/*NOTREACHED*/
347 }
348 
349 /*
350  * Halt the machine and return to the monitor
351  */
352 void
353 halt(char *s)
354 {
355 	stop_other_cpus();	/* send stop signal to other CPUs */
356 	if (s)
357 		prom_printf("(%s) \n", s);
358 	prom_exit_to_mon();
359 	/*NOTREACHED*/
360 }
361 
362 /*
363  * Enter monitor.  Called via cross-call from stop_other_cpus().
364  */
365 void
366 mp_halt(char *msg)
367 {
368 	if (msg)
369 		prom_printf("%s\n", msg);
370 
371 	/*CONSTANTCONDITION*/
372 	while (1)
373 		;
374 }
375 
376 /*
377  * Initiate interrupt redistribution.
378  */
379 void
380 i_ddi_intr_redist_all_cpus()
381 {
382 }
383 
384 /*
385  * XXX These probably ought to live somewhere else
386  * XXX They are called from mem.c
387  */
388 
389 /*
390  * Convert page frame number to an OBMEM page frame number
391  * (i.e. put in the type bits -- zero for this implementation)
392  */
393 pfn_t
394 impl_obmem_pfnum(pfn_t pf)
395 {
396 	return (pf);
397 }
398 
399 #ifdef	NM_DEBUG
400 int nmi_test = 0;	/* checked in intentry.s during clock int */
401 int nmtest = -1;
402 nmfunc1(arg, rp)
403 int	arg;
404 struct regs *rp;
405 {
406 	printf("nmi called with arg = %x, regs = %x\n", arg, rp);
407 	nmtest += 50;
408 	if (arg == nmtest) {
409 		printf("ip = %x\n", rp->r_pc);
410 		return (1);
411 	}
412 	return (0);
413 }
414 
415 #endif
416 
417 #include <sys/bootsvcs.h>
418 
419 /* Hacked up initialization for initial kernel check out is HERE. */
420 /* The basic steps are: */
421 /*	kernel bootfuncs definition/initialization for KADB */
422 /*	kadb bootfuncs pointer initialization */
423 /*	putchar/getchar (interrupts disabled) */
424 
425 /* kadb bootfuncs pointer initialization */
426 
427 int
428 sysp_getchar()
429 {
430 	int i;
431 	int s;
432 
433 	if (cons_polledio == NULL) {
434 		/* Uh oh */
435 		prom_printf("getchar called with no console\n");
436 		for (;;)
437 			/* LOOP FOREVER */;
438 	}
439 
440 	s = clear_int_flag();
441 	i = cons_polledio->cons_polledio_getchar(
442 		cons_polledio->cons_polledio_argument);
443 	restore_int_flag(s);
444 	return (i);
445 }
446 
447 void
448 sysp_putchar(int c)
449 {
450 	int s;
451 
452 	/*
453 	 * We have no alternative but to drop the output on the floor.
454 	 */
455 	if (cons_polledio == NULL ||
456 	    cons_polledio->cons_polledio_putchar == NULL)
457 		return;
458 
459 	s = clear_int_flag();
460 	cons_polledio->cons_polledio_putchar(
461 		cons_polledio->cons_polledio_argument, c);
462 	restore_int_flag(s);
463 }
464 
465 int
466 sysp_ischar()
467 {
468 	int i;
469 	int s;
470 
471 	if (cons_polledio == NULL ||
472 	    cons_polledio->cons_polledio_ischar == NULL)
473 		return (0);
474 
475 	s = clear_int_flag();
476 	i = cons_polledio->cons_polledio_ischar(
477 		cons_polledio->cons_polledio_argument);
478 	restore_int_flag(s);
479 	return (i);
480 }
481 
482 int
483 goany(void)
484 {
485 	prom_printf("Type any key to continue ");
486 	(void) prom_getchar();
487 	prom_printf("\n");
488 	return (1);
489 }
490 
491 static struct boot_syscalls kern_sysp = {
492 	sysp_getchar,	/*	unchar	(*getchar)();	7  */
493 	sysp_putchar,	/*	int	(*putchar)();	8  */
494 	sysp_ischar,	/*	int	(*ischar)();	9  */
495 };
496 
497 void
498 kadb_uses_kernel()
499 {
500 	/*
501 	 * This routine is now totally misnamed, since it does not in fact
502 	 * control kadb's I/O; it only controls the kernel's prom_* I/O.
503 	 */
504 	sysp = &kern_sysp;
505 }
506 
507 /*
508  *	the interface to the outside world
509  */
510 
511 /*
512  * poll_port -- wait for a register to achieve a
513  *		specific state.  Arguments are a mask of bits we care about,
514  *		and two sub-masks.  To return normally, all the bits in the
515  *		first sub-mask must be ON, all the bits in the second sub-
516  *		mask must be OFF.  If about seconds pass without the register
517  *		achieving the desired bit configuration, we return 1, else
518  *		0.
519  */
520 int
521 poll_port(ushort_t port, ushort_t mask, ushort_t onbits, ushort_t offbits)
522 {
523 	int i;
524 	ushort_t maskval;
525 
526 	for (i = 500000; i; i--) {
527 		maskval = inb(port) & mask;
528 		if (((maskval & onbits) == onbits) &&
529 			((maskval & offbits) == 0))
530 			return (0);
531 		drv_usecwait(10);
532 	}
533 	return (1);
534 }
535 
536 /*
537  * set_idle_cpu is called from idle() when a CPU becomes idle.
538  */
539 /*LINTED: static unused */
540 static uint_t last_idle_cpu;
541 
542 /*ARGSUSED*/
543 void
544 set_idle_cpu(int cpun)
545 {
546 	last_idle_cpu = cpun;
547 	(*psm_set_idle_cpuf)(cpun);
548 }
549 
550 /*
551  * unset_idle_cpu is called from idle() when a CPU is no longer idle.
552  */
553 /*ARGSUSED*/
554 void
555 unset_idle_cpu(int cpun)
556 {
557 	(*psm_unset_idle_cpuf)(cpun);
558 }
559 
560 /*
561  * This routine is almost correct now, but not quite.  It still needs the
562  * equivalent concept of "hres_last_tick", just like on the sparc side.
563  * The idea is to take a snapshot of the hi-res timer while doing the
564  * hrestime_adj updates under hres_lock in locore, so that the small
565  * interval between interrupt assertion and interrupt processing is
566  * accounted for correctly.  Once we have this, the code below should
567  * be modified to subtract off hres_last_tick rather than hrtime_base.
568  *
569  * I'd have done this myself, but I don't have source to all of the
570  * vendor-specific hi-res timer routines (grrr...).  The generic hook I
571  * need is something like "gethrtime_unlocked()", which would be just like
572  * gethrtime() but would assume that you're already holding CLOCK_LOCK().
573  * This is what the GET_HRTIME() macro is for on sparc (although it also
574  * serves the function of making time available without a function call
575  * so you don't take a register window overflow while traps are disabled).
576  */
577 void
578 pc_gethrestime(timestruc_t *tp)
579 {
580 	int lock_prev;
581 	timestruc_t now;
582 	int nslt;		/* nsec since last tick */
583 	int adj;		/* amount of adjustment to apply */
584 
585 loop:
586 	lock_prev = hres_lock;
587 	now = hrestime;
588 	nslt = (int)(gethrtime() - hres_last_tick);
589 	if (nslt < 0) {
590 		/*
591 		 * nslt < 0 means a tick came between sampling
592 		 * gethrtime() and hres_last_tick; restart the loop
593 		 */
594 
595 		goto loop;
596 	}
597 	now.tv_nsec += nslt;
598 	if (hrestime_adj != 0) {
599 		if (hrestime_adj > 0) {
600 			adj = (nslt >> ADJ_SHIFT);
601 			if (adj > hrestime_adj)
602 				adj = (int)hrestime_adj;
603 		} else {
604 			adj = -(nslt >> ADJ_SHIFT);
605 			if (adj < hrestime_adj)
606 				adj = (int)hrestime_adj;
607 		}
608 		now.tv_nsec += adj;
609 	}
610 	while ((unsigned long)now.tv_nsec >= NANOSEC) {
611 
612 		/*
613 		 * We might have a large adjustment or have been in the
614 		 * debugger for a long time; take care of (at most) four
615 		 * of those missed seconds (tv_nsec is 32 bits, so
616 		 * anything >4s will be wrapping around).  However,
617 		 * anything more than 2 seconds out of sync will trigger
618 		 * timedelta from clock() to go correct the time anyway,
619 		 * so do what we can, and let the big crowbar do the
620 		 * rest.  A similar correction while loop exists inside
621 		 * hres_tick(); in all cases we'd like tv_nsec to
622 		 * satisfy 0 <= tv_nsec < NANOSEC to avoid confusing
623 		 * user processes, but if tv_sec's a little behind for a
624 		 * little while, that's OK; time still monotonically
625 		 * increases.
626 		 */
627 
628 		now.tv_nsec -= NANOSEC;
629 		now.tv_sec++;
630 	}
631 	if ((hres_lock & ~1) != lock_prev)
632 		goto loop;
633 
634 	*tp = now;
635 }
636 
637 void
638 gethrestime_lasttick(timespec_t *tp)
639 {
640 	int s;
641 
642 	s = hr_clock_lock();
643 	*tp = hrestime;
644 	hr_clock_unlock(s);
645 }
646 
647 time_t
648 gethrestime_sec(void)
649 {
650 	timestruc_t now;
651 
652 	gethrestime(&now);
653 	return (now.tv_sec);
654 }
655 
656 /*
657  * Initialize a kernel thread's stack
658  */
659 
660 caddr_t
661 thread_stk_init(caddr_t stk)
662 {
663 	ASSERT(((uintptr_t)stk & (STACK_ALIGN - 1)) == 0);
664 	return (stk - SA(MINFRAME));
665 }
666 
667 /*
668  * Initialize lwp's kernel stack.
669  */
670 
671 #ifdef TRAPTRACE
672 /*
673  * There's a tricky interdependency here between use of sysenter and
674  * TRAPTRACE which needs recording to avoid future confusion (this is
675  * about the third time I've re-figured this out ..)
676  *
677  * Here's how debugging lcall works with TRAPTRACE.
678  *
679  * 1 We're in userland with a breakpoint on the lcall instruction.
680  * 2 We execute the instruction - the instruction pushes the userland
681  *   %ss, %esp, %efl, %cs, %eip on the stack and zips into the kernel
682  *   via the call gate.
683  * 3 The hardware raises a debug trap in kernel mode, the hardware
684  *   pushes %efl, %cs, %eip and gets to dbgtrap via the idt.
685  * 4 dbgtrap pushes the error code and trapno and calls cmntrap
686  * 5 cmntrap finishes building a trap frame
687  * 6 The TRACE_REGS macros in cmntrap copy a REGSIZE worth chunk
688  *   off the stack into the traptrace buffer.
689  *
690  * This means that the traptrace buffer contains the wrong values in
691  * %esp and %ss, but everything else in there is correct.
692  *
693  * Here's how debugging sysenter works with TRAPTRACE.
694  *
695  * a We're in userland with a breakpoint on the sysenter instruction.
696  * b We execute the instruction - the instruction pushes -nothing-
697  *   on the stack, but sets %cs, %eip, %ss, %esp to prearranged
698  *   values to take us to sys_sysenter, at the top of the lwp's
699  *   stack.
700  * c goto 3
701  *
702  * At this point, because we got into the kernel without the requisite
703  * five pushes on the stack, if we didn't make extra room, we'd
704  * end up with the TRACE_REGS macro fetching the saved %ss and %esp
705  * values from negative (unmapped) stack addresses -- which really bites.
706  * That's why we do the '-= 8' below.
707  *
708  * XXX	Note that reading "up" lwp0's stack works because t0 is declared
709  *	right next to t0stack in locore.s
710  */
711 #endif
712 
713 caddr_t
714 lwp_stk_init(klwp_t *lwp, caddr_t stk)
715 {
716 	caddr_t oldstk;
717 	struct pcb *pcb = &lwp->lwp_pcb;
718 
719 	oldstk = stk;
720 	stk -= SA(sizeof (struct regs) + SA(MINFRAME));
721 #ifdef TRAPTRACE
722 	stk -= 2 * sizeof (greg_t); /* space for phony %ss:%sp (see above) */
723 #endif
724 	stk = (caddr_t)((uintptr_t)stk & ~(STACK_ALIGN - 1ul));
725 	bzero(stk, oldstk - stk);
726 	lwp->lwp_regs = (void *)(stk + SA(MINFRAME));
727 
728 	/*
729 	 * Arrange that the virtualized %fs and %gs GDT descriptors
730 	 * have a well-defined initial state (present, ring 3
731 	 * and of type data).
732 	 */
733 #if defined(__amd64)
734 	if (lwp_getdatamodel(lwp) == DATAMODEL_NATIVE)
735 		pcb->pcb_fsdesc = pcb->pcb_gsdesc = zero_udesc;
736 	else
737 		pcb->pcb_fsdesc = pcb->pcb_gsdesc = zero_u32desc;
738 #elif defined(__i386)
739 	pcb->pcb_fsdesc = pcb->pcb_gsdesc = zero_udesc;
740 #endif	/* __i386 */
741 	lwp_installctx(lwp);
742 	return (stk);
743 }
744 
745 /*ARGSUSED*/
746 void
747 lwp_stk_fini(klwp_t *lwp)
748 {}
749 
750 /*
751  * If we're not the panic CPU, we wait in panic_idle for reboot.
752  */
753 static void
754 panic_idle(void)
755 {
756 	splx(ipltospl(CLOCK_LEVEL));
757 	(void) setjmp(&curthread->t_pcb);
758 
759 	for (;;);
760 }
761 
762 /*
763  * Stop the other CPUs by cross-calling them and forcing them to enter
764  * the panic_idle() loop above.
765  */
766 /*ARGSUSED*/
767 void
768 panic_stopcpus(cpu_t *cp, kthread_t *t, int spl)
769 {
770 	processorid_t i;
771 	cpuset_t xcset;
772 
773 	(void) splzs();
774 
775 	CPUSET_ALL_BUT(xcset, cp->cpu_id);
776 	xc_trycall(NULL, NULL, NULL, xcset, (int (*)())panic_idle);
777 
778 	for (i = 0; i < NCPU; i++) {
779 		if (i != cp->cpu_id && cpu[i] != NULL &&
780 		    (cpu[i]->cpu_flags & CPU_EXISTS))
781 			cpu[i]->cpu_flags |= CPU_QUIESCED;
782 	}
783 }
784 
785 /*
786  * Platform callback following each entry to panicsys().
787  */
788 /*ARGSUSED*/
789 void
790 panic_enter_hw(int spl)
791 {
792 	/* Nothing to do here */
793 }
794 
795 /*
796  * Platform-specific code to execute after panicstr is set: we invoke
797  * the PSM entry point to indicate that a panic has occurred.
798  */
799 /*ARGSUSED*/
800 void
801 panic_quiesce_hw(panic_data_t *pdp)
802 {
803 	psm_notifyf(PSM_PANIC_ENTER);
804 
805 #ifdef	TRAPTRACE
806 	/*
807 	 * Turn off TRAPTRACE
808 	 */
809 	TRAPTRACE_FREEZE;
810 #endif	/* TRAPTRACE */
811 }
812 
813 /*
814  * Platform callback prior to writing crash dump.
815  */
816 /*ARGSUSED*/
817 void
818 panic_dump_hw(int spl)
819 {
820 	/* Nothing to do here */
821 }
822 
823 /*ARGSUSED*/
824 void
825 plat_tod_fault(enum tod_fault_type tod_bad)
826 {
827 }
828 
829 /*ARGSUSED*/
830 int
831 blacklist(int cmd, const char *scheme, nvlist_t *fmri, const char *class)
832 {
833 	return (ENOTSUP);
834 }
835 
836 /*
837  * The underlying console output routines are protected by raising IPL in case
838  * we are still calling into the early boot services.  Once we start calling
839  * the kernel console emulator, it will disable interrupts completely during
840  * character rendering (see sysp_putchar, for example).  Refer to the comments
841  * and code in common/os/console.c for more information on these callbacks.
842  */
843 /*ARGSUSED*/
844 int
845 console_enter(int busy)
846 {
847 	return (splzs());
848 }
849 
850 /*ARGSUSED*/
851 void
852 console_exit(int busy, int spl)
853 {
854 	splx(spl);
855 }
856 
857 /*
858  * Allocate a region of virtual address space, unmapped.
859  * Stubbed out except on sparc, at least for now.
860  */
861 /*ARGSUSED*/
862 void *
863 boot_virt_alloc(void *addr, size_t size)
864 {
865 	return (addr);
866 }
867 
868 volatile unsigned long	tenmicrodata;
869 
870 void
871 tenmicrosec(void)
872 {
873 	extern int	tsc_gethrtime_initted;
874 	int		i;
875 
876 	if (tsc_gethrtime_initted) {
877 		hrtime_t start, end;
878 		start = end =  gethrtime();
879 		while ((end - start) < (10 * (NANOSEC / MICROSEC))) {
880 			SMT_PAUSE();
881 			end = gethrtime();
882 		}
883 	} else {
884 		/*
885 		 * Artificial loop to induce delay.
886 		 */
887 		for (i = 0; i < microdata; i++)
888 			tenmicrodata = microdata;
889 	}
890 }
891 
892 /*
893  * get_cpu_mstate() is passed an array of timestamps, NCMSTATES
894  * long, and it fills in the array with the time spent on cpu in
895  * each of the mstates, where time is returned in nsec.
896  *
897  * No guarantee is made that the returned values in times[] will
898  * monotonically increase on sequential calls, although this will
899  * be true in the long run. Any such guarantee must be handled by
900  * the caller, if needed. This can happen if we fail to account
901  * for elapsed time due to a generation counter conflict, yet we
902  * did account for it on a prior call (see below).
903  *
904  * The complication is that the cpu in question may be updating
905  * its microstate at the same time that we are reading it.
906  * Because the microstate is only updated when the CPU's state
907  * changes, the values in cpu_intracct[] can be indefinitely out
908  * of date. To determine true current values, it is necessary to
909  * compare the current time with cpu_mstate_start, and add the
910  * difference to times[cpu_mstate].
911  *
912  * This can be a problem if those values are changing out from
913  * under us. Because the code path in new_cpu_mstate() is
914  * performance critical, we have not added a lock to it. Instead,
915  * we have added a generation counter. Before beginning
916  * modifications, the counter is set to 0. After modifications,
917  * it is set to the old value plus one.
918  *
919  * get_cpu_mstate() will not consider the values of cpu_mstate
920  * and cpu_mstate_start to be usable unless the value of
921  * cpu_mstate_gen is both non-zero and unchanged, both before and
922  * after reading the mstate information. Note that we must
923  * protect against out-of-order loads around accesses to the
924  * generation counter. Also, this is a best effort approach in
925  * that we do not retry should the counter be found to have
926  * changed.
927  *
928  * cpu_intracct[] is used to identify time spent in each CPU
929  * mstate while handling interrupts. Such time should be reported
930  * against system time, and so is subtracted out from its
931  * corresponding cpu_acct[] time and added to
932  * cpu_acct[CMS_SYSTEM].
933  */
934 
935 void
936 get_cpu_mstate(cpu_t *cpu, hrtime_t *times)
937 {
938 	int i;
939 	hrtime_t now, start;
940 	uint16_t gen;
941 	uint16_t state;
942 	hrtime_t intracct[NCMSTATES];
943 
944 	/*
945 	 * Load all volatile state under the protection of membar.
946 	 * cpu_acct[cpu_mstate] must be loaded to avoid double counting
947 	 * of (now - cpu_mstate_start) by a change in CPU mstate that
948 	 * arrives after we make our last check of cpu_mstate_gen.
949 	 */
950 
951 	now = gethrtime_unscaled();
952 	gen = cpu->cpu_mstate_gen;
953 
954 	membar_consumer();	/* guarantee load ordering */
955 	start = cpu->cpu_mstate_start;
956 	state = cpu->cpu_mstate;
957 	for (i = 0; i < NCMSTATES; i++) {
958 		intracct[i] = cpu->cpu_intracct[i];
959 		times[i] = cpu->cpu_acct[i];
960 	}
961 	membar_consumer();	/* guarantee load ordering */
962 
963 	if (gen != 0 && gen == cpu->cpu_mstate_gen && now > start)
964 		times[state] += now - start;
965 
966 	for (i = 0; i < NCMSTATES; i++) {
967 		if (i == CMS_SYSTEM)
968 			continue;
969 		times[i] -= intracct[i];
970 		if (times[i] < 0) {
971 			intracct[i] += times[i];
972 			times[i] = 0;
973 		}
974 		times[CMS_SYSTEM] += intracct[i];
975 		scalehrtime(&times[i]);
976 	}
977 	scalehrtime(&times[CMS_SYSTEM]);
978 }
979