Created
September 19, 2019 06:04
-
-
Save therealkenc/4b5256af912329cd279cf6f5e6a4f6ac to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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&data=02%7C01%7Ckys%40microsoft.com%7Cc831a45fd63e4a4b083908d641216aa8%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C636768009113747528&sdata=jRSrs9ZWXdmeS7LQUEpoSyUfBS7a5KLYy%2FolFdE2tI0%3D&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