linux/arch/x86/hyperv/hv_init.c
<<
>>
Prefs
   1/*
   2 * X86 specific Hyper-V initialization code.
   3 *
   4 * Copyright (C) 2016, Microsoft, Inc.
   5 *
   6 * Author : K. Y. Srinivasan <kys@microsoft.com>
   7 *
   8 * This program is free software; you can redistribute it and/or modify it
   9 * under the terms of the GNU General Public License version 2 as published
  10 * by the Free Software Foundation.
  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 */
  19
  20#include <linux/types.h>
  21#include <asm/apic.h>
  22#include <asm/desc.h>
  23#include <asm/hypervisor.h>
  24#include <asm/hyperv-tlfs.h>
  25#include <asm/mshyperv.h>
  26#include <linux/version.h>
  27#include <linux/vmalloc.h>
  28#include <linux/mm.h>
  29#include <linux/clockchips.h>
  30#include <linux/hyperv.h>
  31#include <linux/slab.h>
  32#include <linux/cpuhotplug.h>
  33
  34#ifdef CONFIG_HYPERV_TSCPAGE
  35
  36static struct ms_hyperv_tsc_page *tsc_pg;
  37
  38struct ms_hyperv_tsc_page *hv_get_tsc_page(void)
  39{
  40        return tsc_pg;
  41}
  42EXPORT_SYMBOL_GPL(hv_get_tsc_page);
  43
  44static u64 read_hv_clock_tsc(struct clocksource *arg)
  45{
  46        u64 current_tick = hv_read_tsc_page(tsc_pg);
  47
  48        if (current_tick == U64_MAX)
  49                rdmsrl(HV_X64_MSR_TIME_REF_COUNT, current_tick);
  50
  51        return current_tick;
  52}
  53
  54static struct clocksource hyperv_cs_tsc = {
  55                .name           = "hyperv_clocksource_tsc_page",
  56                .rating         = 400,
  57                .read           = read_hv_clock_tsc,
  58                .mask           = CLOCKSOURCE_MASK(64),
  59                .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
  60};
  61#endif
  62
  63static u64 read_hv_clock_msr(struct clocksource *arg)
  64{
  65        u64 current_tick;
  66        /*
  67         * Read the partition counter to get the current tick count. This count
  68         * is set to 0 when the partition is created and is incremented in
  69         * 100 nanosecond units.
  70         */
  71        rdmsrl(HV_X64_MSR_TIME_REF_COUNT, current_tick);
  72        return current_tick;
  73}
  74
  75static struct clocksource hyperv_cs_msr = {
  76        .name           = "hyperv_clocksource_msr",
  77        .rating         = 400,
  78        .read           = read_hv_clock_msr,
  79        .mask           = CLOCKSOURCE_MASK(64),
  80        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
  81};
  82
  83void *hv_hypercall_pg;
  84EXPORT_SYMBOL_GPL(hv_hypercall_pg);
  85struct clocksource *hyperv_cs;
  86EXPORT_SYMBOL_GPL(hyperv_cs);
  87
  88u32 *hv_vp_index;
  89EXPORT_SYMBOL_GPL(hv_vp_index);
  90
  91struct hv_vp_assist_page **hv_vp_assist_page;
  92EXPORT_SYMBOL_GPL(hv_vp_assist_page);
  93
  94u32 hv_max_vp_index;
  95
  96static int hv_cpu_init(unsigned int cpu)
  97{
  98        u64 msr_vp_index;
  99        struct hv_vp_assist_page **hvp = &hv_vp_assist_page[smp_processor_id()];
 100
 101        hv_get_vp_index(msr_vp_index);
 102
 103        hv_vp_index[smp_processor_id()] = msr_vp_index;
 104
 105        if (msr_vp_index > hv_max_vp_index)
 106                hv_max_vp_index = msr_vp_index;
 107
 108        if (!hv_vp_assist_page)
 109                return 0;
 110
 111        if (!*hvp)
 112                *hvp = __vmalloc(PAGE_SIZE, GFP_KERNEL, PAGE_KERNEL);
 113
 114        if (*hvp) {
 115                u64 val;
 116
 117                val = vmalloc_to_pfn(*hvp);
 118                val = (val << HV_X64_MSR_VP_ASSIST_PAGE_ADDRESS_SHIFT) |
 119                        HV_X64_MSR_VP_ASSIST_PAGE_ENABLE;
 120
 121                wrmsrl(HV_X64_MSR_VP_ASSIST_PAGE, val);
 122        }
 123
 124        return 0;
 125}
 126
 127static void (*hv_reenlightenment_cb)(void);
 128
 129static void hv_reenlightenment_notify(struct work_struct *dummy)
 130{
 131        struct hv_tsc_emulation_status emu_status;
 132
 133        rdmsrl(HV_X64_MSR_TSC_EMULATION_STATUS, *(u64 *)&emu_status);
 134
 135        /* Don't issue the callback if TSC accesses are not emulated */
 136        if (hv_reenlightenment_cb && emu_status.inprogress)
 137                hv_reenlightenment_cb();
 138}
 139static DECLARE_DELAYED_WORK(hv_reenlightenment_work, hv_reenlightenment_notify);
 140
 141void hyperv_stop_tsc_emulation(void)
 142{
 143        u64 freq;
 144        struct hv_tsc_emulation_status emu_status;
 145
 146        rdmsrl(HV_X64_MSR_TSC_EMULATION_STATUS, *(u64 *)&emu_status);
 147        emu_status.inprogress = 0;
 148        wrmsrl(HV_X64_MSR_TSC_EMULATION_STATUS, *(u64 *)&emu_status);
 149
 150        rdmsrl(HV_X64_MSR_TSC_FREQUENCY, freq);
 151        tsc_khz = div64_u64(freq, 1000);
 152}
 153EXPORT_SYMBOL_GPL(hyperv_stop_tsc_emulation);
 154
 155static inline bool hv_reenlightenment_available(void)
 156{
 157        /*
 158         * Check for required features and priviliges to make TSC frequency
 159         * change notifications work.
 160         */
 161        return ms_hyperv.features & HV_X64_ACCESS_FREQUENCY_MSRS &&
 162                ms_hyperv.misc_features & HV_FEATURE_FREQUENCY_MSRS_AVAILABLE &&
 163                ms_hyperv.features & HV_X64_ACCESS_REENLIGHTENMENT;
 164}
 165
 166__visible void __irq_entry hyperv_reenlightenment_intr(struct pt_regs *regs)
 167{
 168        entering_ack_irq();
 169
 170        inc_irq_stat(irq_hv_reenlightenment_count);
 171
 172        schedule_delayed_work(&hv_reenlightenment_work, HZ/10);
 173
 174        exiting_irq();
 175}
 176
 177void set_hv_tscchange_cb(void (*cb)(void))
 178{
 179        struct hv_reenlightenment_control re_ctrl = {
 180                .vector = HYPERV_REENLIGHTENMENT_VECTOR,
 181                .enabled = 1,
 182                .target_vp = hv_vp_index[smp_processor_id()]
 183        };
 184        struct hv_tsc_emulation_control emu_ctrl = {.enabled = 1};
 185
 186        if (!hv_reenlightenment_available()) {
 187                pr_warn("Hyper-V: reenlightenment support is unavailable\n");
 188                return;
 189        }
 190
 191        hv_reenlightenment_cb = cb;
 192
 193        /* Make sure callback is registered before we write to MSRs */
 194        wmb();
 195
 196        wrmsrl(HV_X64_MSR_REENLIGHTENMENT_CONTROL, *((u64 *)&re_ctrl));
 197        wrmsrl(HV_X64_MSR_TSC_EMULATION_CONTROL, *((u64 *)&emu_ctrl));
 198}
 199EXPORT_SYMBOL_GPL(set_hv_tscchange_cb);
 200
 201void clear_hv_tscchange_cb(void)
 202{
 203        struct hv_reenlightenment_control re_ctrl;
 204
 205        if (!hv_reenlightenment_available())
 206                return;
 207
 208        rdmsrl(HV_X64_MSR_REENLIGHTENMENT_CONTROL, *(u64 *)&re_ctrl);
 209        re_ctrl.enabled = 0;
 210        wrmsrl(HV_X64_MSR_REENLIGHTENMENT_CONTROL, *(u64 *)&re_ctrl);
 211
 212        hv_reenlightenment_cb = NULL;
 213}
 214EXPORT_SYMBOL_GPL(clear_hv_tscchange_cb);
 215
 216static int hv_cpu_die(unsigned int cpu)
 217{
 218        struct hv_reenlightenment_control re_ctrl;
 219        unsigned int new_cpu;
 220
 221        if (hv_vp_assist_page && hv_vp_assist_page[cpu])
 222                wrmsrl(HV_X64_MSR_VP_ASSIST_PAGE, 0);
 223
 224        if (hv_reenlightenment_cb == NULL)
 225                return 0;
 226
 227        rdmsrl(HV_X64_MSR_REENLIGHTENMENT_CONTROL, *((u64 *)&re_ctrl));
 228        if (re_ctrl.target_vp == hv_vp_index[cpu]) {
 229                /* Reassign to some other online CPU */
 230                new_cpu = cpumask_any_but(cpu_online_mask, cpu);
 231
 232                re_ctrl.target_vp = hv_vp_index[new_cpu];
 233                wrmsrl(HV_X64_MSR_REENLIGHTENMENT_CONTROL, *((u64 *)&re_ctrl));
 234        }
 235
 236        return 0;
 237}
 238
 239/*
 240 * This function is to be invoked early in the boot sequence after the
 241 * hypervisor has been detected.
 242 *
 243 * 1. Setup the hypercall page.
 244 * 2. Register Hyper-V specific clocksource.
 245 */
 246void hyperv_init(void)
 247{
 248        u64 guest_id, required_msrs;
 249        union hv_x64_msr_hypercall_contents hypercall_msr;
 250        int cpuhp;
 251
 252        if (x86_hyper_type != X86_HYPER_MS_HYPERV)
 253                return;
 254
 255        /* Absolutely required MSRs */
 256        required_msrs = HV_X64_MSR_HYPERCALL_AVAILABLE |
 257                HV_X64_MSR_VP_INDEX_AVAILABLE;
 258
 259        if ((ms_hyperv.features & required_msrs) != required_msrs)
 260                return;
 261
 262        /* Allocate percpu VP index */
 263        hv_vp_index = kmalloc_array(num_possible_cpus(), sizeof(*hv_vp_index),
 264                                    GFP_KERNEL);
 265        if (!hv_vp_index)
 266                return;
 267
 268        hv_vp_assist_page = kcalloc(num_possible_cpus(),
 269                                    sizeof(*hv_vp_assist_page), GFP_KERNEL);
 270        if (!hv_vp_assist_page) {
 271                ms_hyperv.hints &= ~HV_X64_ENLIGHTENED_VMCS_RECOMMENDED;
 272                goto free_vp_index;
 273        }
 274
 275        cpuhp = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "x86/hyperv_init:online",
 276                                  hv_cpu_init, hv_cpu_die);
 277        if (cpuhp < 0)
 278                goto free_vp_assist_page;
 279
 280        /*
 281         * Setup the hypercall page and enable hypercalls.
 282         * 1. Register the guest ID
 283         * 2. Enable the hypercall and register the hypercall page
 284         */
 285        guest_id = generate_guest_id(0, LINUX_VERSION_CODE, 0);
 286        wrmsrl(HV_X64_MSR_GUEST_OS_ID, guest_id);
 287
 288        hv_hypercall_pg  = __vmalloc(PAGE_SIZE, GFP_KERNEL, PAGE_KERNEL_RX);
 289        if (hv_hypercall_pg == NULL) {
 290                wrmsrl(HV_X64_MSR_GUEST_OS_ID, 0);
 291                goto remove_cpuhp_state;
 292        }
 293
 294        rdmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
 295        hypercall_msr.enable = 1;
 296        hypercall_msr.guest_physical_address = vmalloc_to_pfn(hv_hypercall_pg);
 297        wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
 298
 299        hyper_alloc_mmu();
 300
 301        /*
 302         * Register Hyper-V specific clocksource.
 303         */
 304#ifdef CONFIG_HYPERV_TSCPAGE
 305        if (ms_hyperv.features & HV_X64_MSR_REFERENCE_TSC_AVAILABLE) {
 306                union hv_x64_msr_hypercall_contents tsc_msr;
 307
 308                tsc_pg = __vmalloc(PAGE_SIZE, GFP_KERNEL, PAGE_KERNEL);
 309                if (!tsc_pg)
 310                        goto register_msr_cs;
 311
 312                hyperv_cs = &hyperv_cs_tsc;
 313
 314                rdmsrl(HV_X64_MSR_REFERENCE_TSC, tsc_msr.as_uint64);
 315
 316                tsc_msr.enable = 1;
 317                tsc_msr.guest_physical_address = vmalloc_to_pfn(tsc_pg);
 318
 319                wrmsrl(HV_X64_MSR_REFERENCE_TSC, tsc_msr.as_uint64);
 320
 321                hyperv_cs_tsc.archdata.vclock_mode = VCLOCK_HVCLOCK;
 322
 323                clocksource_register_hz(&hyperv_cs_tsc, NSEC_PER_SEC/100);
 324                return;
 325        }
 326register_msr_cs:
 327#endif
 328        /*
 329         * For 32 bit guests just use the MSR based mechanism for reading
 330         * the partition counter.
 331         */
 332
 333        hyperv_cs = &hyperv_cs_msr;
 334        if (ms_hyperv.features & HV_X64_MSR_TIME_REF_COUNT_AVAILABLE)
 335                clocksource_register_hz(&hyperv_cs_msr, NSEC_PER_SEC/100);
 336
 337        return;
 338
 339remove_cpuhp_state:
 340        cpuhp_remove_state(cpuhp);
 341free_vp_assist_page:
 342        kfree(hv_vp_assist_page);
 343        hv_vp_assist_page = NULL;
 344free_vp_index:
 345        kfree(hv_vp_index);
 346        hv_vp_index = NULL;
 347}
 348
 349/*
 350 * This routine is called before kexec/kdump, it does the required cleanup.
 351 */
 352void hyperv_cleanup(void)
 353{
 354        union hv_x64_msr_hypercall_contents hypercall_msr;
 355
 356        /* Reset our OS id */
 357        wrmsrl(HV_X64_MSR_GUEST_OS_ID, 0);
 358
 359        /* Reset the hypercall page */
 360        hypercall_msr.as_uint64 = 0;
 361        wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
 362
 363        /* Reset the TSC page */
 364        hypercall_msr.as_uint64 = 0;
 365        wrmsrl(HV_X64_MSR_REFERENCE_TSC, hypercall_msr.as_uint64);
 366}
 367EXPORT_SYMBOL_GPL(hyperv_cleanup);
 368
 369void hyperv_report_panic(struct pt_regs *regs, long err)
 370{
 371        static bool panic_reported;
 372        u64 guest_id;
 373
 374        /*
 375         * We prefer to report panic on 'die' chain as we have proper
 376         * registers to report, but if we miss it (e.g. on BUG()) we need
 377         * to report it on 'panic'.
 378         */
 379        if (panic_reported)
 380                return;
 381        panic_reported = true;
 382
 383        rdmsrl(HV_X64_MSR_GUEST_OS_ID, guest_id);
 384
 385        wrmsrl(HV_X64_MSR_CRASH_P0, err);
 386        wrmsrl(HV_X64_MSR_CRASH_P1, guest_id);
 387        wrmsrl(HV_X64_MSR_CRASH_P2, regs->ip);
 388        wrmsrl(HV_X64_MSR_CRASH_P3, regs->ax);
 389        wrmsrl(HV_X64_MSR_CRASH_P4, regs->sp);
 390
 391        /*
 392         * Let Hyper-V know there is crash data available
 393         */
 394        wrmsrl(HV_X64_MSR_CRASH_CTL, HV_CRASH_CTL_CRASH_NOTIFY);
 395}
 396EXPORT_SYMBOL_GPL(hyperv_report_panic);
 397
 398bool hv_is_hyperv_initialized(void)
 399{
 400        union hv_x64_msr_hypercall_contents hypercall_msr;
 401
 402        /*
 403         * Ensure that we're really on Hyper-V, and not a KVM or Xen
 404         * emulation of Hyper-V
 405         */
 406        if (x86_hyper_type != X86_HYPER_MS_HYPERV)
 407                return false;
 408
 409        /*
 410         * Verify that earlier initialization succeeded by checking
 411         * that the hypercall page is setup
 412         */
 413        hypercall_msr.as_uint64 = 0;
 414        rdmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
 415
 416        return hypercall_msr.enable;
 417}
 418EXPORT_SYMBOL_GPL(hv_is_hyperv_initialized);
 419