root/arch/x86/kernel/cpu/mshyperv.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. hyperv_vector_handler
  2. hv_setup_vmbus_irq
  3. hv_remove_vmbus_irq
  4. hv_stimer0_vector_handler
  5. hv_setup_stimer0_irq
  6. hv_remove_stimer0_irq
  7. hv_setup_kexec_handler
  8. hv_remove_kexec_handler
  9. hv_setup_crash_handler
  10. hv_remove_crash_handler
  11. hv_machine_shutdown
  12. hv_machine_crash_shutdown
  13. ms_hyperv_platform
  14. hv_get_nmi_reason
  15. hv_nmi_unknown
  16. hv_get_tsc_khz
  17. hv_smp_prepare_boot_cpu
  18. ms_hyperv_init_platform
  19. hv_setup_sched_clock

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * HyperV  Detection code.
   4  *
   5  * Copyright (C) 2010, Novell, Inc.
   6  * Author : K. Y. Srinivasan <ksrinivasan@novell.com>
   7  */
   8 
   9 #include <linux/types.h>
  10 #include <linux/time.h>
  11 #include <linux/clocksource.h>
  12 #include <linux/init.h>
  13 #include <linux/export.h>
  14 #include <linux/hardirq.h>
  15 #include <linux/efi.h>
  16 #include <linux/interrupt.h>
  17 #include <linux/irq.h>
  18 #include <linux/kexec.h>
  19 #include <linux/i8253.h>
  20 #include <linux/random.h>
  21 #include <asm/processor.h>
  22 #include <asm/hypervisor.h>
  23 #include <asm/hyperv-tlfs.h>
  24 #include <asm/mshyperv.h>
  25 #include <asm/desc.h>
  26 #include <asm/irq_regs.h>
  27 #include <asm/i8259.h>
  28 #include <asm/apic.h>
  29 #include <asm/timer.h>
  30 #include <asm/reboot.h>
  31 #include <asm/nmi.h>
  32 #include <clocksource/hyperv_timer.h>
  33 
  34 struct ms_hyperv_info ms_hyperv;
  35 EXPORT_SYMBOL_GPL(ms_hyperv);
  36 
  37 #if IS_ENABLED(CONFIG_HYPERV)
  38 static void (*vmbus_handler)(void);
  39 static void (*hv_stimer0_handler)(void);
  40 static void (*hv_kexec_handler)(void);
  41 static void (*hv_crash_handler)(struct pt_regs *regs);
  42 
  43 __visible void __irq_entry hyperv_vector_handler(struct pt_regs *regs)
  44 {
  45         struct pt_regs *old_regs = set_irq_regs(regs);
  46 
  47         entering_irq();
  48         inc_irq_stat(irq_hv_callback_count);
  49         if (vmbus_handler)
  50                 vmbus_handler();
  51 
  52         if (ms_hyperv.hints & HV_DEPRECATING_AEOI_RECOMMENDED)
  53                 ack_APIC_irq();
  54 
  55         exiting_irq();
  56         set_irq_regs(old_regs);
  57 }
  58 
  59 void hv_setup_vmbus_irq(void (*handler)(void))
  60 {
  61         vmbus_handler = handler;
  62 }
  63 
  64 void hv_remove_vmbus_irq(void)
  65 {
  66         /* We have no way to deallocate the interrupt gate */
  67         vmbus_handler = NULL;
  68 }
  69 EXPORT_SYMBOL_GPL(hv_setup_vmbus_irq);
  70 EXPORT_SYMBOL_GPL(hv_remove_vmbus_irq);
  71 
  72 /*
  73  * Routines to do per-architecture handling of stimer0
  74  * interrupts when in Direct Mode
  75  */
  76 
  77 __visible void __irq_entry hv_stimer0_vector_handler(struct pt_regs *regs)
  78 {
  79         struct pt_regs *old_regs = set_irq_regs(regs);
  80 
  81         entering_irq();
  82         inc_irq_stat(hyperv_stimer0_count);
  83         if (hv_stimer0_handler)
  84                 hv_stimer0_handler();
  85         add_interrupt_randomness(HYPERV_STIMER0_VECTOR, 0);
  86         ack_APIC_irq();
  87 
  88         exiting_irq();
  89         set_irq_regs(old_regs);
  90 }
  91 
  92 int hv_setup_stimer0_irq(int *irq, int *vector, void (*handler)(void))
  93 {
  94         *vector = HYPERV_STIMER0_VECTOR;
  95         *irq = -1;   /* Unused on x86/x64 */
  96         hv_stimer0_handler = handler;
  97         return 0;
  98 }
  99 EXPORT_SYMBOL_GPL(hv_setup_stimer0_irq);
 100 
 101 void hv_remove_stimer0_irq(int irq)
 102 {
 103         /* We have no way to deallocate the interrupt gate */
 104         hv_stimer0_handler = NULL;
 105 }
 106 EXPORT_SYMBOL_GPL(hv_remove_stimer0_irq);
 107 
 108 void hv_setup_kexec_handler(void (*handler)(void))
 109 {
 110         hv_kexec_handler = handler;
 111 }
 112 EXPORT_SYMBOL_GPL(hv_setup_kexec_handler);
 113 
 114 void hv_remove_kexec_handler(void)
 115 {
 116         hv_kexec_handler = NULL;
 117 }
 118 EXPORT_SYMBOL_GPL(hv_remove_kexec_handler);
 119 
 120 void hv_setup_crash_handler(void (*handler)(struct pt_regs *regs))
 121 {
 122         hv_crash_handler = handler;
 123 }
 124 EXPORT_SYMBOL_GPL(hv_setup_crash_handler);
 125 
 126 void hv_remove_crash_handler(void)
 127 {
 128         hv_crash_handler = NULL;
 129 }
 130 EXPORT_SYMBOL_GPL(hv_remove_crash_handler);
 131 
 132 #ifdef CONFIG_KEXEC_CORE
 133 static void hv_machine_shutdown(void)
 134 {
 135         if (kexec_in_progress && hv_kexec_handler)
 136                 hv_kexec_handler();
 137         native_machine_shutdown();
 138 }
 139 
 140 static void hv_machine_crash_shutdown(struct pt_regs *regs)
 141 {
 142         if (hv_crash_handler)
 143                 hv_crash_handler(regs);
 144         native_machine_crash_shutdown(regs);
 145 }
 146 #endif /* CONFIG_KEXEC_CORE */
 147 #endif /* CONFIG_HYPERV */
 148 
 149 static uint32_t  __init ms_hyperv_platform(void)
 150 {
 151         u32 eax;
 152         u32 hyp_signature[3];
 153 
 154         if (!boot_cpu_has(X86_FEATURE_HYPERVISOR))
 155                 return 0;
 156 
 157         cpuid(HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS,
 158               &eax, &hyp_signature[0], &hyp_signature[1], &hyp_signature[2]);
 159 
 160         if (eax >= HYPERV_CPUID_MIN &&
 161             eax <= HYPERV_CPUID_MAX &&
 162             !memcmp("Microsoft Hv", hyp_signature, 12))
 163                 return HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS;
 164 
 165         return 0;
 166 }
 167 
 168 static unsigned char hv_get_nmi_reason(void)
 169 {
 170         return 0;
 171 }
 172 
 173 #ifdef CONFIG_X86_LOCAL_APIC
 174 /*
 175  * Prior to WS2016 Debug-VM sends NMIs to all CPUs which makes
 176  * it dificult to process CHANNELMSG_UNLOAD in case of crash. Handle
 177  * unknown NMI on the first CPU which gets it.
 178  */
 179 static int hv_nmi_unknown(unsigned int val, struct pt_regs *regs)
 180 {
 181         static atomic_t nmi_cpu = ATOMIC_INIT(-1);
 182 
 183         if (!unknown_nmi_panic)
 184                 return NMI_DONE;
 185 
 186         if (atomic_cmpxchg(&nmi_cpu, -1, raw_smp_processor_id()) != -1)
 187                 return NMI_HANDLED;
 188 
 189         return NMI_DONE;
 190 }
 191 #endif
 192 
 193 static unsigned long hv_get_tsc_khz(void)
 194 {
 195         unsigned long freq;
 196 
 197         rdmsrl(HV_X64_MSR_TSC_FREQUENCY, freq);
 198 
 199         return freq / 1000;
 200 }
 201 
 202 #if defined(CONFIG_SMP) && IS_ENABLED(CONFIG_HYPERV)
 203 static void __init hv_smp_prepare_boot_cpu(void)
 204 {
 205         native_smp_prepare_boot_cpu();
 206 #if defined(CONFIG_X86_64) && defined(CONFIG_PARAVIRT_SPINLOCKS)
 207         hv_init_spinlocks();
 208 #endif
 209 }
 210 #endif
 211 
 212 static void __init ms_hyperv_init_platform(void)
 213 {
 214         int hv_host_info_eax;
 215         int hv_host_info_ebx;
 216         int hv_host_info_ecx;
 217         int hv_host_info_edx;
 218 
 219 #ifdef CONFIG_PARAVIRT
 220         pv_info.name = "Hyper-V";
 221 #endif
 222 
 223         /*
 224          * Extract the features and hints
 225          */
 226         ms_hyperv.features = cpuid_eax(HYPERV_CPUID_FEATURES);
 227         ms_hyperv.misc_features = cpuid_edx(HYPERV_CPUID_FEATURES);
 228         ms_hyperv.hints    = cpuid_eax(HYPERV_CPUID_ENLIGHTMENT_INFO);
 229 
 230         pr_info("Hyper-V: features 0x%x, hints 0x%x, misc 0x%x\n",
 231                 ms_hyperv.features, ms_hyperv.hints, ms_hyperv.misc_features);
 232 
 233         ms_hyperv.max_vp_index = cpuid_eax(HYPERV_CPUID_IMPLEMENT_LIMITS);
 234         ms_hyperv.max_lp_index = cpuid_ebx(HYPERV_CPUID_IMPLEMENT_LIMITS);
 235 
 236         pr_debug("Hyper-V: max %u virtual processors, %u logical processors\n",
 237                  ms_hyperv.max_vp_index, ms_hyperv.max_lp_index);
 238 
 239         /*
 240          * Extract host information.
 241          */
 242         if (cpuid_eax(HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS) >=
 243             HYPERV_CPUID_VERSION) {
 244                 hv_host_info_eax = cpuid_eax(HYPERV_CPUID_VERSION);
 245                 hv_host_info_ebx = cpuid_ebx(HYPERV_CPUID_VERSION);
 246                 hv_host_info_ecx = cpuid_ecx(HYPERV_CPUID_VERSION);
 247                 hv_host_info_edx = cpuid_edx(HYPERV_CPUID_VERSION);
 248 
 249                 pr_info("Hyper-V Host Build:%d-%d.%d-%d-%d.%d\n",
 250                         hv_host_info_eax, hv_host_info_ebx >> 16,
 251                         hv_host_info_ebx & 0xFFFF, hv_host_info_ecx,
 252                         hv_host_info_edx >> 24, hv_host_info_edx & 0xFFFFFF);
 253         }
 254 
 255         if (ms_hyperv.features & HV_X64_ACCESS_FREQUENCY_MSRS &&
 256             ms_hyperv.misc_features & HV_FEATURE_FREQUENCY_MSRS_AVAILABLE) {
 257                 x86_platform.calibrate_tsc = hv_get_tsc_khz;
 258                 x86_platform.calibrate_cpu = hv_get_tsc_khz;
 259         }
 260 
 261         if (ms_hyperv.hints & HV_X64_ENLIGHTENED_VMCS_RECOMMENDED) {
 262                 ms_hyperv.nested_features =
 263                         cpuid_eax(HYPERV_CPUID_NESTED_FEATURES);
 264         }
 265 
 266         /*
 267          * Hyper-V expects to get crash register data or kmsg when
 268          * crash enlightment is available and system crashes. Set
 269          * crash_kexec_post_notifiers to be true to make sure that
 270          * calling crash enlightment interface before running kdump
 271          * kernel.
 272          */
 273         if (ms_hyperv.misc_features & HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE)
 274                 crash_kexec_post_notifiers = true;
 275 
 276 #ifdef CONFIG_X86_LOCAL_APIC
 277         if (ms_hyperv.features & HV_X64_ACCESS_FREQUENCY_MSRS &&
 278             ms_hyperv.misc_features & HV_FEATURE_FREQUENCY_MSRS_AVAILABLE) {
 279                 /*
 280                  * Get the APIC frequency.
 281                  */
 282                 u64     hv_lapic_frequency;
 283 
 284                 rdmsrl(HV_X64_MSR_APIC_FREQUENCY, hv_lapic_frequency);
 285                 hv_lapic_frequency = div_u64(hv_lapic_frequency, HZ);
 286                 lapic_timer_period = hv_lapic_frequency;
 287                 pr_info("Hyper-V: LAPIC Timer Frequency: %#x\n",
 288                         lapic_timer_period);
 289         }
 290 
 291         register_nmi_handler(NMI_UNKNOWN, hv_nmi_unknown, NMI_FLAG_FIRST,
 292                              "hv_nmi_unknown");
 293 #endif
 294 
 295 #ifdef CONFIG_X86_IO_APIC
 296         no_timer_check = 1;
 297 #endif
 298 
 299 #if IS_ENABLED(CONFIG_HYPERV) && defined(CONFIG_KEXEC_CORE)
 300         machine_ops.shutdown = hv_machine_shutdown;
 301         machine_ops.crash_shutdown = hv_machine_crash_shutdown;
 302 #endif
 303         mark_tsc_unstable("running on Hyper-V");
 304 
 305         /*
 306          * Generation 2 instances don't support reading the NMI status from
 307          * 0x61 port.
 308          */
 309         if (efi_enabled(EFI_BOOT))
 310                 x86_platform.get_nmi_reason = hv_get_nmi_reason;
 311 
 312         /*
 313          * Hyper-V VMs have a PIT emulation quirk such that zeroing the
 314          * counter register during PIT shutdown restarts the PIT. So it
 315          * continues to interrupt @18.2 HZ. Setting i8253_clear_counter
 316          * to false tells pit_shutdown() not to zero the counter so that
 317          * the PIT really is shutdown. Generation 2 VMs don't have a PIT,
 318          * and setting this value has no effect.
 319          */
 320         i8253_clear_counter_on_shutdown = false;
 321 
 322 #if IS_ENABLED(CONFIG_HYPERV)
 323         /*
 324          * Setup the hook to get control post apic initialization.
 325          */
 326         x86_platform.apic_post_init = hyperv_init;
 327         hyperv_setup_mmu_ops();
 328         /* Setup the IDT for hypervisor callback */
 329         alloc_intr_gate(HYPERVISOR_CALLBACK_VECTOR, hyperv_callback_vector);
 330 
 331         /* Setup the IDT for reenlightenment notifications */
 332         if (ms_hyperv.features & HV_X64_ACCESS_REENLIGHTENMENT)
 333                 alloc_intr_gate(HYPERV_REENLIGHTENMENT_VECTOR,
 334                                 hyperv_reenlightenment_vector);
 335 
 336         /* Setup the IDT for stimer0 */
 337         if (ms_hyperv.misc_features & HV_STIMER_DIRECT_MODE_AVAILABLE)
 338                 alloc_intr_gate(HYPERV_STIMER0_VECTOR,
 339                                 hv_stimer0_callback_vector);
 340 
 341 # ifdef CONFIG_SMP
 342         smp_ops.smp_prepare_boot_cpu = hv_smp_prepare_boot_cpu;
 343 # endif
 344 
 345         /*
 346          * Hyper-V doesn't provide irq remapping for IO-APIC. To enable x2apic,
 347          * set x2apic destination mode to physcial mode when x2apic is available
 348          * and Hyper-V IOMMU driver makes sure cpus assigned with IO-APIC irqs
 349          * have 8-bit APIC id.
 350          */
 351 # ifdef CONFIG_X86_X2APIC
 352         if (x2apic_supported())
 353                 x2apic_phys = 1;
 354 # endif
 355 
 356         /* Register Hyper-V specific clocksource */
 357         hv_init_clocksource();
 358 #endif
 359 }
 360 
 361 void hv_setup_sched_clock(void *sched_clock)
 362 {
 363 #ifdef CONFIG_PARAVIRT
 364         pv_ops.time.sched_clock = sched_clock;
 365 #endif
 366 }
 367 
 368 const __initconst struct hypervisor_x86 x86_hyper_ms_hyperv = {
 369         .name                   = "Microsoft Hyper-V",
 370         .detect                 = ms_hyperv_platform,
 371         .type                   = X86_HYPER_MS_HYPERV,
 372         .init.init_platform     = ms_hyperv_init_platform,
 373 };

/* [<][>][^][v][top][bottom][index][help] */