2008-10-27 10:41:46 -07:00
/*
* VMware Detection code .
*
* Copyright ( C ) 2008 , VMware , Inc .
* Author : Alok N Kataria < akataria @ vmware . com >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE , GOOD TITLE or
* NON INFRINGEMENT . See the GNU General Public License for more
* details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA .
*
*/
# include <linux/dmi.h>
2010-04-23 13:18:08 -04:00
# include <linux/module.h>
2008-10-27 10:41:46 -07:00
# include <asm/div64.h>
2009-08-20 17:06:25 +02:00
# include <asm/x86_init.h>
2010-05-07 16:57:28 -07:00
# include <asm/hypervisor.h>
2008-10-27 10:41:46 -07:00
# define CPUID_VMWARE_INFO_LEAF 0x40000000
# define VMWARE_HYPERVISOR_MAGIC 0x564D5868
# define VMWARE_HYPERVISOR_PORT 0x5658
# define VMWARE_PORT_CMD_GETVERSION 10
# define VMWARE_PORT_CMD_GETHZ 45
2013-01-17 15:44:42 -08:00
# define VMWARE_PORT_CMD_GETVCPU_INFO 68
# define VMWARE_PORT_CMD_LEGACY_X2APIC 3
# define VMWARE_PORT_CMD_VCPU_RESERVED 31
2008-10-27 10:41:46 -07:00
# define VMWARE_PORT(cmd, eax, ebx, ecx, edx) \
__asm__ ( " inl (%%dx) " : \
" =a " ( eax ) , " =c " ( ecx ) , " =d " ( edx ) , " =b " ( ebx ) : \
" 0 " ( VMWARE_HYPERVISOR_MAGIC ) , \
" 1 " ( VMWARE_PORT_CMD_ # # cmd ) , \
2008-11-03 11:31:28 -08:00
" 2 " ( VMWARE_HYPERVISOR_PORT ) , " 3 " ( UINT_MAX ) : \
2008-10-27 10:41:46 -07:00
" memory " ) ;
static inline int __vmware_platform ( void )
{
uint32_t eax , ebx , ecx , edx ;
VMWARE_PORT ( GETVERSION , eax , ebx , ecx , edx ) ;
return eax ! = ( uint32_t ) - 1 & & ebx = = VMWARE_HYPERVISOR_MAGIC ;
}
2009-08-20 17:06:25 +02:00
static unsigned long vmware_get_tsc_khz ( void )
2008-10-27 10:41:46 -07:00
{
2010-08-02 16:10:37 -07:00
uint64_t tsc_hz , lpj ;
2009-07-04 00:35:45 +01:00
uint32_t eax , ebx , ecx , edx ;
2008-10-27 10:41:46 -07:00
2009-07-04 00:35:45 +01:00
VMWARE_PORT ( GETHZ , eax , ebx , ecx , edx ) ;
2008-10-27 10:41:46 -07:00
2009-07-04 00:35:45 +01:00
tsc_hz = eax | ( ( ( uint64_t ) ebx ) < < 32 ) ;
do_div ( tsc_hz , 1000 ) ;
BUG_ON ( tsc_hz > > 32 ) ;
2009-09-04 13:13:39 -07:00
printk ( KERN_INFO " TSC freq read from hypervisor : %lu.%03lu MHz \n " ,
( unsigned long ) tsc_hz / 1000 ,
( unsigned long ) tsc_hz % 1000 ) ;
2010-08-02 16:10:37 -07:00
if ( ! preset_lpj ) {
lpj = ( ( u64 ) tsc_hz * 1000 ) ;
do_div ( lpj , HZ ) ;
preset_lpj = lpj ;
}
2009-07-04 00:35:45 +01:00
return tsc_hz ;
2008-10-27 10:41:46 -07:00
}
2010-05-07 16:57:28 -07:00
static void __init vmware_platform_setup ( void )
2009-08-20 17:06:25 +02:00
{
uint32_t eax , ebx , ecx , edx ;
VMWARE_PORT ( GETHZ , eax , ebx , ecx , edx ) ;
if ( ebx ! = UINT_MAX )
x86_platform . calibrate_tsc = vmware_get_tsc_khz ;
2009-09-04 13:13:39 -07:00
else
printk ( KERN_WARNING
" Failed to get TSC freq from the hypervisor \n " ) ;
2009-08-20 17:06:25 +02:00
}
2008-11-03 15:50:38 -08:00
/*
2011-03-17 16:24:16 -03:00
* While checking the dmi string information , just checking the product
2008-11-03 15:50:38 -08:00
* serial key should be enough , as this will always have a VMware
* specific string when running under VMware hypervisor .
*/
2010-05-07 16:57:28 -07:00
static bool __init vmware_platform ( void )
2008-10-27 10:41:46 -07:00
{
if ( cpu_has_hypervisor ) {
2010-05-07 16:57:28 -07:00
unsigned int eax ;
unsigned int hyper_vendor_id [ 3 ] ;
cpuid ( CPUID_VMWARE_INFO_LEAF , & eax , & hyper_vendor_id [ 0 ] ,
& hyper_vendor_id [ 1 ] , & hyper_vendor_id [ 2 ] ) ;
if ( ! memcmp ( hyper_vendor_id , " VMwareVMware " , 12 ) )
return true ;
2008-11-03 15:50:38 -08:00
} else if ( dmi_available & & dmi_name_in_serial ( " VMware " ) & &
2008-10-27 10:41:46 -07:00
__vmware_platform ( ) )
2010-05-07 16:57:28 -07:00
return true ;
2008-10-27 10:41:46 -07:00
2010-05-07 16:57:28 -07:00
return false ;
2008-10-27 10:41:46 -07:00
}
2008-10-31 12:01:58 -07:00
/*
* VMware hypervisor takes care of exporting a reliable TSC to the guest .
* Still , due to timing difference when running on virtual cpus , the TSC can
* be marked as unstable in some cases . For example , the TSC sync check at
* bootup can fail due to a marginal offset between vcpus ' TSCs ( though the
* TSCs do not drift from each other ) . Also , the ACPI PM timer clocksource
* is not suitable as a watchdog when running on a hypervisor because the
* kernel may miss a wrap of the counter if the vcpu is descheduled for a
* long time . To skip these checks at runtime we set these capability bits ,
* so that the kernel could just trust the hypervisor with providing a
* reliable virtual TSC that is suitable for timekeeping .
*/
2010-05-07 16:57:28 -07:00
static void __cpuinit vmware_set_cpu_features ( struct cpuinfo_x86 * c )
2008-10-31 12:01:58 -07:00
{
set_cpu_cap ( c , X86_FEATURE_CONSTANT_TSC ) ;
set_cpu_cap ( c , X86_FEATURE_TSC_RELIABLE ) ;
}
2010-05-07 16:57:28 -07:00
2013-01-17 15:44:42 -08:00
/* Checks if hypervisor supports x2apic without VT-D interrupt remapping. */
static bool __init vmware_legacy_x2apic_available ( void )
{
uint32_t eax , ebx , ecx , edx ;
VMWARE_PORT ( GETVCPU_INFO , eax , ebx , ecx , edx ) ;
return ( eax & ( 1 < < VMWARE_PORT_CMD_VCPU_RESERVED ) ) = = 0 & &
( eax & ( 1 < < VMWARE_PORT_CMD_LEGACY_X2APIC ) ) ! = 0 ;
}
2010-05-07 16:57:28 -07:00
const __refconst struct hypervisor_x86 x86_hyper_vmware = {
. name = " VMware " ,
. detect = vmware_platform ,
. set_cpu_features = vmware_set_cpu_features ,
. init_platform = vmware_platform_setup ,
2013-01-17 15:44:42 -08:00
. x2apic_available = vmware_legacy_x2apic_available ,
2010-05-07 16:57:28 -07:00
} ;
2010-05-09 01:10:34 -07:00
EXPORT_SYMBOL ( x86_hyper_vmware ) ;