319 lines · c
1/* SPDX-License-Identifier: GPL-2.0 */2 3/*4 * Linux-specific definitions for managing interactions with Microsoft's5 * Hyper-V hypervisor. The definitions in this file are architecture6 * independent. See arch/<arch>/include/asm/mshyperv.h for definitions7 * that are specific to architecture <arch>.8 *9 * Definitions that are specified in the Hyper-V Top Level Functional10 * Spec (TLFS) should not go in this file, but should instead go in11 * hyperv-tlfs.h.12 *13 * Copyright (C) 2019, Microsoft, Inc.14 *15 * Author : Michael Kelley <mikelley@microsoft.com>16 */17 18#ifndef _ASM_GENERIC_MSHYPERV_H19#define _ASM_GENERIC_MSHYPERV_H20 21#include <linux/types.h>22#include <linux/atomic.h>23#include <linux/bitops.h>24#include <acpi/acpi_numa.h>25#include <linux/cpumask.h>26#include <linux/nmi.h>27#include <asm/ptrace.h>28#include <asm/hyperv-tlfs.h>29 30#define VTPM_BASE_ADDRESS 0xfed4000031 32struct ms_hyperv_info {33 u32 features;34 u32 priv_high;35 u32 misc_features;36 u32 hints;37 u32 nested_features;38 u32 max_vp_index;39 u32 max_lp_index;40 u8 vtl;41 union {42 u32 isolation_config_a;43 struct {44 u32 paravisor_present : 1;45 u32 reserved_a1 : 31;46 };47 };48 union {49 u32 isolation_config_b;50 struct {51 u32 cvm_type : 4;52 u32 reserved_b1 : 1;53 u32 shared_gpa_boundary_active : 1;54 u32 shared_gpa_boundary_bits : 6;55 u32 reserved_b2 : 20;56 };57 };58 u64 shared_gpa_boundary;59};60extern struct ms_hyperv_info ms_hyperv;61extern bool hv_nested;62 63extern void * __percpu *hyperv_pcpu_input_arg;64extern void * __percpu *hyperv_pcpu_output_arg;65 66extern u64 hv_do_hypercall(u64 control, void *inputaddr, void *outputaddr);67extern u64 hv_do_fast_hypercall8(u16 control, u64 input8);68bool hv_isolation_type_snp(void);69bool hv_isolation_type_tdx(void);70 71static inline struct hv_proximity_domain_info hv_numa_node_to_pxm_info(int node)72{73 struct hv_proximity_domain_info pxm_info = {};74 75 if (node != NUMA_NO_NODE) {76 pxm_info.domain_id = node_to_pxm(node);77 pxm_info.flags.proximity_info_valid = 1;78 pxm_info.flags.proximity_preferred = 1;79 }80 81 return pxm_info;82}83 84/* Helper functions that provide a consistent pattern for checking Hyper-V hypercall status. */85static inline int hv_result(u64 status)86{87 return status & HV_HYPERCALL_RESULT_MASK;88}89 90static inline bool hv_result_success(u64 status)91{92 return hv_result(status) == HV_STATUS_SUCCESS;93}94 95static inline unsigned int hv_repcomp(u64 status)96{97 /* Bits [43:32] of status have 'Reps completed' data. */98 return (status & HV_HYPERCALL_REP_COMP_MASK) >>99 HV_HYPERCALL_REP_COMP_OFFSET;100}101 102/*103 * Rep hypercalls. Callers of this functions are supposed to ensure that104 * rep_count and varhead_size comply with Hyper-V hypercall definition.105 */106static inline u64 hv_do_rep_hypercall(u16 code, u16 rep_count, u16 varhead_size,107 void *input, void *output)108{109 u64 control = code;110 u64 status;111 u16 rep_comp;112 113 control |= (u64)varhead_size << HV_HYPERCALL_VARHEAD_OFFSET;114 control |= (u64)rep_count << HV_HYPERCALL_REP_COMP_OFFSET;115 116 do {117 status = hv_do_hypercall(control, input, output);118 if (!hv_result_success(status))119 return status;120 121 rep_comp = hv_repcomp(status);122 123 control &= ~HV_HYPERCALL_REP_START_MASK;124 control |= (u64)rep_comp << HV_HYPERCALL_REP_START_OFFSET;125 126 touch_nmi_watchdog();127 } while (rep_comp < rep_count);128 129 return status;130}131 132/* Generate the guest OS identifier as described in the Hyper-V TLFS */133static inline u64 hv_generate_guest_id(u64 kernel_version)134{135 u64 guest_id;136 137 guest_id = (((u64)HV_LINUX_VENDOR_ID) << 48);138 guest_id |= (kernel_version << 16);139 140 return guest_id;141}142 143/* Free the message slot and signal end-of-message if required */144static inline void vmbus_signal_eom(struct hv_message *msg, u32 old_msg_type)145{146 /*147 * On crash we're reading some other CPU's message page and we need148 * to be careful: this other CPU may already had cleared the header149 * and the host may already had delivered some other message there.150 * In case we blindly write msg->header.message_type we're going151 * to lose it. We can still lose a message of the same type but152 * we count on the fact that there can only be one153 * CHANNELMSG_UNLOAD_RESPONSE and we don't care about other messages154 * on crash.155 */156 if (cmpxchg(&msg->header.message_type, old_msg_type,157 HVMSG_NONE) != old_msg_type)158 return;159 160 /*161 * The cmxchg() above does an implicit memory barrier to162 * ensure the write to MessageType (ie set to163 * HVMSG_NONE) happens before we read the164 * MessagePending and EOMing. Otherwise, the EOMing165 * will not deliver any more messages since there is166 * no empty slot167 */168 if (msg->header.message_flags.msg_pending) {169 /*170 * This will cause message queue rescan to171 * possibly deliver another msg from the172 * hypervisor173 */174 hv_set_msr(HV_MSR_EOM, 0);175 }176}177 178int hv_get_hypervisor_version(union hv_hypervisor_version_info *info);179 180void hv_setup_vmbus_handler(void (*handler)(void));181void hv_remove_vmbus_handler(void);182void hv_setup_stimer0_handler(void (*handler)(void));183void hv_remove_stimer0_handler(void);184 185void hv_setup_kexec_handler(void (*handler)(void));186void hv_remove_kexec_handler(void);187void hv_setup_crash_handler(void (*handler)(struct pt_regs *regs));188void hv_remove_crash_handler(void);189 190extern int vmbus_interrupt;191extern int vmbus_irq;192 193extern bool hv_root_partition;194 195#if IS_ENABLED(CONFIG_HYPERV)196/*197 * Hypervisor's notion of virtual processor ID is different from198 * Linux' notion of CPU ID. This information can only be retrieved199 * in the context of the calling CPU. Setup a map for easy access200 * to this information.201 */202extern u32 *hv_vp_index;203extern u32 hv_max_vp_index;204 205extern u64 (*hv_read_reference_counter)(void);206 207/* Sentinel value for an uninitialized entry in hv_vp_index array */208#define VP_INVAL U32_MAX209 210int __init hv_common_init(void);211void __init hv_common_free(void);212void __init ms_hyperv_late_init(void);213int hv_common_cpu_init(unsigned int cpu);214int hv_common_cpu_die(unsigned int cpu);215 216void *hv_alloc_hyperv_page(void);217void *hv_alloc_hyperv_zeroed_page(void);218void hv_free_hyperv_page(void *addr);219 220/**221 * hv_cpu_number_to_vp_number() - Map CPU to VP.222 * @cpu_number: CPU number in Linux terms223 *224 * This function returns the mapping between the Linux processor225 * number and the hypervisor's virtual processor number, useful226 * in making hypercalls and such that talk about specific227 * processors.228 *229 * Return: Virtual processor number in Hyper-V terms230 */231static inline int hv_cpu_number_to_vp_number(int cpu_number)232{233 return hv_vp_index[cpu_number];234}235 236static inline int __cpumask_to_vpset(struct hv_vpset *vpset,237 const struct cpumask *cpus,238 bool (*func)(int cpu))239{240 int cpu, vcpu, vcpu_bank, vcpu_offset, nr_bank = 1;241 int max_vcpu_bank = hv_max_vp_index / HV_VCPUS_PER_SPARSE_BANK;242 243 /* vpset.valid_bank_mask can represent up to HV_MAX_SPARSE_VCPU_BANKS banks */244 if (max_vcpu_bank >= HV_MAX_SPARSE_VCPU_BANKS)245 return 0;246 247 /*248 * Clear all banks up to the maximum possible bank as hv_tlb_flush_ex249 * structs are not cleared between calls, we risk flushing unneeded250 * vCPUs otherwise.251 */252 for (vcpu_bank = 0; vcpu_bank <= max_vcpu_bank; vcpu_bank++)253 vpset->bank_contents[vcpu_bank] = 0;254 255 /*256 * Some banks may end up being empty but this is acceptable.257 */258 for_each_cpu(cpu, cpus) {259 if (func && func(cpu))260 continue;261 vcpu = hv_cpu_number_to_vp_number(cpu);262 if (vcpu == VP_INVAL)263 return -1;264 vcpu_bank = vcpu / HV_VCPUS_PER_SPARSE_BANK;265 vcpu_offset = vcpu % HV_VCPUS_PER_SPARSE_BANK;266 __set_bit(vcpu_offset, (unsigned long *)267 &vpset->bank_contents[vcpu_bank]);268 if (vcpu_bank >= nr_bank)269 nr_bank = vcpu_bank + 1;270 }271 vpset->valid_bank_mask = GENMASK_ULL(nr_bank - 1, 0);272 return nr_bank;273}274 275/*276 * Convert a Linux cpumask into a Hyper-V VPset. In the _skip variant,277 * 'func' is called for each CPU present in cpumask. If 'func' returns278 * true, that CPU is skipped -- i.e., that CPU from cpumask is *not*279 * added to the Hyper-V VPset. If 'func' is NULL, no CPUs are280 * skipped.281 */282static inline int cpumask_to_vpset(struct hv_vpset *vpset,283 const struct cpumask *cpus)284{285 return __cpumask_to_vpset(vpset, cpus, NULL);286}287 288static inline int cpumask_to_vpset_skip(struct hv_vpset *vpset,289 const struct cpumask *cpus,290 bool (*func)(int cpu))291{292 return __cpumask_to_vpset(vpset, cpus, func);293}294 295void hyperv_report_panic(struct pt_regs *regs, long err, bool in_die);296bool hv_is_hyperv_initialized(void);297bool hv_is_hibernation_supported(void);298enum hv_isolation_type hv_get_isolation_type(void);299bool hv_is_isolation_supported(void);300bool hv_isolation_type_snp(void);301u64 hv_ghcb_hypercall(u64 control, void *input, void *output, u32 input_size);302u64 hv_tdx_hypercall(u64 control, u64 param1, u64 param2);303void hyperv_cleanup(void);304bool hv_query_ext_cap(u64 cap_query);305void hv_setup_dma_ops(struct device *dev, bool coherent);306#else /* CONFIG_HYPERV */307static inline bool hv_is_hyperv_initialized(void) { return false; }308static inline bool hv_is_hibernation_supported(void) { return false; }309static inline void hyperv_cleanup(void) {}310static inline void ms_hyperv_late_init(void) {}311static inline bool hv_is_isolation_supported(void) { return false; }312static inline enum hv_isolation_type hv_get_isolation_type(void)313{314 return HV_ISOLATION_TYPE_NONE;315}316#endif /* CONFIG_HYPERV */317 318#endif319