LCOV - code coverage report
Current view: top level - arch/x86/kernel/cpu - vmware.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 6 79 7.6 %
Date: 2022-04-01 14:58:12 Functions: 1 9 11.1 %
Branches: 2 39 5.1 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * VMware Detection code.
       3                 :            :  *
       4                 :            :  * Copyright (C) 2008, VMware, Inc.
       5                 :            :  * Author : Alok N Kataria <akataria@vmware.com>
       6                 :            :  *
       7                 :            :  * This program is free software; you can redistribute it and/or modify
       8                 :            :  * it under the terms of the GNU General Public License as published by
       9                 :            :  * the Free Software Foundation; either version 2 of the License, or
      10                 :            :  * (at your option) any later version.
      11                 :            :  *
      12                 :            :  * This program is distributed in the hope that it will be useful, but
      13                 :            :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      14                 :            :  * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
      15                 :            :  * NON INFRINGEMENT.  See the GNU General Public License for more
      16                 :            :  * details.
      17                 :            :  *
      18                 :            :  * You should have received a copy of the GNU General Public License
      19                 :            :  * along with this program; if not, write to the Free Software
      20                 :            :  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
      21                 :            :  *
      22                 :            :  */
      23                 :            : 
      24                 :            : #include <linux/dmi.h>
      25                 :            : #include <linux/init.h>
      26                 :            : #include <linux/export.h>
      27                 :            : #include <linux/clocksource.h>
      28                 :            : #include <asm/div64.h>
      29                 :            : #include <asm/x86_init.h>
      30                 :            : #include <asm/hypervisor.h>
      31                 :            : #include <asm/timer.h>
      32                 :            : #include <asm/apic.h>
      33                 :            : #include <asm/vmware.h>
      34                 :            : 
      35                 :            : #undef pr_fmt
      36                 :            : #define pr_fmt(fmt)     "vmware: " fmt
      37                 :            : 
      38                 :            : #define CPUID_VMWARE_INFO_LEAF               0x40000000
      39                 :            : #define CPUID_VMWARE_FEATURES_LEAF           0x40000010
      40                 :            : #define CPUID_VMWARE_FEATURES_ECX_VMMCALL    BIT(0)
      41                 :            : #define CPUID_VMWARE_FEATURES_ECX_VMCALL     BIT(1)
      42                 :            : 
      43                 :            : #define VMWARE_HYPERVISOR_MAGIC 0x564D5868
      44                 :            : 
      45                 :            : #define VMWARE_CMD_GETVERSION    10
      46                 :            : #define VMWARE_CMD_GETHZ         45
      47                 :            : #define VMWARE_CMD_GETVCPU_INFO  68
      48                 :            : #define VMWARE_CMD_LEGACY_X2APIC  3
      49                 :            : #define VMWARE_CMD_VCPU_RESERVED 31
      50                 :            : 
      51                 :            : #define VMWARE_PORT(cmd, eax, ebx, ecx, edx)                            \
      52                 :            :         __asm__("inl (%%dx), %%eax" :                                 \
      53                 :            :                 "=a"(eax), "=c"(ecx), "=d"(edx), "=b"(ebx) :            \
      54                 :            :                 "a"(VMWARE_HYPERVISOR_MAGIC),                         \
      55                 :            :                 "c"(VMWARE_CMD_##cmd),                                        \
      56                 :            :                 "d"(VMWARE_HYPERVISOR_PORT), "b"(UINT_MAX) :                \
      57                 :            :                 "memory")
      58                 :            : 
      59                 :            : #define VMWARE_VMCALL(cmd, eax, ebx, ecx, edx)                          \
      60                 :            :         __asm__("vmcall" :                                            \
      61                 :            :                 "=a"(eax), "=c"(ecx), "=d"(edx), "=b"(ebx) :            \
      62                 :            :                 "a"(VMWARE_HYPERVISOR_MAGIC),                         \
      63                 :            :                 "c"(VMWARE_CMD_##cmd),                                        \
      64                 :            :                 "d"(0), "b"(UINT_MAX) :                                     \
      65                 :            :                 "memory")
      66                 :            : 
      67                 :            : #define VMWARE_VMMCALL(cmd, eax, ebx, ecx, edx)                         \
      68                 :            :         __asm__("vmmcall" :                                           \
      69                 :            :                 "=a"(eax), "=c"(ecx), "=d"(edx), "=b"(ebx) :            \
      70                 :            :                 "a"(VMWARE_HYPERVISOR_MAGIC),                         \
      71                 :            :                 "c"(VMWARE_CMD_##cmd),                                        \
      72                 :            :                 "d"(0), "b"(UINT_MAX) :                                     \
      73                 :            :                 "memory")
      74                 :            : 
      75                 :            : #define VMWARE_CMD(cmd, eax, ebx, ecx, edx) do {                \
      76                 :            :         switch (vmware_hypercall_mode) {                        \
      77                 :            :         case CPUID_VMWARE_FEATURES_ECX_VMCALL:                  \
      78                 :            :                 VMWARE_VMCALL(cmd, eax, ebx, ecx, edx);         \
      79                 :            :                 break;                                          \
      80                 :            :         case CPUID_VMWARE_FEATURES_ECX_VMMCALL:                 \
      81                 :            :                 VMWARE_VMMCALL(cmd, eax, ebx, ecx, edx);        \
      82                 :            :                 break;                                          \
      83                 :            :         default:                                                \
      84                 :            :                 VMWARE_PORT(cmd, eax, ebx, ecx, edx);           \
      85                 :            :                 break;                                          \
      86                 :            :         }                                                       \
      87                 :            :         } while (0)
      88                 :            : 
      89                 :            : static unsigned long vmware_tsc_khz __ro_after_init;
      90                 :            : static u8 vmware_hypercall_mode     __ro_after_init;
      91                 :            : 
      92                 :          0 : static inline int __vmware_platform(void)
      93                 :            : {
      94                 :          0 :         uint32_t eax, ebx, ecx, edx;
      95      [ #  #  # ]:          0 :         VMWARE_CMD(GETVERSION, eax, ebx, ecx, edx);
      96                 :          0 :         return eax != (uint32_t)-1 && ebx == VMWARE_HYPERVISOR_MAGIC;
      97                 :            : }
      98                 :            : 
      99                 :          0 : static unsigned long vmware_get_tsc_khz(void)
     100                 :            : {
     101                 :          0 :         return vmware_tsc_khz;
     102                 :            : }
     103                 :            : 
     104                 :            : #ifdef CONFIG_PARAVIRT
     105                 :            : static struct cyc2ns_data vmware_cyc2ns __ro_after_init;
     106                 :            : static int vmw_sched_clock __initdata = 1;
     107                 :            : 
     108                 :          0 : static __init int setup_vmw_sched_clock(char *s)
     109                 :            : {
     110                 :          0 :         vmw_sched_clock = 0;
     111                 :          0 :         return 0;
     112                 :            : }
     113                 :            : early_param("no-vmw-sched-clock", setup_vmw_sched_clock);
     114                 :            : 
     115                 :          0 : static unsigned long long notrace vmware_sched_clock(void)
     116                 :            : {
     117                 :          0 :         unsigned long long ns;
     118                 :            : 
     119                 :          0 :         ns = mul_u64_u32_shr(rdtsc(), vmware_cyc2ns.cyc2ns_mul,
     120                 :            :                              vmware_cyc2ns.cyc2ns_shift);
     121                 :          0 :         ns -= vmware_cyc2ns.cyc2ns_offset;
     122                 :          0 :         return ns;
     123                 :            : }
     124                 :            : 
     125                 :          0 : static void __init vmware_sched_clock_setup(void)
     126                 :            : {
     127                 :          0 :         struct cyc2ns_data *d = &vmware_cyc2ns;
     128                 :          0 :         unsigned long long tsc_now = rdtsc();
     129                 :            : 
     130                 :          0 :         clocks_calc_mult_shift(&d->cyc2ns_mul, &d->cyc2ns_shift,
     131                 :            :                                vmware_tsc_khz, NSEC_PER_MSEC, 0);
     132                 :          0 :         d->cyc2ns_offset = mul_u64_u32_shr(tsc_now, d->cyc2ns_mul,
     133                 :            :                                            d->cyc2ns_shift);
     134                 :            : 
     135                 :          0 :         pv_ops.time.sched_clock = vmware_sched_clock;
     136                 :          0 :         pr_info("using sched offset of %llu ns\n", d->cyc2ns_offset);
     137                 :          0 : }
     138                 :            : 
     139                 :          0 : static void __init vmware_paravirt_ops_setup(void)
     140                 :            : {
     141                 :          0 :         pv_info.name = "VMware hypervisor";
     142                 :          0 :         pv_ops.cpu.io_delay = paravirt_nop;
     143                 :            : 
     144   [ #  #  #  # ]:          0 :         if (vmware_tsc_khz && vmw_sched_clock)
     145                 :          0 :                 vmware_sched_clock_setup();
     146                 :          0 : }
     147                 :            : #else
     148                 :            : #define vmware_paravirt_ops_setup() do {} while (0)
     149                 :            : #endif
     150                 :            : 
     151                 :            : /*
     152                 :            :  * VMware hypervisor takes care of exporting a reliable TSC to the guest.
     153                 :            :  * Still, due to timing difference when running on virtual cpus, the TSC can
     154                 :            :  * be marked as unstable in some cases. For example, the TSC sync check at
     155                 :            :  * bootup can fail due to a marginal offset between vcpus' TSCs (though the
     156                 :            :  * TSCs do not drift from each other).  Also, the ACPI PM timer clocksource
     157                 :            :  * is not suitable as a watchdog when running on a hypervisor because the
     158                 :            :  * kernel may miss a wrap of the counter if the vcpu is descheduled for a
     159                 :            :  * long time. To skip these checks at runtime we set these capability bits,
     160                 :            :  * so that the kernel could just trust the hypervisor with providing a
     161                 :            :  * reliable virtual TSC that is suitable for timekeeping.
     162                 :            :  */
     163                 :          0 : static void __init vmware_set_capabilities(void)
     164                 :            : {
     165                 :          0 :         setup_force_cpu_cap(X86_FEATURE_CONSTANT_TSC);
     166                 :          0 :         setup_force_cpu_cap(X86_FEATURE_TSC_RELIABLE);
     167         [ #  # ]:          0 :         if (vmware_hypercall_mode == CPUID_VMWARE_FEATURES_ECX_VMCALL)
     168                 :          0 :                 setup_force_cpu_cap(X86_FEATURE_VMCALL);
     169         [ #  # ]:          0 :         else if (vmware_hypercall_mode == CPUID_VMWARE_FEATURES_ECX_VMMCALL)
     170                 :          0 :                 setup_force_cpu_cap(X86_FEATURE_VMW_VMMCALL);
     171                 :          0 : }
     172                 :            : 
     173                 :          0 : static void __init vmware_platform_setup(void)
     174                 :            : {
     175                 :          0 :         uint32_t eax, ebx, ecx, edx;
     176                 :          0 :         uint64_t lpj, tsc_khz;
     177                 :            : 
     178      [ #  #  # ]:          0 :         VMWARE_CMD(GETHZ, eax, ebx, ecx, edx);
     179                 :            : 
     180         [ #  # ]:          0 :         if (ebx != UINT_MAX) {
     181                 :          0 :                 lpj = tsc_khz = eax | (((uint64_t)ebx) << 32);
     182                 :          0 :                 do_div(tsc_khz, 1000);
     183         [ #  # ]:          0 :                 WARN_ON(tsc_khz >> 32);
     184                 :          0 :                 pr_info("TSC freq read from hypervisor : %lu.%03lu MHz\n",
     185                 :            :                         (unsigned long) tsc_khz / 1000,
     186                 :            :                         (unsigned long) tsc_khz % 1000);
     187                 :            : 
     188         [ #  # ]:          0 :                 if (!preset_lpj) {
     189                 :          0 :                         do_div(lpj, HZ);
     190                 :          0 :                         preset_lpj = lpj;
     191                 :            :                 }
     192                 :            : 
     193                 :          0 :                 vmware_tsc_khz = tsc_khz;
     194                 :          0 :                 x86_platform.calibrate_tsc = vmware_get_tsc_khz;
     195                 :          0 :                 x86_platform.calibrate_cpu = vmware_get_tsc_khz;
     196                 :            : 
     197                 :            : #ifdef CONFIG_X86_LOCAL_APIC
     198                 :            :                 /* Skip lapic calibration since we know the bus frequency. */
     199                 :          0 :                 lapic_timer_period = ecx / HZ;
     200                 :          0 :                 pr_info("Host bus clock speed read from hypervisor : %u Hz\n",
     201                 :            :                         ecx);
     202                 :            : #endif
     203                 :            :         } else {
     204                 :          0 :                 pr_warn("Failed to get TSC freq from the hypervisor\n");
     205                 :            :         }
     206                 :            : 
     207                 :          0 :         vmware_paravirt_ops_setup();
     208                 :            : 
     209                 :            : #ifdef CONFIG_X86_IO_APIC
     210                 :          0 :         no_timer_check = 1;
     211                 :            : #endif
     212                 :            : 
     213                 :          0 :         vmware_set_capabilities();
     214                 :          0 : }
     215                 :            : 
     216                 :          0 : static u8 vmware_select_hypercall(void)
     217                 :            : {
     218                 :          0 :         int eax, ebx, ecx, edx;
     219                 :            : 
     220                 :          0 :         cpuid(CPUID_VMWARE_FEATURES_LEAF, &eax, &ebx, &ecx, &edx);
     221                 :          0 :         return (ecx & (CPUID_VMWARE_FEATURES_ECX_VMMCALL |
     222                 :            :                        CPUID_VMWARE_FEATURES_ECX_VMCALL));
     223                 :            : }
     224                 :            : 
     225                 :            : /*
     226                 :            :  * While checking the dmi string information, just checking the product
     227                 :            :  * serial key should be enough, as this will always have a VMware
     228                 :            :  * specific string when running under VMware hypervisor.
     229                 :            :  * If !boot_cpu_has(X86_FEATURE_HYPERVISOR), vmware_hypercall_mode
     230                 :            :  * intentionally defaults to 0.
     231                 :            :  */
     232                 :          3 : static uint32_t __init vmware_platform(void)
     233                 :            : {
     234         [ +  - ]:          3 :         if (boot_cpu_has(X86_FEATURE_HYPERVISOR)) {
     235                 :          3 :                 unsigned int eax;
     236                 :          3 :                 unsigned int hyper_vendor_id[3];
     237                 :            : 
     238                 :          3 :                 cpuid(CPUID_VMWARE_INFO_LEAF, &eax, &hyper_vendor_id[0],
     239                 :            :                       &hyper_vendor_id[1], &hyper_vendor_id[2]);
     240         [ -  + ]:          3 :                 if (!memcmp(hyper_vendor_id, "VMwareVMware", 12)) {
     241         [ #  # ]:          0 :                         if (eax >= CPUID_VMWARE_FEATURES_LEAF)
     242                 :          0 :                                 vmware_hypercall_mode =
     243                 :            :                                         vmware_select_hypercall();
     244                 :            : 
     245                 :          0 :                         pr_info("hypercall mode: 0x%02x\n",
     246                 :            :                                 (unsigned int) vmware_hypercall_mode);
     247                 :            : 
     248                 :          0 :                         return CPUID_VMWARE_INFO_LEAF;
     249                 :            :                 }
     250   [ #  #  #  #  :          0 :         } else if (dmi_available && dmi_name_in_serial("VMware") &&
                   #  # ]
     251                 :            :                    __vmware_platform())
     252                 :          0 :                 return 1;
     253                 :            : 
     254                 :            :         return 0;
     255                 :            : }
     256                 :            : 
     257                 :            : /* Checks if hypervisor supports x2apic without VT-D interrupt remapping. */
     258                 :          0 : static bool __init vmware_legacy_x2apic_available(void)
     259                 :            : {
     260                 :          0 :         uint32_t eax, ebx, ecx, edx;
     261      [ #  #  # ]:          0 :         VMWARE_CMD(GETVCPU_INFO, eax, ebx, ecx, edx);
     262         [ #  # ]:          0 :         return (eax & (1 << VMWARE_CMD_VCPU_RESERVED)) == 0 &&
     263         [ #  # ]:          0 :                (eax & (1 << VMWARE_CMD_LEGACY_X2APIC)) != 0;
     264                 :            : }
     265                 :            : 
     266                 :            : const __initconst struct hypervisor_x86 x86_hyper_vmware = {
     267                 :            :         .name                   = "VMware",
     268                 :            :         .detect                 = vmware_platform,
     269                 :            :         .type                   = X86_HYPER_VMWARE,
     270                 :            :         .init.init_platform     = vmware_platform_setup,
     271                 :            :         .init.x2apic_available  = vmware_legacy_x2apic_available,
     272                 :            : };

Generated by: LCOV version 1.14