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; 30a6c76bb0SAndrea Parri (Microsoft) u32 features_b; 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 44765e33f5SMichael Kelley 45765e33f5SMichael Kelley /* Generate the guest OS identifier as described in the Hyper-V TLFS */ 46765e33f5SMichael Kelley static inline __u64 generate_guest_id(__u64 d_info1, __u64 kernel_version, 47765e33f5SMichael Kelley __u64 d_info2) 48765e33f5SMichael Kelley { 49765e33f5SMichael Kelley __u64 guest_id = 0; 50765e33f5SMichael Kelley 51765e33f5SMichael Kelley guest_id = (((__u64)HV_LINUX_VENDOR_ID) << 48); 52765e33f5SMichael Kelley guest_id |= (d_info1 << 48); 53765e33f5SMichael Kelley guest_id |= (kernel_version << 16); 54765e33f5SMichael Kelley guest_id |= d_info2; 55765e33f5SMichael Kelley 56765e33f5SMichael Kelley return guest_id; 57765e33f5SMichael Kelley } 58765e33f5SMichael Kelley 59765e33f5SMichael Kelley 60765e33f5SMichael Kelley /* Free the message slot and signal end-of-message if required */ 61765e33f5SMichael Kelley static inline void vmbus_signal_eom(struct hv_message *msg, u32 old_msg_type) 62765e33f5SMichael Kelley { 63765e33f5SMichael Kelley /* 64765e33f5SMichael Kelley * On crash we're reading some other CPU's message page and we need 65765e33f5SMichael Kelley * to be careful: this other CPU may already had cleared the header 66765e33f5SMichael Kelley * and the host may already had delivered some other message there. 67765e33f5SMichael Kelley * In case we blindly write msg->header.message_type we're going 68765e33f5SMichael Kelley * to lose it. We can still lose a message of the same type but 69765e33f5SMichael Kelley * we count on the fact that there can only be one 70765e33f5SMichael Kelley * CHANNELMSG_UNLOAD_RESPONSE and we don't care about other messages 71765e33f5SMichael Kelley * on crash. 72765e33f5SMichael Kelley */ 73765e33f5SMichael Kelley if (cmpxchg(&msg->header.message_type, old_msg_type, 74765e33f5SMichael Kelley HVMSG_NONE) != old_msg_type) 75765e33f5SMichael Kelley return; 76765e33f5SMichael Kelley 77765e33f5SMichael Kelley /* 78765e33f5SMichael Kelley * The cmxchg() above does an implicit memory barrier to 79765e33f5SMichael Kelley * ensure the write to MessageType (ie set to 80765e33f5SMichael Kelley * HVMSG_NONE) happens before we read the 81765e33f5SMichael Kelley * MessagePending and EOMing. Otherwise, the EOMing 82765e33f5SMichael Kelley * will not deliver any more messages since there is 83765e33f5SMichael Kelley * no empty slot 84765e33f5SMichael Kelley */ 85765e33f5SMichael Kelley if (msg->header.message_flags.msg_pending) { 86765e33f5SMichael Kelley /* 87765e33f5SMichael Kelley * This will cause message queue rescan to 88765e33f5SMichael Kelley * possibly deliver another msg from the 89765e33f5SMichael Kelley * hypervisor 90765e33f5SMichael Kelley */ 91765e33f5SMichael Kelley hv_signal_eom(); 92765e33f5SMichael Kelley } 93765e33f5SMichael Kelley } 94765e33f5SMichael Kelley 95626b901fSMichael Kelley int hv_setup_vmbus_irq(int irq, void (*handler)(void)); 96765e33f5SMichael Kelley void hv_remove_vmbus_irq(void); 97765e33f5SMichael Kelley void hv_enable_vmbus_irq(void); 98765e33f5SMichael Kelley void hv_disable_vmbus_irq(void); 99765e33f5SMichael Kelley 100765e33f5SMichael Kelley void hv_setup_kexec_handler(void (*handler)(void)); 101765e33f5SMichael Kelley void hv_remove_kexec_handler(void); 102765e33f5SMichael Kelley void hv_setup_crash_handler(void (*handler)(struct pt_regs *regs)); 103765e33f5SMichael Kelley void hv_remove_crash_handler(void); 104765e33f5SMichael Kelley 105626b901fSMichael Kelley extern int vmbus_interrupt; 106626b901fSMichael Kelley 107765e33f5SMichael Kelley #if IS_ENABLED(CONFIG_HYPERV) 108765e33f5SMichael Kelley /* 109765e33f5SMichael Kelley * Hypervisor's notion of virtual processor ID is different from 110765e33f5SMichael Kelley * Linux' notion of CPU ID. This information can only be retrieved 111765e33f5SMichael Kelley * in the context of the calling CPU. Setup a map for easy access 112765e33f5SMichael Kelley * to this information. 113765e33f5SMichael Kelley */ 114765e33f5SMichael Kelley extern u32 *hv_vp_index; 115765e33f5SMichael Kelley extern u32 hv_max_vp_index; 116765e33f5SMichael Kelley 117765e33f5SMichael Kelley /* Sentinel value for an uninitialized entry in hv_vp_index array */ 118765e33f5SMichael Kelley #define VP_INVAL U32_MAX 119765e33f5SMichael Kelley 120*ca48739eSMichael Kelley void *hv_alloc_hyperv_page(void); 121*ca48739eSMichael Kelley void *hv_alloc_hyperv_zeroed_page(void); 122*ca48739eSMichael Kelley void hv_free_hyperv_page(unsigned long addr); 123*ca48739eSMichael Kelley 124765e33f5SMichael Kelley /** 125765e33f5SMichael Kelley * hv_cpu_number_to_vp_number() - Map CPU to VP. 126765e33f5SMichael Kelley * @cpu_number: CPU number in Linux terms 127765e33f5SMichael Kelley * 128765e33f5SMichael Kelley * This function returns the mapping between the Linux processor 129765e33f5SMichael Kelley * number and the hypervisor's virtual processor number, useful 130765e33f5SMichael Kelley * in making hypercalls and such that talk about specific 131765e33f5SMichael Kelley * processors. 132765e33f5SMichael Kelley * 133765e33f5SMichael Kelley * Return: Virtual processor number in Hyper-V terms 134765e33f5SMichael Kelley */ 135765e33f5SMichael Kelley static inline int hv_cpu_number_to_vp_number(int cpu_number) 136765e33f5SMichael Kelley { 137765e33f5SMichael Kelley return hv_vp_index[cpu_number]; 138765e33f5SMichael Kelley } 139765e33f5SMichael Kelley 140765e33f5SMichael Kelley static inline int cpumask_to_vpset(struct hv_vpset *vpset, 141765e33f5SMichael Kelley const struct cpumask *cpus) 142765e33f5SMichael Kelley { 143765e33f5SMichael Kelley int cpu, vcpu, vcpu_bank, vcpu_offset, nr_bank = 1; 144765e33f5SMichael Kelley 145765e33f5SMichael Kelley /* valid_bank_mask can represent up to 64 banks */ 146765e33f5SMichael Kelley if (hv_max_vp_index / 64 >= 64) 147765e33f5SMichael Kelley return 0; 148765e33f5SMichael Kelley 149765e33f5SMichael Kelley /* 150765e33f5SMichael Kelley * Clear all banks up to the maximum possible bank as hv_tlb_flush_ex 151765e33f5SMichael Kelley * structs are not cleared between calls, we risk flushing unneeded 152765e33f5SMichael Kelley * vCPUs otherwise. 153765e33f5SMichael Kelley */ 154765e33f5SMichael Kelley for (vcpu_bank = 0; vcpu_bank <= hv_max_vp_index / 64; vcpu_bank++) 155765e33f5SMichael Kelley vpset->bank_contents[vcpu_bank] = 0; 156765e33f5SMichael Kelley 157765e33f5SMichael Kelley /* 158765e33f5SMichael Kelley * Some banks may end up being empty but this is acceptable. 159765e33f5SMichael Kelley */ 160765e33f5SMichael Kelley for_each_cpu(cpu, cpus) { 161765e33f5SMichael Kelley vcpu = hv_cpu_number_to_vp_number(cpu); 162765e33f5SMichael Kelley if (vcpu == VP_INVAL) 163765e33f5SMichael Kelley return -1; 164765e33f5SMichael Kelley vcpu_bank = vcpu / 64; 165765e33f5SMichael Kelley vcpu_offset = vcpu % 64; 166765e33f5SMichael Kelley __set_bit(vcpu_offset, (unsigned long *) 167765e33f5SMichael Kelley &vpset->bank_contents[vcpu_bank]); 168765e33f5SMichael Kelley if (vcpu_bank >= nr_bank) 169765e33f5SMichael Kelley nr_bank = vcpu_bank + 1; 170765e33f5SMichael Kelley } 171765e33f5SMichael Kelley vpset->valid_bank_mask = GENMASK_ULL(nr_bank - 1, 0); 172765e33f5SMichael Kelley return nr_bank; 173765e33f5SMichael Kelley } 174765e33f5SMichael Kelley 175f3a99e76STianyu Lan void hyperv_report_panic(struct pt_regs *regs, long err, bool in_die); 176765e33f5SMichael Kelley void hyperv_report_panic_msg(phys_addr_t pa, size_t size); 177765e33f5SMichael Kelley bool hv_is_hyperv_initialized(void); 178b96f8653SDexuan Cui bool hv_is_hibernation_supported(void); 179a6c76bb0SAndrea Parri (Microsoft) enum hv_isolation_type hv_get_isolation_type(void); 180a6c76bb0SAndrea Parri (Microsoft) bool hv_is_isolation_supported(void); 181765e33f5SMichael Kelley void hyperv_cleanup(void); 182765e33f5SMichael Kelley #else /* CONFIG_HYPERV */ 183765e33f5SMichael Kelley static inline bool hv_is_hyperv_initialized(void) { return false; } 184b96f8653SDexuan Cui static inline bool hv_is_hibernation_supported(void) { return false; } 185765e33f5SMichael Kelley static inline void hyperv_cleanup(void) {} 186765e33f5SMichael Kelley #endif /* CONFIG_HYPERV */ 187765e33f5SMichael Kelley 188765e33f5SMichael Kelley #if IS_ENABLED(CONFIG_HYPERV) 189765e33f5SMichael Kelley extern int hv_setup_stimer0_irq(int *irq, int *vector, void (*handler)(void)); 190765e33f5SMichael Kelley extern void hv_remove_stimer0_irq(int irq); 191765e33f5SMichael Kelley #endif 192765e33f5SMichael Kelley 193765e33f5SMichael Kelley #endif 194