Drivers: hv vmbus: Move Hypercall page setup out of common code
authorK. Y. Srinivasan <kys@microsoft.com>
Wed, 18 Jan 2017 23:45:02 +0000 (16:45 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 19 Jan 2017 10:42:07 +0000 (11:42 +0100)
As part of the effort to separate out architecture specific code, move the
hypercall page setup to an architecture specific file.

Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
MAINTAINERS
arch/x86/Kbuild
arch/x86/hyperv/Makefile [new file with mode: 0644]
arch/x86/hyperv/hv_init.c [new file with mode: 0644]
arch/x86/include/asm/mshyperv.h
arch/x86/kernel/cpu/mshyperv.c
drivers/hv/hv.c

index c36976d3bd1a72f42afa53b0c1c548e8f2456d19..be8de24fd6dd80ac9916c1c4ba10d0f5fd242986 100644 (file)
@@ -5962,6 +5962,7 @@ S:        Maintained
 F:     arch/x86/include/asm/mshyperv.h
 F:     arch/x86/include/uapi/asm/hyperv.h
 F:     arch/x86/kernel/cpu/mshyperv.c
+F:     arch/x86/hyperv
 F:     drivers/hid/hid-hyperv.c
 F:     drivers/hv/
 F:     drivers/input/serio/hyperv-keyboard.c
index eb3abf8ac44eb33f333ed29727dfd49ba6bfbf38..586b786b3edf9a6930bfdf05c47b4c8e0c57e718 100644 (file)
@@ -7,6 +7,9 @@ obj-$(CONFIG_KVM) += kvm/
 # Xen paravirtualization support
 obj-$(CONFIG_XEN) += xen/
 
+# Hyper-V paravirtualization support
+obj-$(CONFIG_HYPERVISOR_GUEST) += hyperv/
+
 # lguest paravirtualization support
 obj-$(CONFIG_LGUEST_GUEST) += lguest/
 
diff --git a/arch/x86/hyperv/Makefile b/arch/x86/hyperv/Makefile
new file mode 100644 (file)
index 0000000..171ae09
--- /dev/null
@@ -0,0 +1 @@
+obj-y          := hv_init.o
diff --git a/arch/x86/hyperv/hv_init.c b/arch/x86/hyperv/hv_init.c
new file mode 100644 (file)
index 0000000..3206bfd
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * X86 specific Hyper-V initialization code.
+ *
+ * Copyright (C) 2016, Microsoft, Inc.
+ *
+ * Author : K. Y. Srinivasan <kys@microsoft.com>
+ *
+ * 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 <asm/hypervisor.h>
+#include <asm/hyperv.h>
+#include <asm/mshyperv.h>
+#include <linux/version.h>
+#include <linux/vmalloc.h>
+#include <linux/mm.h>
+
+void *hv_hypercall_pg;
+/*
+ * This function is to be invoked early in the boot sequence after the
+ * hypervisor has been detected.
+ *
+ * 1. Setup the hypercall page.
+ */
+void hyperv_init(void)
+{
+       u64 guest_id;
+       union hv_x64_msr_hypercall_contents hypercall_msr;
+
+       if (x86_hyper != &x86_hyper_ms_hyperv)
+               return;
+
+       /*
+        * Setup the hypercall page and enable hypercalls.
+        * 1. Register the guest ID
+        * 2. Enable the hypercall and register the hypercall page
+        */
+       guest_id = generate_guest_id(0, LINUX_VERSION_CODE, 0);
+       wrmsrl(HV_X64_MSR_GUEST_OS_ID, guest_id);
+
+       hv_hypercall_pg  = __vmalloc(PAGE_SIZE, GFP_KERNEL, PAGE_KERNEL_EXEC);
+       if (hv_hypercall_pg == NULL) {
+               wrmsrl(HV_X64_MSR_GUEST_OS_ID, 0);
+               return;
+       }
+
+       rdmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
+       hypercall_msr.enable = 1;
+       hypercall_msr.guest_physical_address = vmalloc_to_pfn(hv_hypercall_pg);
+       wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
+}
+EXPORT_SYMBOL_GPL(hv_hypercall_pg);
index 15a0c275c82e36f45f92de8a01b82d5043fb8acf..e5f57e15a507b0558ffc2805814ac282bd480bdb 100644 (file)
@@ -80,4 +80,9 @@ 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)
+void hyperv_init(void);
+extern void *hv_hypercall_pg;
+#endif
 #endif
index 65e20c97e04b1e2591a356eda4e922ed92ec0310..c5a1e9ba9ae07b34830906d62b938ee3a69d1ed6 100644 (file)
@@ -227,6 +227,13 @@ static void __init ms_hyperv_init_platform(void)
         */
        if (efi_enabled(EFI_BOOT))
                x86_platform.get_nmi_reason = hv_get_nmi_reason;
+
+#if IS_ENABLED(CONFIG_HYPERV)
+       /*
+        * Setup the hook to get control post apic initialization.
+        */
+       x86_platform.apic_post_init = hyperv_init;
+#endif
 }
 
 const __refconst struct hypervisor_x86 x86_hyper_ms_hyperv = {
index 714e1ebc834cb0ae5f0be8f06714a7da5762737a..d8d41542d93c22c72601d3163d764f505d6969ef 100644 (file)
@@ -193,7 +193,6 @@ int hv_init(void)
 {
        int max_leaf;
        union hv_x64_msr_hypercall_contents hypercall_msr;
-       void *virtaddr = NULL;
 
        memset(hv_context.synic_event_page, 0, sizeof(void *) * NR_CPUS);
        memset(hv_context.synic_message_page, 0,
@@ -211,33 +210,15 @@ int hv_init(void)
 
        max_leaf = query_hypervisor_info();
 
-       /*
-        * Write our OS ID.
-        */
-       hv_context.guestid = generate_guest_id(0, LINUX_VERSION_CODE, 0);
-       wrmsrl(HV_X64_MSR_GUEST_OS_ID, hv_context.guestid);
 
        /* See if the hypercall page is already set */
-       rdmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
-
-       virtaddr = __vmalloc(PAGE_SIZE, GFP_KERNEL, PAGE_KERNEL_EXEC);
-
-       if (!virtaddr)
-               goto cleanup;
-
-       hypercall_msr.enable = 1;
-
-       hypercall_msr.guest_physical_address = vmalloc_to_pfn(virtaddr);
-       wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
-
-       /* Confirm that hypercall page did get setup. */
        hypercall_msr.as_uint64 = 0;
        rdmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
 
        if (!hypercall_msr.enable)
-               goto cleanup;
+               return -ENOTSUPP;
 
-       hv_context.hypercall_page = virtaddr;
+       hv_context.hypercall_page = hv_hypercall_pg;
 
 #ifdef CONFIG_X86_64
        if (ms_hyperv.features & HV_X64_MSR_REFERENCE_TSC_AVAILABLE) {
@@ -261,15 +242,6 @@ int hv_init(void)
        return 0;
 
 cleanup:
-       if (virtaddr) {
-               if (hypercall_msr.enable) {
-                       hypercall_msr.as_uint64 = 0;
-                       wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
-               }
-
-               vfree(virtaddr);
-       }
-
        return -ENOTSUPP;
 }
 
@@ -280,20 +252,9 @@ cleanup:
  */
 void hv_cleanup(bool crash)
 {
-       union hv_x64_msr_hypercall_contents hypercall_msr;
-
-       /* Reset our OS id */
-       wrmsrl(HV_X64_MSR_GUEST_OS_ID, 0);
-
-       if (hv_context.hypercall_page) {
-               hypercall_msr.as_uint64 = 0;
-               wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
-               if (!crash)
-                       vfree(hv_context.hypercall_page);
-               hv_context.hypercall_page = NULL;
-       }
 
 #ifdef CONFIG_X86_64
+       union hv_x64_msr_hypercall_contents hypercall_msr;
        /*
         * Cleanup the TSC page based CS.
         */