diff --git a/kernel/arch/i386/arch_reset.c b/kernel/arch/i386/arch_reset.c index 89b43a4a1..0fd32770d 100644 --- a/kernel/arch/i386/arch_reset.c +++ b/kernel/arch/i386/arch_reset.c @@ -84,7 +84,14 @@ reset(void) } } -void +static __dead void +halt(void) +{ + for ( ; ; ) + halt_cpu(); +} + +static __dead void poweroff(void) { const char *shutdown_str; @@ -96,8 +103,11 @@ poweroff(void) shutdown_str = "Shutdown"; while (*shutdown_str) outb(0x8900, *(shutdown_str++)); + /* VMware magic power off; likely to halt CPU */ + poweroff_vmware_clihlt(); + /* fallback option: hang */ - for (; ; ) halt_cpu(); + halt(); } __dead void arch_shutdown(int how) diff --git a/kernel/arch/i386/include/arch_proto.h b/kernel/arch/i386/include/arch_proto.h index 9748b6c52..3aa879096 100644 --- a/kernel/arch/i386/include/arch_proto.h +++ b/kernel/arch/i386/include/arch_proto.h @@ -81,9 +81,10 @@ struct exception_frame { void exception(struct exception_frame * frame); -/* klib386.s */ +/* klib.S */ __dead void monitor(void); __dead void reset(void); +__dead void poweroff_vmware_clihlt(void); __dead void x86_triplefault(void); reg_t read_cr0(void); reg_t read_cr2(void); diff --git a/kernel/arch/i386/klib.S b/kernel/arch/i386/klib.S index abd43faa8..83663a759 100644 --- a/kernel/arch/i386/klib.S +++ b/kernel/arch/i386/klib.S @@ -382,6 +382,35 @@ ENTRY(halt_cpu) */ ret +/*===========================================================================*/ +/* poweroff_vmware_clihlt */ +/*===========================================================================*/ +/* + * PUBLIC void poweroff_vmware_clihlt(void); + * VMware detects this peculiar sequence and forces the virtual machine off + * when the parameter gui.exitOnCLIHLT is set to TRUE. + * Otherwise this sequence just hangs the CPU, requiring a power down action. + */ +ENTRY(poweroff_vmware_clihlt) +#ifndef NO_VMWARE_DETECTION + mov $1, %eax + cpuid + test $[1<<31], %ecx /* "virtualized" */ + jz 1f /* always 0 on real hardware */ + mov $0x40000000, %eax /* select hypervisor-use leaf */ + cpuid + cmp $0x61774D56, %ebx /* ASCII "VMwa" */ + jne 1f + cmp $0x4D566572, %ecx /* ASCII "reVM" */ + jne 1f + cmp $0x65726177, %edx /* ASCII "ware" */ + jne 1f + /* we are virtualized by some VMware product! */ +#endif + cli + hlt +1: ret + /*===========================================================================*/ /* read_flags */ /*===========================================================================*/