Login
[x]
Log in using an account from:
Fedora Account System
Red Hat Associate
Red Hat Customer
Or login using a Red Hat Bugzilla account
Forgot Password
Login:
Hide Forgot
Create an Account
Red Hat Bugzilla – Attachment 317536 Details for
Bug 463573
Patches to improve timekeeping for RHEL kernels running under VMware.
[?]
New
Simple Search
Advanced Search
My Links
Browse
Requests
Reports
Current State
Search
Tabular reports
Graphical reports
Duplicates
Other Reports
User Changes
Plotly Reports
Bug Status
Bug Severity
Non-Defaults
|
Product Dashboard
Help
Page Help!
Bug Writing Guidelines
What's new
Browser Support Policy
5.0.4.rh83 Release notes
FAQ
Guides index
User guide
Web Services
Contact
Legal
This site requires JavaScript to be enabled to function correctly, please enable it.
[patch]
x86: Code to detect if running on VMware.
vm_tsc_calibration.patch (text/plain), 14.24 KB, created by
Alok Kataria
on 2008-09-23 21:35:33 UTC
(
hide
)
Description:
x86: Code to detect if running on VMware.
Filename:
MIME Type:
Creator:
Alok Kataria
Created:
2008-09-23 21:35:33 UTC
Size:
14.24 KB
patch
obsolete
>x86: Code to detect if running on VMware. > >From: Alok N Kataria <akataria@vmware.com> > >Use backdoor calls to detect whether running on VMware. >If so get the tsc frequency from the hypervisor instead of calibrating it >since calibration can be error prone in virtualized environment. > >Finally, if a VMware hypervisor is detected, skip the code that detects >broken PIT wiring. In a VM, this code can result in false positives, >due to difference in timing. We know that virtual hardware always has >the correct wiring anyway. > >Signed-off-by: Alok N Kataria <akataria@vmware.com> >Signed-off-by: Dan Hecht <dhecht@vmware.com> >--- > > arch/i386/kernel/cpu/common.c | 9 +++ > arch/i386/kernel/io_apic.c | 10 ++++ > arch/i386/kernel/tsc.c | 34 ++++++++++++ > arch/x86_64/kernel/io_apic.c | 10 ++++ > arch/x86_64/kernel/setup.c | 11 ++++ > arch/x86_64/kernel/time.c | 16 ++++++ > include/asm-i386/mach-xen/asm/processor.h | 4 + > include/asm-i386/processor.h | 4 + > include/asm-x86_64/processor.h | 4 + > include/linux/vmware_backdoor.h | 79 +++++++++++++++++++++++++++++ > 10 files changed, 181 insertions(+), 0 deletions(-) > create mode 100644 include/linux/vmware_backdoor.h > > >diff --git a/arch/i386/kernel/cpu/common.c b/arch/i386/kernel/cpu/common.c >index f279008..bf2ba97 100644 >--- a/arch/i386/kernel/cpu/common.c >+++ b/arch/i386/kernel/cpu/common.c >@@ -5,6 +5,8 @@ > #include <linux/module.h> > #include <linux/percpu.h> > #include <linux/bootmem.h> >+#include <linux/vmware_backdoor.h> >+ > #include <asm/semaphore.h> > #include <asm/processor.h> > #include <asm/i387.h> >@@ -181,6 +183,11 @@ static void __cpuinit get_cpu_vendor(struct cpuinfo_x86 *c, int early) > this_cpu = &default_cpu; > } > >+static void __cpuinit get_hypervisor_vendor(struct cpuinfo_x86 *c) >+{ >+ if (vmware_platform()) >+ c->x86_hyper_vendor = X86_HYPER_VENDOR_VMWARE; >+} > > static int __init x86_fxsr_setup(char * s) > { >@@ -237,6 +244,7 @@ static void __init early_cpu_detect(void) > struct cpuinfo_x86 *c = &boot_cpu_data; > > c->x86_cache_alignment = 32; >+ c->x86_hyper_vendor = X86_HYPER_VENDOR_NONE; > > if (!have_cpuid_p()) > return; >@@ -263,6 +271,7 @@ static void __init early_cpu_detect(void) > if (cap0 & (1<<19)) > c->x86_cache_alignment = ((misc >> 8) & 0xff) * 8; > } >+ get_hypervisor_vendor(c); > } > > void __cpuinit generic_identify(struct cpuinfo_x86 * c) >diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c >index 4fb32c5..79f3d9b 100644 >--- a/arch/i386/kernel/io_apic.c >+++ b/arch/i386/kernel/io_apic.c >@@ -18,6 +18,8 @@ > * and Rolf G. Tews > * for testing these extensively > * Paul Diefenbaugh : Added full ACPI support >+ * >+ * Copyright (c) 2008, VMware, Inc. Skip timer_irq_works on hypervisors. > */ > > #include <linux/mm.h> >@@ -1883,6 +1885,14 @@ static int __init timer_irq_works(void) > unsigned long t1 = jiffies; > > local_irq_enable(); >+ >+ /* >+ * Hypervisors don't emulate old broken boards, and this time >+ * sensitive test is prone to failure on a hypervisor, so skip it. >+ */ >+ if (boot_cpu_data.x86_hyper_vendor != X86_HYPER_VENDOR_NONE) >+ return 1; >+ > /* Let ten ticks pass... */ > mdelay((10 * 1000) / HZ); > >diff --git a/arch/i386/kernel/tsc.c b/arch/i386/kernel/tsc.c >index 16dbae7..eff9958 100644 >--- a/arch/i386/kernel/tsc.c >+++ b/arch/i386/kernel/tsc.c >@@ -2,6 +2,7 @@ > * This code largely moved from arch/i386/kernel/timer/timer_tsc.c > * which was originally moved from arch/i386/kernel/time.c. > * See comments there for proper credits. >+ * Copyright (c) 2008 VMware, Inc. Get TSC frequency from the hypervisor > */ > > #include <linux/clocksource.h> >@@ -10,6 +11,7 @@ > #include <linux/jiffies.h> > #include <linux/init.h> > #include <linux/dmi.h> >+#include <linux/vmware_backdoor.h> > > #include <asm/delay.h> > #include <asm/tsc.h> >@@ -24,6 +26,7 @@ > * an extra value to store the TSC freq > */ > unsigned int tsc_khz; >+extern unsigned long preset_lpj; > > int tsc_disable __cpuinitdata = 0; > >@@ -202,6 +205,29 @@ void tsc_init(void) > cpu_khz = calculate_cpu_khz(); > tsc_khz = cpu_khz; > >+ if (boot_cpu_data.x86_hyper_vendor == X86_HYPER_VENDOR_VMWARE) { >+ /* Ask the hypervisor for the TSC frequency since >+ * calibrating it inside a VM is prone to error. */ >+ unsigned long vm_tsc_khz = vmware_get_tsc_khz(); >+ if (vm_tsc_khz) { >+ tsc_khz = vm_tsc_khz; >+ cpu_khz = tsc_khz; >+ preset_lpj = (vm_tsc_khz * 1000) / HZ; >+ /* >+ * Enable "lazy" timer emulation. Rather than holding >+ * back virtual time when timer interrupt delivery falls >+ * behind and attempting to "catch up", in lazy mode, >+ * missed periodic interrupts are skipped and virtual >+ * time always reflects real time. >+ */ >+ if (!vmware_enable_lazy_timer_emulation()) >+ printk(KERN_WARNING "time.c: failed to enable " >+ "lazy timer emulation.\n"); >+ } else >+ printk(KERN_WARNING "time.c: failed to get tsc " >+ "frequency from hypervisor.\n"); >+ } >+ > if (!cpu_khz) > return; > >@@ -414,6 +440,8 @@ static void verify_tsc_freq(unsigned long unused) > u64 now_tsc, interval_tsc; > unsigned long now_jiffies, interval_jiffies; > >+ if (boot_cpu_data.x86_hyper_vendor == X86_HYPER_VENDOR_VMWARE) >+ return; > > if (check_tsc_unstable()) > return; >@@ -458,6 +486,12 @@ static __init int unsynchronized_tsc(void) > if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) > return 0; > >+ /* >+ * TSC's are normally synchronized on a hypervisor. >+ */ >+ if (boot_cpu_data.x86_hyper_vendor == X86_HYPER_VENDOR_VMWARE) >+ return 0; >+ > /* assume multi socket systems are not synchronized: */ > return num_possible_cpus() > 1; > } >diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c >index 610d316..e6b1492 100644 >--- a/arch/x86_64/kernel/io_apic.c >+++ b/arch/x86_64/kernel/io_apic.c >@@ -18,6 +18,8 @@ > * and Rolf G. Tews > * for testing these extensively > * Paul Diefenbaugh : Added full ACPI support >+ * >+ * Copyright (c) 2008, VMware, Inc. Skip timer_irq_works on hypervisors. > */ > > #include <linux/mm.h> >@@ -1460,6 +1462,14 @@ static int __init timer_irq_works(void) > unsigned long t1 = jiffies; > > local_irq_enable(); >+ >+ /* >+ * Hypervisors don't emulate old broken boards, and this time >+ * sensitive test is prone to failure on a hypervisor, so skip it. >+ */ >+ if (boot_cpu_data.x86_hyper_vendor != X86_HYPER_VENDOR_NONE) >+ return 1; >+ > /* Let ten ticks pass... */ > mdelay((10 * 1000) / HZ); > >diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c >index 19ca938..4365057 100644 >--- a/arch/x86_64/kernel/setup.c >+++ b/arch/x86_64/kernel/setup.c >@@ -5,6 +5,8 @@ > * > * Nov 2001 Dave Jones <davej@suse.de> > * Forked from i386 setup code. >+ * >+ * Copyright (c) 2008 VMware, Inc. Detect if running on a VMware Hypervisor. > */ > > /* >@@ -45,6 +47,7 @@ > #include <linux/dmi.h> > #include <linux/dma-mapping.h> > #include <linux/ctype.h> >+#include <linux/vmware_backdoor.h> > > #include <asm/mtrr.h> > #include <asm/uaccess.h> >@@ -1043,6 +1046,12 @@ static void __cpuinit get_cpu_vendor(struct cpuinfo_x86 *c) > c->x86_vendor = X86_VENDOR_UNKNOWN; > } > >+static void __cpuinit get_hypervisor_vendor(struct cpuinfo_x86 *c) >+{ >+ if (vmware_platform()) >+ c->x86_hyper_vendor = X86_HYPER_VENDOR_VMWARE; >+} >+ > struct cpu_model_info { > int vendor; > int family; >@@ -1066,6 +1075,7 @@ void __cpuinit early_identify_cpu(struct cpuinfo_x86 *c) > c->x86_cache_alignment = c->x86_clflush_size; > c->x86_max_cores = 1; > c->extended_cpuid_level = 0; >+ c->x86_hyper_vendor = X86_HYPER_VENDOR_NONE; > memset(&c->x86_capability, 0, sizeof c->x86_capability); > > /* Get vendor name */ >@@ -1075,6 +1085,7 @@ void __cpuinit early_identify_cpu(struct cpuinfo_x86 *c) > (unsigned int *)&c->x86_vendor_id[4]); > > get_cpu_vendor(c); >+ get_hypervisor_vendor(c); > > /* Initialize the standard set of capabilities */ > /* Note that the vendor-specific code below might override */ >diff --git a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c >index 867760d..fab019d 100644 >--- a/arch/x86_64/kernel/time.c >+++ b/arch/x86_64/kernel/time.c >@@ -10,6 +10,7 @@ > * Copyright (c) 1998 Andrea Arcangeli > * Copyright (c) 2002,2006 Vojtech Pavlik > * Copyright (c) 2003 Andi Kleen >+ * Copyright (c) 2008 VMware, Inc. get TSC frequency from the hypervisor. > * RTC support code taken from arch/i386/kernel/timers/time_hpet.c > */ > >@@ -28,6 +29,7 @@ > #include <linux/cpu.h> > #include <linux/kallsyms.h> > #include <linux/acpi.h> >+#include <linux/vmware_backdoor.h> > #ifdef CONFIG_ACPI > #include <acpi/achware.h> /* for PM timer frequency */ > #include <acpi/acpi_bus.h> >@@ -89,6 +91,7 @@ unsigned long __wall_jiffies __section_wall_jiffies = INITIAL_JIFFIES; > struct timespec __xtime __section_xtime; > struct timezone __sys_tz __section_sys_tz; > >+extern unsigned long preset_lpj; > /* > * do_gettimeoffset() returns microseconds since last timer interrupt was > * triggered by hardware. A memory read of HPET is slower than a register read >@@ -996,6 +999,19 @@ void __init time_init(void) > boot_cpu_data.x86 == 16) > cpu_khz = tsc_calibrate_cpu_khz(); > >+ if (boot_cpu_data.x86_hyper_vendor == X86_HYPER_VENDOR_VMWARE) { >+ /* Ask the hypervisor for the TSC frequency since >+ * calibrating it inside a VM is prone to error. */ >+ unsigned long vm_tsc_khz = vmware_get_tsc_khz(); >+ if (vm_tsc_khz) { >+ tsc_khz = vm_tsc_khz; >+ cpu_khz = tsc_khz; >+ preset_lpj = (vm_tsc_khz * 1000) / HZ; >+ } else >+ printk(KERN_WARNING "time.c: failed to get tsc " >+ "frequency from hypervisor.\n"); >+ } >+ > vxtime.mode = VXTIME_TSC; > vxtime.quot = (USEC_PER_SEC << US_SCALE) / vxtime_hz; > vxtime.tsc_quot = (USEC_PER_MSEC << US_SCALE) / cpu_khz; >diff --git a/include/asm-i386/mach-xen/asm/processor.h b/include/asm-i386/mach-xen/asm/processor.h >index d8a4b7b..e5e3402 100644 >--- a/include/asm-i386/mach-xen/asm/processor.h >+++ b/include/asm-i386/mach-xen/asm/processor.h >@@ -78,6 +78,7 @@ struct cpuinfo_x86 { > __u8 phys_proc_id; /* Physical processor id. */ > __u8 cpu_core_id; /* Core id */ > #endif >+ __u8 x86_hyper_vendor; > } __attribute__((__aligned__(SMP_CACHE_BYTES))); > > #define X86_VENDOR_INTEL 0 >@@ -92,6 +93,9 @@ struct cpuinfo_x86 { > #define X86_VENDOR_NUM 9 > #define X86_VENDOR_UNKNOWN 0xff > >+#define X86_HYPER_VENDOR_NONE 0 >+#define X86_HYPER_VENDOR_VMWARE 1 >+ > /* > * capabilities of CPUs > */ >diff --git a/include/asm-i386/processor.h b/include/asm-i386/processor.h >index c108225..6977965 100644 >--- a/include/asm-i386/processor.h >+++ b/include/asm-i386/processor.h >@@ -77,6 +77,7 @@ struct cpuinfo_x86 { > __u8 phys_proc_id; /* Physical processor id. */ > __u8 cpu_core_id; /* Core id */ > #endif >+ __u8 x86_hyper_vendor; > } __attribute__((__aligned__(SMP_CACHE_BYTES))); > > #define X86_VENDOR_INTEL 0 >@@ -91,6 +92,9 @@ struct cpuinfo_x86 { > #define X86_VENDOR_NUM 9 > #define X86_VENDOR_UNKNOWN 0xff > >+#define X86_HYPER_VENDOR_NONE 0 >+#define X86_HYPER_VENDOR_VMWARE 1 >+ > /* > * capabilities of CPUs > */ >diff --git a/include/asm-x86_64/processor.h b/include/asm-x86_64/processor.h >index 2dd19a7..d7331f5 100644 >--- a/include/asm-x86_64/processor.h >+++ b/include/asm-x86_64/processor.h >@@ -74,6 +74,7 @@ struct cpuinfo_x86 { > __u8 phys_proc_id; /* Physical Processor id. */ > __u8 cpu_core_id; /* Core id. */ > #endif >+ __u8 x86_hyper_vendor; > } ____cacheline_aligned; > > #define X86_VENDOR_INTEL 0 >@@ -87,6 +88,9 @@ struct cpuinfo_x86 { > #define X86_VENDOR_NUM 8 > #define X86_VENDOR_UNKNOWN 0xff > >+#define X86_HYPER_VENDOR_NONE 0 >+#define X86_HYPER_VENDOR_VMWARE 1 >+ > #ifdef CONFIG_SMP > extern struct cpuinfo_x86 cpu_data[]; > #define current_cpu_data cpu_data[smp_processor_id()] >diff --git a/include/linux/vmware_backdoor.h b/include/linux/vmware_backdoor.h >new file mode 100644 >index 0000000..49a31fc >--- /dev/null >+++ b/include/linux/vmware_backdoor.h >@@ -0,0 +1,79 @@ >+/* >+ * Copyright (C) 2007-2008, VMware, Inc. >+ * >+ * 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, version 2 and no 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. >+ * >+ * Send any feedback to akataria@vmware.com, dhecht@vmware.com >+ */ >+ >+#ifndef _VMWARE_BACKDOOR_H >+#define _VMWARE_BACKDOOR_H >+ >+#include <linux/types.h> >+ >+#define VMWARE_BDOOR_MAGIC 0x564D5868 >+#define VMWARE_BDOOR_PORT 0x5658 >+ >+#define VMWARE_BDOOR_CMD_GETVERSION 10 >+#define VMWARE_BDOOR_CMD_GETHZ 45 >+#define VMWARE_BDOOR_CMD_LAZYTIMEREMULATION 49 >+ >+#define VMWARE_BDOOR(cmd, eax, ebx, ecx, edx) \ >+ __asm__("inl (%%dx)" : \ >+ "=a"(eax), "=c"(ecx), "=d"(edx), "=b"(ebx) : \ >+ "0"(VMWARE_BDOOR_MAGIC), "1"(VMWARE_BDOOR_CMD_##cmd), \ >+ "2"(VMWARE_BDOOR_PORT), "3"(0) : \ >+ "memory"); >+ >+ >+static inline int vmware_platform(void) >+{ >+ uint32_t eax, ebx, ecx, edx; >+ VMWARE_BDOOR(GETVERSION, eax, ebx, ecx, edx); >+ return eax != (uint32_t)-1 && ebx == VMWARE_BDOOR_MAGIC; >+} >+ >+static inline unsigned int vmware_get_tsc_khz(void) >+{ >+ uint64_t tsc_hz; >+ uint32_t eax, ebx, ecx, edx; >+ >+ VMWARE_BDOOR(GETHZ, eax, ebx, ecx, edx); >+ >+ if (eax == (uint32_t)-1) >+ return 0; >+ tsc_hz = eax | (((uint64_t)ebx) << 32); >+ do_div(tsc_hz, 1000); >+ BUG_ON(tsc_hz >> 32); >+ return tsc_hz; >+} >+ >+/* >+ * Usually, all timer devices in the VM are kept consistent, but this >+ * can cause time in the VM to fall behind (e.g., if the VM is >+ * descheduled for long periods of time, the hypervisor may not have had >+ * an opportunity to deliver timer interrupts, and so the time in the VM >+ * will be behind until it can catch up. In lazy timer emulation mode, >+ * the TSC tracks real time regardless of whether e.g. timer interrupts >+ * are delivered on time. >+ */ >+static inline int vmware_enable_lazy_timer_emulation(void) >+{ >+ uint32_t eax, ebx, ecx, edx; >+ VMWARE_BDOOR(LAZYTIMEREMULATION, eax, ebx, ecx, edx); >+ return ebx == VMWARE_BDOOR_MAGIC; >+} >+ >+#endif
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 463573
:
317536
|
317537
|
317538
|
317727
|
317728
|
317734
|
317735
|
319716
|
319717
|
319718
|
319719
|
319720
|
319799
|
319817
|
320098
|
320133
|
320485
|
321043
|
325724
|
325725
|
325726
|
325727
|
325728
|
326672
|
329135
|
329213
|
332979