* RE: [Xen-users] Re: Linux hangs during reboot on Jeremy's git kernel
2010-02-09 16:50 ` Re: [Xen-devel] " Mike Viau
@ 2010-02-09 17:02 ` Mike Viau
2010-02-09 20:31 ` 2.6.32.6 (baremetal) fails to shutdown Intel i7 860 with P55 chipset Konrad Rzeszutek Wilk
0 siblings, 1 reply; 10+ messages in thread
From: Mike Viau @ 2010-02-09 17:02 UTC (permalink / raw)
To: konrad.wilk; +Cc: xen-devel, xen-users
[-- Attachment #1.1: Type: text/plain, Size: 4259 bytes --]
From: mike.viau@sheridanc.on.ca
To: konrad.wilk@oracle.com
Subject: RE: [Xen-users] Re: [Xen-devel] Linux hangs during reboot on Jeremy's git kernel
Date: Tue, 9 Feb 2010 11:50:29 -0500
CC: xen-devel@lists.xensource.com; xen-users@lists.xensource.com
> Date: Mon, 8 Feb 2010 16:07:36 -0500
> From: konrad.wilk@oracle.com
> To: mike.viau@sheridanc.on.ca
> Subject: Re: [Xen-users] Re: [Xen-devel] Linux hangs during reboot on Jeremy's git kernel
> CC: xen-devel@lists.xensource.com; xen-users@lists.xensource.com
>
> > > a). Bare-metal. Boot pv-ops and shutdown. Does it do it?
> >
> > Yes oddly enough, shutdown is fine, only hangs on reboot.
> >
> > Also I'd like to note I am only using the kernel as a bare-metal kernel, so I have not loaded it as a module in grub with the hypervisor.
> >
> > > b). If it does not, try an earlier kernel or a distro supplied one.
> > >
> > > If the a) or b) don't work then you have a very unique motherboard
> > > and we will need to play a bit with 'reboot=' command line arguments.
> > > Look in arch/x86/kernel/reboot.c for details.
> > >
> >
> > I have tried using different reboot=X kernel command line arguments, but none of them have correct the rebooting issue. In fact the system hangs the same way in all cases.
>
> <scratches his head> That is most bizzare.
> Can you try to get the latest linux kernel and see how it works?
>
Well its not the 'latest' linux kernel, but I installed 2.6.30-8-amd64 from http://packages.debian.org/lenny-backports/kernel/linux-image-2.6.30-bpo.2-amd64 and the reboot hangs the same way.
That leads me to believe something in the mechanism of a system reboot has changed since 2.6.26-2-amd64.
> >
> > > Lets assume that a) or b) do work. We want to find out what it does
> > > to the machine. You can instrument the code (reboot.c?) and find out
> > > which mechanism it uses.
> > >
> >
> > I know that the system reboot fine with the Debian 2.6.26-2-amd64 kernel. Please suggest how one might compare these kernels reboot.c. Shall I simply run the diff utility. I can read C source, but to truly understand it I feel I need to have written the code... With help I believe I can find the mechanism it uses.
>
> Diff would do it. Look for shutdown.c and reboot.c file.
I don't find any shutdown.c file oddly enough. I have found multiple reboot.c though.
/usr/src/linux-2.6-xen/arch/sparc/kernel/reboot.c
/usr/src/linux-2.6-xen/arch/um/kernel/reboot.c
/usr/src/linux-2.6-xen/arch/x86/kernel/reboot.c
/usr/src/linux-2.6-xen/arch/blackfin/kernel/reboot.c
/usr/src/linux-2.6-xen/drivers/acpi/reboot.c
and
/usr/src/linux-2.6-2.6.26/arch/um/kernel/reboot.c
/usr/src/linux-2.6-2.6.26/arch/x86/kernel/reboot.c
/usr/src/linux-2.6-2.6.26/arch/x86/mach-visws/reboot.c
/usr/src/linux-2.6-2.6.26/arch/blackfin/kernel/reboot.c
Which one of these reboot.c should I diff against each other?
EDIT: Attached are diff.out & diff.out2 (with side-by-side)
Working reboot.c as first file, Jermemy's reboot.c as second file.
root@localhost:/usr/src# diff ./linux-2.6-2.6.26/arch/x86/kernel/reboot.c ./linux-2.6-xen/arch/x86/kernel/reboot.c > diff.out
root@localhost:/usr/src# nano diff.out
root@localhost:/usr/src# diff -y ./linux-2.6-2.6.26/arch/x86/kernel/reboot.c ./linux-2.6-xen/arch/x86/kernel/reboot.c > diff.out2
> ..snip ..
> > > What is weird is that your screenshot says "machine reboot" which only
> > > shows up when you are running on bare-metal. Was that screen shot taken
> > > when pv-ops was running under Xen or bare-metal?
> >
> > As mentioned previous, I was using bare-metal indeed. Should I expect the reboot functionality to work with Jeremy's kernel after using the Xen Hypervisor?
>
> Probably not. The shutdown/reboot code is similar to the upstream
> kernel. So if the upstream is not working, then this one wouldn't
> either.
>
> _______________________________________________
> Xen-devel mailing list
> Xen-devel@lists.xensource.com
> http://lists.xensource.com/xen-devel
-M
Windows® phone-your Windows stuff, on the go. See more.
_________________________________________________________________
[-- Attachment #1.2: Type: text/html, Size: 5274 bytes --]
[-- Attachment #2: diff.out --]
[-- Type: application/octet-stream, Size: 9769 bytes --]
5a6
> #include <linux/dmi.h>
14a16,18
> #include <asm/pci_x86.h>
> #include <asm/virtext.h>
> #include <asm/cpu.h>
17d20
< # include <linux/dmi.h>
30c33
< static long no_idt[3];
---
> static const struct desc_ptr no_idt = {};
39c42,51
< /* reboot=b[ios] | s[mp] | t[riple] | k[bd] | e[fi] [, [w]arm | [c]old]
---
> /* This is set if we need to go through the 'emergency' path.
> * When machine_emergency_restart() is called, we may be on
> * an inconsistent state and won't be able to do a clean cleanup
> */
> static int reboot_emergency;
>
> /* This is set by the PCI code if either type 1 or type 2 PCI is detected */
> bool port_cf9_safe = false;
>
> /* reboot=b[ios] | s[mp] | t[riple] | k[bd] | e[fi] [, [w]arm | [c]old] | p[ci]
47a60
> pci Use the so-called "PCI reset register", CF9
81a95
> case 'p':
171a186,203
> { /* Handle problems with rebooting on Dell Optiplex 330 with 0KP561 */
> .callback = set_bios_reboot,
> .ident = "Dell OptiPlex 330",
> .matches = {
> DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
> DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 330"),
> DMI_MATCH(DMI_BOARD_NAME, "0KP561"),
> },
> },
> { /* Handle problems with rebooting on Dell Optiplex 360 with 0T656F */
> .callback = set_bios_reboot,
> .ident = "Dell OptiPlex 360",
> .matches = {
> DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
> DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 360"),
> DMI_MATCH(DMI_BOARD_NAME, "0T656F"),
> },
> },
179a212,219
> { /* Handle problems with rebooting on Dell T5400's */
> .callback = set_bios_reboot,
> .ident = "Dell Precision T5400",
> .matches = {
> DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
> DMI_MATCH(DMI_PRODUCT_NAME, "Precision WorkStation T5400"),
> },
> },
187a228,259
> { /* Handle problems with rebooting on Dell XPS710 */
> .callback = set_bios_reboot,
> .ident = "Dell XPS710",
> .matches = {
> DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
> DMI_MATCH(DMI_PRODUCT_NAME, "Dell XPS710"),
> },
> },
> { /* Handle problems with rebooting on Dell DXP061 */
> .callback = set_bios_reboot,
> .ident = "Dell DXP061",
> .matches = {
> DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
> DMI_MATCH(DMI_PRODUCT_NAME, "Dell DXP061"),
> },
> },
> { /* Handle problems with rebooting on Sony VGN-Z540N */
> .callback = set_bios_reboot,
> .ident = "Sony VGN-Z540N",
> .matches = {
> DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
> DMI_MATCH(DMI_PRODUCT_NAME, "VGN-Z540N"),
> },
> },
> { /* Handle problems with rebooting on CompuLab SBC-FITPC2 */
> .callback = set_bios_reboot,
> .ident = "CompuLab SBC-FITPC2",
> .matches = {
> DMI_MATCH(DMI_SYS_VENDOR, "CompuLab"),
> DMI_MATCH(DMI_PRODUCT_NAME, "SBC-FITPC2"),
> },
> },
204c276
< static unsigned long long
---
> static const unsigned long long
208,209c280,281
< 0x00009a000000ffffULL, /* 16-bit real-mode 64k code at 0x00000000 */
< 0x000092000100ffffULL /* 16-bit real-mode 64k data at 0x00000100 */
---
> 0x00009b000000ffffULL, /* 16-bit real-mode 64k code at 0x00000000 */
> 0x000093000100ffffULL /* 16-bit real-mode 64k data at 0x00000100 */
212c284
< static struct desc_ptr
---
> static const struct desc_ptr
234c306
< static unsigned char real_mode_switch [] =
---
> static const unsigned char real_mode_switch [] =
248c320
< static unsigned char jump_to_bios [] =
---
> static const unsigned char jump_to_bios [] =
258c330
< void machine_real_restart(unsigned char *code, int length)
---
> void machine_real_restart(const unsigned char *code, int length)
334a407,446
> /*
> * Some Apple MacBook and MacBookPro's needs reboot=p to be able to reboot
> */
> static int __init set_pci_reboot(const struct dmi_system_id *d)
> {
> if (reboot_type != BOOT_CF9) {
> reboot_type = BOOT_CF9;
> printk(KERN_INFO "%s series board detected. "
> "Selecting PCI-method for reboots.\n", d->ident);
> }
> return 0;
> }
>
> static struct dmi_system_id __initdata pci_reboot_dmi_table[] = {
> { /* Handle problems with rebooting on Apple MacBook5 */
> .callback = set_pci_reboot,
> .ident = "Apple MacBook5",
> .matches = {
> DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
> DMI_MATCH(DMI_PRODUCT_NAME, "MacBook5"),
> },
> },
> { /* Handle problems with rebooting on Apple MacBookPro5 */
> .callback = set_pci_reboot,
> .ident = "Apple MacBookPro5",
> .matches = {
> DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
> DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5"),
> },
> },
> { }
> };
>
> static int __init pci_reboot_init(void)
> {
> dmi_check_system(pci_reboot_dmi_table);
> return 0;
> }
> core_initcall(pci_reboot_init);
>
345a458,499
> static void vmxoff_nmi(int cpu, struct die_args *args)
> {
> cpu_emergency_vmxoff();
> }
>
> /* Use NMIs as IPIs to tell all CPUs to disable virtualization
> */
> static void emergency_vmx_disable_all(void)
> {
> /* Just make sure we won't change CPUs while doing this */
> local_irq_disable();
>
> /* We need to disable VMX on all CPUs before rebooting, otherwise
> * we risk hanging up the machine, because the CPU ignore INIT
> * signals when VMX is enabled.
> *
> * We can't take any locks and we may be on an inconsistent
> * state, so we use NMIs as IPIs to tell the other CPUs to disable
> * VMX and halt.
> *
> * For safety, we will avoid running the nmi_shootdown_cpus()
> * stuff unnecessarily, but we don't have a way to check
> * if other CPUs have VMX enabled. So we will call it only if the
> * CPU we are running on has VMX enabled.
> *
> * We will miss cases where VMX is not enabled on all CPUs. This
> * shouldn't do much harm because KVM always enable VMX on all
> * CPUs anyway. But we can miss it on the small window where KVM
> * is still enabling VMX.
> */
> if (cpu_has_vmx() && cpu_vmx_enabled()) {
> /* Disable VMX on this CPU.
> */
> cpu_vmxoff();
>
> /* Halt and disable VMX on the other CPUs */
> nmi_shootdown_cpus(vmxoff_nmi);
>
> }
> }
>
>
353a508,510
> if (reboot_emergency)
> emergency_vmx_disable_all();
>
371c528
< load_idt((const struct desc_ptr *)&no_idt);
---
> load_idt(&no_idt);
390d546
<
393c549,551
< efi.reset_system(reboot_mode ? EFI_RESET_WARM : EFI_RESET_COLD,
---
> efi.reset_system(reboot_mode ?
> EFI_RESET_WARM :
> EFI_RESET_COLD,
394a553,554
> reboot_type = BOOT_KBD;
> break;
395a556,567
> case BOOT_CF9:
> port_cf9_safe = true;
> /* fall through */
>
> case BOOT_CF9_COND:
> if (port_cf9_safe) {
> u8 cf9 = inb(0xcf9) & ~6;
> outb(cf9|2, 0xcf9); /* Request hard reset */
> udelay(50);
> outb(cf9|6, 0xcf9); /* Actually do the reset */
> udelay(50);
> }
406d577
< int reboot_cpu_id;
409c580
< reboot_cpu_id = 0;
---
> int reboot_cpu_id = 0;
413c584
< if ((reboot_cpu != -1) && (reboot_cpu < NR_CPUS) &&
---
> if ((reboot_cpu != -1) && (reboot_cpu < nr_cpu_ids) &&
423c594
< set_cpus_allowed_ptr(current, &cpumask_of_cpu(reboot_cpu_id));
---
> set_cpus_allowed_ptr(current, cpumask_of(reboot_cpu_id));
445a617,622
> static void __machine_emergency_restart(int emergency)
> {
> reboot_emergency = emergency;
> machine_ops.emergency_restart();
> }
>
452c629
< machine_emergency_restart();
---
> __machine_emergency_restart(0);
456a634,638
> /* stop other cpus and apics */
> machine_shutdown();
>
> /* stop this cpu */
> stop_this_cpu(NULL);
491c673
< machine_ops.emergency_restart();
---
> __machine_emergency_restart(1);
509a692,780
>
>
> #if defined(CONFIG_SMP)
>
> /* This keeps a track of which one is crashing cpu. */
> static int crashing_cpu;
> static nmi_shootdown_cb shootdown_callback;
>
> static atomic_t waiting_for_crash_ipi;
>
> static int crash_nmi_callback(struct notifier_block *self,
> unsigned long val, void *data)
> {
> int cpu;
>
> if (val != DIE_NMI_IPI)
> return NOTIFY_OK;
>
> cpu = raw_smp_processor_id();
>
> /* Don't do anything if this handler is invoked on crashing cpu.
> * Otherwise, system will completely hang. Crashing cpu can get
> * an NMI if system was initially booted with nmi_watchdog parameter.
> */
> if (cpu == crashing_cpu)
> return NOTIFY_STOP;
> local_irq_disable();
>
> shootdown_callback(cpu, (struct die_args *)data);
>
> atomic_dec(&waiting_for_crash_ipi);
> /* Assume hlt works */
> halt();
> for (;;)
> cpu_relax();
>
> return 1;
> }
>
> static void smp_send_nmi_allbutself(void)
> {
> apic->send_IPI_allbutself(NMI_VECTOR);
> }
>
> static struct notifier_block crash_nmi_nb = {
> .notifier_call = crash_nmi_callback,
> };
>
> /* Halt all other CPUs, calling the specified function on each of them
> *
> * This function can be used to halt all other CPUs on crash
> * or emergency reboot time. The function passed as parameter
> * will be called inside a NMI handler on all CPUs.
> */
> void nmi_shootdown_cpus(nmi_shootdown_cb callback)
> {
> unsigned long msecs;
> local_irq_disable();
>
> /* Make a note of crashing cpu. Will be used in NMI callback.*/
> crashing_cpu = safe_smp_processor_id();
>
> shootdown_callback = callback;
>
> atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1);
> /* Would it be better to replace the trap vector here? */
> if (register_die_notifier(&crash_nmi_nb))
> return; /* return what? */
> /* Ensure the new callback function is set before sending
> * out the NMI
> */
> wmb();
>
> smp_send_nmi_allbutself();
>
> msecs = 1000; /* Wait at most a second for the other cpus to stop */
> while ((atomic_read(&waiting_for_crash_ipi) > 0) && msecs) {
> mdelay(1);
> msecs--;
> }
>
> /* Leave the nmi callback set */
> }
> #else /* !CONFIG_SMP */
> void nmi_shootdown_cpus(nmi_shootdown_cb callback)
> {
> /* No other CPUs to shoot down */
> }
> #endif
[-- Attachment #3: diff.out2 --]
[-- Type: application/octet-stream, Size: 37051 bytes --]
#include <linux/module.h> #include <linux/module.h>
#include <linux/reboot.h> #include <linux/reboot.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/pm.h> #include <linux/pm.h>
#include <linux/efi.h> #include <linux/efi.h>
> #include <linux/dmi.h>
#include <acpi/reboot.h> #include <acpi/reboot.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/apic.h> #include <asm/apic.h>
#include <asm/desc.h> #include <asm/desc.h>
#include <asm/hpet.h> #include <asm/hpet.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
#include <asm/proto.h> #include <asm/proto.h>
#include <asm/reboot_fixups.h> #include <asm/reboot_fixups.h>
#include <asm/reboot.h> #include <asm/reboot.h>
> #include <asm/pci_x86.h>
> #include <asm/virtext.h>
> #include <asm/cpu.h>
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
# include <linux/dmi.h> <
# include <linux/ctype.h> # include <linux/ctype.h>
# include <linux/mc146818rtc.h> # include <linux/mc146818rtc.h>
#else #else
# include <asm/iommu.h> # include <asm/iommu.h>
#endif #endif
/* /*
* Power off function, if any * Power off function, if any
*/ */
void (*pm_power_off)(void); void (*pm_power_off)(void);
EXPORT_SYMBOL(pm_power_off); EXPORT_SYMBOL(pm_power_off);
static long no_idt[3]; | static const struct desc_ptr no_idt = {};
static int reboot_mode; static int reboot_mode;
enum reboot_type reboot_type = BOOT_KBD; enum reboot_type reboot_type = BOOT_KBD;
int reboot_force; int reboot_force;
#if defined(CONFIG_X86_32) && defined(CONFIG_SMP) #if defined(CONFIG_X86_32) && defined(CONFIG_SMP)
static int reboot_cpu = -1; static int reboot_cpu = -1;
#endif #endif
/* reboot=b[ios] | s[mp] | t[riple] | k[bd] | e[fi] [, [w]arm | /* This is set if we need to go through the 'emergency' path.
> * When machine_emergency_restart() is called, we may be on
> * an inconsistent state and won't be able to do a clean clea
> */
> static int reboot_emergency;
>
> /* This is set by the PCI code if either type 1 or type 2 PCI
> bool port_cf9_safe = false;
>
> /* reboot=b[ios] | s[mp] | t[riple] | k[bd] | e[fi] [, [w]arm
warm Don't set the cold reboot flag warm Don't set the cold reboot flag
cold Set the cold reboot flag cold Set the cold reboot flag
bios Reboot by jumping through the BIOS (only for X86_32 bios Reboot by jumping through the BIOS (only for X86_32
smp Reboot by executing reset on BSP or other CPU (only smp Reboot by executing reset on BSP or other CPU (only
triple Force a triple fault (init) triple Force a triple fault (init)
kbd Use the keyboard controller. cold reset (default) kbd Use the keyboard controller. cold reset (default)
acpi Use the RESET_REG in the FADT acpi Use the RESET_REG in the FADT
efi Use efi reset_system runtime service efi Use efi reset_system runtime service
> pci Use the so-called "PCI reset register", CF9
force Avoid anything that could hang. force Avoid anything that could hang.
*/ */
static int __init reboot_setup(char *str) static int __init reboot_setup(char *str)
{ {
for (;;) { for (;;) {
switch (*str) { switch (*str) {
case 'w': case 'w':
reboot_mode = 0x1234; reboot_mode = 0x1234;
break; break;
case 'c': case 'c':
reboot_mode = 0; reboot_mode = 0;
break; break;
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
case 's': case 's':
if (isdigit(*(str+1))) { if (isdigit(*(str+1))) {
reboot_cpu = (int) (*(str+1) reboot_cpu = (int) (*(str+1)
if (isdigit(*(str+2))) if (isdigit(*(str+2)))
reboot_cpu = reboot_c reboot_cpu = reboot_c
} }
/* we will leave sorting out /* we will leave sorting out
when we are ready to reboo when we are ready to reboo
have set up boot_cpu_id or have set up boot_cpu_id or
break; break;
#endif /* CONFIG_SMP */ #endif /* CONFIG_SMP */
case 'b': case 'b':
#endif #endif
case 'a': case 'a':
case 'k': case 'k':
case 't': case 't':
case 'e': case 'e':
> case 'p':
reboot_type = *str; reboot_type = *str;
break; break;
case 'f': case 'f':
reboot_force = 1; reboot_force = 1;
break; break;
} }
str = strchr(str, ','); str = strchr(str, ',');
if (str) if (str)
str++; str++;
else else
break; break;
} }
return 1; return 1;
} }
__setup("reboot=", reboot_setup); __setup("reboot=", reboot_setup);
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
/* /*
* Reboot options and system auto-detection code provided by * Reboot options and system auto-detection code provided by
* Dell Inc. so their systems "just work". :-) * Dell Inc. so their systems "just work". :-)
*/ */
/* /*
* Some machines require the "reboot=b" commandline option, * Some machines require the "reboot=b" commandline option,
* this quirk makes that automatic. * this quirk makes that automatic.
*/ */
static int __init set_bios_reboot(const struct dmi_system_id static int __init set_bios_reboot(const struct dmi_system_id
{ {
if (reboot_type != BOOT_BIOS) { if (reboot_type != BOOT_BIOS) {
reboot_type = BOOT_BIOS; reboot_type = BOOT_BIOS;
printk(KERN_INFO "%s series board detected. S printk(KERN_INFO "%s series board detected. S
} }
return 0; return 0;
} }
static struct dmi_system_id __initdata reboot_dmi_table[] = { static struct dmi_system_id __initdata reboot_dmi_table[] = {
{ /* Handle problems with rebooting on Dell E52 { /* Handle problems with rebooting on Dell E52
.callback = set_bios_reboot, .callback = set_bios_reboot,
.ident = "Dell E520", .ident = "Dell E520",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc." DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."
DMI_MATCH(DMI_PRODUCT_NAME, "Dell DM0 DMI_MATCH(DMI_PRODUCT_NAME, "Dell DM0
}, },
}, },
{ /* Handle problems with rebooting on Dell 130 { /* Handle problems with rebooting on Dell 130
.callback = set_bios_reboot, .callback = set_bios_reboot,
.ident = "Dell PowerEdge 1300", .ident = "Dell PowerEdge 1300",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Compu DMI_MATCH(DMI_SYS_VENDOR, "Dell Compu
DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdg DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdg
}, },
}, },
{ /* Handle problems with rebooting on Dell 300 { /* Handle problems with rebooting on Dell 300
.callback = set_bios_reboot, .callback = set_bios_reboot,
.ident = "Dell PowerEdge 300", .ident = "Dell PowerEdge 300",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Compu DMI_MATCH(DMI_SYS_VENDOR, "Dell Compu
DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdg DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdg
}, },
}, },
{ /* Handle problems with rebooting on Dell Opt { /* Handle problems with rebooting on Dell Opt
.callback = set_bios_reboot, .callback = set_bios_reboot,
.ident = "Dell OptiPlex 745", .ident = "Dell OptiPlex 745",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc." DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."
DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex
}, },
}, },
{ /* Handle problems with rebooting on Dell Opt { /* Handle problems with rebooting on Dell Opt
.callback = set_bios_reboot, .callback = set_bios_reboot,
.ident = "Dell OptiPlex 745", .ident = "Dell OptiPlex 745",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc." DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."
DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex
DMI_MATCH(DMI_BOARD_NAME, "0MM599"), DMI_MATCH(DMI_BOARD_NAME, "0MM599"),
}, },
}, },
{ /* Handle problems with rebooting on Dell Opt { /* Handle problems with rebooting on Dell Opt
.callback = set_bios_reboot, .callback = set_bios_reboot,
.ident = "Dell OptiPlex 745", .ident = "Dell OptiPlex 745",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc." DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."
DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex
DMI_MATCH(DMI_BOARD_NAME, "0KW626"), DMI_MATCH(DMI_BOARD_NAME, "0KW626"),
}, },
}, },
> { /* Handle problems with rebooting on Dell Optiple
> .callback = set_bios_reboot,
> .ident = "Dell OptiPlex 330",
> .matches = {
> DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."
> DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex
> DMI_MATCH(DMI_BOARD_NAME, "0KP561"),
> },
> },
> { /* Handle problems with rebooting on Dell Optiple
> .callback = set_bios_reboot,
> .ident = "Dell OptiPlex 360",
> .matches = {
> DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."
> DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex
> DMI_MATCH(DMI_BOARD_NAME, "0T656F"),
> },
> },
{ /* Handle problems with rebooting on Dell 240 { /* Handle problems with rebooting on Dell 240
.callback = set_bios_reboot, .callback = set_bios_reboot,
.ident = "Dell PowerEdge 2400", .ident = "Dell PowerEdge 2400",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Compu DMI_MATCH(DMI_SYS_VENDOR, "Dell Compu
DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdg DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdg
}, },
}, },
> { /* Handle problems with rebooting on Dell T54
> .callback = set_bios_reboot,
> .ident = "Dell Precision T5400",
> .matches = {
> DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."
> DMI_MATCH(DMI_PRODUCT_NAME, "Precisio
> },
> },
{ /* Handle problems with rebooting on HP lapto { /* Handle problems with rebooting on HP lapto
.callback = set_bios_reboot, .callback = set_bios_reboot,
.ident = "HP Compaq Laptop", .ident = "HP Compaq Laptop",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Pa DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Pa
DMI_MATCH(DMI_PRODUCT_NAME, "HP Compa DMI_MATCH(DMI_PRODUCT_NAME, "HP Compa
}, },
}, },
> { /* Handle problems with rebooting on Dell XPS
> .callback = set_bios_reboot,
> .ident = "Dell XPS710",
> .matches = {
> DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."
> DMI_MATCH(DMI_PRODUCT_NAME, "Dell XPS
> },
> },
> { /* Handle problems with rebooting on Dell DXP
> .callback = set_bios_reboot,
> .ident = "Dell DXP061",
> .matches = {
> DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."
> DMI_MATCH(DMI_PRODUCT_NAME, "Dell DXP
> },
> },
> { /* Handle problems with rebooting on Sony VGN
> .callback = set_bios_reboot,
> .ident = "Sony VGN-Z540N",
> .matches = {
> DMI_MATCH(DMI_SYS_VENDOR, "Sony Corpo
> DMI_MATCH(DMI_PRODUCT_NAME, "VGN-Z540
> },
> },
> { /* Handle problems with rebooting on CompuLab
> .callback = set_bios_reboot,
> .ident = "CompuLab SBC-FITPC2",
> .matches = {
> DMI_MATCH(DMI_SYS_VENDOR, "CompuLab")
> DMI_MATCH(DMI_PRODUCT_NAME, "SBC-FITP
> },
> },
{ } { }
}; };
static int __init reboot_init(void) static int __init reboot_init(void)
{ {
dmi_check_system(reboot_dmi_table); dmi_check_system(reboot_dmi_table);
return 0; return 0;
} }
core_initcall(reboot_init); core_initcall(reboot_init);
/* The following code and data reboots the machine by switchi /* The following code and data reboots the machine by switchi
mode and jumping to the BIOS reset entry point, as if the mode and jumping to the BIOS reset entry point, as if the
really been reset. The previous version asked the keyboar really been reset. The previous version asked the keyboar
controller to pulse the CPU reset line, which is more thor controller to pulse the CPU reset line, which is more thor
doesn't work with at least one type of 486 motherboard. I doesn't work with at least one type of 486 motherboard. I
to stop this code working; hence the copious comments. */ to stop this code working; hence the copious comments. */
static unsigned long long | static const unsigned long long
real_mode_gdt_entries [3] = real_mode_gdt_entries [3] =
{ {
0x0000000000000000ULL, /* Null descriptor */ 0x0000000000000000ULL, /* Null descriptor */
0x00009a000000ffffULL, /* 16-bit real-mode 64k code | 0x00009b000000ffffULL, /* 16-bit real-mode 64k code
0x000092000100ffffULL /* 16-bit real-mode 64k data | 0x000093000100ffffULL /* 16-bit real-mode 64k data
}; };
static struct desc_ptr | static const struct desc_ptr
real_mode_gdt = { sizeof (real_mode_gdt_entries) - 1, (long)r real_mode_gdt = { sizeof (real_mode_gdt_entries) - 1, (long)r
real_mode_idt = { 0x3ff, 0 }; real_mode_idt = { 0x3ff, 0 };
/* This is 16-bit protected mode code to disable paging and t /* This is 16-bit protected mode code to disable paging and t
switch to real mode and jump to the BIOS reset code. switch to real mode and jump to the BIOS reset code.
The instruction that switches to real mode by writing to C The instruction that switches to real mode by writing to C
followed immediately by a far jump instruction, which set followed immediately by a far jump instruction, which set
valid value for real mode, and flushes the prefetch queue valid value for real mode, and flushes the prefetch queue
running instructions that have already been decoded in pro running instructions that have already been decoded in pro
mode. mode.
Clears all the flags except ET, especially PG (paging), PE Clears all the flags except ET, especially PG (paging), PE
(protected-mode enable) and TS (task switch for coprocesso (protected-mode enable) and TS (task switch for coprocesso
save). Flushes the TLB after paging has been disabled. S save). Flushes the TLB after paging has been disabled. S
NW, to disable the cache on a 486, and invalidates the cac NW, to disable the cache on a 486, and invalidates the cac
is more like the state of a 486 after reset. I don't know is more like the state of a 486 after reset. I don't know
something else should be done for other chips. something else should be done for other chips.
More could be done here to set up the registers as if a CP More could be done here to set up the registers as if a CP
occurred; hopefully real BIOSs don't assume much. */ occurred; hopefully real BIOSs don't assume much. */
static unsigned char real_mode_switch [] = | static const unsigned char real_mode_switch [] =
{ {
0x66, 0x0f, 0x20, 0xc0, /* movl % 0x66, 0x0f, 0x20, 0xc0, /* movl %
0x66, 0x83, 0xe0, 0x11, /* andl $ 0x66, 0x83, 0xe0, 0x11, /* andl $
0x66, 0x0d, 0x00, 0x00, 0x00, 0x60, /* orl $ 0x66, 0x0d, 0x00, 0x00, 0x00, 0x60, /* orl $
0x66, 0x0f, 0x22, 0xc0, /* movl % 0x66, 0x0f, 0x22, 0xc0, /* movl %
0x66, 0x0f, 0x22, 0xd8, /* movl % 0x66, 0x0f, 0x22, 0xd8, /* movl %
0x66, 0x0f, 0x20, 0xc3, /* movl % 0x66, 0x0f, 0x20, 0xc3, /* movl %
0x66, 0x81, 0xe3, 0x00, 0x00, 0x00, 0x60, /* 0x66, 0x81, 0xe3, 0x00, 0x00, 0x00, 0x60, /*
0x74, 0x02, /* jz f 0x74, 0x02, /* jz f
0x0f, 0x09, /* wbinvd 0x0f, 0x09, /* wbinvd
0x24, 0x10, /* f: andb $ 0x24, 0x10, /* f: andb $
0x66, 0x0f, 0x22, 0xc0 /* movl % 0x66, 0x0f, 0x22, 0xc0 /* movl %
}; };
static unsigned char jump_to_bios [] = | static const unsigned char jump_to_bios [] =
{ {
0xea, 0x00, 0x00, 0xff, 0xff /* ljmp $ 0xea, 0x00, 0x00, 0xff, 0xff /* ljmp $
}; };
/* /*
* Switch to real mode and then execute the code * Switch to real mode and then execute the code
* specified by the code and length parameters. * specified by the code and length parameters.
* We assume that length will aways be less that 100! * We assume that length will aways be less that 100!
*/ */
void machine_real_restart(unsigned char *code, int length) | void machine_real_restart(const unsigned char *code, int leng
{ {
local_irq_disable(); local_irq_disable();
/* Write zero to CMOS register number 0x0f, which the /* Write zero to CMOS register number 0x0f, which the
routine will recognize as telling it to do a prope routine will recognize as telling it to do a prope
that's what this book in front of me says -- it ma that's what this book in front of me says -- it ma
the Phoenix BIOS though, it's not clear). At the the Phoenix BIOS though, it's not clear). At the
disable NMIs by setting the top bit in the CMOS ad disable NMIs by setting the top bit in the CMOS ad
as we're about to do peculiar things to the CPU. as we're about to do peculiar things to the CPU.
`outb_p' is needed instead of just `outb'. Use it `outb_p' is needed instead of just `outb'. Use it
safe side. (Yes, CMOS_WRITE does outb_p's. - Pau safe side. (Yes, CMOS_WRITE does outb_p's. - Pau
*/ */
spin_lock(&rtc_lock); spin_lock(&rtc_lock);
CMOS_WRITE(0x00, 0x8f); CMOS_WRITE(0x00, 0x8f);
spin_unlock(&rtc_lock); spin_unlock(&rtc_lock);
/* Remap the kernel at virtual address zero, as well /* Remap the kernel at virtual address zero, as well
from the kernel segment. This assumes the kernel from the kernel segment. This assumes the kernel
virtual address PAGE_OFFSET. */ virtual address PAGE_OFFSET. */
memcpy(swapper_pg_dir, swapper_pg_dir + KERNEL_PGD_BO memcpy(swapper_pg_dir, swapper_pg_dir + KERNEL_PGD_BO
sizeof(swapper_pg_dir [0]) * KERNEL_PGD_PTRS) sizeof(swapper_pg_dir [0]) * KERNEL_PGD_PTRS)
/* /*
* Use `swapper_pg_dir' as our page directory. * Use `swapper_pg_dir' as our page directory.
*/ */
load_cr3(swapper_pg_dir); load_cr3(swapper_pg_dir);
/* Write 0x1234 to absolute memory location 0x472. T /* Write 0x1234 to absolute memory location 0x472. T
this on booting to tell it to "Bypass memory test this on booting to tell it to "Bypass memory test
boot)". This seems like a fairly standard thing t boot)". This seems like a fairly standard thing t
REBOOT.COM programs, and the previous reset routin REBOOT.COM programs, and the previous reset routin
too. */ too. */
*((unsigned short *)0x472) = reboot_mode; *((unsigned short *)0x472) = reboot_mode;
/* For the switch to real mode, copy some code to low /* For the switch to real mode, copy some code to low
to be in the first 64k because it is running in 16 to be in the first 64k because it is running in 16
has to have the same physical and virtual address, has to have the same physical and virtual address,
off paging. Copy it near the end of the first pag off paging. Copy it near the end of the first pag
of BIOS variables. */ of BIOS variables. */
memcpy((void *)(0x1000 - sizeof(real_mode_switch) - 1 memcpy((void *)(0x1000 - sizeof(real_mode_switch) - 1
real_mode_switch, sizeof (real_mode_switch)); real_mode_switch, sizeof (real_mode_switch));
memcpy((void *)(0x1000 - 100), code, length); memcpy((void *)(0x1000 - 100), code, length);
/* Set up the IDT for real mode. */ /* Set up the IDT for real mode. */
load_idt(&real_mode_idt); load_idt(&real_mode_idt);
/* Set up a GDT from which we can load segment descri /* Set up a GDT from which we can load segment descri
mode. The GDT is not used in real mode; it is jus mode. The GDT is not used in real mode; it is jus
prepare the descriptors. */ prepare the descriptors. */
load_gdt(&real_mode_gdt); load_gdt(&real_mode_gdt);
/* Load the data segment registers, and thus the desc /* Load the data segment registers, and thus the desc
real mode. The base address of each segment is 0x real mode. The base address of each segment is 0x
selector value being loaded here. This is so that selector value being loaded here. This is so that
registers don't have to be reloaded after switchin registers don't have to be reloaded after switchin
the values are consistent for real mode operation the values are consistent for real mode operation
__asm__ __volatile__ ("movl $0x0010,%%eax\n" __asm__ __volatile__ ("movl $0x0010,%%eax\n"
"\tmovl %%eax,%%ds\n" "\tmovl %%eax,%%ds\n"
"\tmovl %%eax,%%es\n" "\tmovl %%eax,%%es\n"
"\tmovl %%eax,%%fs\n" "\tmovl %%eax,%%fs\n"
"\tmovl %%eax,%%gs\n" "\tmovl %%eax,%%gs\n"
"\tmovl %%eax,%%ss" : : : "ea "\tmovl %%eax,%%ss" : : : "ea
/* Jump to the 16-bit code that we copied earlier. I /* Jump to the 16-bit code that we copied earlier. I
and the cache, switches to real mode, and jumps to and the cache, switches to real mode, and jumps to
entry point. */ entry point. */
__asm__ __volatile__ ("ljmp $0x0008,%0" __asm__ __volatile__ ("ljmp $0x0008,%0"
: :
: "i" ((void *)(0x1000 - size : "i" ((void *)(0x1000 - size
} }
#ifdef CONFIG_APM_MODULE #ifdef CONFIG_APM_MODULE
EXPORT_SYMBOL(machine_real_restart); EXPORT_SYMBOL(machine_real_restart);
#endif #endif
#endif /* CONFIG_X86_32 */ #endif /* CONFIG_X86_32 */
> /*
> * Some Apple MacBook and MacBookPro's needs reboot=p to be a
> */
> static int __init set_pci_reboot(const struct dmi_system_id *
> {
> if (reboot_type != BOOT_CF9) {
> reboot_type = BOOT_CF9;
> printk(KERN_INFO "%s series board detected. "
> "Selecting PCI-method for reboots.\n",
> }
> return 0;
> }
>
> static struct dmi_system_id __initdata pci_reboot_dmi_table[]
> { /* Handle problems with rebooting on Apple Ma
> .callback = set_pci_reboot,
> .ident = "Apple MacBook5",
> .matches = {
> DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc.
> DMI_MATCH(DMI_PRODUCT_NAME, "MacBook5
> },
> },
> { /* Handle problems with rebooting on Apple Ma
> .callback = set_pci_reboot,
> .ident = "Apple MacBookPro5",
> .matches = {
> DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc.
> DMI_MATCH(DMI_PRODUCT_NAME, "MacBookP
> },
> },
> { }
> };
>
> static int __init pci_reboot_init(void)
> {
> dmi_check_system(pci_reboot_dmi_table);
> return 0;
> }
> core_initcall(pci_reboot_init);
>
static inline void kb_wait(void) static inline void kb_wait(void)
{ {
int i; int i;
for (i = 0; i < 0x10000; i++) { for (i = 0; i < 0x10000; i++) {
if ((inb(0x64) & 0x02) == 0) if ((inb(0x64) & 0x02) == 0)
break; break;
udelay(2); udelay(2);
} }
} }
> static void vmxoff_nmi(int cpu, struct die_args *args)
> {
> cpu_emergency_vmxoff();
> }
>
> /* Use NMIs as IPIs to tell all CPUs to disable virtualizatio
> */
> static void emergency_vmx_disable_all(void)
> {
> /* Just make sure we won't change CPUs while doing th
> local_irq_disable();
>
> /* We need to disable VMX on all CPUs before rebootin
> * we risk hanging up the machine, because the CPU ig
> * signals when VMX is enabled.
> *
> * We can't take any locks and we may be on an incons
> * state, so we use NMIs as IPIs to tell the other CP
> * VMX and halt.
> *
> * For safety, we will avoid running the nmi_shootdow
> * stuff unnecessarily, but we don't have a way to ch
> * if other CPUs have VMX enabled. So we will call it
> * CPU we are running on has VMX enabled.
> *
> * We will miss cases where VMX is not enabled on all
> * shouldn't do much harm because KVM always enable V
> * CPUs anyway. But we can miss it on the small windo
> * is still enabling VMX.
> */
> if (cpu_has_vmx() && cpu_vmx_enabled()) {
> /* Disable VMX on this CPU.
> */
> cpu_vmxoff();
>
> /* Halt and disable VMX on the other CPUs */
> nmi_shootdown_cpus(vmxoff_nmi);
>
> }
> }
>
>
void __attribute__((weak)) mach_reboot_fixups(void) void __attribute__((weak)) mach_reboot_fixups(void)
{ {
} }
static void native_machine_emergency_restart(void) static void native_machine_emergency_restart(void)
{ {
int i; int i;
> if (reboot_emergency)
> emergency_vmx_disable_all();
>
/* Tell the BIOS if we want cold or warm reboot */ /* Tell the BIOS if we want cold or warm reboot */
*((unsigned short *)__va(0x472)) = reboot_mode; *((unsigned short *)__va(0x472)) = reboot_mode;
for (;;) { for (;;) {
/* Could also try the reset bit in the Hammer /* Could also try the reset bit in the Hammer
switch (reboot_type) { switch (reboot_type) {
case BOOT_KBD: case BOOT_KBD:
mach_reboot_fixups(); /* for board sp mach_reboot_fixups(); /* for board sp
for (i = 0; i < 10; i++) { for (i = 0; i < 10; i++) {
kb_wait(); kb_wait();
udelay(50); udelay(50);
outb(0xfe, 0x64); /* pulse re outb(0xfe, 0x64); /* pulse re
udelay(50); udelay(50);
} }
case BOOT_TRIPLE: case BOOT_TRIPLE:
load_idt((const struct desc_ptr *)&no | load_idt(&no_idt);
__asm__ __volatile__("int3"); __asm__ __volatile__("int3");
reboot_type = BOOT_KBD; reboot_type = BOOT_KBD;
break; break;
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
case BOOT_BIOS: case BOOT_BIOS:
machine_real_restart(jump_to_bios, si machine_real_restart(jump_to_bios, si
reboot_type = BOOT_KBD; reboot_type = BOOT_KBD;
break; break;
#endif #endif
case BOOT_ACPI: case BOOT_ACPI:
acpi_reboot(); acpi_reboot();
reboot_type = BOOT_KBD; reboot_type = BOOT_KBD;
break; break;
<
case BOOT_EFI: case BOOT_EFI:
if (efi_enabled) if (efi_enabled)
efi.reset_system(reboot_mode | efi.reset_system(reboot_mode
> EFI_RESET_WA
> EFI_RESET_CO
EFI_SUCCESS, EFI_SUCCESS,
> reboot_type = BOOT_KBD;
> break;
> case BOOT_CF9:
> port_cf9_safe = true;
> /* fall through */
>
> case BOOT_CF9_COND:
> if (port_cf9_safe) {
> u8 cf9 = inb(0xcf9) & ~6;
> outb(cf9|2, 0xcf9); /* Reques
> udelay(50);
> outb(cf9|6, 0xcf9); /* Actual
> udelay(50);
> }
reboot_type = BOOT_KBD; reboot_type = BOOT_KBD;
break; break;
} }
} }
} }
void native_machine_shutdown(void) void native_machine_shutdown(void)
{ {
/* Stop the cpus and apics */ /* Stop the cpus and apics */
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
int reboot_cpu_id; <
/* The boot cpu is always logical cpu 0 */ /* The boot cpu is always logical cpu 0 */
reboot_cpu_id = 0; | int reboot_cpu_id = 0;
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
/* See if there has been given a command line overrid /* See if there has been given a command line overrid
if ((reboot_cpu != -1) && (reboot_cpu < NR_CPUS) && | if ((reboot_cpu != -1) && (reboot_cpu < nr_cpu_ids) &
cpu_online(reboot_cpu)) cpu_online(reboot_cpu))
reboot_cpu_id = reboot_cpu; reboot_cpu_id = reboot_cpu;
#endif #endif
/* Make certain the cpu I'm about to reboot on is onl /* Make certain the cpu I'm about to reboot on is onl
if (!cpu_online(reboot_cpu_id)) if (!cpu_online(reboot_cpu_id))
reboot_cpu_id = smp_processor_id(); reboot_cpu_id = smp_processor_id();
/* Make certain I only run on the appropriate process /* Make certain I only run on the appropriate process
set_cpus_allowed_ptr(current, &cpumask_of_cpu(reboot_ | set_cpus_allowed_ptr(current, cpumask_of(reboot_cpu_i
/* O.K Now that I'm on the appropriate processor, /* O.K Now that I'm on the appropriate processor,
* stop all of the others. * stop all of the others.
*/ */
smp_send_stop(); smp_send_stop();
#endif #endif
lapic_shutdown(); lapic_shutdown();
#ifdef CONFIG_X86_IO_APIC #ifdef CONFIG_X86_IO_APIC
disable_IO_APIC(); disable_IO_APIC();
#endif #endif
#ifdef CONFIG_HPET_TIMER #ifdef CONFIG_HPET_TIMER
hpet_disable(); hpet_disable();
#endif #endif
#ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64
pci_iommu_shutdown(); pci_iommu_shutdown();
#endif #endif
} }
> static void __machine_emergency_restart(int emergency)
> {
> reboot_emergency = emergency;
> machine_ops.emergency_restart();
> }
>
static void native_machine_restart(char *__unused) static void native_machine_restart(char *__unused)
{ {
printk("machine restart\n"); printk("machine restart\n");
if (!reboot_force) if (!reboot_force)
machine_shutdown(); machine_shutdown();
machine_emergency_restart(); | __machine_emergency_restart(0);
} }
static void native_machine_halt(void) static void native_machine_halt(void)
{ {
> /* stop other cpus and apics */
> machine_shutdown();
>
> /* stop this cpu */
> stop_this_cpu(NULL);
} }
static void native_machine_power_off(void) static void native_machine_power_off(void)
{ {
if (pm_power_off) { if (pm_power_off) {
if (!reboot_force) if (!reboot_force)
machine_shutdown(); machine_shutdown();
pm_power_off(); pm_power_off();
} }
} }
struct machine_ops machine_ops = { struct machine_ops machine_ops = {
.power_off = native_machine_power_off, .power_off = native_machine_power_off,
.shutdown = native_machine_shutdown, .shutdown = native_machine_shutdown,
.emergency_restart = native_machine_emergency_restart .emergency_restart = native_machine_emergency_restart
.restart = native_machine_restart, .restart = native_machine_restart,
.halt = native_machine_halt, .halt = native_machine_halt,
#ifdef CONFIG_KEXEC #ifdef CONFIG_KEXEC
.crash_shutdown = native_machine_crash_shutdown, .crash_shutdown = native_machine_crash_shutdown,
#endif #endif
}; };
void machine_power_off(void) void machine_power_off(void)
{ {
machine_ops.power_off(); machine_ops.power_off();
} }
void machine_shutdown(void) void machine_shutdown(void)
{ {
machine_ops.shutdown(); machine_ops.shutdown();
} }
void machine_emergency_restart(void) void machine_emergency_restart(void)
{ {
machine_ops.emergency_restart(); | __machine_emergency_restart(1);
} }
void machine_restart(char *cmd) void machine_restart(char *cmd)
{ {
machine_ops.restart(cmd); machine_ops.restart(cmd);
} }
void machine_halt(void) void machine_halt(void)
{ {
machine_ops.halt(); machine_ops.halt();
} }
#ifdef CONFIG_KEXEC #ifdef CONFIG_KEXEC
void machine_crash_shutdown(struct pt_regs *regs) void machine_crash_shutdown(struct pt_regs *regs)
{ {
machine_ops.crash_shutdown(regs); machine_ops.crash_shutdown(regs);
} }
#endif #endif
>
>
> #if defined(CONFIG_SMP)
>
> /* This keeps a track of which one is crashing cpu. */
> static int crashing_cpu;
> static nmi_shootdown_cb shootdown_callback;
>
> static atomic_t waiting_for_crash_ipi;
>
> static int crash_nmi_callback(struct notifier_block *self,
> unsigned long val, void *data)
> {
> int cpu;
>
> if (val != DIE_NMI_IPI)
> return NOTIFY_OK;
>
> cpu = raw_smp_processor_id();
>
> /* Don't do anything if this handler is invoked on cr
> * Otherwise, system will completely hang. Crashing c
> * an NMI if system was initially booted with nmi_wat
> */
> if (cpu == crashing_cpu)
> return NOTIFY_STOP;
> local_irq_disable();
>
> shootdown_callback(cpu, (struct die_args *)data);
>
> atomic_dec(&waiting_for_crash_ipi);
> /* Assume hlt works */
> halt();
> for (;;)
> cpu_relax();
>
> return 1;
> }
>
> static void smp_send_nmi_allbutself(void)
> {
> apic->send_IPI_allbutself(NMI_VECTOR);
> }
>
> static struct notifier_block crash_nmi_nb = {
> .notifier_call = crash_nmi_callback,
> };
>
> /* Halt all other CPUs, calling the specified function on eac
> *
> * This function can be used to halt all other CPUs on crash
> * or emergency reboot time. The function passed as parameter
> * will be called inside a NMI handler on all CPUs.
> */
> void nmi_shootdown_cpus(nmi_shootdown_cb callback)
> {
> unsigned long msecs;
> local_irq_disable();
>
> /* Make a note of crashing cpu. Will be used in NMI c
> crashing_cpu = safe_smp_processor_id();
>
> shootdown_callback = callback;
>
> atomic_set(&waiting_for_crash_ipi, num_online_cpus()
> /* Would it be better to replace the trap vector here
> if (register_die_notifier(&crash_nmi_nb))
> return; /* return what? */
> /* Ensure the new callback function is set before sen
> * out the NMI
> */
> wmb();
>
> smp_send_nmi_allbutself();
>
> msecs = 1000; /* Wait at most a second for the other
> while ((atomic_read(&waiting_for_crash_ipi) > 0) && m
> mdelay(1);
> msecs--;
> }
>
> /* Leave the nmi callback set */
> }
> #else /* !CONFIG_SMP */
> void nmi_shootdown_cpus(nmi_shootdown_cb callback)
> {
> /* No other CPUs to shoot down */
> }
> #endif
[-- Attachment #4: Type: text/plain, Size: 138 bytes --]
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel
^ permalink raw reply [flat|nested] 10+ messages in thread