/* * Offline CPUs run this code even under a pause_cpus(), so we must * check if we need to enter the safe phase. */ void mach_cpu_idle(void) { if (IN_XPV_PANIC()) { xpv_panic_halt(); } else { (void) HYPERVISOR_block(); if (cpu_phase[CPU->cpu_id] == CPU_PHASE_WAIT_SAFE) enter_safe_phase(); } }
void reset(void) { extern void acpi_reset_system(); #if !defined(__xpv) ushort_t *bios_memchk; /* * Can't use psm_map_phys or acpi_reset_system before the hat is * initialized. */ if (khat_running) { bios_memchk = (ushort_t *)psm_map_phys(0x472, sizeof (ushort_t), PROT_READ | PROT_WRITE); if (bios_memchk) *bios_memchk = 0x1234; /* bios memory check disable */ if (options_dip != NULL && ddi_prop_exists(DDI_DEV_T_ANY, ddi_root_node(), 0, "efi-systab")) { if (bootops == NULL) acpi_reset_system(); efi_reset(); } /* * The problem with using stubs is that we can call * acpi_reset_system only after the kernel is up and running. * * We should create a global state to keep track of how far * up the kernel is but for the time being we will depend on * bootops. bootops cleared in startup_end(). */ if (bootops == NULL) acpi_reset_system(); } pc_reset(); #else if (IN_XPV_PANIC()) { if (khat_running && bootops == NULL) { acpi_reset_system(); } pc_reset(); } (void) HYPERVISOR_shutdown(SHUTDOWN_reboot); panic("HYPERVISOR_shutdown() failed"); #endif /*NOTREACHED*/ }
/*ARGSUSED*/ void mdboot(int cmd, int fcn, char *mdep, boolean_t invoke_cb) { processorid_t bootcpuid = 0; static int is_first_quiesce = 1; static int is_first_reset = 1; int reset_status = 0; static char fallback_str[] = "Falling back to regular reboot.\n"; if (fcn == AD_FASTREBOOT && !newkernel.fi_valid) fcn = AD_BOOT; if (!panicstr) { kpreempt_disable(); if (fcn == AD_FASTREBOOT) { mutex_enter(&cpu_lock); if (CPU_ACTIVE(cpu_get(bootcpuid))) { affinity_set(bootcpuid); } mutex_exit(&cpu_lock); } else { affinity_set(CPU_CURRENT); } } if (force_shutdown_method != AD_UNKNOWN) fcn = force_shutdown_method; /* * XXX - rconsvp is set to NULL to ensure that output messages * are sent to the underlying "hardware" device using the * monitor's printf routine since we are in the process of * either rebooting or halting the machine. */ rconsvp = NULL; /* * Print the reboot message now, before pausing other cpus. * There is a race condition in the printing support that * can deadlock multiprocessor machines. */ if (!(fcn == AD_HALT || fcn == AD_POWEROFF)) prom_printf("rebooting...\n"); if (IN_XPV_PANIC()) reset(); /* * We can't bring up the console from above lock level, so do it now */ pm_cfb_check_and_powerup(); /* make sure there are no more changes to the device tree */ devtree_freeze(); if (invoke_cb) (void) callb_execute_class(CB_CL_MDBOOT, NULL); /* * Clear any unresolved UEs from memory. */ page_retire_mdboot(); #if defined(__xpv) /* * XXPV Should probably think some more about how we deal * with panicing before it's really safe to panic. * On hypervisors, we reboot very quickly.. Perhaps panic * should only attempt to recover by rebooting if, * say, we were able to mount the root filesystem, * or if we successfully launched init(1m). */ if (panicstr && proc_init == NULL) (void) HYPERVISOR_shutdown(SHUTDOWN_poweroff); #endif /* * stop other cpus and raise our priority. since there is only * one active cpu after this, and our priority will be too high * for us to be preempted, we're essentially single threaded * from here on out. */ (void) spl6(); if (!panicstr) { mutex_enter(&cpu_lock); pause_cpus(NULL, NULL); mutex_exit(&cpu_lock); } /* * If the system is panicking, the preloaded kernel is valid, and * fastreboot_onpanic has been set, and the system has been up for * longer than fastreboot_onpanic_uptime (default to 10 minutes), * choose Fast Reboot. */ if (fcn == AD_BOOT && panicstr && newkernel.fi_valid && fastreboot_onpanic && (panic_lbolt - lbolt_at_boot) > fastreboot_onpanic_uptime) { fcn = AD_FASTREBOOT; } /* * Try to quiesce devices. */ if (is_first_quiesce) { /* * Clear is_first_quiesce before calling quiesce_devices() * so that if quiesce_devices() causes panics, it will not * be invoked again. */ is_first_quiesce = 0; quiesce_active = 1; quiesce_devices(ddi_root_node(), &reset_status); if (reset_status == -1) { if (fcn == AD_FASTREBOOT && !force_fastreboot) { prom_printf("Driver(s) not capable of fast " "reboot.\n"); prom_printf(fallback_str); fastreboot_capable = 0; fcn = AD_BOOT; } else if (fcn != AD_FASTREBOOT) fastreboot_capable = 0; } quiesce_active = 0; } /* * Try to reset devices. reset_leaves() should only be called * a) when there are no other threads that could be accessing devices, * and * b) on a system that's not capable of fast reboot (fastreboot_capable * being 0), or on a system where quiesce_devices() failed to * complete (quiesce_active being 1). */ if (is_first_reset && (!fastreboot_capable || quiesce_active)) { /* * Clear is_first_reset before calling reset_devices() * so that if reset_devices() causes panics, it will not * be invoked again. */ is_first_reset = 0; reset_leaves(); } /* Verify newkernel checksum */ if (fastreboot_capable && fcn == AD_FASTREBOOT && fastboot_cksum_verify(&newkernel) != 0) { fastreboot_capable = 0; prom_printf("Fast reboot: checksum failed for the new " "kernel.\n"); prom_printf(fallback_str); } (void) spl8(); if (fastreboot_capable && fcn == AD_FASTREBOOT) { /* * psm_shutdown is called within fast_reboot() */ fast_reboot(); } else { (*psm_shutdownf)(cmd, fcn); if (fcn == AD_HALT || fcn == AD_POWEROFF) halt((char *)NULL); else prom_reboot(""); } /*NOTREACHED*/ }
void panicsys(const char *format, va_list alist, struct regs *rp, int on_panic_stack) { int s = spl8(); kthread_t *t = curthread; cpu_t *cp = CPU; caddr_t intr_stack = NULL; uint_t intr_actv; ushort_t schedflag = t->t_schedflag; cpu_t *bound_cpu = t->t_bound_cpu; char preempt = t->t_preempt; (void) setjmp(&t->t_pcb); t->t_flag |= T_PANIC; t->t_schedflag |= TS_DONT_SWAP; t->t_bound_cpu = cp; t->t_preempt++; /* * Switch lbolt to event driven mode. */ lbolt_hybrid = lbolt_event_driven; panic_enter_hw(s); /* * If we're on the interrupt stack and an interrupt thread is available * in this CPU's pool, preserve the interrupt stack by detaching an * interrupt thread and making its stack the intr_stack. */ if (CPU_ON_INTR(cp) && cp->cpu_intr_thread != NULL) { kthread_t *it = cp->cpu_intr_thread; intr_stack = cp->cpu_intr_stack; intr_actv = cp->cpu_intr_actv; cp->cpu_intr_stack = thread_stk_init(it->t_stk); cp->cpu_intr_thread = it->t_link; /* * Clear only the high level bits of cpu_intr_actv. * We want to indicate that high-level interrupts are * not active without destroying the low-level interrupt * information stored there. */ cp->cpu_intr_actv &= ((1 << (LOCK_LEVEL + 1)) - 1); } /* * Record one-time panic information and quiesce the other CPUs. * Then print out the panic message and stack trace. */ if (on_panic_stack) { panic_data_t *pdp = (panic_data_t *)panicbuf; pdp->pd_version = PANICBUFVERS; pdp->pd_msgoff = sizeof (panic_data_t) - sizeof (panic_nv_t); if (t->t_panic_trap != NULL) panic_savetrap(pdp, t->t_panic_trap); else panic_saveregs(pdp, rp); (void) vsnprintf(&panicbuf[pdp->pd_msgoff], PANICBUFSIZE - pdp->pd_msgoff, format, alist); /* * Call into the platform code to stop the other CPUs. * We currently have all interrupts blocked, and expect that * the platform code will lower ipl only as far as needed to * perform cross-calls, and will acquire as *few* locks as is * possible -- panicstr is not set so we can still deadlock. */ panic_stopcpus(cp, t, s); panicstr = (char *)format; va_copy(panicargs, alist); panic_lbolt = LBOLT_NO_ACCOUNT; panic_lbolt64 = LBOLT_NO_ACCOUNT64; panic_hrestime = hrestime; panic_hrtime = gethrtime_waitfree(); panic_thread = t; panic_regs = t->t_pcb; panic_reg = rp; panic_cpu = *cp; panic_ipl = spltoipl(s); panic_schedflag = schedflag; panic_bound_cpu = bound_cpu; panic_preempt = preempt; if (intr_stack != NULL) { panic_cpu.cpu_intr_stack = intr_stack; panic_cpu.cpu_intr_actv = intr_actv; } /* * Lower ipl to 10 to keep clock() from running, but allow * keyboard interrupts to enter the debugger. These callbacks * are executed with panicstr set so they can bypass locks. */ splx(ipltospl(CLOCK_LEVEL)); panic_quiesce_hw(pdp); (void) FTRACE_STOP(); (void) callb_execute_class(CB_CL_PANIC, NULL); if (log_intrq != NULL) log_flushq(log_intrq); /* * If log_consq has been initialized and syslogd has started, * print any messages in log_consq that haven't been consumed. */ if (log_consq != NULL && log_consq != log_backlogq) log_printq(log_consq); fm_banner(); #if defined(__x86) /* * A hypervisor panic originates outside of Solaris, so we * don't want to prepend the panic message with misleading * pointers from within Solaris. */ if (!IN_XPV_PANIC()) #endif printf("\n\rpanic[cpu%d]/thread=%p: ", cp->cpu_id, (void *)t); vprintf(format, alist); printf("\n\n"); if (t->t_panic_trap != NULL) { panic_showtrap(t->t_panic_trap); printf("\n"); } traceregs(rp); printf("\n"); if (((boothowto & RB_DEBUG) || obpdebug) && !nopanicdebug && !panic_forced) { if (dumpvp != NULL) { debug_enter("panic: entering debugger " "(continue to save dump)"); } else { debug_enter("panic: entering debugger " "(no dump device, continue to reboot)"); } } } else if (panic_dump != 0 || panic_sync != 0 || panicstr != NULL) { printf("\n\rpanic[cpu%d]/thread=%p: ", cp->cpu_id, (void *)t); vprintf(format, alist); printf("\n"); } else goto spin; /* * Prior to performing sync or dump, we make sure that do_polled_io is * set, but we'll leave ipl at 10; deadman(), a CY_HIGH_LEVEL cyclic, * will re-enter panic if we are not making progress with sync or dump. */ /* * Sync the filesystems. Reset t_cred if not set because much of * the filesystem code depends on CRED() being valid. */ if (!in_sync && panic_trigger(&panic_sync)) { if (t->t_cred == NULL) t->t_cred = kcred; splx(ipltospl(CLOCK_LEVEL)); do_polled_io = 1; vfs_syncall(); } /* * Take the crash dump. If the dump trigger is already set, try to * enter the debugger again before rebooting the system. */ if (panic_trigger(&panic_dump)) { panic_dump_hw(s); splx(ipltospl(CLOCK_LEVEL)); errorq_panic(); do_polled_io = 1; dumpsys(); } else if (((boothowto & RB_DEBUG) || obpdebug) && !nopanicdebug) { debug_enter("panic: entering debugger (continue to reboot)"); } else printf("dump aborted: please record the above information!\n"); if (halt_on_panic) mdboot(A_REBOOT, AD_HALT, NULL, B_FALSE); else mdboot(A_REBOOT, panic_bootfcn, panic_bootstr, B_FALSE); spin: /* * Restore ipl to at most CLOCK_LEVEL so we don't end up spinning * and unable to jump into the debugger. */ splx(MIN(s, ipltospl(CLOCK_LEVEL))); for (;;) ; }