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> 25765e33f5SMichael Kelley #include <asm/ptrace.h> 26765e33f5SMichael Kelley #include <asm/hyperv-tlfs.h> 27765e33f5SMichael Kelley 28765e33f5SMichael Kelley struct ms_hyperv_info { 29765e33f5SMichael Kelley u32 features; 306dc2a774SSunil Muthuswamy u32 priv_high; 31765e33f5SMichael Kelley u32 misc_features; 32765e33f5SMichael Kelley u32 hints; 33765e33f5SMichael Kelley u32 nested_features; 34765e33f5SMichael Kelley u32 max_vp_index; 35765e33f5SMichael Kelley u32 max_lp_index; 36a6c76bb0SAndrea Parri (Microsoft) u32 isolation_config_a; 37a6c76bb0SAndrea Parri (Microsoft) u32 isolation_config_b; 38765e33f5SMichael Kelley }; 39765e33f5SMichael Kelley extern struct ms_hyperv_info ms_hyperv; 40765e33f5SMichael Kelley 41765e33f5SMichael Kelley extern u64 hv_do_hypercall(u64 control, void *inputaddr, void *outputaddr); 42765e33f5SMichael Kelley extern u64 hv_do_fast_hypercall8(u16 control, u64 input8); 43765e33f5SMichael Kelley 44*6523592cSJoseph Salisbury /* 45*6523592cSJoseph Salisbury * Rep hypercalls. Callers of this functions are supposed to ensure that 46*6523592cSJoseph Salisbury * rep_count and varhead_size comply with Hyper-V hypercall definition. 47*6523592cSJoseph Salisbury */ 48*6523592cSJoseph Salisbury static inline u64 hv_do_rep_hypercall(u16 code, u16 rep_count, u16 varhead_size, 49*6523592cSJoseph Salisbury void *input, void *output) 50*6523592cSJoseph Salisbury { 51*6523592cSJoseph Salisbury u64 control = code; 52*6523592cSJoseph Salisbury u64 status; 53*6523592cSJoseph Salisbury u16 rep_comp; 54*6523592cSJoseph Salisbury 55*6523592cSJoseph Salisbury control |= (u64)varhead_size << HV_HYPERCALL_VARHEAD_OFFSET; 56*6523592cSJoseph Salisbury control |= (u64)rep_count << HV_HYPERCALL_REP_COMP_OFFSET; 57*6523592cSJoseph Salisbury 58*6523592cSJoseph Salisbury do { 59*6523592cSJoseph Salisbury status = hv_do_hypercall(control, input, output); 60*6523592cSJoseph Salisbury if ((status & HV_HYPERCALL_RESULT_MASK) != HV_STATUS_SUCCESS) 61*6523592cSJoseph Salisbury return status; 62*6523592cSJoseph Salisbury 63*6523592cSJoseph Salisbury /* Bits 32-43 of status have 'Reps completed' data. */ 64*6523592cSJoseph Salisbury rep_comp = (status & HV_HYPERCALL_REP_COMP_MASK) >> 65*6523592cSJoseph Salisbury HV_HYPERCALL_REP_COMP_OFFSET; 66*6523592cSJoseph Salisbury 67*6523592cSJoseph Salisbury control &= ~HV_HYPERCALL_REP_START_MASK; 68*6523592cSJoseph Salisbury control |= (u64)rep_comp << HV_HYPERCALL_REP_START_OFFSET; 69*6523592cSJoseph Salisbury 70*6523592cSJoseph Salisbury touch_nmi_watchdog(); 71*6523592cSJoseph Salisbury } while (rep_comp < rep_count); 72*6523592cSJoseph Salisbury 73*6523592cSJoseph Salisbury return status; 74*6523592cSJoseph Salisbury } 75765e33f5SMichael Kelley 76765e33f5SMichael Kelley /* Generate the guest OS identifier as described in the Hyper-V TLFS */ 77765e33f5SMichael Kelley static inline __u64 generate_guest_id(__u64 d_info1, __u64 kernel_version, 78765e33f5SMichael Kelley __u64 d_info2) 79765e33f5SMichael Kelley { 80765e33f5SMichael Kelley __u64 guest_id = 0; 81765e33f5SMichael Kelley 82765e33f5SMichael Kelley guest_id = (((__u64)HV_LINUX_VENDOR_ID) << 48); 83765e33f5SMichael Kelley guest_id |= (d_info1 << 48); 84765e33f5SMichael Kelley guest_id |= (kernel_version << 16); 85765e33f5SMichael Kelley guest_id |= d_info2; 86765e33f5SMichael Kelley 87765e33f5SMichael Kelley return guest_id; 88765e33f5SMichael Kelley } 89765e33f5SMichael Kelley 90765e33f5SMichael Kelley 91765e33f5SMichael Kelley /* Free the message slot and signal end-of-message if required */ 92765e33f5SMichael Kelley static inline void vmbus_signal_eom(struct hv_message *msg, u32 old_msg_type) 93765e33f5SMichael Kelley { 94765e33f5SMichael Kelley /* 95765e33f5SMichael Kelley * On crash we're reading some other CPU's message page and we need 96765e33f5SMichael Kelley * to be careful: this other CPU may already had cleared the header 97765e33f5SMichael Kelley * and the host may already had delivered some other message there. 98765e33f5SMichael Kelley * In case we blindly write msg->header.message_type we're going 99765e33f5SMichael Kelley * to lose it. We can still lose a message of the same type but 100765e33f5SMichael Kelley * we count on the fact that there can only be one 101765e33f5SMichael Kelley * CHANNELMSG_UNLOAD_RESPONSE and we don't care about other messages 102765e33f5SMichael Kelley * on crash. 103765e33f5SMichael Kelley */ 104765e33f5SMichael Kelley if (cmpxchg(&msg->header.message_type, old_msg_type, 105765e33f5SMichael Kelley HVMSG_NONE) != old_msg_type) 106765e33f5SMichael Kelley return; 107765e33f5SMichael Kelley 108765e33f5SMichael Kelley /* 109765e33f5SMichael Kelley * The cmxchg() above does an implicit memory barrier to 110765e33f5SMichael Kelley * ensure the write to MessageType (ie set to 111765e33f5SMichael Kelley * HVMSG_NONE) happens before we read the 112765e33f5SMichael Kelley * MessagePending and EOMing. Otherwise, the EOMing 113765e33f5SMichael Kelley * will not deliver any more messages since there is 114765e33f5SMichael Kelley * no empty slot 115765e33f5SMichael Kelley */ 116765e33f5SMichael Kelley if (msg->header.message_flags.msg_pending) { 117765e33f5SMichael Kelley /* 118765e33f5SMichael Kelley * This will cause message queue rescan to 119765e33f5SMichael Kelley * possibly deliver another msg from the 120765e33f5SMichael Kelley * hypervisor 121765e33f5SMichael Kelley */ 122f3c5e63cSMichael Kelley hv_set_register(HV_REGISTER_EOM, 0); 123765e33f5SMichael Kelley } 124765e33f5SMichael Kelley } 125765e33f5SMichael Kelley 126d608715dSMichael Kelley void hv_setup_vmbus_handler(void (*handler)(void)); 127d608715dSMichael Kelley void hv_remove_vmbus_handler(void); 128a620bbaaSMichael Kelley void hv_setup_stimer0_handler(void (*handler)(void)); 129a620bbaaSMichael Kelley void hv_remove_stimer0_handler(void); 130765e33f5SMichael Kelley 131765e33f5SMichael Kelley void hv_setup_kexec_handler(void (*handler)(void)); 132765e33f5SMichael Kelley void hv_remove_kexec_handler(void); 133765e33f5SMichael Kelley void hv_setup_crash_handler(void (*handler)(struct pt_regs *regs)); 134765e33f5SMichael Kelley void hv_remove_crash_handler(void); 135765e33f5SMichael Kelley 136626b901fSMichael Kelley extern int vmbus_interrupt; 137d608715dSMichael Kelley extern int vmbus_irq; 138626b901fSMichael Kelley 139765e33f5SMichael Kelley #if IS_ENABLED(CONFIG_HYPERV) 140765e33f5SMichael Kelley /* 141765e33f5SMichael Kelley * Hypervisor's notion of virtual processor ID is different from 142765e33f5SMichael Kelley * Linux' notion of CPU ID. This information can only be retrieved 143765e33f5SMichael Kelley * in the context of the calling CPU. Setup a map for easy access 144765e33f5SMichael Kelley * to this information. 145765e33f5SMichael Kelley */ 146765e33f5SMichael Kelley extern u32 *hv_vp_index; 147765e33f5SMichael Kelley extern u32 hv_max_vp_index; 148765e33f5SMichael Kelley 149765e33f5SMichael Kelley /* Sentinel value for an uninitialized entry in hv_vp_index array */ 150765e33f5SMichael Kelley #define VP_INVAL U32_MAX 151765e33f5SMichael Kelley 152ca48739eSMichael Kelley void *hv_alloc_hyperv_page(void); 153ca48739eSMichael Kelley void *hv_alloc_hyperv_zeroed_page(void); 154ca48739eSMichael Kelley void hv_free_hyperv_page(unsigned long addr); 155ca48739eSMichael Kelley 156765e33f5SMichael Kelley /** 157765e33f5SMichael Kelley * hv_cpu_number_to_vp_number() - Map CPU to VP. 158765e33f5SMichael Kelley * @cpu_number: CPU number in Linux terms 159765e33f5SMichael Kelley * 160765e33f5SMichael Kelley * This function returns the mapping between the Linux processor 161765e33f5SMichael Kelley * number and the hypervisor's virtual processor number, useful 162765e33f5SMichael Kelley * in making hypercalls and such that talk about specific 163765e33f5SMichael Kelley * processors. 164765e33f5SMichael Kelley * 165765e33f5SMichael Kelley * Return: Virtual processor number in Hyper-V terms 166765e33f5SMichael Kelley */ 167765e33f5SMichael Kelley static inline int hv_cpu_number_to_vp_number(int cpu_number) 168765e33f5SMichael Kelley { 169765e33f5SMichael Kelley return hv_vp_index[cpu_number]; 170765e33f5SMichael Kelley } 171765e33f5SMichael Kelley 172765e33f5SMichael Kelley static inline int cpumask_to_vpset(struct hv_vpset *vpset, 173765e33f5SMichael Kelley const struct cpumask *cpus) 174765e33f5SMichael Kelley { 175765e33f5SMichael Kelley int cpu, vcpu, vcpu_bank, vcpu_offset, nr_bank = 1; 176765e33f5SMichael Kelley 177765e33f5SMichael Kelley /* valid_bank_mask can represent up to 64 banks */ 178765e33f5SMichael Kelley if (hv_max_vp_index / 64 >= 64) 179765e33f5SMichael Kelley return 0; 180765e33f5SMichael Kelley 181765e33f5SMichael Kelley /* 182765e33f5SMichael Kelley * Clear all banks up to the maximum possible bank as hv_tlb_flush_ex 183765e33f5SMichael Kelley * structs are not cleared between calls, we risk flushing unneeded 184765e33f5SMichael Kelley * vCPUs otherwise. 185765e33f5SMichael Kelley */ 186765e33f5SMichael Kelley for (vcpu_bank = 0; vcpu_bank <= hv_max_vp_index / 64; vcpu_bank++) 187765e33f5SMichael Kelley vpset->bank_contents[vcpu_bank] = 0; 188765e33f5SMichael Kelley 189765e33f5SMichael Kelley /* 190765e33f5SMichael Kelley * Some banks may end up being empty but this is acceptable. 191765e33f5SMichael Kelley */ 192765e33f5SMichael Kelley for_each_cpu(cpu, cpus) { 193765e33f5SMichael Kelley vcpu = hv_cpu_number_to_vp_number(cpu); 194765e33f5SMichael Kelley if (vcpu == VP_INVAL) 195765e33f5SMichael Kelley return -1; 196765e33f5SMichael Kelley vcpu_bank = vcpu / 64; 197765e33f5SMichael Kelley vcpu_offset = vcpu % 64; 198765e33f5SMichael Kelley __set_bit(vcpu_offset, (unsigned long *) 199765e33f5SMichael Kelley &vpset->bank_contents[vcpu_bank]); 200765e33f5SMichael Kelley if (vcpu_bank >= nr_bank) 201765e33f5SMichael Kelley nr_bank = vcpu_bank + 1; 202765e33f5SMichael Kelley } 203765e33f5SMichael Kelley vpset->valid_bank_mask = GENMASK_ULL(nr_bank - 1, 0); 204765e33f5SMichael Kelley return nr_bank; 205765e33f5SMichael Kelley } 206765e33f5SMichael Kelley 207f3a99e76STianyu Lan void hyperv_report_panic(struct pt_regs *regs, long err, bool in_die); 208765e33f5SMichael Kelley bool hv_is_hyperv_initialized(void); 209b96f8653SDexuan Cui bool hv_is_hibernation_supported(void); 210a6c76bb0SAndrea Parri (Microsoft) enum hv_isolation_type hv_get_isolation_type(void); 211a6c76bb0SAndrea Parri (Microsoft) bool hv_is_isolation_supported(void); 212765e33f5SMichael Kelley void hyperv_cleanup(void); 2136dc2a774SSunil Muthuswamy bool hv_query_ext_cap(u64 cap_query); 214765e33f5SMichael Kelley #else /* CONFIG_HYPERV */ 215765e33f5SMichael Kelley static inline bool hv_is_hyperv_initialized(void) { return false; } 216b96f8653SDexuan Cui static inline bool hv_is_hibernation_supported(void) { return false; } 217765e33f5SMichael Kelley static inline void hyperv_cleanup(void) {} 218765e33f5SMichael Kelley #endif /* CONFIG_HYPERV */ 219765e33f5SMichael Kelley 220765e33f5SMichael Kelley #endif 221