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; 38a6c76bb0SAndrea Parri (Microsoft) u32 isolation_config_b; 39765e33f5SMichael Kelley }; 40765e33f5SMichael Kelley extern struct ms_hyperv_info ms_hyperv; 41765e33f5SMichael Kelley 42*afca4d95SMichael Kelley extern void __percpu **hyperv_pcpu_input_arg; 43*afca4d95SMichael Kelley extern void __percpu **hyperv_pcpu_output_arg; 44*afca4d95SMichael Kelley 45765e33f5SMichael Kelley extern u64 hv_do_hypercall(u64 control, void *inputaddr, void *outputaddr); 46765e33f5SMichael Kelley extern u64 hv_do_fast_hypercall8(u16 control, u64 input8); 47765e33f5SMichael Kelley 48753ed9c9SJoseph Salisbury /* Helper functions that provide a consistent pattern for checking Hyper-V hypercall status. */ 49753ed9c9SJoseph Salisbury static inline int hv_result(u64 status) 50753ed9c9SJoseph Salisbury { 51753ed9c9SJoseph Salisbury return status & HV_HYPERCALL_RESULT_MASK; 52753ed9c9SJoseph Salisbury } 53753ed9c9SJoseph Salisbury 54753ed9c9SJoseph Salisbury static inline bool hv_result_success(u64 status) 55753ed9c9SJoseph Salisbury { 56753ed9c9SJoseph Salisbury return hv_result(status) == HV_STATUS_SUCCESS; 57753ed9c9SJoseph Salisbury } 58753ed9c9SJoseph Salisbury 59753ed9c9SJoseph Salisbury static inline unsigned int hv_repcomp(u64 status) 60753ed9c9SJoseph Salisbury { 61753ed9c9SJoseph Salisbury /* Bits [43:32] of status have 'Reps completed' data. */ 62753ed9c9SJoseph Salisbury return (status & HV_HYPERCALL_REP_COMP_MASK) >> 63753ed9c9SJoseph Salisbury HV_HYPERCALL_REP_COMP_OFFSET; 64753ed9c9SJoseph Salisbury } 65753ed9c9SJoseph Salisbury 666523592cSJoseph Salisbury /* 676523592cSJoseph Salisbury * Rep hypercalls. Callers of this functions are supposed to ensure that 686523592cSJoseph Salisbury * rep_count and varhead_size comply with Hyper-V hypercall definition. 696523592cSJoseph Salisbury */ 706523592cSJoseph Salisbury static inline u64 hv_do_rep_hypercall(u16 code, u16 rep_count, u16 varhead_size, 716523592cSJoseph Salisbury void *input, void *output) 726523592cSJoseph Salisbury { 736523592cSJoseph Salisbury u64 control = code; 746523592cSJoseph Salisbury u64 status; 756523592cSJoseph Salisbury u16 rep_comp; 766523592cSJoseph Salisbury 776523592cSJoseph Salisbury control |= (u64)varhead_size << HV_HYPERCALL_VARHEAD_OFFSET; 786523592cSJoseph Salisbury control |= (u64)rep_count << HV_HYPERCALL_REP_COMP_OFFSET; 796523592cSJoseph Salisbury 806523592cSJoseph Salisbury do { 816523592cSJoseph Salisbury status = hv_do_hypercall(control, input, output); 82753ed9c9SJoseph Salisbury if (!hv_result_success(status)) 836523592cSJoseph Salisbury return status; 846523592cSJoseph Salisbury 85753ed9c9SJoseph Salisbury rep_comp = hv_repcomp(status); 866523592cSJoseph Salisbury 876523592cSJoseph Salisbury control &= ~HV_HYPERCALL_REP_START_MASK; 886523592cSJoseph Salisbury control |= (u64)rep_comp << HV_HYPERCALL_REP_START_OFFSET; 896523592cSJoseph Salisbury 906523592cSJoseph Salisbury touch_nmi_watchdog(); 916523592cSJoseph Salisbury } while (rep_comp < rep_count); 926523592cSJoseph Salisbury 936523592cSJoseph Salisbury return status; 946523592cSJoseph Salisbury } 95765e33f5SMichael Kelley 96765e33f5SMichael Kelley /* Generate the guest OS identifier as described in the Hyper-V TLFS */ 97765e33f5SMichael Kelley static inline __u64 generate_guest_id(__u64 d_info1, __u64 kernel_version, 98765e33f5SMichael Kelley __u64 d_info2) 99765e33f5SMichael Kelley { 100765e33f5SMichael Kelley __u64 guest_id = 0; 101765e33f5SMichael Kelley 102765e33f5SMichael Kelley guest_id = (((__u64)HV_LINUX_VENDOR_ID) << 48); 103765e33f5SMichael Kelley guest_id |= (d_info1 << 48); 104765e33f5SMichael Kelley guest_id |= (kernel_version << 16); 105765e33f5SMichael Kelley guest_id |= d_info2; 106765e33f5SMichael Kelley 107765e33f5SMichael Kelley return guest_id; 108765e33f5SMichael Kelley } 109765e33f5SMichael Kelley 110765e33f5SMichael Kelley /* Free the message slot and signal end-of-message if required */ 111765e33f5SMichael Kelley static inline void vmbus_signal_eom(struct hv_message *msg, u32 old_msg_type) 112765e33f5SMichael Kelley { 113765e33f5SMichael Kelley /* 114765e33f5SMichael Kelley * On crash we're reading some other CPU's message page and we need 115765e33f5SMichael Kelley * to be careful: this other CPU may already had cleared the header 116765e33f5SMichael Kelley * and the host may already had delivered some other message there. 117765e33f5SMichael Kelley * In case we blindly write msg->header.message_type we're going 118765e33f5SMichael Kelley * to lose it. We can still lose a message of the same type but 119765e33f5SMichael Kelley * we count on the fact that there can only be one 120765e33f5SMichael Kelley * CHANNELMSG_UNLOAD_RESPONSE and we don't care about other messages 121765e33f5SMichael Kelley * on crash. 122765e33f5SMichael Kelley */ 123765e33f5SMichael Kelley if (cmpxchg(&msg->header.message_type, old_msg_type, 124765e33f5SMichael Kelley HVMSG_NONE) != old_msg_type) 125765e33f5SMichael Kelley return; 126765e33f5SMichael Kelley 127765e33f5SMichael Kelley /* 128765e33f5SMichael Kelley * The cmxchg() above does an implicit memory barrier to 129765e33f5SMichael Kelley * ensure the write to MessageType (ie set to 130765e33f5SMichael Kelley * HVMSG_NONE) happens before we read the 131765e33f5SMichael Kelley * MessagePending and EOMing. Otherwise, the EOMing 132765e33f5SMichael Kelley * will not deliver any more messages since there is 133765e33f5SMichael Kelley * no empty slot 134765e33f5SMichael Kelley */ 135765e33f5SMichael Kelley if (msg->header.message_flags.msg_pending) { 136765e33f5SMichael Kelley /* 137765e33f5SMichael Kelley * This will cause message queue rescan to 138765e33f5SMichael Kelley * possibly deliver another msg from the 139765e33f5SMichael Kelley * hypervisor 140765e33f5SMichael Kelley */ 141f3c5e63cSMichael Kelley hv_set_register(HV_REGISTER_EOM, 0); 142765e33f5SMichael Kelley } 143765e33f5SMichael Kelley } 144765e33f5SMichael Kelley 145d608715dSMichael Kelley void hv_setup_vmbus_handler(void (*handler)(void)); 146d608715dSMichael Kelley void hv_remove_vmbus_handler(void); 147a620bbaaSMichael Kelley void hv_setup_stimer0_handler(void (*handler)(void)); 148a620bbaaSMichael Kelley void hv_remove_stimer0_handler(void); 149765e33f5SMichael Kelley 150765e33f5SMichael Kelley void hv_setup_kexec_handler(void (*handler)(void)); 151765e33f5SMichael Kelley void hv_remove_kexec_handler(void); 152765e33f5SMichael Kelley void hv_setup_crash_handler(void (*handler)(struct pt_regs *regs)); 153765e33f5SMichael Kelley void hv_remove_crash_handler(void); 154765e33f5SMichael Kelley 155626b901fSMichael Kelley extern int vmbus_interrupt; 156d608715dSMichael Kelley extern int vmbus_irq; 157626b901fSMichael Kelley 158*afca4d95SMichael Kelley extern bool hv_root_partition; 159*afca4d95SMichael Kelley 160765e33f5SMichael Kelley #if IS_ENABLED(CONFIG_HYPERV) 161765e33f5SMichael Kelley /* 162765e33f5SMichael Kelley * Hypervisor's notion of virtual processor ID is different from 163765e33f5SMichael Kelley * Linux' notion of CPU ID. This information can only be retrieved 164765e33f5SMichael Kelley * in the context of the calling CPU. Setup a map for easy access 165765e33f5SMichael Kelley * to this information. 166765e33f5SMichael Kelley */ 167765e33f5SMichael Kelley extern u32 *hv_vp_index; 168765e33f5SMichael Kelley extern u32 hv_max_vp_index; 169765e33f5SMichael Kelley 170765e33f5SMichael Kelley /* Sentinel value for an uninitialized entry in hv_vp_index array */ 171765e33f5SMichael Kelley #define VP_INVAL U32_MAX 172765e33f5SMichael Kelley 173*afca4d95SMichael Kelley int __init hv_common_init(void); 174*afca4d95SMichael Kelley void __init hv_common_free(void); 175*afca4d95SMichael Kelley int hv_common_cpu_init(unsigned int cpu); 176*afca4d95SMichael Kelley int hv_common_cpu_die(unsigned int cpu); 177*afca4d95SMichael Kelley 178ca48739eSMichael Kelley void *hv_alloc_hyperv_page(void); 179ca48739eSMichael Kelley void *hv_alloc_hyperv_zeroed_page(void); 180ca48739eSMichael Kelley void hv_free_hyperv_page(unsigned long addr); 181ca48739eSMichael Kelley 182765e33f5SMichael Kelley /** 183765e33f5SMichael Kelley * hv_cpu_number_to_vp_number() - Map CPU to VP. 184765e33f5SMichael Kelley * @cpu_number: CPU number in Linux terms 185765e33f5SMichael Kelley * 186765e33f5SMichael Kelley * This function returns the mapping between the Linux processor 187765e33f5SMichael Kelley * number and the hypervisor's virtual processor number, useful 188765e33f5SMichael Kelley * in making hypercalls and such that talk about specific 189765e33f5SMichael Kelley * processors. 190765e33f5SMichael Kelley * 191765e33f5SMichael Kelley * Return: Virtual processor number in Hyper-V terms 192765e33f5SMichael Kelley */ 193765e33f5SMichael Kelley static inline int hv_cpu_number_to_vp_number(int cpu_number) 194765e33f5SMichael Kelley { 195765e33f5SMichael Kelley return hv_vp_index[cpu_number]; 196765e33f5SMichael Kelley } 197765e33f5SMichael Kelley 198765e33f5SMichael Kelley static inline int cpumask_to_vpset(struct hv_vpset *vpset, 199765e33f5SMichael Kelley const struct cpumask *cpus) 200765e33f5SMichael Kelley { 201765e33f5SMichael Kelley int cpu, vcpu, vcpu_bank, vcpu_offset, nr_bank = 1; 202765e33f5SMichael Kelley 203765e33f5SMichael Kelley /* valid_bank_mask can represent up to 64 banks */ 204765e33f5SMichael Kelley if (hv_max_vp_index / 64 >= 64) 205765e33f5SMichael Kelley return 0; 206765e33f5SMichael Kelley 207765e33f5SMichael Kelley /* 208765e33f5SMichael Kelley * Clear all banks up to the maximum possible bank as hv_tlb_flush_ex 209765e33f5SMichael Kelley * structs are not cleared between calls, we risk flushing unneeded 210765e33f5SMichael Kelley * vCPUs otherwise. 211765e33f5SMichael Kelley */ 212765e33f5SMichael Kelley for (vcpu_bank = 0; vcpu_bank <= hv_max_vp_index / 64; vcpu_bank++) 213765e33f5SMichael Kelley vpset->bank_contents[vcpu_bank] = 0; 214765e33f5SMichael Kelley 215765e33f5SMichael Kelley /* 216765e33f5SMichael Kelley * Some banks may end up being empty but this is acceptable. 217765e33f5SMichael Kelley */ 218765e33f5SMichael Kelley for_each_cpu(cpu, cpus) { 219765e33f5SMichael Kelley vcpu = hv_cpu_number_to_vp_number(cpu); 220765e33f5SMichael Kelley if (vcpu == VP_INVAL) 221765e33f5SMichael Kelley return -1; 222765e33f5SMichael Kelley vcpu_bank = vcpu / 64; 223765e33f5SMichael Kelley vcpu_offset = vcpu % 64; 224765e33f5SMichael Kelley __set_bit(vcpu_offset, (unsigned long *) 225765e33f5SMichael Kelley &vpset->bank_contents[vcpu_bank]); 226765e33f5SMichael Kelley if (vcpu_bank >= nr_bank) 227765e33f5SMichael Kelley nr_bank = vcpu_bank + 1; 228765e33f5SMichael Kelley } 229765e33f5SMichael Kelley vpset->valid_bank_mask = GENMASK_ULL(nr_bank - 1, 0); 230765e33f5SMichael Kelley return nr_bank; 231765e33f5SMichael Kelley } 232765e33f5SMichael Kelley 233f3a99e76STianyu Lan void hyperv_report_panic(struct pt_regs *regs, long err, bool in_die); 234765e33f5SMichael Kelley bool hv_is_hyperv_initialized(void); 235b96f8653SDexuan Cui bool hv_is_hibernation_supported(void); 236a6c76bb0SAndrea Parri (Microsoft) enum hv_isolation_type hv_get_isolation_type(void); 237a6c76bb0SAndrea Parri (Microsoft) bool hv_is_isolation_supported(void); 238765e33f5SMichael Kelley void hyperv_cleanup(void); 2396dc2a774SSunil Muthuswamy bool hv_query_ext_cap(u64 cap_query); 240765e33f5SMichael Kelley #else /* CONFIG_HYPERV */ 241765e33f5SMichael Kelley static inline bool hv_is_hyperv_initialized(void) { return false; } 242b96f8653SDexuan Cui static inline bool hv_is_hibernation_supported(void) { return false; } 243765e33f5SMichael Kelley static inline void hyperv_cleanup(void) {} 244765e33f5SMichael Kelley #endif /* CONFIG_HYPERV */ 245765e33f5SMichael Kelley 246765e33f5SMichael Kelley #endif 247