Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

arm64: hyperv: Add Hyper-V hypercall and register access utilities

hyperv-tlfs.h defines Hyper-V interfaces from the Hyper-V Top Level
Functional Spec (TLFS), and #includes the architecture-independent
part of hyperv-tlfs.h in include/asm-generic. The published TLFS
is distinctly oriented to x86/x64, so the ARM64-specific
hyperv-tlfs.h includes information for ARM64 that is not yet formally
published. The TLFS is available here:

docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/reference/tlfs

mshyperv.h defines Linux-specific structures and routines for
interacting with Hyper-V on ARM64, and #includes the architecture-
independent part of mshyperv.h in include/asm-generic.

Use these definitions to provide utility functions to make
Hyper-V hypercalls and to get and set Hyper-V provided
registers associated with a virtual processor.

Signed-off-by: Michael Kelley <mikelley@microsoft.com>
Reviewed-by: Sunil Muthuswamy <sunilmut@microsoft.com>
Acked-by: Marc Zyngier <maz@kernel.org>
Acked-by: Mark Rutland <mark.rutland@arm.com>
Acked-by: Catalin Marinas <catalin.marinas@arm.com>
Link: https://lore.kernel.org/r/1628092359-61351-2-git-send-email-mikelley@microsoft.com
Signed-off-by: Wei Liu <wei.liu@kernel.org>

authored by

Michael Kelley and committed by
Wei Liu
57d276bb e5d9b714

+258
+3
MAINTAINERS
··· 8594 8594 F: Documentation/ABI/stable/sysfs-bus-vmbus 8595 8595 F: Documentation/ABI/testing/debugfs-hyperv 8596 8596 F: Documentation/networking/device_drivers/ethernet/microsoft/netvsc.rst 8597 + F: arch/arm64/hyperv 8598 + F: arch/arm64/include/asm/hyperv-tlfs.h 8599 + F: arch/arm64/include/asm/mshyperv.h 8597 8600 F: arch/x86/hyperv 8598 8601 F: arch/x86/include/asm/hyperv-tlfs.h 8599 8602 F: arch/x86/include/asm/mshyperv.h
+1
arch/arm64/Kbuild
··· 2 2 obj-y += kernel/ mm/ net/ 3 3 obj-$(CONFIG_KVM) += kvm/ 4 4 obj-$(CONFIG_XEN) += xen/ 5 + obj-$(subst m,y,$(CONFIG_HYPERV)) += hyperv/ 5 6 obj-$(CONFIG_CRYPTO) += crypto/
+2
arch/arm64/hyperv/Makefile
··· 1 + # SPDX-License-Identifier: GPL-2.0 2 + obj-y := hv_core.o
+129
arch/arm64/hyperv/hv_core.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + /* 4 + * Low level utility routines for interacting with Hyper-V. 5 + * 6 + * Copyright (C) 2021, Microsoft, Inc. 7 + * 8 + * Author : Michael Kelley <mikelley@microsoft.com> 9 + */ 10 + 11 + #include <linux/types.h> 12 + #include <linux/export.h> 13 + #include <linux/mm.h> 14 + #include <linux/hyperv.h> 15 + #include <linux/arm-smccc.h> 16 + #include <linux/module.h> 17 + #include <asm-generic/bug.h> 18 + #include <asm/hyperv-tlfs.h> 19 + #include <asm/mshyperv.h> 20 + 21 + /* 22 + * hv_do_hypercall- Invoke the specified hypercall 23 + */ 24 + u64 hv_do_hypercall(u64 control, void *input, void *output) 25 + { 26 + struct arm_smccc_res res; 27 + u64 input_address; 28 + u64 output_address; 29 + 30 + input_address = input ? virt_to_phys(input) : 0; 31 + output_address = output ? virt_to_phys(output) : 0; 32 + 33 + arm_smccc_1_1_hvc(HV_FUNC_ID, control, 34 + input_address, output_address, &res); 35 + return res.a0; 36 + } 37 + EXPORT_SYMBOL_GPL(hv_do_hypercall); 38 + 39 + /* 40 + * hv_do_fast_hypercall8 -- Invoke the specified hypercall 41 + * with arguments in registers instead of physical memory. 42 + * Avoids the overhead of virt_to_phys for simple hypercalls. 43 + */ 44 + 45 + u64 hv_do_fast_hypercall8(u16 code, u64 input) 46 + { 47 + struct arm_smccc_res res; 48 + u64 control; 49 + 50 + control = (u64)code | HV_HYPERCALL_FAST_BIT; 51 + 52 + arm_smccc_1_1_hvc(HV_FUNC_ID, control, input, &res); 53 + return res.a0; 54 + } 55 + EXPORT_SYMBOL_GPL(hv_do_fast_hypercall8); 56 + 57 + /* 58 + * Set a single VP register to a 64-bit value. 59 + */ 60 + void hv_set_vpreg(u32 msr, u64 value) 61 + { 62 + struct arm_smccc_res res; 63 + 64 + arm_smccc_1_1_hvc(HV_FUNC_ID, 65 + HVCALL_SET_VP_REGISTERS | HV_HYPERCALL_FAST_BIT | 66 + HV_HYPERCALL_REP_COMP_1, 67 + HV_PARTITION_ID_SELF, 68 + HV_VP_INDEX_SELF, 69 + msr, 70 + 0, 71 + value, 72 + 0, 73 + &res); 74 + 75 + /* 76 + * Something is fundamentally broken in the hypervisor if 77 + * setting a VP register fails. There's really no way to 78 + * continue as a guest VM, so panic. 79 + */ 80 + BUG_ON(!hv_result_success(res.a0)); 81 + } 82 + EXPORT_SYMBOL_GPL(hv_set_vpreg); 83 + 84 + /* 85 + * Get the value of a single VP register. One version 86 + * returns just 64 bits and another returns the full 128 bits. 87 + * The two versions are separate to avoid complicating the 88 + * calling sequence for the more frequently used 64 bit version. 89 + */ 90 + 91 + void hv_get_vpreg_128(u32 msr, struct hv_get_vp_registers_output *result) 92 + { 93 + struct arm_smccc_1_2_regs args; 94 + struct arm_smccc_1_2_regs res; 95 + 96 + args.a0 = HV_FUNC_ID; 97 + args.a1 = HVCALL_GET_VP_REGISTERS | HV_HYPERCALL_FAST_BIT | 98 + HV_HYPERCALL_REP_COMP_1; 99 + args.a2 = HV_PARTITION_ID_SELF; 100 + args.a3 = HV_VP_INDEX_SELF; 101 + args.a4 = msr; 102 + 103 + /* 104 + * Use the SMCCC 1.2 interface because the results are in registers 105 + * beyond X0-X3. 106 + */ 107 + arm_smccc_1_2_hvc(&args, &res); 108 + 109 + /* 110 + * Something is fundamentally broken in the hypervisor if 111 + * getting a VP register fails. There's really no way to 112 + * continue as a guest VM, so panic. 113 + */ 114 + BUG_ON(!hv_result_success(res.a0)); 115 + 116 + result->as64.low = res.a6; 117 + result->as64.high = res.a7; 118 + } 119 + EXPORT_SYMBOL_GPL(hv_get_vpreg_128); 120 + 121 + u64 hv_get_vpreg(u32 msr) 122 + { 123 + struct hv_get_vp_registers_output output; 124 + 125 + hv_get_vpreg_128(msr, &output); 126 + 127 + return output.as64.low; 128 + } 129 + EXPORT_SYMBOL_GPL(hv_get_vpreg);
+69
arch/arm64/include/asm/hyperv-tlfs.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + 3 + /* 4 + * This file contains definitions from the Hyper-V Hypervisor Top-Level 5 + * Functional Specification (TLFS): 6 + * https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/reference/tlfs 7 + * 8 + * Copyright (C) 2021, Microsoft, Inc. 9 + * 10 + * Author : Michael Kelley <mikelley@microsoft.com> 11 + */ 12 + 13 + #ifndef _ASM_HYPERV_TLFS_H 14 + #define _ASM_HYPERV_TLFS_H 15 + 16 + #include <linux/types.h> 17 + 18 + /* 19 + * All data structures defined in the TLFS that are shared between Hyper-V 20 + * and a guest VM use Little Endian byte ordering. This matches the default 21 + * byte ordering of Linux running on ARM64, so no special handling is required. 22 + */ 23 + 24 + /* 25 + * These Hyper-V registers provide information equivalent to the CPUID 26 + * instruction on x86/x64. 27 + */ 28 + #define HV_REGISTER_HYPERVISOR_VERSION 0x00000100 /*CPUID 0x40000002 */ 29 + #define HV_REGISTER_FEATURES 0x00000200 /*CPUID 0x40000003 */ 30 + #define HV_REGISTER_ENLIGHTENMENTS 0x00000201 /*CPUID 0x40000004 */ 31 + 32 + /* 33 + * Group C Features. See the asm-generic version of hyperv-tlfs.h 34 + * for a description of Feature Groups. 35 + */ 36 + 37 + /* Crash MSRs available */ 38 + #define HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE BIT(8) 39 + 40 + /* STIMER direct mode is available */ 41 + #define HV_STIMER_DIRECT_MODE_AVAILABLE BIT(13) 42 + 43 + /* 44 + * Synthetic register definitions equivalent to MSRs on x86/x64 45 + */ 46 + #define HV_REGISTER_CRASH_P0 0x00000210 47 + #define HV_REGISTER_CRASH_P1 0x00000211 48 + #define HV_REGISTER_CRASH_P2 0x00000212 49 + #define HV_REGISTER_CRASH_P3 0x00000213 50 + #define HV_REGISTER_CRASH_P4 0x00000214 51 + #define HV_REGISTER_CRASH_CTL 0x00000215 52 + 53 + #define HV_REGISTER_GUEST_OSID 0x00090002 54 + #define HV_REGISTER_VP_INDEX 0x00090003 55 + #define HV_REGISTER_TIME_REF_COUNT 0x00090004 56 + #define HV_REGISTER_REFERENCE_TSC 0x00090017 57 + 58 + #define HV_REGISTER_SINT0 0x000A0000 59 + #define HV_REGISTER_SCONTROL 0x000A0010 60 + #define HV_REGISTER_SIEFP 0x000A0012 61 + #define HV_REGISTER_SIMP 0x000A0013 62 + #define HV_REGISTER_EOM 0x000A0014 63 + 64 + #define HV_REGISTER_STIMER0_CONFIG 0x000B0000 65 + #define HV_REGISTER_STIMER0_COUNT 0x000B0001 66 + 67 + #include <asm-generic/hyperv-tlfs.h> 68 + 69 + #endif
+54
arch/arm64/include/asm/mshyperv.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + 3 + /* 4 + * Linux-specific definitions for managing interactions with Microsoft's 5 + * Hyper-V hypervisor. The definitions in this file are specific to 6 + * the ARM64 architecture. See include/asm-generic/mshyperv.h for 7 + * definitions are that architecture independent. 8 + * 9 + * Definitions that are specified in the Hyper-V Top Level Functional 10 + * Spec (TLFS) should not go in this file, but should instead go in 11 + * hyperv-tlfs.h. 12 + * 13 + * Copyright (C) 2021, Microsoft, Inc. 14 + * 15 + * Author : Michael Kelley <mikelley@microsoft.com> 16 + */ 17 + 18 + #ifndef _ASM_MSHYPERV_H 19 + #define _ASM_MSHYPERV_H 20 + 21 + #include <linux/types.h> 22 + #include <linux/arm-smccc.h> 23 + #include <asm/hyperv-tlfs.h> 24 + 25 + /* 26 + * Declare calls to get and set Hyper-V VP register values on ARM64, which 27 + * requires a hypercall. 28 + */ 29 + 30 + void hv_set_vpreg(u32 reg, u64 value); 31 + u64 hv_get_vpreg(u32 reg); 32 + void hv_get_vpreg_128(u32 reg, struct hv_get_vp_registers_output *result); 33 + 34 + static inline void hv_set_register(unsigned int reg, u64 value) 35 + { 36 + hv_set_vpreg(reg, value); 37 + } 38 + 39 + static inline u64 hv_get_register(unsigned int reg) 40 + { 41 + return hv_get_vpreg(reg); 42 + } 43 + 44 + /* SMCCC hypercall parameters */ 45 + #define HV_SMCCC_FUNC_NUMBER 1 46 + #define HV_FUNC_ID ARM_SMCCC_CALL_VAL( \ 47 + ARM_SMCCC_STD_CALL, \ 48 + ARM_SMCCC_SMC_64, \ 49 + ARM_SMCCC_OWNER_VENDOR_HYP, \ 50 + HV_SMCCC_FUNC_NUMBER) 51 + 52 + #include <asm-generic/mshyperv.h> 53 + 54 + #endif