1 // SPDX-License-Identifier: GPL-2.0
2 
3 /*
4  * Core routines for interacting with Microsoft's Hyper-V hypervisor,
5  * including hypervisor initialization.
6  *
7  * Copyright (C) 2021, Microsoft, Inc.
8  *
9  * Author : Michael Kelley <mikelley@microsoft.com>
10  */
11 
12 #include <linux/types.h>
13 #include <linux/acpi.h>
14 #include <linux/export.h>
15 #include <linux/errno.h>
16 #include <linux/version.h>
17 #include <linux/cpuhotplug.h>
18 #include <asm/mshyperv.h>
19 
20 static bool hyperv_initialized;
21 
hv_get_hypervisor_version(union hv_hypervisor_version_info * info)22 int hv_get_hypervisor_version(union hv_hypervisor_version_info *info)
23 {
24 	hv_get_vpreg_128(HV_REGISTER_HYPERVISOR_VERSION,
25 			 (struct hv_get_vp_registers_output *)info);
26 
27 	return 0;
28 }
29 EXPORT_SYMBOL_GPL(hv_get_hypervisor_version);
30 
hyperv_init(void)31 static int __init hyperv_init(void)
32 {
33 	struct hv_get_vp_registers_output	result;
34 	u64	guest_id;
35 	int	ret;
36 
37 	/*
38 	 * Allow for a kernel built with CONFIG_HYPERV to be running in
39 	 * a non-Hyper-V environment, including on DT instead of ACPI.
40 	 * In such cases, do nothing and return success.
41 	 */
42 	if (acpi_disabled)
43 		return 0;
44 
45 	if (strncmp((char *)&acpi_gbl_FADT.hypervisor_id, "MsHyperV", 8))
46 		return 0;
47 
48 	/* Setup the guest ID */
49 	guest_id = hv_generate_guest_id(LINUX_VERSION_CODE);
50 	hv_set_vpreg(HV_REGISTER_GUEST_OS_ID, guest_id);
51 
52 	/* Get the features and hints from Hyper-V */
53 	hv_get_vpreg_128(HV_REGISTER_PRIVILEGES_AND_FEATURES_INFO, &result);
54 	ms_hyperv.features = result.as32.a;
55 	ms_hyperv.priv_high = result.as32.b;
56 	ms_hyperv.misc_features = result.as32.c;
57 
58 	hv_get_vpreg_128(HV_REGISTER_FEATURES_INFO, &result);
59 	ms_hyperv.hints = result.as32.a;
60 
61 	pr_info("Hyper-V: privilege flags low 0x%x, high 0x%x, hints 0x%x, misc 0x%x\n",
62 		ms_hyperv.features, ms_hyperv.priv_high, ms_hyperv.hints,
63 		ms_hyperv.misc_features);
64 
65 	hv_identify_partition_type();
66 
67 	ret = hv_common_init();
68 	if (ret)
69 		return ret;
70 
71 	ret = cpuhp_setup_state(CPUHP_AP_HYPERV_ONLINE, "arm64/hyperv_init:online",
72 				hv_common_cpu_init, hv_common_cpu_die);
73 	if (ret < 0) {
74 		hv_common_free();
75 		return ret;
76 	}
77 
78 	if (ms_hyperv.priv_high & HV_ACCESS_PARTITION_ID)
79 		hv_get_partition_id();
80 
81 	ms_hyperv_late_init();
82 
83 	hyperv_initialized = true;
84 	return 0;
85 }
86 
87 early_initcall(hyperv_init);
88 
hv_is_hyperv_initialized(void)89 bool hv_is_hyperv_initialized(void)
90 {
91 	return hyperv_initialized;
92 }
93 EXPORT_SYMBOL_GPL(hv_is_hyperv_initialized);
94