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 29765e33f5SMichael Kelley struct ms_hyperv_info { 30765e33f5SMichael Kelley u32 features; 316dc2a774SSunil Muthuswamy u32 priv_high; 32765e33f5SMichael Kelley u32 misc_features; 33765e33f5SMichael Kelley u32 hints; 34765e33f5SMichael Kelley u32 nested_features; 35765e33f5SMichael Kelley u32 max_vp_index; 36765e33f5SMichael Kelley u32 max_lp_index; 37a6c76bb0SAndrea Parri (Microsoft) u32 isolation_config_a; 38af788f35STianyu Lan union { 39a6c76bb0SAndrea Parri (Microsoft) u32 isolation_config_b; 40af788f35STianyu Lan struct { 41af788f35STianyu Lan u32 cvm_type : 4; 42af788f35STianyu Lan u32 reserved1 : 1; 43af788f35STianyu Lan u32 shared_gpa_boundary_active : 1; 44af788f35STianyu Lan u32 shared_gpa_boundary_bits : 6; 45af788f35STianyu Lan u32 reserved2 : 20; 46af788f35STianyu Lan }; 47af788f35STianyu Lan }; 48af788f35STianyu Lan u64 shared_gpa_boundary; 49765e33f5SMichael Kelley }; 50765e33f5SMichael Kelley extern struct ms_hyperv_info ms_hyperv; 51765e33f5SMichael Kelley 52afca4d95SMichael Kelley extern void __percpu **hyperv_pcpu_input_arg; 53afca4d95SMichael Kelley extern void __percpu **hyperv_pcpu_output_arg; 54afca4d95SMichael Kelley 55765e33f5SMichael Kelley extern u64 hv_do_hypercall(u64 control, void *inputaddr, void *outputaddr); 56765e33f5SMichael Kelley extern u64 hv_do_fast_hypercall8(u16 control, u64 input8); 57faff4406STianyu Lan extern bool hv_isolation_type_snp(void); 58765e33f5SMichael Kelley 59753ed9c9SJoseph Salisbury /* Helper functions that provide a consistent pattern for checking Hyper-V hypercall status. */ 60753ed9c9SJoseph Salisbury static inline int hv_result(u64 status) 61753ed9c9SJoseph Salisbury { 62753ed9c9SJoseph Salisbury return status & HV_HYPERCALL_RESULT_MASK; 63753ed9c9SJoseph Salisbury } 64753ed9c9SJoseph Salisbury 65753ed9c9SJoseph Salisbury static inline bool hv_result_success(u64 status) 66753ed9c9SJoseph Salisbury { 67753ed9c9SJoseph Salisbury return hv_result(status) == HV_STATUS_SUCCESS; 68753ed9c9SJoseph Salisbury } 69753ed9c9SJoseph Salisbury 70753ed9c9SJoseph Salisbury static inline unsigned int hv_repcomp(u64 status) 71753ed9c9SJoseph Salisbury { 72753ed9c9SJoseph Salisbury /* Bits [43:32] of status have 'Reps completed' data. */ 73753ed9c9SJoseph Salisbury return (status & HV_HYPERCALL_REP_COMP_MASK) >> 74753ed9c9SJoseph Salisbury HV_HYPERCALL_REP_COMP_OFFSET; 75753ed9c9SJoseph Salisbury } 76753ed9c9SJoseph Salisbury 776523592cSJoseph Salisbury /* 786523592cSJoseph Salisbury * Rep hypercalls. Callers of this functions are supposed to ensure that 796523592cSJoseph Salisbury * rep_count and varhead_size comply with Hyper-V hypercall definition. 806523592cSJoseph Salisbury */ 816523592cSJoseph Salisbury static inline u64 hv_do_rep_hypercall(u16 code, u16 rep_count, u16 varhead_size, 826523592cSJoseph Salisbury void *input, void *output) 836523592cSJoseph Salisbury { 846523592cSJoseph Salisbury u64 control = code; 856523592cSJoseph Salisbury u64 status; 866523592cSJoseph Salisbury u16 rep_comp; 876523592cSJoseph Salisbury 886523592cSJoseph Salisbury control |= (u64)varhead_size << HV_HYPERCALL_VARHEAD_OFFSET; 896523592cSJoseph Salisbury control |= (u64)rep_count << HV_HYPERCALL_REP_COMP_OFFSET; 906523592cSJoseph Salisbury 916523592cSJoseph Salisbury do { 926523592cSJoseph Salisbury status = hv_do_hypercall(control, input, output); 93753ed9c9SJoseph Salisbury if (!hv_result_success(status)) 946523592cSJoseph Salisbury return status; 956523592cSJoseph Salisbury 96753ed9c9SJoseph Salisbury rep_comp = hv_repcomp(status); 976523592cSJoseph Salisbury 986523592cSJoseph Salisbury control &= ~HV_HYPERCALL_REP_START_MASK; 996523592cSJoseph Salisbury control |= (u64)rep_comp << HV_HYPERCALL_REP_START_OFFSET; 1006523592cSJoseph Salisbury 1016523592cSJoseph Salisbury touch_nmi_watchdog(); 1026523592cSJoseph Salisbury } while (rep_comp < rep_count); 1036523592cSJoseph Salisbury 1046523592cSJoseph Salisbury return status; 1056523592cSJoseph Salisbury } 106765e33f5SMichael Kelley 107765e33f5SMichael Kelley /* Generate the guest OS identifier as described in the Hyper-V TLFS */ 108765e33f5SMichael Kelley static inline __u64 generate_guest_id(__u64 d_info1, __u64 kernel_version, 109765e33f5SMichael Kelley __u64 d_info2) 110765e33f5SMichael Kelley { 111765e33f5SMichael Kelley __u64 guest_id = 0; 112765e33f5SMichael Kelley 113765e33f5SMichael Kelley guest_id = (((__u64)HV_LINUX_VENDOR_ID) << 48); 114765e33f5SMichael Kelley guest_id |= (d_info1 << 48); 115765e33f5SMichael Kelley guest_id |= (kernel_version << 16); 116765e33f5SMichael Kelley guest_id |= d_info2; 117765e33f5SMichael Kelley 118765e33f5SMichael Kelley return guest_id; 119765e33f5SMichael Kelley } 120765e33f5SMichael Kelley 121765e33f5SMichael Kelley /* Free the message slot and signal end-of-message if required */ 122765e33f5SMichael Kelley static inline void vmbus_signal_eom(struct hv_message *msg, u32 old_msg_type) 123765e33f5SMichael Kelley { 124765e33f5SMichael Kelley /* 125765e33f5SMichael Kelley * On crash we're reading some other CPU's message page and we need 126765e33f5SMichael Kelley * to be careful: this other CPU may already had cleared the header 127765e33f5SMichael Kelley * and the host may already had delivered some other message there. 128765e33f5SMichael Kelley * In case we blindly write msg->header.message_type we're going 129765e33f5SMichael Kelley * to lose it. We can still lose a message of the same type but 130765e33f5SMichael Kelley * we count on the fact that there can only be one 131765e33f5SMichael Kelley * CHANNELMSG_UNLOAD_RESPONSE and we don't care about other messages 132765e33f5SMichael Kelley * on crash. 133765e33f5SMichael Kelley */ 134765e33f5SMichael Kelley if (cmpxchg(&msg->header.message_type, old_msg_type, 135765e33f5SMichael Kelley HVMSG_NONE) != old_msg_type) 136765e33f5SMichael Kelley return; 137765e33f5SMichael Kelley 138765e33f5SMichael Kelley /* 139765e33f5SMichael Kelley * The cmxchg() above does an implicit memory barrier to 140765e33f5SMichael Kelley * ensure the write to MessageType (ie set to 141765e33f5SMichael Kelley * HVMSG_NONE) happens before we read the 142765e33f5SMichael Kelley * MessagePending and EOMing. Otherwise, the EOMing 143765e33f5SMichael Kelley * will not deliver any more messages since there is 144765e33f5SMichael Kelley * no empty slot 145765e33f5SMichael Kelley */ 146765e33f5SMichael Kelley if (msg->header.message_flags.msg_pending) { 147765e33f5SMichael Kelley /* 148765e33f5SMichael Kelley * This will cause message queue rescan to 149765e33f5SMichael Kelley * possibly deliver another msg from the 150765e33f5SMichael Kelley * hypervisor 151765e33f5SMichael Kelley */ 152f3c5e63cSMichael Kelley hv_set_register(HV_REGISTER_EOM, 0); 153765e33f5SMichael Kelley } 154765e33f5SMichael Kelley } 155765e33f5SMichael Kelley 156d608715dSMichael Kelley void hv_setup_vmbus_handler(void (*handler)(void)); 157d608715dSMichael Kelley void hv_remove_vmbus_handler(void); 158a620bbaaSMichael Kelley void hv_setup_stimer0_handler(void (*handler)(void)); 159a620bbaaSMichael Kelley void hv_remove_stimer0_handler(void); 160765e33f5SMichael Kelley 161765e33f5SMichael Kelley void hv_setup_kexec_handler(void (*handler)(void)); 162765e33f5SMichael Kelley void hv_remove_kexec_handler(void); 163765e33f5SMichael Kelley void hv_setup_crash_handler(void (*handler)(struct pt_regs *regs)); 164765e33f5SMichael Kelley void hv_remove_crash_handler(void); 165765e33f5SMichael Kelley 166626b901fSMichael Kelley extern int vmbus_interrupt; 167d608715dSMichael Kelley extern int vmbus_irq; 168626b901fSMichael Kelley 169afca4d95SMichael Kelley extern bool hv_root_partition; 170afca4d95SMichael Kelley 171765e33f5SMichael Kelley #if IS_ENABLED(CONFIG_HYPERV) 172765e33f5SMichael Kelley /* 173765e33f5SMichael Kelley * Hypervisor's notion of virtual processor ID is different from 174765e33f5SMichael Kelley * Linux' notion of CPU ID. This information can only be retrieved 175765e33f5SMichael Kelley * in the context of the calling CPU. Setup a map for easy access 176765e33f5SMichael Kelley * to this information. 177765e33f5SMichael Kelley */ 178765e33f5SMichael Kelley extern u32 *hv_vp_index; 179765e33f5SMichael Kelley extern u32 hv_max_vp_index; 180765e33f5SMichael Kelley 18131e5e646SMichael Kelley extern u64 (*hv_read_reference_counter)(void); 18231e5e646SMichael Kelley 183765e33f5SMichael Kelley /* Sentinel value for an uninitialized entry in hv_vp_index array */ 184765e33f5SMichael Kelley #define VP_INVAL U32_MAX 185765e33f5SMichael Kelley 186afca4d95SMichael Kelley int __init hv_common_init(void); 187afca4d95SMichael Kelley void __init hv_common_free(void); 188afca4d95SMichael Kelley int hv_common_cpu_init(unsigned int cpu); 189afca4d95SMichael Kelley int hv_common_cpu_die(unsigned int cpu); 190afca4d95SMichael Kelley 191ca48739eSMichael Kelley void *hv_alloc_hyperv_page(void); 192ca48739eSMichael Kelley void *hv_alloc_hyperv_zeroed_page(void); 193ca48739eSMichael Kelley void hv_free_hyperv_page(unsigned long addr); 194ca48739eSMichael Kelley 195765e33f5SMichael Kelley /** 196765e33f5SMichael Kelley * hv_cpu_number_to_vp_number() - Map CPU to VP. 197765e33f5SMichael Kelley * @cpu_number: CPU number in Linux terms 198765e33f5SMichael Kelley * 199765e33f5SMichael Kelley * This function returns the mapping between the Linux processor 200765e33f5SMichael Kelley * number and the hypervisor's virtual processor number, useful 201765e33f5SMichael Kelley * in making hypercalls and such that talk about specific 202765e33f5SMichael Kelley * processors. 203765e33f5SMichael Kelley * 204765e33f5SMichael Kelley * Return: Virtual processor number in Hyper-V terms 205765e33f5SMichael Kelley */ 206765e33f5SMichael Kelley static inline int hv_cpu_number_to_vp_number(int cpu_number) 207765e33f5SMichael Kelley { 208765e33f5SMichael Kelley return hv_vp_index[cpu_number]; 209765e33f5SMichael Kelley } 210765e33f5SMichael Kelley 2117ad9bb9dSWei Liu static inline int __cpumask_to_vpset(struct hv_vpset *vpset, 2127ad9bb9dSWei Liu const struct cpumask *cpus, 2137ad9bb9dSWei Liu bool exclude_self) 214765e33f5SMichael Kelley { 215765e33f5SMichael Kelley int cpu, vcpu, vcpu_bank, vcpu_offset, nr_bank = 1; 2167ad9bb9dSWei Liu int this_cpu = smp_processor_id(); 217765e33f5SMichael Kelley 218765e33f5SMichael Kelley /* valid_bank_mask can represent up to 64 banks */ 219765e33f5SMichael Kelley if (hv_max_vp_index / 64 >= 64) 220765e33f5SMichael Kelley return 0; 221765e33f5SMichael Kelley 222765e33f5SMichael Kelley /* 223765e33f5SMichael Kelley * Clear all banks up to the maximum possible bank as hv_tlb_flush_ex 224765e33f5SMichael Kelley * structs are not cleared between calls, we risk flushing unneeded 225765e33f5SMichael Kelley * vCPUs otherwise. 226765e33f5SMichael Kelley */ 227765e33f5SMichael Kelley for (vcpu_bank = 0; vcpu_bank <= hv_max_vp_index / 64; vcpu_bank++) 228765e33f5SMichael Kelley vpset->bank_contents[vcpu_bank] = 0; 229765e33f5SMichael Kelley 230765e33f5SMichael Kelley /* 231765e33f5SMichael Kelley * Some banks may end up being empty but this is acceptable. 232765e33f5SMichael Kelley */ 233765e33f5SMichael Kelley for_each_cpu(cpu, cpus) { 2347ad9bb9dSWei Liu if (exclude_self && cpu == this_cpu) 2357ad9bb9dSWei Liu continue; 236765e33f5SMichael Kelley vcpu = hv_cpu_number_to_vp_number(cpu); 237765e33f5SMichael Kelley if (vcpu == VP_INVAL) 238765e33f5SMichael Kelley return -1; 239765e33f5SMichael Kelley vcpu_bank = vcpu / 64; 240765e33f5SMichael Kelley vcpu_offset = vcpu % 64; 241765e33f5SMichael Kelley __set_bit(vcpu_offset, (unsigned long *) 242765e33f5SMichael Kelley &vpset->bank_contents[vcpu_bank]); 243765e33f5SMichael Kelley if (vcpu_bank >= nr_bank) 244765e33f5SMichael Kelley nr_bank = vcpu_bank + 1; 245765e33f5SMichael Kelley } 246765e33f5SMichael Kelley vpset->valid_bank_mask = GENMASK_ULL(nr_bank - 1, 0); 247765e33f5SMichael Kelley return nr_bank; 248765e33f5SMichael Kelley } 249765e33f5SMichael Kelley 2507ad9bb9dSWei Liu static inline int cpumask_to_vpset(struct hv_vpset *vpset, 2517ad9bb9dSWei Liu const struct cpumask *cpus) 2527ad9bb9dSWei Liu { 2537ad9bb9dSWei Liu return __cpumask_to_vpset(vpset, cpus, false); 2547ad9bb9dSWei Liu } 2557ad9bb9dSWei Liu 2567ad9bb9dSWei Liu static inline int cpumask_to_vpset_noself(struct hv_vpset *vpset, 2577ad9bb9dSWei Liu const struct cpumask *cpus) 2587ad9bb9dSWei Liu { 2597ad9bb9dSWei Liu WARN_ON_ONCE(preemptible()); 2607ad9bb9dSWei Liu return __cpumask_to_vpset(vpset, cpus, true); 2617ad9bb9dSWei Liu } 2627ad9bb9dSWei Liu 263f3a99e76STianyu Lan void hyperv_report_panic(struct pt_regs *regs, long err, bool in_die); 264765e33f5SMichael Kelley bool hv_is_hyperv_initialized(void); 265b96f8653SDexuan Cui bool hv_is_hibernation_supported(void); 266a6c76bb0SAndrea Parri (Microsoft) enum hv_isolation_type hv_get_isolation_type(void); 267a6c76bb0SAndrea Parri (Microsoft) bool hv_is_isolation_supported(void); 2680cc4f6d9STianyu Lan bool hv_isolation_type_snp(void); 269*20c89a55STianyu Lan u64 hv_ghcb_hypercall(u64 control, void *input, void *output, u32 input_size); 270765e33f5SMichael Kelley void hyperv_cleanup(void); 2716dc2a774SSunil Muthuswamy bool hv_query_ext_cap(u64 cap_query); 272765e33f5SMichael Kelley #else /* CONFIG_HYPERV */ 273765e33f5SMichael Kelley static inline bool hv_is_hyperv_initialized(void) { return false; } 274b96f8653SDexuan Cui static inline bool hv_is_hibernation_supported(void) { return false; } 275765e33f5SMichael Kelley static inline void hyperv_cleanup(void) {} 2760cc4f6d9STianyu Lan static inline bool hv_is_isolation_supported(void) { return false; } 2770cc4f6d9STianyu Lan static inline enum hv_isolation_type hv_get_isolation_type(void) 2780cc4f6d9STianyu Lan { 2790cc4f6d9STianyu Lan return HV_ISOLATION_TYPE_NONE; 2800cc4f6d9STianyu Lan } 281765e33f5SMichael Kelley #endif /* CONFIG_HYPERV */ 282765e33f5SMichael Kelley 283765e33f5SMichael Kelley #endif 284