Skip to content

Commit 16a7518

Browse files
kelleymhtyhicks
authored andcommitted
arm64: hyperv: Initialize hypervisor on boot
Add ARM64-specific code to initialize the Hyper-V hypervisor when booting as a guest VM. Provide functions and data structures indicating hypervisor status that are needed by VMbus driver. This code is built only when CONFIG_HYPERV is enabled. Signed-off-by: Michael Kelley <mikelley@microsoft.com>
1 parent 6a7797b commit 16a7518

3 files changed

Lines changed: 129 additions & 0 deletions

File tree

arch/arm64/hyperv/mshyperv.c

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,125 @@
1414
#include <linux/types.h>
1515
#include <linux/export.h>
1616
#include <linux/ptrace.h>
17+
#include <linux/errno.h>
18+
#include <linux/acpi.h>
19+
#include <linux/version.h>
20+
#include <linux/cpuhotplug.h>
21+
#include <linux/slab.h>
22+
#include <linux/cpumask.h>
23+
#include <asm/mshyperv.h>
24+
25+
static bool hyperv_initialized;
26+
struct ms_hyperv_info ms_hyperv __ro_after_init;
27+
EXPORT_SYMBOL_GPL(ms_hyperv);
28+
29+
u32 *hv_vp_index;
30+
EXPORT_SYMBOL_GPL(hv_vp_index);
31+
32+
u32 hv_max_vp_index;
33+
EXPORT_SYMBOL_GPL(hv_max_vp_index);
34+
35+
static int hv_cpu_init(unsigned int cpu)
36+
{
37+
hv_vp_index[cpu] = hv_get_vpreg(HV_REGISTER_VP_INDEX);
38+
return 0;
39+
}
40+
41+
void __init hyperv_early_init(void)
42+
{
43+
struct hv_get_vp_registers_output result;
44+
u32 a, b, c, d;
45+
u64 guest_id;
46+
47+
/*
48+
* If we're in a VM on Hyper-V, the ACPI hypervisor_id field will
49+
* have the string "MsHyperV".
50+
*/
51+
if (strncmp((char *)&acpi_gbl_FADT.hypervisor_id, "MsHyperV", 8))
52+
return;
53+
54+
/* Setup the guest ID */
55+
guest_id = generate_guest_id(0, LINUX_VERSION_CODE, 0);
56+
hv_set_vpreg(HV_REGISTER_GUEST_OSID, guest_id);
57+
58+
/* Get the features and hints from Hyper-V */
59+
hv_get_vpreg_128(HV_REGISTER_FEATURES, &result);
60+
ms_hyperv.features = result.as32.a;
61+
ms_hyperv.misc_features = result.as32.c;
62+
63+
hv_get_vpreg_128(HV_REGISTER_ENLIGHTENMENTS, &result);
64+
ms_hyperv.hints = result.as32.a;
65+
66+
pr_info("Hyper-V: Features 0x%x, hints 0x%x, misc 0x%x\n",
67+
ms_hyperv.features, ms_hyperv.hints, ms_hyperv.misc_features);
68+
69+
/*
70+
* If Hyper-V has crash notifications, set crash_kexec_post_notifiers
71+
* so that we will report the panic to Hyper-V before running kdump.
72+
*/
73+
if (ms_hyperv.misc_features & HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE)
74+
crash_kexec_post_notifiers = true;
75+
76+
/* Get information about the Hyper-V host version */
77+
hv_get_vpreg_128(HV_REGISTER_HYPERVISOR_VERSION, &result);
78+
a = result.as32.a;
79+
b = result.as32.b;
80+
c = result.as32.c;
81+
d = result.as32.d;
82+
pr_info("Hyper-V: Host Build %d.%d.%d.%d-%d-%d\n",
83+
b >> 16, b & 0xFFFF, a, d & 0xFFFFFF, c, d >> 24);
84+
85+
hyperv_initialized = true;
86+
}
87+
88+
static int __init hyperv_init(void)
89+
{
90+
int i;
91+
92+
/* Allocate and initialize percpu VP index array */
93+
hv_max_vp_index = num_possible_cpus();
94+
hv_vp_index = kmalloc_array(hv_max_vp_index, sizeof(*hv_vp_index),
95+
GFP_KERNEL);
96+
if (!hv_vp_index) {
97+
hv_max_vp_index = 0;
98+
return -ENOMEM;
99+
}
100+
101+
for (i = 0; i < hv_max_vp_index; i++)
102+
hv_vp_index[i] = VP_INVAL;
103+
104+
if (cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "arm64/hyperv_init:online",
105+
hv_cpu_init, NULL) < 0) {
106+
hv_max_vp_index = 0;
107+
kfree(hv_vp_index);
108+
hv_vp_index = NULL;
109+
return -EINVAL;
110+
}
111+
112+
return 0;
113+
}
114+
115+
early_initcall(hyperv_init);
116+
117+
/* This routine is called before kexec/kdump. It does required cleanup. */
118+
void hyperv_cleanup(void)
119+
{
120+
hv_set_vpreg(HV_REGISTER_GUEST_OSID, 0);
121+
122+
}
123+
EXPORT_SYMBOL_GPL(hyperv_cleanup);
124+
125+
bool hv_is_hyperv_initialized(void)
126+
{
127+
return hyperv_initialized;
128+
}
129+
EXPORT_SYMBOL_GPL(hv_is_hyperv_initialized);
130+
131+
bool hv_is_hibernation_supported(void)
132+
{
133+
return false;
134+
}
135+
EXPORT_SYMBOL_GPL(hv_is_hibernation_supported);
17136

18137
/*
19138
* The VMbus handler functions are no-ops on ARM64 because

arch/arm64/include/asm/mshyperv.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@
2323
#include <asm/hyperv-tlfs.h>
2424
#include <clocksource/arm_arch_timer.h>
2525

26+
#if IS_ENABLED(CONFIG_HYPERV)
27+
void __init hyperv_early_init(void);
28+
#else
29+
static inline void hyperv_early_init(void) {};
30+
#endif
31+
2632
/*
2733
* Declare calls to get and set Hyper-V VP register values on ARM64, which
2834
* requires a hypercall.

arch/arm64/kernel/setup.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
#include <asm/traps.h>
5050
#include <asm/efi.h>
5151
#include <asm/xen/hypervisor.h>
52+
#include <asm/mshyperv.h>
5253
#include <asm/mmu_context.h>
5354

5455
static int num_standard_resources;
@@ -340,6 +341,9 @@ void __init __no_sanitize_address setup_arch(char **cmdline_p)
340341
if (acpi_disabled)
341342
unflatten_device_tree();
342343

344+
/* Do after acpi_boot_table_init() so local FADT is available */
345+
hyperv_early_init();
346+
343347
bootmem_init();
344348

345349
kasan_init();

0 commit comments

Comments
 (0)