Skip to content

Instantly share code, notes, and snippets.

@therealkenc
Created September 19, 2019 06:04
Show Gist options
  • Save therealkenc/4b5256af912329cd279cf6f5e6a4f6ac to your computer and use it in GitHub Desktop.
Save therealkenc/4b5256af912329cd279cf6f5e6a4f6ac to your computer and use it in GitHub Desktop.
diff -N -r -u linux-4.19.72/arch/arm64/hyperv/hv_hvc.S WSL2-Linux-Kernel-4.19.72-microsoft-standard/arch/arm64/hyperv/hv_hvc.S
--- linux-4.19.72/arch/arm64/hyperv/hv_hvc.S 1969-12-31 16:00:00.000000000 -0800
+++ WSL2-Linux-Kernel-4.19.72-microsoft-standard/arch/arm64/hyperv/hv_hvc.S 2019-09-15 02:24:17.000000000 -0700
@@ -0,0 +1,54 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/*
+ * Microsoft Hyper-V hypervisor invocation routines
+ *
+ * Copyright (C) 2018, Microsoft, Inc.
+ *
+ * Author : Michael Kelley <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include <linux/linkage.h>
+
+ .text
+/*
+ * Do the HVC instruction. For Hyper-V the argument is always 1.
+ * x0 contains the hypercall control value, while additional registers
+ * vary depending on the hypercall, and whether the hypercall arguments
+ * are in memory or in registers (a "fast" hypercall per the Hyper-V
+ * TLFS). When the arguments are in memory x1 is the guest physical
+ * address of the input arguments, and x2 is the guest physical
+ * address of the output arguments. When the arguments are in
+ * registers, the register values depends on the hypercall. Note
+ * that this version cannot return any values in registers.
+ */
+ENTRY(hv_do_hvc)
+ hvc #1
+ ret
+ENDPROC(hv_do_hvc)
+
+/*
+ * This variant of HVC invocation is for hv_get_vpreg and
+ * hv_get_vpreg_128. The input parameters are passed in registers
+ * along with a pointer in x4 to where the output result should
+ * be stored. The output is returned in x15 and x16. x18 is used as
+ * scratch space to avoid buildng a stack frame, as Hyper-V does
+ * not preserve registers x0-x17.
+ */
+ENTRY(hv_do_hvc_fast_get)
+ mov x18, x4
+ hvc #1
+ str x15,[x18]
+ str x16,[x18,#8]
+ ret
+ENDPROC(hv_do_hvc_fast_get)
diff -N -r -u linux-4.19.72/arch/arm64/hyperv/hv_init.c WSL2-Linux-Kernel-4.19.72-microsoft-standard/arch/arm64/hyperv/hv_init.c
--- linux-4.19.72/arch/arm64/hyperv/hv_init.c 1969-12-31 16:00:00.000000000 -0800
+++ WSL2-Linux-Kernel-4.19.72-microsoft-standard/arch/arm64/hyperv/hv_init.c 2019-09-15 02:24:17.000000000 -0700
@@ -0,0 +1,441 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * Initialization of the interface with Microsoft's Hyper-V hypervisor,
+ * and various low level utility routines for interacting with Hyper-V.
+ *
+ * Copyright (C) 2018, Microsoft, Inc.
+ *
+ * Author : Michael Kelley <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+
+#include <linux/types.h>
+#include <linux/version.h>
+#include <linux/export.h>
+#include <linux/vmalloc.h>
+#include <linux/mm.h>
+#include <linux/clocksource.h>
+#include <linux/sched_clock.h>
+#include <linux/acpi.h>
+#include <linux/module.h>
+#include <linux/hyperv.h>
+#include <linux/slab.h>
+#include <linux/cpuhotplug.h>
+#include <linux/psci.h>
+#include <asm-generic/bug.h>
+#include <asm/hypervisor.h>
+#include <asm/hyperv-tlfs.h>
+#include <asm/mshyperv.h>
+#include <asm/sysreg.h>
+#include <clocksource/arm_arch_timer.h>
+
+static bool hyperv_initialized;
+struct ms_hyperv_info ms_hyperv;
+EXPORT_SYMBOL_GPL(ms_hyperv);
+
+static struct ms_hyperv_tsc_page *tsc_pg;
+
+struct ms_hyperv_tsc_page *hv_get_tsc_page(void)
+{
+ return tsc_pg;
+}
+EXPORT_SYMBOL_GPL(hv_get_tsc_page);
+
+static u64 read_hv_sched_clock_tsc(void)
+{
+ u64 current_tick = hv_read_tsc_page(tsc_pg);
+
+ if (current_tick == U64_MAX)
+ current_tick = hv_get_vpreg(HV_REGISTER_TIME_REFCOUNT);
+
+ return current_tick;
+}
+
+static u64 read_hv_clock_tsc(struct clocksource *arg)
+{
+ u64 current_tick = hv_read_tsc_page(tsc_pg);
+
+ if (current_tick == U64_MAX)
+ current_tick = hv_get_vpreg(HV_REGISTER_TIME_REFCOUNT);
+
+ return current_tick;
+}
+
+static struct clocksource hyperv_cs_tsc = {
+ .name = "hyperv_clocksource_tsc_page",
+ .rating = 400,
+ .read = read_hv_clock_tsc,
+ .mask = CLOCKSOURCE_MASK(64),
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static u64 read_hv_sched_clock_msr(void)
+{
+ return hv_get_vpreg(HV_REGISTER_TIME_REFCOUNT);
+}
+
+static u64 read_hv_clock_msr(struct clocksource *arg)
+{
+ return hv_get_vpreg(HV_REGISTER_TIME_REFCOUNT);
+}
+
+static struct clocksource hyperv_cs_msr = {
+ .name = "hyperv_clocksource_msr",
+ .rating = 400,
+ .read = read_hv_clock_msr,
+ .mask = CLOCKSOURCE_MASK(64),
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+struct clocksource *hyperv_cs;
+EXPORT_SYMBOL_GPL(hyperv_cs);
+
+u32 *hv_vp_index;
+EXPORT_SYMBOL_GPL(hv_vp_index);
+
+u32 hv_max_vp_index;
+
+static int hv_cpu_init(unsigned int cpu)
+{
+ u64 msr_vp_index;
+
+ hv_get_vp_index(msr_vp_index);
+
+ hv_vp_index[smp_processor_id()] = msr_vp_index;
+
+ if (msr_vp_index > hv_max_vp_index)
+ hv_max_vp_index = msr_vp_index;
+
+ return 0;
+}
+
+/*
+ * This function is invoked via the ACPI clocksource probe mechanism. We
+ * don't actually use any values from the ACPI GTDT table, but we set up
+ * the Hyper-V synthetic clocksource and do other initialization for
+ * interacting with Hyper-V the first time. Using early_initcall to invoke
+ * this function is too late because interrupts are already enabled at that
+ * point, and sched_clock_register must run before interrupts are enabled.
+ *
+ * 1. Setup the guest ID.
+ * 2. Get features and hints info from Hyper-V
+ * 3. Setup per-cpu VP indices.
+ * 4. Register Hyper-V specific clocksource.
+ * 5. Register the scheduler clock.
+ */
+
+static int __init hyperv_init(struct acpi_table_header *table)
+{
+ struct hv_get_vp_register_output result;
+ u32 a, b, c, d;
+ u64 guest_id;
+ int i;
+
+ /*
+ * If we're in a VM on Hyper-V, the ACPI hypervisor_id field will
+ * have the string "MsHyperV".
+ */
+ if (strncmp((char *)&acpi_gbl_FADT.hypervisor_id, "MsHyperV", 8))
+ return 1;
+
+ /* Setup the guest ID */
+ guest_id = generate_guest_id(0, LINUX_VERSION_CODE, 0);
+ hv_set_vpreg(HV_REGISTER_GUEST_OSID, guest_id);
+
+ /* Get the features and hints from Hyper-V */
+ hv_get_vpreg_128(HV_REGISTER_PRIVILEGES_AND_FEATURES, &result);
+ ms_hyperv.features = lower_32_bits(result.registervaluelow);
+ ms_hyperv.misc_features = upper_32_bits(result.registervaluehigh);
+
+ hv_get_vpreg_128(HV_REGISTER_FEATURES, &result);
+ ms_hyperv.hints = lower_32_bits(result.registervaluelow);
+
+ pr_info("Hyper-V: Features 0x%x, hints 0x%x\n",
+ ms_hyperv.features, ms_hyperv.hints);
+
+ /*
+ * Direct mode is the only option for STIMERs provided Hyper-V
+ * on ARM64, so Hyper-V doesn't actually set the flag. But add the
+ * flag so the architecture independent code in drivers/hv/hv.c
+ * will correctly use that mode.
+ */
+ ms_hyperv.misc_features |= HV_STIMER_DIRECT_MODE_AVAILABLE;
+
+ /*
+ * Hyper-V on ARM64 doesn't support AutoEOI. Add the hint
+ * that tells architecture independent code not to use this
+ * feature.
+ */
+ ms_hyperv.hints |= HV_DEPRECATING_AEOI_RECOMMENDED;
+
+ /* Get information about the Hyper-V host version */
+ hv_get_vpreg_128(HV_REGISTER_HYPERVISOR_VERSION, &result);
+ a = lower_32_bits(result.registervaluelow);
+ b = upper_32_bits(result.registervaluelow);
+ c = lower_32_bits(result.registervaluehigh);
+ d = upper_32_bits(result.registervaluehigh);
+ pr_info("Hyper-V: Host Build %d.%d.%d.%d-%d-%d\n",
+ b >> 16, b & 0xFFFF, a, d & 0xFFFFFF, c, d >> 24);
+
+ /* Allocate percpu VP index */
+ hv_vp_index = kmalloc_array(num_possible_cpus(), sizeof(*hv_vp_index),
+ GFP_KERNEL);
+ if (!hv_vp_index)
+ return 1;
+
+ for (i = 0; i < num_possible_cpus(); i++)
+ hv_vp_index[i] = VP_INVAL;
+
+ if (cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "arm64/hyperv_init:online",
+ hv_cpu_init, NULL) < 0)
+ goto free_vp_index;
+
+ /*
+ * Try to set up what Hyper-V calls the "TSC reference page", which
+ * uses the ARM Generic Timer virtual counter with some scaling
+ * information to provide a fast and stable guest VM clocksource.
+ * If the TSC reference page can't be set up, fall back to reading
+ * the guest clock provided by Hyper-V's synthetic reference time
+ * register.
+ */
+ if (ms_hyperv.features & HV_MSR_REFERENCE_TSC_AVAILABLE) {
+
+ u64 tsc_msr;
+ phys_addr_t phys_addr;
+
+ tsc_pg = __vmalloc(HV_HYP_PAGE_SIZE, GFP_KERNEL, PAGE_KERNEL);
+ if (tsc_pg) {
+ phys_addr = page_to_phys(vmalloc_to_page(tsc_pg));
+ tsc_msr = hv_get_vpreg(HV_REGISTER_REFERENCE_TSC);
+ tsc_msr &= GENMASK_ULL(11, 0);
+ tsc_msr = tsc_msr | 0x1 | (u64)phys_addr;
+ hv_set_vpreg(HV_REGISTER_REFERENCE_TSC, tsc_msr);
+ hyperv_cs = &hyperv_cs_tsc;
+ sched_clock_register(read_hv_sched_clock_tsc,
+ 64, HV_CLOCK_HZ);
+ }
+ }
+
+ if (!hyperv_cs &&
+ (ms_hyperv.features & HV_MSR_TIME_REF_COUNT_AVAILABLE)) {
+ hyperv_cs = &hyperv_cs_msr;
+ sched_clock_register(read_hv_sched_clock_msr,
+ 64, HV_CLOCK_HZ);
+ }
+
+ if (hyperv_cs) {
+ hyperv_cs->archdata.vdso_direct = false;
+ clocksource_register_hz(hyperv_cs, HV_CLOCK_HZ);
+ }
+
+ hyperv_initialized = true;
+ return 0;
+
+free_vp_index:
+ kfree(hv_vp_index);
+ hv_vp_index = NULL;
+ return 1;
+}
+TIMER_ACPI_DECLARE(hyperv, ACPI_SIG_GTDT, hyperv_init);
+
+/*
+ * This routine is called before kexec/kdump, it does the required cleanup.
+ */
+void hyperv_cleanup(void)
+{
+ /* Reset our OS id */
+ hv_set_vpreg(HV_REGISTER_GUEST_OSID, 0);
+
+}
+EXPORT_SYMBOL_GPL(hyperv_cleanup);
+
+/*
+ * hv_do_hypercall- Invoke the specified hypercall
+ */
+u64 hv_do_hypercall(u64 control, void *input, void *output)
+{
+ u64 input_address;
+ u64 output_address;
+
+ input_address = input ? virt_to_phys(input) : 0;
+ output_address = output ? virt_to_phys(output) : 0;
+ return hv_do_hvc(control, input_address, output_address);
+}
+EXPORT_SYMBOL_GPL(hv_do_hypercall);
+
+/*
+ * hv_do_fast_hypercall8 -- Invoke the specified hypercall
+ * with arguments in registers instead of physical memory.
+ * Avoids the overhead of virt_to_phys for simple hypercalls.
+ */
+
+u64 hv_do_fast_hypercall8(u16 code, u64 input)
+{
+ u64 control;
+
+ control = (u64)code | HV_HYPERCALL_FAST_BIT;
+ return hv_do_hvc(control, input);
+}
+EXPORT_SYMBOL_GPL(hv_do_fast_hypercall8);
+
+
+/*
+ * Set a single VP register to a 64-bit value.
+ */
+void hv_set_vpreg(u32 msr, u64 value)
+{
+ union hv_hypercall_status status;
+
+ status.as_uint64 = hv_do_hvc(
+ HVCALL_SET_VP_REGISTERS | HV_HYPERCALL_FAST_BIT |
+ HV_HYPERCALL_REP_COUNT_1,
+ HV_PARTITION_ID_SELF,
+ HV_VP_INDEX_SELF,
+ msr,
+ 0,
+ value,
+ 0);
+
+ /*
+ * Something is fundamentally broken in the hypervisor if
+ * setting a VP register fails. There's really no way to
+ * continue as a guest VM, so panic.
+ */
+ BUG_ON(status.status != HV_STATUS_SUCCESS);
+}
+EXPORT_SYMBOL_GPL(hv_set_vpreg);
+
+
+/*
+ * Get the value of a single VP register, and only the low order 64 bits.
+ */
+u64 hv_get_vpreg(u32 msr)
+{
+ union hv_hypercall_status status;
+ struct hv_get_vp_register_output output;
+
+ status.as_uint64 = hv_do_hvc_fast_get(
+ HVCALL_GET_VP_REGISTERS | HV_HYPERCALL_FAST_BIT |
+ HV_HYPERCALL_REP_COUNT_1,
+ HV_PARTITION_ID_SELF,
+ HV_VP_INDEX_SELF,
+ msr,
+ &output);
+
+ /*
+ * Something is fundamentally broken in the hypervisor if
+ * getting a VP register fails. There's really no way to
+ * continue as a guest VM, so panic.
+ */
+ BUG_ON(status.status != HV_STATUS_SUCCESS);
+
+ return output.registervaluelow;
+}
+EXPORT_SYMBOL_GPL(hv_get_vpreg);
+
+/*
+ * Get the value of a single VP register that is 128 bits in size. This is a
+ * separate call in order to avoid complicating the calling sequence for
+ * the much more frequently used 64-bit version.
+ */
+void hv_get_vpreg_128(u32 msr, struct hv_get_vp_register_output *result)
+{
+ union hv_hypercall_status status;
+
+ status.as_uint64 = hv_do_hvc_fast_get(
+ HVCALL_GET_VP_REGISTERS | HV_HYPERCALL_FAST_BIT |
+ HV_HYPERCALL_REP_COUNT_1,
+ HV_PARTITION_ID_SELF,
+ HV_VP_INDEX_SELF,
+ msr,
+ result);
+
+ /*
+ * Something is fundamentally broken in the hypervisor if
+ * getting a VP register fails. There's really no way to
+ * continue as a guest VM, so panic.
+ */
+ BUG_ON(status.status != HV_STATUS_SUCCESS);
+
+ return;
+
+}
+EXPORT_SYMBOL_GPL(hv_get_vpreg_128);
+
+void hyperv_report_panic(struct pt_regs *regs, long err)
+{
+ static bool panic_reported;
+ u64 guest_id;
+
+ /*
+ * We prefer to report panic on 'die' chain as we have proper
+ * registers to report, but if we miss it (e.g. on BUG()) we need
+ * to report it on 'panic'.
+ */
+ if (panic_reported)
+ return;
+ panic_reported = true;
+
+ guest_id = hv_get_vpreg(HV_REGISTER_GUEST_OSID);
+
+ /*
+ * Hyper-V provides the ability to store only 5 values.
+ * Pick the passed in error value, the guest_id, and the PC.
+ * The first two general registers are added arbitrarily.
+ */
+ hv_set_vpreg(HV_REGISTER_CRASH_P0, err);
+ hv_set_vpreg(HV_REGISTER_CRASH_P1, guest_id);
+ hv_set_vpreg(HV_REGISTER_CRASH_P2, regs->pc);
+ hv_set_vpreg(HV_REGISTER_CRASH_P3, regs->regs[0]);
+ hv_set_vpreg(HV_REGISTER_CRASH_P4, regs->regs[1]);
+
+ /*
+ * Let Hyper-V know there is crash data available
+ */
+ hv_set_vpreg(HV_REGISTER_CRASH_CTL, HV_CRASH_CTL_CRASH_NOTIFY);
+}
+EXPORT_SYMBOL_GPL(hyperv_report_panic);
+
+/*
+ * hyperv_report_panic_msg - report panic message to Hyper-V
+ * @pa: physical address of the panic page containing the message
+ * @size: size of the message in the page
+ */
+void hyperv_report_panic_msg(phys_addr_t pa, size_t size)
+{
+ /*
+ * P3 to contain the physical address of the panic page & P4 to
+ * contain the size of the panic data in that page. Rest of the
+ * registers are no-op when the NOTIFY_MSG flag is set.
+ */
+ hv_set_vpreg(HV_REGISTER_CRASH_P0, 0);
+ hv_set_vpreg(HV_REGISTER_CRASH_P1, 0);
+ hv_set_vpreg(HV_REGISTER_CRASH_P2, 0);
+ hv_set_vpreg(HV_REGISTER_CRASH_P3, pa);
+ hv_set_vpreg(HV_REGISTER_CRASH_P4, size);
+
+ /*
+ * Let Hyper-V know there is crash data available along with
+ * the panic message.
+ */
+ hv_set_vpreg(HV_REGISTER_CRASH_CTL,
+ (HV_CRASH_CTL_CRASH_NOTIFY | HV_CRASH_CTL_CRASH_NOTIFY_MSG));
+}
+EXPORT_SYMBOL_GPL(hyperv_report_panic_msg);
+
+bool hv_is_hyperv_initialized(void)
+{
+ return hyperv_initialized;
+}
+EXPORT_SYMBOL_GPL(hv_is_hyperv_initialized);
diff -N -r -u linux-4.19.72/arch/arm64/hyperv/Makefile WSL2-Linux-Kernel-4.19.72-microsoft-standard/arch/arm64/hyperv/Makefile
--- linux-4.19.72/arch/arm64/hyperv/Makefile 1969-12-31 16:00:00.000000000 -0800
+++ WSL2-Linux-Kernel-4.19.72-microsoft-standard/arch/arm64/hyperv/Makefile 2019-09-15 02:24:17.000000000 -0700
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-y := hv_init.o hv_hvc.o mshyperv.o
diff -N -r -u linux-4.19.72/arch/arm64/hyperv/mshyperv.c WSL2-Linux-Kernel-4.19.72-microsoft-standard/arch/arm64/hyperv/mshyperv.c
--- linux-4.19.72/arch/arm64/hyperv/mshyperv.c 1969-12-31 16:00:00.000000000 -0800
+++ WSL2-Linux-Kernel-4.19.72-microsoft-standard/arch/arm64/hyperv/mshyperv.c 2019-09-15 02:24:17.000000000 -0700
@@ -0,0 +1,178 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * Core routines for interacting with Microsoft's Hyper-V hypervisor,
+ * including setting up VMbus and STIMER interrupts, and handling
+ * crashes and kexecs. These interactions are through a set of
+ * static "handler" variables set by the architecture independent
+ * VMbus and STIMER drivers. This design is used to meet x86/x64
+ * requirements for avoiding direct linkages and allowing the VMbus
+ * and STIMER drivers to be unloaded and reloaded.
+ *
+ * Copyright (C) 2018, Microsoft, Inc.
+ *
+ * Author : Michael Kelley <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include <linux/types.h>
+#include <linux/export.h>
+#include <linux/interrupt.h>
+#include <linux/kexec.h>
+#include <linux/acpi.h>
+#include <linux/ptrace.h>
+#include <asm/hyperv-tlfs.h>
+#include <asm/mshyperv.h>
+
+static void (*vmbus_handler)(void);
+static void (*hv_stimer0_handler)(void);
+static void (*hv_kexec_handler)(void);
+static void (*hv_crash_handler)(struct pt_regs *regs);
+
+static int vmbus_irq;
+static long __percpu *vmbus_evt;
+static long __percpu *stimer0_evt;
+
+irqreturn_t hyperv_vector_handler(int irq, void *dev_id)
+{
+ if (vmbus_handler)
+ vmbus_handler();
+ return IRQ_HANDLED;
+}
+
+/* Must be done just once */
+void hv_setup_vmbus_irq(void (*handler)(void))
+{
+ int result;
+
+ vmbus_handler = handler;
+ vmbus_irq = acpi_register_gsi(NULL, HYPERVISOR_CALLBACK_VECTOR,
+ ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_HIGH);
+ if (vmbus_irq <= 0) {
+ pr_err("Can't register Hyper-V VMBus GSI. Error %d",
+ vmbus_irq);
+ vmbus_irq = 0;
+ return;
+ }
+ vmbus_evt = alloc_percpu(long);
+ result = request_percpu_irq(vmbus_irq, hyperv_vector_handler,
+ "Hyper-V VMbus", vmbus_evt);
+ if (result) {
+ pr_err("Can't request Hyper-V VMBus IRQ %d. Error %d",
+ vmbus_irq, result);
+ free_percpu(vmbus_evt);
+ acpi_unregister_gsi(vmbus_irq);
+ vmbus_irq = 0;
+ }
+}
+EXPORT_SYMBOL_GPL(hv_setup_vmbus_irq);
+
+/* Must be done just once */
+void hv_remove_vmbus_irq(void)
+{
+ if (vmbus_irq) {
+ free_percpu_irq(vmbus_irq, vmbus_evt);
+ free_percpu(vmbus_evt);
+ acpi_unregister_gsi(vmbus_irq);
+ }
+}
+EXPORT_SYMBOL_GPL(hv_remove_vmbus_irq);
+
+/* Must be done by each CPU */
+void hv_enable_vmbus_irq(void)
+{
+ enable_percpu_irq(vmbus_irq, 0);
+}
+EXPORT_SYMBOL_GPL(hv_enable_vmbus_irq);
+
+/* Must be done by each CPU */
+void hv_disable_vmbus_irq(void)
+{
+ disable_percpu_irq(vmbus_irq);
+}
+EXPORT_SYMBOL_GPL(hv_disable_vmbus_irq);
+
+/* Routines to do per-architecture handling of STIMER0 when in Direct Mode */
+
+static irqreturn_t hv_stimer0_vector_handler(int irq, void *dev_id)
+{
+ if (hv_stimer0_handler)
+ hv_stimer0_handler();
+ return IRQ_HANDLED;
+}
+
+int hv_setup_stimer0_irq(int *irq, int *vector, void (*handler)(void))
+{
+ int localirq;
+ int result;
+
+ localirq = acpi_register_gsi(NULL, HV_STIMER0_IRQNR,
+ ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_HIGH);
+ if (localirq <= 0) {
+ pr_err("Can't register Hyper-V stimer0 GSI. Error %d",
+ localirq);
+ *irq = 0;
+ return -1;
+ }
+ stimer0_evt = alloc_percpu(long);
+ result = request_percpu_irq(localirq, hv_stimer0_vector_handler,
+ "Hyper-V stimer0", stimer0_evt);
+ if (result) {
+ pr_err("Can't request Hyper-V stimer0 IRQ %d. Error %d",
+ localirq, result);
+ free_percpu(stimer0_evt);
+ acpi_unregister_gsi(localirq);
+ *irq = 0;
+ return -1;
+ }
+
+ hv_stimer0_handler = handler;
+ *vector = HV_STIMER0_IRQNR;
+ *irq = localirq;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(hv_setup_stimer0_irq);
+
+void hv_remove_stimer0_irq(int irq)
+{
+ hv_stimer0_handler = NULL;
+ if (irq) {
+ free_percpu_irq(irq, stimer0_evt);
+ free_percpu(stimer0_evt);
+ acpi_unregister_gsi(irq);
+ }
+}
+EXPORT_SYMBOL_GPL(hv_remove_stimer0_irq);
+
+void hv_setup_kexec_handler(void (*handler)(void))
+{
+ hv_kexec_handler = handler;
+}
+EXPORT_SYMBOL_GPL(hv_setup_kexec_handler);
+
+void hv_remove_kexec_handler(void)
+{
+ hv_kexec_handler = NULL;
+}
+EXPORT_SYMBOL_GPL(hv_remove_kexec_handler);
+
+void hv_setup_crash_handler(void (*handler)(struct pt_regs *regs))
+{
+ hv_crash_handler = handler;
+}
+EXPORT_SYMBOL_GPL(hv_setup_crash_handler);
+
+void hv_remove_crash_handler(void)
+{
+ hv_crash_handler = NULL;
+}
+EXPORT_SYMBOL_GPL(hv_remove_crash_handler);
diff -N -r -u linux-4.19.72/arch/arm64/include/asm/hyperv-tlfs.h WSL2-Linux-Kernel-4.19.72-microsoft-standard/arch/arm64/include/asm/hyperv-tlfs.h
--- linux-4.19.72/arch/arm64/include/asm/hyperv-tlfs.h 1969-12-31 16:00:00.000000000 -0800
+++ WSL2-Linux-Kernel-4.19.72-microsoft-standard/arch/arm64/include/asm/hyperv-tlfs.h 2019-09-15 02:24:17.000000000 -0700
@@ -0,0 +1,338 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/*
+ * This file contains definitions from the Hyper-V Hypervisor Top-Level
+ * Functional Specification (TLFS):
+ * https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fvirtualization%2Fhyper-v-on-windows%2Freference%2Ftlfs&amp;data=02%7C01%7Ckys%40microsoft.com%7Cc831a45fd63e4a4b083908d641216aa8%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C636768009113747528&amp;sdata=jRSrs9ZWXdmeS7LQUEpoSyUfBS7a5KLYy%2FolFdE2tI0%3D&amp;reserved=0
+ *
+ * Copyright (C) 2018, Microsoft, Inc.
+ *
+ * Author : Michael Kelley <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef _ASM_ARM64_HYPERV_H
+#define _ASM_ARM64_HYPERV_H
+
+#include <linux/types.h>
+
+/*
+ * These Hyper-V registers provide information equivalent to the CPUID
+ * instruction on x86/x64.
+ */
+#define HV_REGISTER_HYPERVISOR_VERSION 0x00000100 /*CPUID 0x40000002 */
+#define HV_REGISTER_PRIVILEGES_AND_FEATURES 0x00000200 /*CPUID 0x40000003 */
+#define HV_REGISTER_FEATURES 0x00000201 /*CPUID 0x40000004 */
+#define HV_REGISTER_IMPLEMENTATION_LIMITS 0x00000202 /*CPUID 0x40000005 */
+#define HV_ARM64_REGISTER_INTERFACE_VERSION 0x00090006 /*CPUID 0x40000001 */
+
+/*
+ * Feature identification. HvRegisterPrivilegesAndFeaturesInfo returns a
+ * 128-bit value with flags indicating which features are available to the
+ * partition based upon the current partition privileges. The 128-bit
+ * value is broken up with different portions stored in different 32-bit
+ * fields in the ms_hyperv structure.
+ */
+
+/* Partition Reference Counter available*/
+#define HV_MSR_TIME_REF_COUNT_AVAILABLE (1 << 1)
+
+/*
+ * Synthetic Timers available
+ */
+#define HV_MSR_SYNTIMER_AVAILABLE (1 << 3)
+
+/* Frequency MSRs available */
+#define HV_FEATURE_FREQUENCY_MSRS_AVAILABLE (1 << 8)
+
+/* Reference TSC available */
+#define HV_MSR_REFERENCE_TSC_AVAILABLE (1 << 9)
+
+/* Crash MSR available */
+#define HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE (1 << 10)
+
+
+/*
+ * This group of flags is in the high order 64-bits of the returned
+ * 128-bit value.
+ */
+
+/* STIMER direct mode is available */
+#define HV_STIMER_DIRECT_MODE_AVAILABLE (1 << 19)
+
+/*
+ * Implementation recommendations in register
+ * HvRegisterFeaturesInfo. Indicates which behaviors the hypervisor
+ * recommends the OS implement for optimal performance.
+ */
+
+/*
+ * Recommend not using Auto EOI
+ */
+#define HV_DEPRECATING_AEOI_RECOMMENDED (1 << 9)
+
+/*
+ * Synthetic register definitions equivalent to MSRs on x86/x64
+ */
+#define HV_REGISTER_CRASH_P0 0x00000210
+#define HV_REGISTER_CRASH_P1 0x00000211
+#define HV_REGISTER_CRASH_P2 0x00000212
+#define HV_REGISTER_CRASH_P3 0x00000213
+#define HV_REGISTER_CRASH_P4 0x00000214
+#define HV_REGISTER_CRASH_CTL 0x00000215
+
+#define HV_REGISTER_GUEST_OSID 0x00090002
+#define HV_REGISTER_VPINDEX 0x00090003
+#define HV_REGISTER_TIME_REFCOUNT 0x00090004
+#define HV_REGISTER_REFERENCE_TSC 0x00090017
+
+#define HV_REGISTER_SINT0 0x000A0000
+#define HV_REGISTER_SINT1 0x000A0001
+#define HV_REGISTER_SINT2 0x000A0002
+#define HV_REGISTER_SINT3 0x000A0003
+#define HV_REGISTER_SINT4 0x000A0004
+#define HV_REGISTER_SINT5 0x000A0005
+#define HV_REGISTER_SINT6 0x000A0006
+#define HV_REGISTER_SINT7 0x000A0007
+#define HV_REGISTER_SINT8 0x000A0008
+#define HV_REGISTER_SINT9 0x000A0009
+#define HV_REGISTER_SINT10 0x000A000A
+#define HV_REGISTER_SINT11 0x000A000B
+#define HV_REGISTER_SINT12 0x000A000C
+#define HV_REGISTER_SINT13 0x000A000D
+#define HV_REGISTER_SINT14 0x000A000E
+#define HV_REGISTER_SINT15 0x000A000F
+#define HV_REGISTER_SCONTROL 0x000A0010
+#define HV_REGISTER_SVERSION 0x000A0011
+#define HV_REGISTER_SIFP 0x000A0012
+#define HV_REGISTER_SIPP 0x000A0013
+#define HV_REGISTER_EOM 0x000A0014
+#define HV_REGISTER_SIRBP 0x000A0015
+
+#define HV_REGISTER_STIMER0_CONFIG 0x000B0000
+#define HV_REGISTER_STIMER0_COUNT 0x000B0001
+#define HV_REGISTER_STIMER1_CONFIG 0x000B0002
+#define HV_REGISTER_STIMER1_COUNT 0x000B0003
+#define HV_REGISTER_STIMER2_CONFIG 0x000B0004
+#define HV_REGISTER_STIMER2_COUNT 0x000B0005
+#define HV_REGISTER_STIMER3_CONFIG 0x000B0006
+#define HV_REGISTER_STIMER3_COUNT 0x000B0007
+
+/*
+ * Crash notification flags.
+ */
+#define HV_CRASH_CTL_CRASH_NOTIFY_MSG BIT_ULL(62)
+#define HV_CRASH_CTL_CRASH_NOTIFY BIT_ULL(63)
+
+/*
+ * The guest OS needs to register the guest ID with the hypervisor.
+ * The guest ID is a 64 bit entity and the structure of this ID is
+ * specified in the Hyper-V specification:
+ *
+ * msdn.microsoft.com/en-us/library/windows/hardware/ff542653%28v=vs.85%29.aspx
+ *
+ * While the current guideline does not specify how Linux guest ID(s)
+ * need to be generated, our plan is to publish the guidelines for
+ * Linux and other guest operating systems that currently are hosted
+ * on Hyper-V. The implementation here conforms to this yet
+ * unpublished guidelines.
+ *
+ *
+ * Bit(s)
+ * 63 - Indicates if the OS is Open Source or not; 1 is Open Source
+ * 62:56 - Os Type; Linux is 0x100
+ * 55:48 - Distro specific identification
+ * 47:16 - Linux kernel version number
+ * 15:0 - Distro specific identification
+ *
+ *
+ */
+#define HV_LINUX_VENDOR_ID 0x8100
+
+/* Declare the various hypercall operations. */
+#define HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE 0x0002
+#define HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST 0x0003
+#define HVCALL_NOTIFY_LONG_SPIN_WAIT 0x0008
+#define HVCALL_SEND_IPI 0x000b
+#define HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE_EX 0x0013
+#define HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST_EX 0x0014
+#define HVCALL_SEND_IPI_EX 0x0015
+#define HVCALL_GET_VP_REGISTERS 0x0050
+#define HVCALL_SET_VP_REGISTERS 0x0051
+#define HVCALL_POST_MESSAGE 0x005c
+#define HVCALL_SIGNAL_EVENT 0x005d
+#define HVCALL_RETARGET_INTERRUPT 0x007e
+#define HVCALL_START_VIRTUAL_PROCESSOR 0x0099
+#define HVCALL_GET_VP_INDEX_FROM_APICID 0x009a
+
+/* Declare standard hypercall field values. */
+#define HV_PARTITION_ID_SELF ((u64)-1)
+#define HV_VP_INDEX_SELF ((u32)-2)
+
+#define HV_HYPERCALL_FAST_BIT BIT(16)
+#define HV_HYPERCALL_REP_COUNT_1 BIT_ULL(32)
+#define HV_HYPERCALL_RESULT_MASK GENMASK_ULL(15, 0)
+
+/* Define the hypercall status result */
+
+union hv_hypercall_status {
+ u64 as_uint64;
+ struct {
+ u16 status;
+ u16 reserved;
+ u16 reps_completed; /* Low 12 bits */
+ u16 reserved2;
+ };
+};
+
+/* hypercall status code */
+#define HV_STATUS_SUCCESS 0
+#define HV_STATUS_INVALID_HYPERCALL_CODE 2
+#define HV_STATUS_INVALID_HYPERCALL_INPUT 3
+#define HV_STATUS_INVALID_ALIGNMENT 4
+#define HV_STATUS_INSUFFICIENT_MEMORY 11
+#define HV_STATUS_INVALID_CONNECTION_ID 18
+#define HV_STATUS_INSUFFICIENT_BUFFERS 19
+
+/* Define output layout for Get VP Register hypercall */
+struct hv_get_vp_register_output {
+ u64 registervaluelow;
+ u64 registervaluehigh;
+};
+
+#define HV_FLUSH_ALL_PROCESSORS BIT(0)
+#define HV_FLUSH_ALL_VIRTUAL_ADDRESS_SPACES BIT(1)
+#define HV_FLUSH_NON_GLOBAL_MAPPINGS_ONLY BIT(2)
+#define HV_FLUSH_USE_EXTENDED_RANGE_FORMAT BIT(3)
+
+enum HV_GENERIC_SET_FORMAT {
+ HV_GENERIC_SET_SPARSE_4K,
+ HV_GENERIC_SET_ALL,
+};
+
+/*
+ * The Hyper-V TimeRefCount register and the TSC
+ * page provide a guest VM clock with 100ns tick rate
+ */
+#define HV_CLOCK_HZ (NSEC_PER_SEC/100)
+
+/*
+ * The fields in this structure are set by Hyper-V and read
+ * by the Linux guest. They should be accessed with READ_ONCE()
+ * so the compiler doesn't optimize in a way that will cause
+ * problems.
+ */
+struct ms_hyperv_tsc_page {
+ u32 tsc_sequence;
+ u32 reserved1;
+ u64 tsc_scale;
+ s64 tsc_offset;
+ u64 reserved2[509];
+};
+
+/* Define the number of synthetic interrupt sources. */
+#define HV_SYNIC_SINT_COUNT (16)
+/* Define the expected SynIC version. */
+#define HV_SYNIC_VERSION_1 (0x1)
+
+#define HV_SYNIC_CONTROL_ENABLE (1ULL << 0)
+#define HV_SYNIC_SIMP_ENABLE (1ULL << 0)
+#define HV_SYNIC_SIEFP_ENABLE (1ULL << 0)
+#define HV_SYNIC_SINT_MASKED (1ULL << 16)
+#define HV_SYNIC_SINT_AUTO_EOI (1ULL << 17)
+#define HV_SYNIC_SINT_VECTOR_MASK (0xFF)
+
+#define HV_SYNIC_STIMER_COUNT (4)
+
+/* Define synthetic interrupt controller message constants. */
+#define HV_MESSAGE_SIZE (256)
+#define HV_MESSAGE_PAYLOAD_BYTE_COUNT (240)
+#define HV_MESSAGE_PAYLOAD_QWORD_COUNT (30)
+
+/* Define hypervisor message types. */
+enum hv_message_type {
+ HVMSG_NONE = 0x00000000,
+
+ /* Memory access messages. */
+ HVMSG_UNMAPPED_GPA = 0x80000000,
+ HVMSG_GPA_INTERCEPT = 0x80000001,
+
+ /* Timer notification messages. */
+ HVMSG_TIMER_EXPIRED = 0x80000010,
+
+ /* Error messages. */
+ HVMSG_INVALID_VP_REGISTER_VALUE = 0x80000020,
+ HVMSG_UNRECOVERABLE_EXCEPTION = 0x80000021,
+ HVMSG_UNSUPPORTED_FEATURE = 0x80000022,
+
+ /* Trace buffer complete messages. */
+ HVMSG_EVENTLOG_BUFFERCOMPLETE = 0x80000040,
+};
+
+/* Define synthetic interrupt controller message flags. */
+union hv_message_flags {
+ __u8 asu8;
+ struct {
+ __u8 msg_pending:1;
+ __u8 reserved:7;
+ };
+};
+
+/* Define port identifier type. */
+union hv_port_id {
+ __u32 asu32;
+ struct {
+ __u32 id:24;
+ __u32 reserved:8;
+ } u;
+};
+
+/* Define synthetic interrupt controller message header. */
+struct hv_message_header {
+ __u32 message_type;
+ __u8 payload_size;
+ union hv_message_flags message_flags;
+ __u8 reserved[2];
+ union {
+ __u64 sender;
+ union hv_port_id port;
+ };
+};
+
+/* Define synthetic interrupt controller message format. */
+struct hv_message {
+ struct hv_message_header header;
+ union {
+ __u64 payload[HV_MESSAGE_PAYLOAD_QWORD_COUNT];
+ } u;
+};
+
+/* Define the synthetic interrupt message page layout. */
+struct hv_message_page {
+ struct hv_message sint_message[HV_SYNIC_SINT_COUNT];
+};
+
+/* Define timer message payload structure. */
+struct hv_timer_message_payload {
+ __u32 timer_index;
+ __u32 reserved;
+ __u64 expiration_time; /* When the timer expired */
+ __u64 delivery_time; /* When the message was delivered */
+};
+
+#define HV_STIMER_ENABLE (1ULL << 0)
+#define HV_STIMER_PERIODIC (1ULL << 1)
+#define HV_STIMER_LAZY (1ULL << 2)
+#define HV_STIMER_AUTOENABLE (1ULL << 3)
+#define HV_STIMER_SINT(config) (__u8)(((config) >> 16) & 0x0F)
+
+#endif
diff -N -r -u linux-4.19.72/arch/arm64/include/asm/mshyperv.h WSL2-Linux-Kernel-4.19.72-microsoft-standard/arch/arm64/include/asm/mshyperv.h
--- linux-4.19.72/arch/arm64/include/asm/mshyperv.h 1969-12-31 16:00:00.000000000 -0800
+++ WSL2-Linux-Kernel-4.19.72-microsoft-standard/arch/arm64/include/asm/mshyperv.h 2019-09-15 02:24:17.000000000 -0700
@@ -0,0 +1,116 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/*
+ * Linux-specific definitions for managing interactions with Microsoft's
+ * Hyper-V hypervisor. The definitions in this file are specific to
+ * the ARM64 architecture. See include/asm-generic/mshyperv.h for
+ * definitions are that architecture independent.
+ *
+ * Definitions that are specified in the Hyper-V Top Level Functional
+ * Spec (TLFS) should not go in this file, but should instead go in
+ * hyperv-tlfs.h.
+ *
+ * Copyright (C) 2018, Microsoft, Inc.
+ *
+ * Author : Michael Kelley <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef _ASM_ARM64_MSHYPERV_H
+#define _ASM_ARM64_MSHYPERV_H
+
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/clocksource.h>
+#include <linux/irq.h>
+#include <linux/irqdesc.h>
+#include <asm/hyperv-tlfs.h>
+
+/*
+ * Define the IRQ numbers/vectors used by Hyper-V VMbus interrupts
+ * and by STIMER0 Direct Mode interrupts. Hyper-V should be supplying
+ * these values through ACPI, but there are no other interrupting
+ * devices in a Hyper-V VM on ARM64, so it's OK to hard code for now.
+ * The "CALLBACK_VECTOR" terminology is a left-over from the x86/x64
+ * world that is used in architecture independent Hyper-V code.
+ */
+#define HYPERVISOR_CALLBACK_VECTOR 16
+#define HV_STIMER0_IRQNR 17
+
+extern u64 hv_do_hvc(u64 control, ...);
+extern u64 hv_do_hvc_fast_get(u64 control, u64 input1, u64 input2, u64 input3,
+ struct hv_get_vp_register_output *output);
+
+/*
+ * Declare calls to get and set Hyper-V VP register values on ARM64, which
+ * requires a hypercall.
+ */
+extern void hv_set_vpreg(u32 reg, u64 value);
+extern u64 hv_get_vpreg(u32 reg);
+extern void hv_get_vpreg_128(u32 reg, struct hv_get_vp_register_output *result);
+
+/*
+ * Use the Hyper-V provided stimer0 as the timer that is made
+ * available to the architecture independent Hyper-V drivers.
+ */
+#define hv_init_timer(timer, tick) \
+ hv_set_vpreg(HV_REGISTER_STIMER0_COUNT + (2*timer), tick)
+#define hv_init_timer_config(timer, val) \
+ hv_set_vpreg(HV_REGISTER_STIMER0_CONFIG + (2*timer), val)
+#define hv_get_current_tick(tick) \
+ (tick = hv_get_vpreg(HV_REGISTER_TIME_REFCOUNT))
+
+#define hv_get_simp(val) (val = hv_get_vpreg(HV_REGISTER_SIPP))
+#define hv_set_simp(val) hv_set_vpreg(HV_REGISTER_SIPP, val)
+
+#define hv_get_siefp(val) (val = hv_get_vpreg(HV_REGISTER_SIFP))
+#define hv_set_siefp(val) hv_set_vpreg(HV_REGISTER_SIFP, val)
+
+#define hv_get_synic_state(val) (val = hv_get_vpreg(HV_REGISTER_SCONTROL))
+#define hv_set_synic_state(val) hv_set_vpreg(HV_REGISTER_SCONTROL, val)
+
+#define hv_get_vp_index(index) (index = hv_get_vpreg(HV_REGISTER_VPINDEX))
+
+#define hv_signal_eom() hv_set_vpreg(HV_REGISTER_EOM, 0)
+
+/*
+ * Hyper-V SINT registers are numbered sequentially, so we can just
+ * add the SINT number to the register number of SINT0
+ */
+#define hv_get_synint_state(sint_num, val) \
+ (val = hv_get_vpreg(HV_REGISTER_SINT0 + sint_num))
+#define hv_set_synint_state(sint_num, val) \
+ hv_set_vpreg(HV_REGISTER_SINT0 + sint_num, val)
+
+#define hv_get_crash_ctl(val) \
+ (val = hv_get_vpreg(HV_REGISTER_CRASH_CTL))
+
+#if IS_ENABLED(CONFIG_HYPERV)
+#define hv_enable_stimer0_percpu_irq(irq) enable_percpu_irq(irq, 0)
+#define hv_disable_stimer0_percpu_irq(irq) disable_percpu_irq(irq)
+#endif
+
+/* ARM64 specific code to read the hardware clock */
+static inline u64 hv_read_hwclock(void)
+{
+ u64 result;
+
+ isb();
+ result = read_sysreg(cntvct_el0);
+ isb();
+
+ return result;
+}
+
+#include <asm-generic/mshyperv.h>
+
+#endif
diff -N -r -u linux-4.19.72/arch/arm64/Kconfig WSL2-Linux-Kernel-4.19.72-microsoft-standard/arch/arm64/Kconfig
--- linux-4.19.72/arch/arm64/Kconfig 2019-09-10 02:33:54.000000000 -0700
+++ WSL2-Linux-Kernel-4.19.72-microsoft-standard/arch/arm64/Kconfig 2019-09-15 02:24:17.000000000 -0700
@@ -5,7 +5,7 @@
select ACPI_GTDT if ACPI
select ACPI_IORT if ACPI
select ACPI_REDUCED_HARDWARE_ONLY if ACPI
- select ACPI_MCFG if ACPI
+ select ACPI_MCFG if (ACPI && PCI)
select ACPI_SPCR_TABLE if ACPI
select ACPI_PPTT if ACPI
select ARCH_CLOCKSOURCE_DATA
@@ -158,7 +158,7 @@
select OF
select OF_EARLY_FLATTREE
select OF_RESERVED_MEM
- select PCI_ECAM if ACPI
+ select PCI_ECAM if (ACPI && PCI)
select POWER_RESET
select POWER_SUPPLY
select REFCOUNT_FULL
diff -N -r -u linux-4.19.72/arch/arm64/Makefile WSL2-Linux-Kernel-4.19.72-microsoft-standard/arch/arm64/Makefile
--- linux-4.19.72/arch/arm64/Makefile 2019-09-10 02:33:54.000000000 -0700
+++ WSL2-Linux-Kernel-4.19.72-microsoft-standard/arch/arm64/Makefile 2019-09-15 02:24:17.000000000 -0700
@@ -107,6 +107,7 @@
core-$(CONFIG_NET) += arch/arm64/net/
core-$(CONFIG_KVM) += arch/arm64/kvm/
core-$(CONFIG_XEN) += arch/arm64/xen/
+core-$(CONFIG_HYPERV) += arch/arm64/hyperv/
core-$(CONFIG_CRYPTO) += arch/arm64/crypto/
libs-y := arch/arm64/lib/ $(libs-y)
core-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a
diff -N -r -u linux-4.19.72/arch/x86/include/asm/mshyperv.h WSL2-Linux-Kernel-4.19.72-microsoft-standard/arch/x86/include/asm/mshyperv.h
--- linux-4.19.72/arch/x86/include/asm/mshyperv.h 2019-09-10 02:33:54.000000000 -0700
+++ WSL2-Linux-Kernel-4.19.72-microsoft-standard/arch/x86/include/asm/mshyperv.h 2019-09-15 02:24:17.000000000 -0700
@@ -109,6 +109,10 @@
void hv_setup_vmbus_irq(void (*handler)(void));
void hv_remove_vmbus_irq(void);
+/* On x86/x64, there isn't a real IRQ to be enabled/disable */
+static inline void hv_enable_vmbus_irq(void) {}
+static inline void hv_disable_vmbus_irq(void) {}
+
void hv_setup_kexec_handler(void (*handler)(void));
void hv_remove_kexec_handler(void);
void hv_setup_crash_handler(void (*handler)(struct pt_regs *regs));
diff -N -r -u linux-4.19.72/arch/x86/include/asm/pci_x86.h WSL2-Linux-Kernel-4.19.72-microsoft-standard/arch/x86/include/asm/pci_x86.h
--- linux-4.19.72/arch/x86/include/asm/pci_x86.h 2019-09-10 02:33:54.000000000 -0700
+++ WSL2-Linux-Kernel-4.19.72-microsoft-standard/arch/x86/include/asm/pci_x86.h 2019-09-15 02:24:17.000000000 -0700
@@ -121,7 +121,12 @@
extern void __init dmi_check_skip_isa_align(void);
/* some common used subsys_initcalls */
+#ifdef CONFIG_PCI
extern int __init pci_acpi_init(void);
+#else
+static inline int __init pci_acpi_init(void)
+{ return -EINVAL; }
+#endif
extern void __init pcibios_irq_init(void);
extern int __init pcibios_init(void);
extern int pci_legacy_init(void);
diff -N -r -u linux-4.19.72/drivers/acpi/acpica/dsutils.c WSL2-Linux-Kernel-4.19.72-microsoft-standard/drivers/acpi/acpica/dsutils.c
--- linux-4.19.72/drivers/acpi/acpica/dsutils.c 2019-09-10 02:33:54.000000000 -0700
+++ WSL2-Linux-Kernel-4.19.72-microsoft-standard/drivers/acpi/acpica/dsutils.c 2019-09-15 02:24:17.000000000 -0700
@@ -670,6 +670,8 @@
union acpi_parse_object *arguments[ACPI_OBJ_NUM_OPERANDS];
u32 arg_count = 0;
u32 index = walk_state->num_operands;
+ u32 prev_num_operands = walk_state->num_operands;
+ u32 new_num_operands;
u32 i;
ACPI_FUNCTION_TRACE_PTR(ds_create_operands, first_arg);
@@ -698,6 +700,7 @@
/* Create the interpreter arguments, in reverse order */
+ new_num_operands = index;
index--;
for (i = 0; i < arg_count; i++) {
arg = arguments[index];
@@ -722,7 +725,11 @@
* pop everything off of the operand stack and delete those
* objects
*/
- acpi_ds_obj_stack_pop_and_delete(arg_count, walk_state);
+ walk_state->num_operands = i;
+ acpi_ds_obj_stack_pop_and_delete(new_num_operands, walk_state);
+
+ /* Restore operand count */
+ walk_state->num_operands = prev_num_operands;
ACPI_EXCEPTION((AE_INFO, status, "While creating Arg %u", index));
return_ACPI_STATUS(status);
diff -N -r -u linux-4.19.72/drivers/acpi/arm64/iort.c WSL2-Linux-Kernel-4.19.72-microsoft-standard/drivers/acpi/arm64/iort.c
--- linux-4.19.72/drivers/acpi/arm64/iort.c 2019-09-10 02:33:54.000000000 -0700
+++ WSL2-Linux-Kernel-4.19.72-microsoft-standard/drivers/acpi/arm64/iort.c 2019-09-15 02:24:17.000000000 -0700
@@ -1445,8 +1445,14 @@
return ret;
}
-static bool __init iort_enable_acs(struct acpi_iort_node *iort_node)
+#ifdef CONFIG_PCI
+static void __init iort_enable_acs(struct acpi_iort_node *iort_node)
{
+ static bool acs_enabled __initdata;
+
+ if (acs_enabled)
+ return;
+
if (iort_node->type == ACPI_IORT_NODE_PCI_ROOT_COMPLEX) {
struct acpi_iort_node *parent;
struct acpi_iort_id_mapping *map;
@@ -1468,13 +1474,15 @@
if ((parent->type == ACPI_IORT_NODE_SMMU) ||
(parent->type == ACPI_IORT_NODE_SMMU_V3)) {
pci_request_acs();
- return true;
+ acs_enabled = true;
+ return;
}
}
}
-
- return false;
}
+#else
+static inline void iort_enable_acs(struct acpi_iort_node *iort_node) { }
+#endif
static void __init iort_init_platform_devices(void)
{
@@ -1482,7 +1490,6 @@
struct acpi_table_iort *iort;
struct fwnode_handle *fwnode;
int i, ret;
- bool acs_enabled = false;
const struct iort_dev_config *ops;
/*
@@ -1503,8 +1510,7 @@
return;
}
- if (!acs_enabled)
- acs_enabled = iort_enable_acs(iort_node);
+ iort_enable_acs(iort_node);
ops = iort_get_dev_cfg(iort_node);
if (ops) {
diff -N -r -u linux-4.19.72/drivers/acpi/internal.h WSL2-Linux-Kernel-4.19.72-microsoft-standard/drivers/acpi/internal.h
--- linux-4.19.72/drivers/acpi/internal.h 2019-09-10 02:33:54.000000000 -0700
+++ WSL2-Linux-Kernel-4.19.72-microsoft-standard/drivers/acpi/internal.h 2019-09-15 02:24:17.000000000 -0700
@@ -25,8 +25,13 @@
acpi_status acpi_os_initialize1(void);
void init_acpi_device_notify(void);
int acpi_scan_init(void);
+#ifdef CONFIG_PCI
void acpi_pci_root_init(void);
void acpi_pci_link_init(void);
+#else
+static inline void acpi_pci_root_init(void) {}
+static inline void acpi_pci_link_init(void) {}
+#endif
void acpi_processor_init(void);
void acpi_platform_init(void);
void acpi_pnp_init(void);
diff -N -r -u linux-4.19.72/drivers/acpi/Kconfig WSL2-Linux-Kernel-4.19.72-microsoft-standard/drivers/acpi/Kconfig
--- linux-4.19.72/drivers/acpi/Kconfig 2019-09-10 02:33:54.000000000 -0700
+++ WSL2-Linux-Kernel-4.19.72-microsoft-standard/drivers/acpi/Kconfig 2019-09-15 02:24:17.000000000 -0700
@@ -9,7 +9,6 @@
menuconfig ACPI
bool "ACPI (Advanced Configuration and Power Interface) Support"
depends on ARCH_SUPPORTS_ACPI
- depends on PCI
select PNP
default y if X86
help
diff -N -r -u linux-4.19.72/drivers/acpi/Makefile WSL2-Linux-Kernel-4.19.72-microsoft-standard/drivers/acpi/Makefile
--- linux-4.19.72/drivers/acpi/Makefile 2019-09-10 02:33:54.000000000 -0700
+++ WSL2-Linux-Kernel-4.19.72-microsoft-standard/drivers/acpi/Makefile 2019-09-15 02:24:17.000000000 -0700
@@ -39,7 +39,7 @@
acpi-$(CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC) += processor_pdc.o
acpi-y += ec.o
acpi-$(CONFIG_ACPI_DOCK) += dock.o
-acpi-y += pci_root.o pci_link.o pci_irq.o
+acpi-$(CONFIG_PCI) += pci_root.o pci_link.o pci_irq.o
obj-$(CONFIG_ACPI_MCFG) += pci_mcfg.o
acpi-y += acpi_lpss.o acpi_apd.o
acpi-y += acpi_platform.o
diff -N -r -u linux-4.19.72/drivers/acpi/nfit/core.c WSL2-Linux-Kernel-4.19.72-microsoft-standard/drivers/acpi/nfit/core.c
--- linux-4.19.72/drivers/acpi/nfit/core.c 2019-09-10 02:33:54.000000000 -0700
+++ WSL2-Linux-Kernel-4.19.72-microsoft-standard/drivers/acpi/nfit/core.c 2019-09-15 02:24:17.000000000 -0700
@@ -3594,6 +3594,9 @@
.remove = acpi_nfit_remove,
.notify = acpi_nfit_notify,
},
+ .drv = {
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
+ },
};
static __init int nfit_init(void)
diff -N -r -u linux-4.19.72/drivers/hv/channel_mgmt.c WSL2-Linux-Kernel-4.19.72-microsoft-standard/drivers/hv/channel_mgmt.c
--- linux-4.19.72/drivers/hv/channel_mgmt.c 2019-09-10 02:33:54.000000000 -0700
+++ WSL2-Linux-Kernel-4.19.72-microsoft-standard/drivers/hv/channel_mgmt.c 2019-09-15 02:24:17.000000000 -0700
@@ -1022,9 +1022,24 @@
{
BUG_ON(!is_hvsock_channel(channel));
- /* We always get a rescind msg when a connection is closed. */
- while (!READ_ONCE(channel->probe_done) || !READ_ONCE(channel->rescind))
+ for (;;) {
+ if (!READ_ONCE(channel->probe_done)) {
+ msleep(1);
+ continue;
+ }
+
+ /* We always get a rescind msg when a connection is closed. */
+ if (READ_ONCE(channel->rescind))
+ break;
+
+ if (hv_get_bytes_to_read(&channel->outbound) == 0)
+ break;
+
msleep(1);
+ }
+
+ /* FIXME: in case vmbus_onoffer_rescin() runs too slow */
+ channel->rescind = true;
vmbus_device_unregister(channel->device_obj);
}
diff -N -r -u linux-4.19.72/drivers/hv/hv.c WSL2-Linux-Kernel-4.19.72-microsoft-standard/drivers/hv/hv.c
--- linux-4.19.72/drivers/hv/hv.c 2019-09-10 02:33:54.000000000 -0700
+++ WSL2-Linux-Kernel-4.19.72-microsoft-standard/drivers/hv/hv.c 2019-09-15 02:24:17.000000000 -0700
@@ -300,6 +300,7 @@
hv_set_siefp(siefp.as_uint64);
/* Setup the shared SINT. */
+ hv_enable_vmbus_irq();
hv_get_synint_state(VMBUS_MESSAGE_SINT, shared_sint.as_uint64);
shared_sint.vector = HYPERVISOR_CALLBACK_VECTOR;
@@ -428,6 +429,7 @@
hv_get_synic_state(sctrl.as_uint64);
sctrl.enable = 0;
hv_set_synic_state(sctrl.as_uint64);
+ hv_disable_vmbus_irq();
return 0;
}
diff -N -r -u linux-4.19.72/drivers/hv/Kconfig WSL2-Linux-Kernel-4.19.72-microsoft-standard/drivers/hv/Kconfig
--- linux-4.19.72/drivers/hv/Kconfig 2019-09-10 02:33:54.000000000 -0700
+++ WSL2-Linux-Kernel-4.19.72-microsoft-standard/drivers/hv/Kconfig 2019-09-15 02:24:17.000000000 -0700
@@ -4,14 +4,14 @@
config HYPERV
tristate "Microsoft Hyper-V client drivers"
- depends on X86 && ACPI && X86_LOCAL_APIC && HYPERVISOR_GUEST
+ depends on ACPI && ((X86 && X86_LOCAL_APIC && HYPERVISOR_GUEST) || ARM64)
select PARAVIRT
help
Select this option to run Linux as a Hyper-V client operating
system.
config HYPERV_TSCPAGE
- def_bool HYPERV && X86_64
+ def_bool HYPERV && (X86_64 || ARM64)
config HYPERV_UTILS
tristate "Microsoft Hyper-V Utilities driver"
diff -N -r -u linux-4.19.72/drivers/pci/Makefile WSL2-Linux-Kernel-4.19.72-microsoft-standard/drivers/pci/Makefile
--- linux-4.19.72/drivers/pci/Makefile 2019-09-10 02:33:54.000000000 -0700
+++ WSL2-Linux-Kernel-4.19.72-microsoft-standard/drivers/pci/Makefile 2019-09-15 02:24:17.000000000 -0700
@@ -11,6 +11,7 @@
obj-$(CONFIG_PROC_FS) += proc.o
obj-$(CONFIG_SYSFS) += slot.o
obj-$(CONFIG_OF) += of.o
+obj-$(CONFIG_ACPI) += pci-acpi.o
endif
obj-$(CONFIG_PCI_QUIRKS) += quirks.o
@@ -19,7 +20,6 @@
obj-$(CONFIG_PCI_MSI) += msi.o
obj-$(CONFIG_PCI_ATS) += ats.o
obj-$(CONFIG_PCI_IOV) += iov.o
-obj-$(CONFIG_ACPI) += pci-acpi.o
obj-$(CONFIG_PCI_LABEL) += pci-label.o
obj-$(CONFIG_X86_INTEL_MID) += pci-mid.o
obj-$(CONFIG_PCI_SYSCALL) += syscall.o
diff -N -r -u linux-4.19.72/drivers/tty/sysrq.c WSL2-Linux-Kernel-4.19.72-microsoft-standard/drivers/tty/sysrq.c
--- linux-4.19.72/drivers/tty/sysrq.c 2019-09-10 02:33:54.000000000 -0700
+++ WSL2-Linux-Kernel-4.19.72-microsoft-standard/drivers/tty/sysrq.c 2019-09-15 02:24:17.000000000 -0700
@@ -1072,8 +1072,10 @@
* A concurrent __handle_sysrq either got the old op or the new op.
* Wait for it to go away before returning, so the code for an old
* op is not freed (eg. on module unload) while it is in use.
+ * This is only relevant if the old op is not NULL of course.
*/
- synchronize_rcu();
+ if (remove_op_p)
+ synchronize_rcu();
return retval;
}
diff -N -r -u linux-4.19.72/include/acpi/acpi_drivers.h WSL2-Linux-Kernel-4.19.72-microsoft-standard/include/acpi/acpi_drivers.h
--- linux-4.19.72/include/acpi/acpi_drivers.h 2019-09-10 02:33:54.000000000 -0700
+++ WSL2-Linux-Kernel-4.19.72-microsoft-standard/include/acpi/acpi_drivers.h 2019-09-15 02:24:17.000000000 -0700
@@ -88,7 +88,12 @@
struct pci_bus;
+#ifdef CONFIG_PCI
struct pci_dev *acpi_get_pci_dev(acpi_handle);
+#else
+static inline struct pci_dev *acpi_get_pci_dev(acpi_handle hndl)
+{ return NULL; }
+#endif
/* Arch-defined function to add a bus to the system */
diff -N -r -u linux-4.19.72/include/asm-generic/mshyperv.h WSL2-Linux-Kernel-4.19.72-microsoft-standard/include/asm-generic/mshyperv.h
--- linux-4.19.72/include/asm-generic/mshyperv.h 1969-12-31 16:00:00.000000000 -0800
+++ WSL2-Linux-Kernel-4.19.72-microsoft-standard/include/asm-generic/mshyperv.h 2019-09-15 02:24:17.000000000 -0700
@@ -0,0 +1,240 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/*
+ * Linux-specific definitions for managing interactions with Microsoft's
+ * Hyper-V hypervisor. The definitions in this file are architecture
+ * independent. See arch/<arch>/include/asm/mshyperv.h for definitions
+ * that are specific to architecture <arch>.
+ *
+ * Definitions that are specified in the Hyper-V Top Level Functional
+ * Spec (TLFS) should not go in this file, but should instead go in
+ * hyperv-tlfs.h.
+ *
+ * Copyright (C) 2018, Microsoft, Inc.
+ *
+ * Author : Michael Kelley <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef _ASM_GENERIC_MSHYPERV_H
+#define _ASM_GENERIC_MSHYPERV_H
+
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/clocksource.h>
+#include <linux/irq.h>
+#include <linux/irqdesc.h>
+#include <asm/hyperv-tlfs.h>
+
+/*
+ * Hyper-V always runs with a page size of 4096. These definitions
+ * are used when communicating with Hyper-V using guest physical
+ * pages and guest physical page addresses, since the guest page
+ * size may not be 4096 on ARM64.
+ */
+#define HV_HYP_PAGE_SIZE 4096
+#define HV_HYP_PAGE_SHIFT 12
+#define HV_HYP_PAGE_MASK (~(HV_HYP_PAGE_SIZE - 1))
+
+
+struct ms_hyperv_info {
+ u32 features;
+ u32 misc_features;
+ u32 hints;
+ u32 max_vp_index;
+ u32 max_lp_index;
+};
+extern struct ms_hyperv_info ms_hyperv;
+
+extern u64 hv_do_hypercall(u64 control, void *inputaddr, void *outputaddr);
+extern u64 hv_do_fast_hypercall8(u16 control, u64 input8);
+
+/*
+ * The guest OS needs to register the guest ID with the hypervisor.
+ * The guest ID is a 64 bit entity and the structure of this ID is
+ * specified in the Hyper-V specification:
+ *
+ * msdn.microsoft.com/en-us/library/windows/hardware/ff542653%28v=vs.85%29.aspx
+ *
+ * While the current guideline does not specify how Linux guest ID(s)
+ * need to be generated, our plan is to publish the guidelines for
+ * Linux and other guest operating systems that currently are hosted
+ * on Hyper-V. The implementation here conforms to this yet
+ * unpublished guidelines.
+ *
+ *
+ * Bit(s)
+ * 63 - Indicates if the OS is Open Source or not; 1 is Open Source
+ * 62:56 - Os Type; Linux is 0x100
+ * 55:48 - Distro specific identification
+ * 47:16 - Linux kernel version number
+ * 15:0 - Distro specific identification
+ *
+ * Generate the guest ID based on the guideline described above.
+ */
+
+static inline __u64 generate_guest_id(__u64 d_info1, __u64 kernel_version,
+ __u64 d_info2)
+{
+ __u64 guest_id = 0;
+
+ guest_id = (((__u64)HV_LINUX_VENDOR_ID) << 48);
+ guest_id |= (d_info1 << 48);
+ guest_id |= (kernel_version << 16);
+ guest_id |= d_info2;
+
+ return guest_id;
+}
+
+
+/* Free the message slot and signal end-of-message if required */
+static inline void vmbus_signal_eom(struct hv_message *msg, u32 old_msg_type)
+{
+ /*
+ * On crash we're reading some other CPU's message page and we need
+ * to be careful: this other CPU may already had cleared the header
+ * and the host may already had delivered some other message there.
+ * In case we blindly write msg->header.message_type we're going
+ * to lose it. We can still lose a message of the same type but
+ * we count on the fact that there can only be one
+ * CHANNELMSG_UNLOAD_RESPONSE and we don't care about other messages
+ * on crash.
+ */
+ if (cmpxchg(&msg->header.message_type, old_msg_type,
+ HVMSG_NONE) != old_msg_type)
+ return;
+
+ /*
+ * Make sure the write to MessageType (ie set to
+ * HVMSG_NONE) happens before we read the
+ * MessagePending and EOMing. Otherwise, the EOMing
+ * will not deliver any more messages since there is
+ * no empty slot
+ */
+ mb();
+
+ if (msg->header.message_flags.msg_pending) {
+ /*
+ * This will cause message queue rescan to
+ * possibly deliver another msg from the
+ * hypervisor
+ */
+ hv_signal_eom();
+ }
+}
+
+void hv_setup_vmbus_irq(void (*handler)(void));
+void hv_remove_vmbus_irq(void);
+void hv_enable_vmbus_irq(void);
+void hv_disable_vmbus_irq(void);
+
+void hv_setup_kexec_handler(void (*handler)(void));
+void hv_remove_kexec_handler(void);
+void hv_setup_crash_handler(void (*handler)(struct pt_regs *regs));
+void hv_remove_crash_handler(void);
+
+#if IS_ENABLED(CONFIG_HYPERV)
+extern struct clocksource *hyperv_cs;
+
+/*
+ * Hypervisor's notion of virtual processor ID is different from
+ * Linux' notion of CPU ID. This information can only be retrieved
+ * in the context of the calling CPU. Setup a map for easy access
+ * to this information.
+ */
+extern u32 *hv_vp_index;
+extern u32 hv_max_vp_index;
+
+/* Sentinel value for an uninitialized entry in hv_vp_index array */
+#define VP_INVAL U32_MAX
+
+/**
+ * hv_cpu_number_to_vp_number() - Map CPU to VP.
+ * @cpu_number: CPU number in Linux terms
+ *
+ * This function returns the mapping between the Linux processor
+ * number and the hypervisor's virtual processor number, useful
+ * in making hypercalls and such that talk about specific
+ * processors.
+ *
+ * Return: Virtual processor number in Hyper-V terms
+ */
+static inline int hv_cpu_number_to_vp_number(int cpu_number)
+{
+ return hv_vp_index[cpu_number];
+}
+
+void hyperv_report_panic(struct pt_regs *regs, long err);
+void hyperv_report_panic_msg(phys_addr_t pa, size_t size);
+bool hv_is_hyperv_initialized(void);
+void hyperv_cleanup(void);
+#else /* CONFIG_HYPERV */
+static inline bool hv_is_hyperv_initialized(void) { return false; }
+static inline void hyperv_cleanup(void) {}
+#endif /* CONFIG_HYPERV */
+
+#if IS_ENABLED(CONFIG_HYPERV)
+extern int hv_setup_stimer0_irq(int *irq, int *vector, void (*handler)(void));
+extern void hv_remove_stimer0_irq(int irq);
+#endif
+
+static inline u64 hv_read_tsc_page_tsc(const struct ms_hyperv_tsc_page *tsc_pg,
+ u64 *cur_tsc)
+{
+ u64 scale, offset;
+ u32 sequence;
+
+ /*
+ * The protocol for reading Hyper-V TSC page is specified in Hypervisor
+ * Top-Level Functional Specification. To get the reference time we
+ * must do the following:
+ * - READ ReferenceTscSequence
+ * A special '0' value indicates the time source is unreliable and we
+ * need to use something else.
+ * - ReferenceTime =
+ * ((HWclock val) * ReferenceTscScale) >> 64) + ReferenceTscOffset
+ * - READ ReferenceTscSequence again. In case its value has changed
+ * since our first reading we need to discard ReferenceTime and repeat
+ * the whole sequence as the hypervisor was updating the page in
+ * between.
+ */
+ do {
+ sequence = READ_ONCE(tsc_pg->tsc_sequence);
+ /*
+ * Make sure we read sequence before we read other values from
+ * TSC page.
+ */
+ smp_rmb();
+
+ scale = READ_ONCE(tsc_pg->tsc_scale);
+ offset = READ_ONCE(tsc_pg->tsc_offset);
+ *cur_tsc = hv_read_hwclock();
+
+ /*
+ * Make sure we read sequence after we read all other values
+ * from TSC page.
+ */
+ smp_rmb();
+
+ } while (READ_ONCE(tsc_pg->tsc_sequence) != sequence);
+
+ return mul_u64_u64_shr(*cur_tsc, scale, 64) + offset;
+}
+
+static inline u64 hv_read_tsc_page(const struct ms_hyperv_tsc_page *tsc_pg)
+{
+ u64 cur_tsc;
+
+ return hv_read_tsc_page_tsc(tsc_pg, &cur_tsc);
+}
+
+#endif
diff -N -r -u linux-4.19.72/include/linux/acpi.h WSL2-Linux-Kernel-4.19.72-microsoft-standard/include/linux/acpi.h
--- linux-4.19.72/include/linux/acpi.h 2019-09-10 02:33:54.000000000 -0700
+++ WSL2-Linux-Kernel-4.19.72-microsoft-standard/include/linux/acpi.h 2019-09-15 02:24:17.000000000 -0700
@@ -343,7 +343,13 @@
int acpi_pci_irq_enable (struct pci_dev *dev);
void acpi_penalize_isa_irq(int irq, int active);
bool acpi_isa_irq_available(int irq);
+#ifdef CONFIG_PCI
void acpi_penalize_sci_irq(int irq, int trigger, int polarity);
+#else
+static inline void acpi_penalize_sci_irq(int irq, int trigger,
+ int polarity)
+{}
+#endif
void acpi_pci_irq_disable (struct pci_dev *dev);
extern int ec_read(u8 addr, u8 *val);
diff -N -r -u linux-4.19.72/include/linux/pci.h WSL2-Linux-Kernel-4.19.72-microsoft-standard/include/linux/pci.h
--- linux-4.19.72/include/linux/pci.h 2019-09-10 02:33:54.000000000 -0700
+++ WSL2-Linux-Kernel-4.19.72-microsoft-standard/include/linux/pci.h 2019-09-15 02:24:17.000000000 -0700
@@ -678,10 +678,22 @@
* ACPI needs to be able to access PCI config space before we've done a
* PCI bus scan and created pci_bus structures.
*/
+#ifdef CONFIG_PCI
int raw_pci_read(unsigned int domain, unsigned int bus, unsigned int devfn,
int reg, int len, u32 *val);
int raw_pci_write(unsigned int domain, unsigned int bus, unsigned int devfn,
int reg, int len, u32 val);
+#else
+static inline int raw_pci_read(unsigned int domain, unsigned int bus,
+ unsigned int devfn, int reg, int len, u32 *val)
+{
+ *val = 0;
+ return -EINVAL;
+}
+static inline int raw_pci_write(unsigned int domain, unsigned int bus,
+ unsigned int devfn, int reg, int len, u32 val)
+{ return -EINVAL; }
+#endif
#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
typedef u64 pci_bus_addr_t;
@@ -1596,7 +1608,27 @@
}
#else /* CONFIG_PCI is not enabled */
+static inline int pci_bus_read_config_byte(struct pci_bus *bus,
+ unsigned int devfn, int where, u8 *val)
+{ return -EINVAL; }
+static inline int pci_bus_read_config_word(struct pci_bus *bus,
+ unsigned int devfn, int where, u16 *val)
+{ return -EINVAL; }
+static inline int pci_bus_read_config_dword(struct pci_bus *bus,
+ unsigned int devfn, int where, u32 *val)
+{ return -EINVAL; }
+static inline int pci_bus_write_config_byte(struct pci_bus *bus,
+ unsigned int devfn, int where, u8 val)
+{ return -EINVAL; }
+static inline int pci_bus_write_config_word(struct pci_bus *bus,
+ unsigned int devfn, int where, u16 val)
+{ return -EINVAL; }
+static inline int pci_bus_write_config_dword(struct pci_bus *bus,
+ unsigned int devfn, int where, u32 val)
+{ return -EINVAL; }
+static inline struct pci_bus *pci_find_bus(int domain, int busnr)
+{ return NULL; }
static inline void pci_set_flags(int flags) { }
static inline void pci_add_flags(int flags) { }
static inline void pci_clear_flags(int flags) { }
@@ -1953,7 +1985,11 @@
enum pcie_reset_state state);
int pcibios_add_device(struct pci_dev *dev);
void pcibios_release_device(struct pci_dev *dev);
+#ifdef CONFIG_PCI
void pcibios_penalize_isa_irq(int irq, int active);
+#else
+static inline void pcibios_penalize_isa_irq(int irq, int active) {}
+#endif
int pcibios_alloc_irq(struct pci_dev *dev);
void pcibios_free_irq(struct pci_dev *dev);
resource_size_t pcibios_default_alignment(void);
diff -N -r -u linux-4.19.72/include/uapi/linux/ndctl.h WSL2-Linux-Kernel-4.19.72-microsoft-standard/include/uapi/linux/ndctl.h
--- linux-4.19.72/include/uapi/linux/ndctl.h 2019-09-10 02:33:54.000000000 -0700
+++ WSL2-Linux-Kernel-4.19.72-microsoft-standard/include/uapi/linux/ndctl.h 2019-09-15 02:24:17.000000000 -0700
@@ -203,7 +203,7 @@
};
enum {
- ND_MIN_NAMESPACE_SIZE = PAGE_SIZE,
+ ND_MIN_NAMESPACE_SIZE = 0x00001000,
};
enum ars_masks {
diff -N -r -u linux-4.19.72/init/Kconfig WSL2-Linux-Kernel-4.19.72-microsoft-standard/init/Kconfig
--- linux-4.19.72/init/Kconfig 2019-09-10 02:33:54.000000000 -0700
+++ WSL2-Linux-Kernel-4.19.72-microsoft-standard/init/Kconfig 2019-09-15 02:24:17.000000000 -0700
@@ -1158,8 +1158,6 @@
menuconfig EXPERT
bool "Configure standard kernel features (expert users)"
- # Unhide debug options, to make the on-by-default options visible
- select DEBUG_KERNEL
help
This option allows certain base kernel options and settings
to be disabled or tweaked. This is for specialized
diff -N -r -u linux-4.19.72/kernel/ksysfs.c WSL2-Linux-Kernel-4.19.72-microsoft-standard/kernel/ksysfs.c
--- linux-4.19.72/kernel/ksysfs.c 2019-09-10 02:33:54.000000000 -0700
+++ WSL2-Linux-Kernel-4.19.72-microsoft-standard/kernel/ksysfs.c 2019-09-15 02:24:17.000000000 -0700
@@ -149,7 +149,7 @@
KERNEL_ATTR_RO(fscaps);
#ifndef CONFIG_TINY_RCU
-int rcu_expedited;
+int rcu_expedited = 1;
static ssize_t rcu_expedited_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
diff -N -r -u linux-4.19.72/lib/Kconfig WSL2-Linux-Kernel-4.19.72-microsoft-standard/lib/Kconfig
--- linux-4.19.72/lib/Kconfig 2019-09-10 02:33:54.000000000 -0700
+++ WSL2-Linux-Kernel-4.19.72-microsoft-standard/lib/Kconfig 2019-09-15 02:24:17.000000000 -0700
@@ -7,8 +7,7 @@
menu "Library routines"
-config RAID6_PQ
- tristate
+source "lib/raid6/Kconfig"
config BITREVERSE
tristate
diff -N -r -u linux-4.19.72/lib/Kconfig.debug WSL2-Linux-Kernel-4.19.72-microsoft-standard/lib/Kconfig.debug
--- linux-4.19.72/lib/Kconfig.debug 2019-09-10 02:33:54.000000000 -0700
+++ WSL2-Linux-Kernel-4.19.72-microsoft-standard/lib/Kconfig.debug 2019-09-15 02:24:17.000000000 -0700
@@ -978,8 +978,8 @@
config SCHED_DEBUG
bool "Collect scheduler debugging info"
- depends on DEBUG_KERNEL && PROC_FS
- default y
+ depends on PROC_FS
+ default n
help
If you say Y here, the /proc/sched_debug file will be provided
that can help debug the scheduler. The runtime overhead of this
@@ -991,7 +991,7 @@
config SCHEDSTATS
bool "Collect scheduler statistics"
- depends on DEBUG_KERNEL && PROC_FS
+ depends on PROC_FS
select SCHED_INFO
help
If you say Y here, additional code will be inserted into the
@@ -1004,7 +1004,6 @@
config SCHED_STACK_END_CHECK
bool "Detect stack corruption on calls to schedule()"
- depends on DEBUG_KERNEL
default n
help
This option checks for a stack overrun on calls to schedule().
diff -N -r -u linux-4.19.72/lib/raid6/algos.c WSL2-Linux-Kernel-4.19.72-microsoft-standard/lib/raid6/algos.c
--- linux-4.19.72/lib/raid6/algos.c 2019-09-10 02:33:54.000000000 -0700
+++ WSL2-Linux-Kernel-4.19.72-microsoft-standard/lib/raid6/algos.c 2019-09-15 02:24:17.000000000 -0700
@@ -129,6 +129,66 @@
#define time_before(x, y) ((x) < (y))
#endif
+#ifdef CONFIG_RAID6_FORCE_ALGO
+/* TODO don't compile in algos that will never be used */
+int __init raid6_select_algo(void)
+{
+ const struct raid6_recov_calls *recov_fallback = &raid6_recov_intx1;
+ const struct raid6_recov_calls *recov_algo;
+ const struct raid6_calls *gen_fallback;
+ const struct raid6_calls *gen_algo;
+
+#if defined(__i386__)
+ gen_fallback = &raid6_intx32;
+#elif defined(__x86_64__)
+ gen_fallback = &raid6_sse2x2;
+#elif defined(__aarch64__)
+ gen_fallback = &raid6_neonx8;
+ recov_algo = &raid6_recov_neon;
+#else
+# error "TODO"
+#endif
+
+#if defined(CONFIG_RAID6_FORCE_INT) && (defined(__i386__) || defined(__x86_64__))
+ recov_algo = &raid6_recov_intx1;
+ gen_algo = &raid6_intx32;
+
+#elif defined(CONFIG_RAID6_FORCE_SSSE3) && (defined(__i386__) || defined(__x86_64__))
+ recov_algo = &raid6_recov_ssse3;
+#if defined(__i386__)
+ gen_algo = &raid6_sse2x2;
+#else
+ gen_algo = &raid6_sse2x4;
+#endif
+
+#elif defined(CONFIG_RAID6_FORCE_AVX2) && (defined(__i386__) || defined(__x86_64__))
+ recov_algo = &raid6_recov_avx2;
+
+#if defined(__i386__)
+ gen_algo = &raid6_avx2x2;
+#else
+ gen_algo = &raid6_avx2x4;
+#endif
+
+#elif !defined(__aarch64__)
+#error "RAID6 Forced Recov Algo: Unsupported selection"
+#endif
+
+ if (recov_algo->valid != NULL && recov_algo->valid() == 0)
+ recov_algo = recov_fallback;
+
+ pr_info("raid6: Forced to use recovery algorithm %s\n", recov_algo->name);
+
+ raid6_2data_recov = recov_algo->data2;
+ raid6_datap_recov = recov_algo->datap;
+
+ pr_info("raid6: Forced gen() algo %s\n", gen_algo->name);
+
+ raid6_call = *gen_algo;
+
+ return gen_algo && recov_algo ? 0 : -EINVAL;
+}
+#else
static inline const struct raid6_recov_calls *raid6_choose_recov(void)
{
const struct raid6_recov_calls *const *algo;
@@ -260,6 +320,7 @@
return gen_best && rec_best ? 0 : -EINVAL;
}
+#endif
static void raid6_exit(void)
{
diff -N -r -u linux-4.19.72/lib/raid6/Kconfig WSL2-Linux-Kernel-4.19.72-microsoft-standard/lib/raid6/Kconfig
--- linux-4.19.72/lib/raid6/Kconfig 1969-12-31 16:00:00.000000000 -0800
+++ WSL2-Linux-Kernel-4.19.72-microsoft-standard/lib/raid6/Kconfig 2019-09-15 02:24:17.000000000 -0700
@@ -0,0 +1,38 @@
+menu "RAID 6"
+
+config RAID6_PQ
+ tristate
+
+config RAID6_FORCE_ALGO
+ bool "Always use specified recovery algorithm"
+ default n
+ depends on RAID6_PQ
+ help
+ If this option is not set, on every boot the kernel will
+ benchmark each optimized version of the RAID6 recovery and
+ syndrome generation algorithms and will select the one that
+ performs best. Microbenchmarking each version negatively
+ affects boot time.
+
+ Enabling this option skips the benchmark at boot, and
+ instead always uses the algorithm selected. The only exception
+ is if the selected algorithm relies on a cpu feature not
+ supported at runtime. In this case, one of the lower performance
+ fallbacks are used.
+
+choice
+ prompt "RAID6 Recovery Algorithm"
+ default RAID6_FORCE_INT
+ depends on RAID6_FORCE_ALGO
+ ---help---
+ Select the RAID6 recovery algorithm to unconditionally use
+
+ config RAID6_FORCE_INT
+ bool "Reference Implementation"
+ config RAID6_FORCE_SSSE3
+ bool "SSSE3"
+ config RAID6_FORCE_AVX2
+ bool "AVX2"
+endchoice
+
+endmenu
diff -N -r -u linux-4.19.72/MAINTAINERS WSL2-Linux-Kernel-4.19.72-microsoft-standard/MAINTAINERS
--- linux-4.19.72/MAINTAINERS 2019-09-10 02:33:54.000000000 -0700
+++ WSL2-Linux-Kernel-4.19.72-microsoft-standard/MAINTAINERS 2019-09-15 02:24:17.000000000 -0700
@@ -6788,6 +6788,9 @@
F: arch/x86/include/asm/hyperv-tlfs.h
F: arch/x86/kernel/cpu/mshyperv.c
F: arch/x86/hyperv
+F: arch/arm64/include/asm/hyperv-tlfs.h
+F: arch/arm64/include/asm/mshyperv.h
+F: arch/arm64/hyperv
F: drivers/hid/hid-hyperv.c
F: drivers/hv/
F: drivers/input/serio/hyperv-keyboard.c
@@ -6799,6 +6802,7 @@
F: net/vmw_vsock/hyperv_transport.c
F: include/linux/hyperv.h
F: include/uapi/linux/hyperv.h
+F: include/asm-generic/mshyperv.h
F: tools/hv/
F: Documentation/ABI/stable/sysfs-bus-vmbus
diff -N -r -u linux-4.19.72/net/vmw_vsock/hyperv_transport.c WSL2-Linux-Kernel-4.19.72-microsoft-standard/net/vmw_vsock/hyperv_transport.c
--- linux-4.19.72/net/vmw_vsock/hyperv_transport.c 2019-09-10 02:33:54.000000000 -0700
+++ WSL2-Linux-Kernel-4.19.72-microsoft-standard/net/vmw_vsock/hyperv_transport.c 2019-09-15 02:24:17.000000000 -0700
@@ -23,14 +23,14 @@
#include <net/sock.h>
#include <net/af_vsock.h>
-/* The host side's design of the feature requires 6 exact 4KB pages for
- * recv/send rings respectively -- this is suboptimal considering memory
- * consumption, however unluckily we have to live with it, before the
- * host comes up with a better design in the future.
+/* Older (VMBUS version 'VERSION_WIN10' or before) Windows hosts have some
+ * stricter requirements on the hv_sock ring buffer size of six 4K pages. Newer
+ * hosts don't have this limitation; but, keep the defaults the same for compat.
*/
#define PAGE_SIZE_4K 4096
#define RINGBUFFER_HVS_RCV_SIZE (PAGE_SIZE_4K * 6)
#define RINGBUFFER_HVS_SND_SIZE (PAGE_SIZE_4K * 6)
+#define RINGBUFFER_HVS_MAX_SIZE (PAGE_SIZE_4K * 64)
/* The MTU is 16KB per the host side's design */
#define HVS_MTU_SIZE (1024 * 16)
@@ -55,8 +55,9 @@
};
/* We can send up to HVS_MTU_SIZE bytes of payload to the host, but let's use
- * a small size, i.e. HVS_SEND_BUF_SIZE, to minimize the dynamically-allocated
- * buffer, because tests show there is no significant performance difference.
+ * a smaller size, i.e. HVS_SEND_BUF_SIZE, to maximize concurrency between the
+ * guest and the host processing as one VMBUS packet is the smallest processing
+ * unit.
*
* Note: the buffer can be eliminated in the future when we add new VMBus
* ringbuffer APIs that allow us to directly copy data from userspace buffer
@@ -332,7 +333,9 @@
struct vsock_sock *vnew = NULL;
struct hvsock *hvs = NULL;
struct hvsock *hvs_new = NULL;
+ int rcvbuf;
int ret;
+ int sndbuf;
if_type = &chan->offermsg.offer.if_type;
if_instance = &chan->offermsg.offer.if_instance;
@@ -374,9 +377,34 @@
}
set_channel_read_mode(chan, HV_CALL_DIRECT);
- ret = vmbus_open(chan, RINGBUFFER_HVS_SND_SIZE,
- RINGBUFFER_HVS_RCV_SIZE, NULL, 0,
- hvs_channel_cb, conn_from_host ? new : sk);
+
+ /* Use the socket buffer sizes as hints for the VMBUS ring size. For
+ * server side sockets, 'sk' is the parent socket and thus, this will
+ * allow the child sockets to inherit the size from the parent. Keep
+ * the mins to the default value and align to page size as per VMBUS
+ * requirements.
+ * For the max, the socket core library will limit the socket buffer
+ * size that can be set by the user, but, since currently, the hv_sock
+ * VMBUS ring buffer is physically contiguous allocation, restrict it
+ * further.
+ * Older versions of hv_sock host side code cannot handle bigger VMBUS
+ * ring buffer size. Use the version number to limit the change to newer
+ * versions.
+ */
+ if (vmbus_proto_version < VERSION_WIN10_V5) {
+ sndbuf = RINGBUFFER_HVS_SND_SIZE;
+ rcvbuf = RINGBUFFER_HVS_RCV_SIZE;
+ } else {
+ sndbuf = max_t(int, sk->sk_sndbuf, RINGBUFFER_HVS_SND_SIZE);
+ sndbuf = min_t(int, sndbuf, RINGBUFFER_HVS_MAX_SIZE);
+ sndbuf = ALIGN(sndbuf, PAGE_SIZE);
+ rcvbuf = max_t(int, sk->sk_rcvbuf, RINGBUFFER_HVS_RCV_SIZE);
+ rcvbuf = min_t(int, rcvbuf, RINGBUFFER_HVS_MAX_SIZE);
+ rcvbuf = ALIGN(rcvbuf, PAGE_SIZE);
+ }
+
+ ret = vmbus_open(chan, sndbuf, rcvbuf, NULL, 0, hvs_channel_cb,
+ conn_from_host ? new : sk);
if (ret != 0) {
if (conn_from_host) {
hvs_new->chan = NULL;
@@ -434,6 +462,7 @@
static int hvs_sock_init(struct vsock_sock *vsk, struct vsock_sock *psk)
{
struct hvsock *hvs;
+ struct sock *sk = sk_vsock(vsk);
hvs = kzalloc(sizeof(*hvs), GFP_KERNEL);
if (!hvs)
@@ -441,7 +470,8 @@
vsk->trans = hvs;
hvs->vsk = vsk;
-
+ sk->sk_sndbuf = RINGBUFFER_HVS_SND_SIZE;
+ sk->sk_rcvbuf = RINGBUFFER_HVS_RCV_SIZE;
return 0;
}
@@ -637,7 +667,9 @@
struct hvsock *hvs = vsk->trans;
struct vmbus_channel *chan = hvs->chan;
struct hvs_send_buf *send_buf;
- ssize_t to_write, max_writable, ret;
+ ssize_t to_write, max_writable;
+ ssize_t ret = 0;
+ ssize_t bytes_written = 0;
BUILD_BUG_ON(sizeof(*send_buf) != PAGE_SIZE_4K);
@@ -645,20 +677,34 @@
if (!send_buf)
return -ENOMEM;
- max_writable = hvs_channel_writable_bytes(chan);
- to_write = min_t(ssize_t, len, max_writable);
- to_write = min_t(ssize_t, to_write, HVS_SEND_BUF_SIZE);
-
- ret = memcpy_from_msg(send_buf->data, msg, to_write);
- if (ret < 0)
- goto out;
+ /* Reader(s) could be draining data from the channel as we write.
+ * Maximize bandwidth, by iterating until the channel is found to be
+ * full.
+ */
+ while (len) {
+ max_writable = hvs_channel_writable_bytes(chan);
+ if (!max_writable)
+ break;
+ to_write = min_t(ssize_t, len, max_writable);
+ to_write = min_t(ssize_t, to_write, HVS_SEND_BUF_SIZE);
+ /* memcpy_from_msg is safe for loop as it advances the offsets
+ * within the message iterator.
+ */
+ ret = memcpy_from_msg(send_buf->data, msg, to_write);
+ if (ret < 0)
+ goto out;
- ret = hvs_send_data(hvs->chan, send_buf, to_write);
- if (ret < 0)
- goto out;
+ ret = hvs_send_data(hvs->chan, send_buf, to_write);
+ if (ret < 0)
+ goto out;
- ret = to_write;
+ bytes_written += to_write;
+ len -= to_write;
+ }
out:
+ /* If any data has been sent, return that */
+ if (bytes_written)
+ ret = bytes_written;
kfree(send_buf);
return ret;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment