1765e33f5SMichael Kelley /* SPDX-License-Identifier: GPL-2.0 */ 2765e33f5SMichael Kelley 3765e33f5SMichael Kelley /* 4765e33f5SMichael Kelley * Linux-specific definitions for managing interactions with Microsoft's 5765e33f5SMichael Kelley * Hyper-V hypervisor. The definitions in this file are architecture 6765e33f5SMichael Kelley * independent. See arch/<arch>/include/asm/mshyperv.h for definitions 7765e33f5SMichael Kelley * that are specific to architecture <arch>. 8765e33f5SMichael Kelley * 9765e33f5SMichael Kelley * Definitions that are specified in the Hyper-V Top Level Functional 10765e33f5SMichael Kelley * Spec (TLFS) should not go in this file, but should instead go in 11765e33f5SMichael Kelley * hyperv-tlfs.h. 12765e33f5SMichael Kelley * 13765e33f5SMichael Kelley * Copyright (C) 2019, Microsoft, Inc. 14765e33f5SMichael Kelley * 15765e33f5SMichael Kelley * Author : Michael Kelley <mikelley@microsoft.com> 16765e33f5SMichael Kelley */ 17765e33f5SMichael Kelley 18765e33f5SMichael Kelley #ifndef _ASM_GENERIC_MSHYPERV_H 19765e33f5SMichael Kelley #define _ASM_GENERIC_MSHYPERV_H 20765e33f5SMichael Kelley 21765e33f5SMichael Kelley #include <linux/types.h> 22765e33f5SMichael Kelley #include <linux/atomic.h> 23765e33f5SMichael Kelley #include <linux/bitops.h> 24765e33f5SMichael Kelley #include <linux/cpumask.h> 25ba3f5839SMichael Kelley #include <linux/nmi.h> 26765e33f5SMichael Kelley #include <asm/ptrace.h> 27765e33f5SMichael Kelley #include <asm/hyperv-tlfs.h> 28765e33f5SMichael Kelley 29812b0597SMichael Kelley #define VTPM_BASE_ADDRESS 0xfed40000 30812b0597SMichael Kelley 31765e33f5SMichael Kelley struct ms_hyperv_info { 32765e33f5SMichael Kelley u32 features; 336dc2a774SSunil Muthuswamy u32 priv_high; 34765e33f5SMichael Kelley u32 misc_features; 35765e33f5SMichael Kelley u32 hints; 36765e33f5SMichael Kelley u32 nested_features; 37765e33f5SMichael Kelley u32 max_vp_index; 38765e33f5SMichael Kelley u32 max_lp_index; 39d6e2d652STianyu Lan union { 40a6c76bb0SAndrea Parri (Microsoft) u32 isolation_config_a; 41d6e2d652STianyu Lan struct { 42d6e2d652STianyu Lan u32 paravisor_present : 1; 43d6e2d652STianyu Lan u32 reserved_a1 : 31; 44d6e2d652STianyu Lan }; 45d6e2d652STianyu Lan }; 46af788f35STianyu Lan union { 47a6c76bb0SAndrea Parri (Microsoft) u32 isolation_config_b; 48af788f35STianyu Lan struct { 49af788f35STianyu Lan u32 cvm_type : 4; 50d6e2d652STianyu Lan u32 reserved_b1 : 1; 51af788f35STianyu Lan u32 shared_gpa_boundary_active : 1; 52af788f35STianyu Lan u32 shared_gpa_boundary_bits : 6; 53d6e2d652STianyu Lan u32 reserved_b2 : 20; 54af788f35STianyu Lan }; 55af788f35STianyu Lan }; 56af788f35STianyu Lan u64 shared_gpa_boundary; 578387ce06STianyu Lan u8 vtl; 58765e33f5SMichael Kelley }; 59765e33f5SMichael Kelley extern struct ms_hyperv_info ms_hyperv; 60c4bdf94fSJinank Jain extern bool hv_nested; 61765e33f5SMichael Kelley 62db3c65bcSMichael Kelley extern void * __percpu *hyperv_pcpu_input_arg; 63db3c65bcSMichael Kelley extern void * __percpu *hyperv_pcpu_output_arg; 64afca4d95SMichael Kelley 65765e33f5SMichael Kelley extern u64 hv_do_hypercall(u64 control, void *inputaddr, void *outputaddr); 66765e33f5SMichael Kelley extern u64 hv_do_fast_hypercall8(u16 control, u64 input8); 67*e3131f1cSDexuan Cui bool hv_isolation_type_snp(void); 6808e9d120SDexuan Cui bool hv_isolation_type_tdx(void); 69765e33f5SMichael Kelley 70753ed9c9SJoseph Salisbury /* Helper functions that provide a consistent pattern for checking Hyper-V hypercall status. */ 71753ed9c9SJoseph Salisbury static inline int hv_result(u64 status) 72753ed9c9SJoseph Salisbury { 73753ed9c9SJoseph Salisbury return status & HV_HYPERCALL_RESULT_MASK; 74753ed9c9SJoseph Salisbury } 75753ed9c9SJoseph Salisbury 76753ed9c9SJoseph Salisbury static inline bool hv_result_success(u64 status) 77753ed9c9SJoseph Salisbury { 78753ed9c9SJoseph Salisbury return hv_result(status) == HV_STATUS_SUCCESS; 79753ed9c9SJoseph Salisbury } 80753ed9c9SJoseph Salisbury 81753ed9c9SJoseph Salisbury static inline unsigned int hv_repcomp(u64 status) 82753ed9c9SJoseph Salisbury { 83753ed9c9SJoseph Salisbury /* Bits [43:32] of status have 'Reps completed' data. */ 84753ed9c9SJoseph Salisbury return (status & HV_HYPERCALL_REP_COMP_MASK) >> 85753ed9c9SJoseph Salisbury HV_HYPERCALL_REP_COMP_OFFSET; 86753ed9c9SJoseph Salisbury } 87753ed9c9SJoseph Salisbury 886523592cSJoseph Salisbury /* 896523592cSJoseph Salisbury * Rep hypercalls. Callers of this functions are supposed to ensure that 906523592cSJoseph Salisbury * rep_count and varhead_size comply with Hyper-V hypercall definition. 916523592cSJoseph Salisbury */ 926523592cSJoseph Salisbury static inline u64 hv_do_rep_hypercall(u16 code, u16 rep_count, u16 varhead_size, 936523592cSJoseph Salisbury void *input, void *output) 946523592cSJoseph Salisbury { 956523592cSJoseph Salisbury u64 control = code; 966523592cSJoseph Salisbury u64 status; 976523592cSJoseph Salisbury u16 rep_comp; 986523592cSJoseph Salisbury 996523592cSJoseph Salisbury control |= (u64)varhead_size << HV_HYPERCALL_VARHEAD_OFFSET; 1006523592cSJoseph Salisbury control |= (u64)rep_count << HV_HYPERCALL_REP_COMP_OFFSET; 1016523592cSJoseph Salisbury 1026523592cSJoseph Salisbury do { 1036523592cSJoseph Salisbury status = hv_do_hypercall(control, input, output); 104753ed9c9SJoseph Salisbury if (!hv_result_success(status)) 1056523592cSJoseph Salisbury return status; 1066523592cSJoseph Salisbury 107753ed9c9SJoseph Salisbury rep_comp = hv_repcomp(status); 1086523592cSJoseph Salisbury 1096523592cSJoseph Salisbury control &= ~HV_HYPERCALL_REP_START_MASK; 1106523592cSJoseph Salisbury control |= (u64)rep_comp << HV_HYPERCALL_REP_START_OFFSET; 1116523592cSJoseph Salisbury 1126523592cSJoseph Salisbury touch_nmi_watchdog(); 1136523592cSJoseph Salisbury } while (rep_comp < rep_count); 1146523592cSJoseph Salisbury 1156523592cSJoseph Salisbury return status; 1166523592cSJoseph Salisbury } 117765e33f5SMichael Kelley 118765e33f5SMichael Kelley /* Generate the guest OS identifier as described in the Hyper-V TLFS */ 119d5ebde1eSLi kunyu static inline u64 hv_generate_guest_id(u64 kernel_version) 120765e33f5SMichael Kelley { 121d5ebde1eSLi kunyu u64 guest_id; 122765e33f5SMichael Kelley 123d5ebde1eSLi kunyu guest_id = (((u64)HV_LINUX_VENDOR_ID) << 48); 124765e33f5SMichael Kelley guest_id |= (kernel_version << 16); 125765e33f5SMichael Kelley 126765e33f5SMichael Kelley return guest_id; 127765e33f5SMichael Kelley } 128765e33f5SMichael Kelley 129765e33f5SMichael Kelley /* Free the message slot and signal end-of-message if required */ 130765e33f5SMichael Kelley static inline void vmbus_signal_eom(struct hv_message *msg, u32 old_msg_type) 131765e33f5SMichael Kelley { 132765e33f5SMichael Kelley /* 133765e33f5SMichael Kelley * On crash we're reading some other CPU's message page and we need 134765e33f5SMichael Kelley * to be careful: this other CPU may already had cleared the header 135765e33f5SMichael Kelley * and the host may already had delivered some other message there. 136765e33f5SMichael Kelley * In case we blindly write msg->header.message_type we're going 137765e33f5SMichael Kelley * to lose it. We can still lose a message of the same type but 138765e33f5SMichael Kelley * we count on the fact that there can only be one 139765e33f5SMichael Kelley * CHANNELMSG_UNLOAD_RESPONSE and we don't care about other messages 140765e33f5SMichael Kelley * on crash. 141765e33f5SMichael Kelley */ 142765e33f5SMichael Kelley if (cmpxchg(&msg->header.message_type, old_msg_type, 143765e33f5SMichael Kelley HVMSG_NONE) != old_msg_type) 144765e33f5SMichael Kelley return; 145765e33f5SMichael Kelley 146765e33f5SMichael Kelley /* 147765e33f5SMichael Kelley * The cmxchg() above does an implicit memory barrier to 148765e33f5SMichael Kelley * ensure the write to MessageType (ie set to 149765e33f5SMichael Kelley * HVMSG_NONE) happens before we read the 150765e33f5SMichael Kelley * MessagePending and EOMing. Otherwise, the EOMing 151765e33f5SMichael Kelley * will not deliver any more messages since there is 152765e33f5SMichael Kelley * no empty slot 153765e33f5SMichael Kelley */ 154765e33f5SMichael Kelley if (msg->header.message_flags.msg_pending) { 155765e33f5SMichael Kelley /* 156765e33f5SMichael Kelley * This will cause message queue rescan to 157765e33f5SMichael Kelley * possibly deliver another msg from the 158765e33f5SMichael Kelley * hypervisor 159765e33f5SMichael Kelley */ 160f3c5e63cSMichael Kelley hv_set_register(HV_REGISTER_EOM, 0); 161765e33f5SMichael Kelley } 162765e33f5SMichael Kelley } 163765e33f5SMichael Kelley 164d608715dSMichael Kelley void hv_setup_vmbus_handler(void (*handler)(void)); 165d608715dSMichael Kelley void hv_remove_vmbus_handler(void); 166a620bbaaSMichael Kelley void hv_setup_stimer0_handler(void (*handler)(void)); 167a620bbaaSMichael Kelley void hv_remove_stimer0_handler(void); 168765e33f5SMichael Kelley 169765e33f5SMichael Kelley void hv_setup_kexec_handler(void (*handler)(void)); 170765e33f5SMichael Kelley void hv_remove_kexec_handler(void); 171765e33f5SMichael Kelley void hv_setup_crash_handler(void (*handler)(struct pt_regs *regs)); 172765e33f5SMichael Kelley void hv_remove_crash_handler(void); 173765e33f5SMichael Kelley 174626b901fSMichael Kelley extern int vmbus_interrupt; 175d608715dSMichael Kelley extern int vmbus_irq; 176626b901fSMichael Kelley 177afca4d95SMichael Kelley extern bool hv_root_partition; 178afca4d95SMichael Kelley 179765e33f5SMichael Kelley #if IS_ENABLED(CONFIG_HYPERV) 180765e33f5SMichael Kelley /* 181765e33f5SMichael Kelley * Hypervisor's notion of virtual processor ID is different from 182765e33f5SMichael Kelley * Linux' notion of CPU ID. This information can only be retrieved 183765e33f5SMichael Kelley * in the context of the calling CPU. Setup a map for easy access 184765e33f5SMichael Kelley * to this information. 185765e33f5SMichael Kelley */ 186765e33f5SMichael Kelley extern u32 *hv_vp_index; 187765e33f5SMichael Kelley extern u32 hv_max_vp_index; 188765e33f5SMichael Kelley 18931e5e646SMichael Kelley extern u64 (*hv_read_reference_counter)(void); 19031e5e646SMichael Kelley 191765e33f5SMichael Kelley /* Sentinel value for an uninitialized entry in hv_vp_index array */ 192765e33f5SMichael Kelley #define VP_INVAL U32_MAX 193765e33f5SMichael Kelley 194afca4d95SMichael Kelley int __init hv_common_init(void); 195afca4d95SMichael Kelley void __init hv_common_free(void); 196afca4d95SMichael Kelley int hv_common_cpu_init(unsigned int cpu); 197afca4d95SMichael Kelley int hv_common_cpu_die(unsigned int cpu); 198afca4d95SMichael Kelley 199ca48739eSMichael Kelley void *hv_alloc_hyperv_page(void); 200ca48739eSMichael Kelley void *hv_alloc_hyperv_zeroed_page(void); 201ca48739eSMichael Kelley void hv_free_hyperv_page(unsigned long addr); 202ca48739eSMichael Kelley 203765e33f5SMichael Kelley /** 204765e33f5SMichael Kelley * hv_cpu_number_to_vp_number() - Map CPU to VP. 205765e33f5SMichael Kelley * @cpu_number: CPU number in Linux terms 206765e33f5SMichael Kelley * 207765e33f5SMichael Kelley * This function returns the mapping between the Linux processor 208765e33f5SMichael Kelley * number and the hypervisor's virtual processor number, useful 209765e33f5SMichael Kelley * in making hypercalls and such that talk about specific 210765e33f5SMichael Kelley * processors. 211765e33f5SMichael Kelley * 212765e33f5SMichael Kelley * Return: Virtual processor number in Hyper-V terms 213765e33f5SMichael Kelley */ 214765e33f5SMichael Kelley static inline int hv_cpu_number_to_vp_number(int cpu_number) 215765e33f5SMichael Kelley { 216765e33f5SMichael Kelley return hv_vp_index[cpu_number]; 217765e33f5SMichael Kelley } 218765e33f5SMichael Kelley 2197ad9bb9dSWei Liu static inline int __cpumask_to_vpset(struct hv_vpset *vpset, 2207ad9bb9dSWei Liu const struct cpumask *cpus, 221d7b6ba96SMichael Kelley bool (*func)(int cpu)) 222765e33f5SMichael Kelley { 223765e33f5SMichael Kelley int cpu, vcpu, vcpu_bank, vcpu_offset, nr_bank = 1; 224bd19c94aSVitaly Kuznetsov int max_vcpu_bank = hv_max_vp_index / HV_VCPUS_PER_SPARSE_BANK; 225765e33f5SMichael Kelley 226bd19c94aSVitaly Kuznetsov /* vpset.valid_bank_mask can represent up to HV_MAX_SPARSE_VCPU_BANKS banks */ 227bd19c94aSVitaly Kuznetsov if (max_vcpu_bank >= HV_MAX_SPARSE_VCPU_BANKS) 228765e33f5SMichael Kelley return 0; 229765e33f5SMichael Kelley 230765e33f5SMichael Kelley /* 231765e33f5SMichael Kelley * Clear all banks up to the maximum possible bank as hv_tlb_flush_ex 232765e33f5SMichael Kelley * structs are not cleared between calls, we risk flushing unneeded 233765e33f5SMichael Kelley * vCPUs otherwise. 234765e33f5SMichael Kelley */ 235bd19c94aSVitaly Kuznetsov for (vcpu_bank = 0; vcpu_bank <= max_vcpu_bank; vcpu_bank++) 236765e33f5SMichael Kelley vpset->bank_contents[vcpu_bank] = 0; 237765e33f5SMichael Kelley 238765e33f5SMichael Kelley /* 239765e33f5SMichael Kelley * Some banks may end up being empty but this is acceptable. 240765e33f5SMichael Kelley */ 241765e33f5SMichael Kelley for_each_cpu(cpu, cpus) { 242d7b6ba96SMichael Kelley if (func && func(cpu)) 2437ad9bb9dSWei Liu continue; 244765e33f5SMichael Kelley vcpu = hv_cpu_number_to_vp_number(cpu); 245765e33f5SMichael Kelley if (vcpu == VP_INVAL) 246765e33f5SMichael Kelley return -1; 247bd19c94aSVitaly Kuznetsov vcpu_bank = vcpu / HV_VCPUS_PER_SPARSE_BANK; 248bd19c94aSVitaly Kuznetsov vcpu_offset = vcpu % HV_VCPUS_PER_SPARSE_BANK; 249765e33f5SMichael Kelley __set_bit(vcpu_offset, (unsigned long *) 250765e33f5SMichael Kelley &vpset->bank_contents[vcpu_bank]); 251765e33f5SMichael Kelley if (vcpu_bank >= nr_bank) 252765e33f5SMichael Kelley nr_bank = vcpu_bank + 1; 253765e33f5SMichael Kelley } 254765e33f5SMichael Kelley vpset->valid_bank_mask = GENMASK_ULL(nr_bank - 1, 0); 255765e33f5SMichael Kelley return nr_bank; 256765e33f5SMichael Kelley } 257765e33f5SMichael Kelley 258d7b6ba96SMichael Kelley /* 259d7b6ba96SMichael Kelley * Convert a Linux cpumask into a Hyper-V VPset. In the _skip variant, 260d7b6ba96SMichael Kelley * 'func' is called for each CPU present in cpumask. If 'func' returns 261d7b6ba96SMichael Kelley * true, that CPU is skipped -- i.e., that CPU from cpumask is *not* 262d7b6ba96SMichael Kelley * added to the Hyper-V VPset. If 'func' is NULL, no CPUs are 263d7b6ba96SMichael Kelley * skipped. 264d7b6ba96SMichael Kelley */ 2657ad9bb9dSWei Liu static inline int cpumask_to_vpset(struct hv_vpset *vpset, 2667ad9bb9dSWei Liu const struct cpumask *cpus) 2677ad9bb9dSWei Liu { 268d7b6ba96SMichael Kelley return __cpumask_to_vpset(vpset, cpus, NULL); 2697ad9bb9dSWei Liu } 2707ad9bb9dSWei Liu 271d7b6ba96SMichael Kelley static inline int cpumask_to_vpset_skip(struct hv_vpset *vpset, 272d7b6ba96SMichael Kelley const struct cpumask *cpus, 273d7b6ba96SMichael Kelley bool (*func)(int cpu)) 2747ad9bb9dSWei Liu { 275d7b6ba96SMichael Kelley return __cpumask_to_vpset(vpset, cpus, func); 2767ad9bb9dSWei Liu } 2777ad9bb9dSWei Liu 278f3a99e76STianyu Lan void hyperv_report_panic(struct pt_regs *regs, long err, bool in_die); 279765e33f5SMichael Kelley bool hv_is_hyperv_initialized(void); 280b96f8653SDexuan Cui bool hv_is_hibernation_supported(void); 281a6c76bb0SAndrea Parri (Microsoft) enum hv_isolation_type hv_get_isolation_type(void); 282a6c76bb0SAndrea Parri (Microsoft) bool hv_is_isolation_supported(void); 2830cc4f6d9STianyu Lan bool hv_isolation_type_snp(void); 28420c89a55STianyu Lan u64 hv_ghcb_hypercall(u64 control, void *input, void *output, u32 input_size); 285d6e0228dSDexuan Cui u64 hv_tdx_hypercall(u64 control, u64 param1, u64 param2); 286765e33f5SMichael Kelley void hyperv_cleanup(void); 2876dc2a774SSunil Muthuswamy bool hv_query_ext_cap(u64 cap_query); 28837200078SMichael Kelley void hv_setup_dma_ops(struct device *dev, bool coherent); 289765e33f5SMichael Kelley #else /* CONFIG_HYPERV */ 290765e33f5SMichael Kelley static inline bool hv_is_hyperv_initialized(void) { return false; } 291b96f8653SDexuan Cui static inline bool hv_is_hibernation_supported(void) { return false; } 292765e33f5SMichael Kelley static inline void hyperv_cleanup(void) {} 2930cc4f6d9STianyu Lan static inline bool hv_is_isolation_supported(void) { return false; } 2940cc4f6d9STianyu Lan static inline enum hv_isolation_type hv_get_isolation_type(void) 2950cc4f6d9STianyu Lan { 2960cc4f6d9STianyu Lan return HV_ISOLATION_TYPE_NONE; 2970cc4f6d9STianyu Lan } 298765e33f5SMichael Kelley #endif /* CONFIG_HYPERV */ 299765e33f5SMichael Kelley 300765e33f5SMichael Kelley #endif 301