162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci 362306a36Sopenharmony_ci/* 462306a36Sopenharmony_ci * Linux-specific definitions for managing interactions with Microsoft's 562306a36Sopenharmony_ci * Hyper-V hypervisor. The definitions in this file are architecture 662306a36Sopenharmony_ci * independent. See arch/<arch>/include/asm/mshyperv.h for definitions 762306a36Sopenharmony_ci * that are specific to architecture <arch>. 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Definitions that are specified in the Hyper-V Top Level Functional 1062306a36Sopenharmony_ci * Spec (TLFS) should not go in this file, but should instead go in 1162306a36Sopenharmony_ci * hyperv-tlfs.h. 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * Copyright (C) 2019, Microsoft, Inc. 1462306a36Sopenharmony_ci * 1562306a36Sopenharmony_ci * Author : Michael Kelley <mikelley@microsoft.com> 1662306a36Sopenharmony_ci */ 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#ifndef _ASM_GENERIC_MSHYPERV_H 1962306a36Sopenharmony_ci#define _ASM_GENERIC_MSHYPERV_H 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#include <linux/types.h> 2262306a36Sopenharmony_ci#include <linux/atomic.h> 2362306a36Sopenharmony_ci#include <linux/bitops.h> 2462306a36Sopenharmony_ci#include <linux/cpumask.h> 2562306a36Sopenharmony_ci#include <linux/nmi.h> 2662306a36Sopenharmony_ci#include <asm/ptrace.h> 2762306a36Sopenharmony_ci#include <asm/hyperv-tlfs.h> 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#define VTPM_BASE_ADDRESS 0xfed40000 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistruct ms_hyperv_info { 3262306a36Sopenharmony_ci u32 features; 3362306a36Sopenharmony_ci u32 priv_high; 3462306a36Sopenharmony_ci u32 misc_features; 3562306a36Sopenharmony_ci u32 hints; 3662306a36Sopenharmony_ci u32 nested_features; 3762306a36Sopenharmony_ci u32 max_vp_index; 3862306a36Sopenharmony_ci u32 max_lp_index; 3962306a36Sopenharmony_ci u8 vtl; 4062306a36Sopenharmony_ci union { 4162306a36Sopenharmony_ci u32 isolation_config_a; 4262306a36Sopenharmony_ci struct { 4362306a36Sopenharmony_ci u32 paravisor_present : 1; 4462306a36Sopenharmony_ci u32 reserved_a1 : 31; 4562306a36Sopenharmony_ci }; 4662306a36Sopenharmony_ci }; 4762306a36Sopenharmony_ci union { 4862306a36Sopenharmony_ci u32 isolation_config_b; 4962306a36Sopenharmony_ci struct { 5062306a36Sopenharmony_ci u32 cvm_type : 4; 5162306a36Sopenharmony_ci u32 reserved_b1 : 1; 5262306a36Sopenharmony_ci u32 shared_gpa_boundary_active : 1; 5362306a36Sopenharmony_ci u32 shared_gpa_boundary_bits : 6; 5462306a36Sopenharmony_ci u32 reserved_b2 : 20; 5562306a36Sopenharmony_ci }; 5662306a36Sopenharmony_ci }; 5762306a36Sopenharmony_ci u64 shared_gpa_boundary; 5862306a36Sopenharmony_ci}; 5962306a36Sopenharmony_ciextern struct ms_hyperv_info ms_hyperv; 6062306a36Sopenharmony_ciextern bool hv_nested; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ciextern void * __percpu *hyperv_pcpu_input_arg; 6362306a36Sopenharmony_ciextern void * __percpu *hyperv_pcpu_output_arg; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ciextern u64 hv_do_hypercall(u64 control, void *inputaddr, void *outputaddr); 6662306a36Sopenharmony_ciextern u64 hv_do_fast_hypercall8(u16 control, u64 input8); 6762306a36Sopenharmony_cibool hv_isolation_type_snp(void); 6862306a36Sopenharmony_cibool hv_isolation_type_tdx(void); 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci/* Helper functions that provide a consistent pattern for checking Hyper-V hypercall status. */ 7162306a36Sopenharmony_cistatic inline int hv_result(u64 status) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci return status & HV_HYPERCALL_RESULT_MASK; 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cistatic inline bool hv_result_success(u64 status) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci return hv_result(status) == HV_STATUS_SUCCESS; 7962306a36Sopenharmony_ci} 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_cistatic inline unsigned int hv_repcomp(u64 status) 8262306a36Sopenharmony_ci{ 8362306a36Sopenharmony_ci /* Bits [43:32] of status have 'Reps completed' data. */ 8462306a36Sopenharmony_ci return (status & HV_HYPERCALL_REP_COMP_MASK) >> 8562306a36Sopenharmony_ci HV_HYPERCALL_REP_COMP_OFFSET; 8662306a36Sopenharmony_ci} 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci/* 8962306a36Sopenharmony_ci * Rep hypercalls. Callers of this functions are supposed to ensure that 9062306a36Sopenharmony_ci * rep_count and varhead_size comply with Hyper-V hypercall definition. 9162306a36Sopenharmony_ci */ 9262306a36Sopenharmony_cistatic inline u64 hv_do_rep_hypercall(u16 code, u16 rep_count, u16 varhead_size, 9362306a36Sopenharmony_ci void *input, void *output) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci u64 control = code; 9662306a36Sopenharmony_ci u64 status; 9762306a36Sopenharmony_ci u16 rep_comp; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci control |= (u64)varhead_size << HV_HYPERCALL_VARHEAD_OFFSET; 10062306a36Sopenharmony_ci control |= (u64)rep_count << HV_HYPERCALL_REP_COMP_OFFSET; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci do { 10362306a36Sopenharmony_ci status = hv_do_hypercall(control, input, output); 10462306a36Sopenharmony_ci if (!hv_result_success(status)) 10562306a36Sopenharmony_ci return status; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci rep_comp = hv_repcomp(status); 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci control &= ~HV_HYPERCALL_REP_START_MASK; 11062306a36Sopenharmony_ci control |= (u64)rep_comp << HV_HYPERCALL_REP_START_OFFSET; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci touch_nmi_watchdog(); 11362306a36Sopenharmony_ci } while (rep_comp < rep_count); 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci return status; 11662306a36Sopenharmony_ci} 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci/* Generate the guest OS identifier as described in the Hyper-V TLFS */ 11962306a36Sopenharmony_cistatic inline u64 hv_generate_guest_id(u64 kernel_version) 12062306a36Sopenharmony_ci{ 12162306a36Sopenharmony_ci u64 guest_id; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci guest_id = (((u64)HV_LINUX_VENDOR_ID) << 48); 12462306a36Sopenharmony_ci guest_id |= (kernel_version << 16); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci return guest_id; 12762306a36Sopenharmony_ci} 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci/* Free the message slot and signal end-of-message if required */ 13062306a36Sopenharmony_cistatic inline void vmbus_signal_eom(struct hv_message *msg, u32 old_msg_type) 13162306a36Sopenharmony_ci{ 13262306a36Sopenharmony_ci /* 13362306a36Sopenharmony_ci * On crash we're reading some other CPU's message page and we need 13462306a36Sopenharmony_ci * to be careful: this other CPU may already had cleared the header 13562306a36Sopenharmony_ci * and the host may already had delivered some other message there. 13662306a36Sopenharmony_ci * In case we blindly write msg->header.message_type we're going 13762306a36Sopenharmony_ci * to lose it. We can still lose a message of the same type but 13862306a36Sopenharmony_ci * we count on the fact that there can only be one 13962306a36Sopenharmony_ci * CHANNELMSG_UNLOAD_RESPONSE and we don't care about other messages 14062306a36Sopenharmony_ci * on crash. 14162306a36Sopenharmony_ci */ 14262306a36Sopenharmony_ci if (cmpxchg(&msg->header.message_type, old_msg_type, 14362306a36Sopenharmony_ci HVMSG_NONE) != old_msg_type) 14462306a36Sopenharmony_ci return; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci /* 14762306a36Sopenharmony_ci * The cmxchg() above does an implicit memory barrier to 14862306a36Sopenharmony_ci * ensure the write to MessageType (ie set to 14962306a36Sopenharmony_ci * HVMSG_NONE) happens before we read the 15062306a36Sopenharmony_ci * MessagePending and EOMing. Otherwise, the EOMing 15162306a36Sopenharmony_ci * will not deliver any more messages since there is 15262306a36Sopenharmony_ci * no empty slot 15362306a36Sopenharmony_ci */ 15462306a36Sopenharmony_ci if (msg->header.message_flags.msg_pending) { 15562306a36Sopenharmony_ci /* 15662306a36Sopenharmony_ci * This will cause message queue rescan to 15762306a36Sopenharmony_ci * possibly deliver another msg from the 15862306a36Sopenharmony_ci * hypervisor 15962306a36Sopenharmony_ci */ 16062306a36Sopenharmony_ci hv_set_register(HV_REGISTER_EOM, 0); 16162306a36Sopenharmony_ci } 16262306a36Sopenharmony_ci} 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_civoid hv_setup_vmbus_handler(void (*handler)(void)); 16562306a36Sopenharmony_civoid hv_remove_vmbus_handler(void); 16662306a36Sopenharmony_civoid hv_setup_stimer0_handler(void (*handler)(void)); 16762306a36Sopenharmony_civoid hv_remove_stimer0_handler(void); 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_civoid hv_setup_kexec_handler(void (*handler)(void)); 17062306a36Sopenharmony_civoid hv_remove_kexec_handler(void); 17162306a36Sopenharmony_civoid hv_setup_crash_handler(void (*handler)(struct pt_regs *regs)); 17262306a36Sopenharmony_civoid hv_remove_crash_handler(void); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ciextern int vmbus_interrupt; 17562306a36Sopenharmony_ciextern int vmbus_irq; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ciextern bool hv_root_partition; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_HYPERV) 18062306a36Sopenharmony_ci/* 18162306a36Sopenharmony_ci * Hypervisor's notion of virtual processor ID is different from 18262306a36Sopenharmony_ci * Linux' notion of CPU ID. This information can only be retrieved 18362306a36Sopenharmony_ci * in the context of the calling CPU. Setup a map for easy access 18462306a36Sopenharmony_ci * to this information. 18562306a36Sopenharmony_ci */ 18662306a36Sopenharmony_ciextern u32 *hv_vp_index; 18762306a36Sopenharmony_ciextern u32 hv_max_vp_index; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ciextern u64 (*hv_read_reference_counter)(void); 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci/* Sentinel value for an uninitialized entry in hv_vp_index array */ 19262306a36Sopenharmony_ci#define VP_INVAL U32_MAX 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ciint __init hv_common_init(void); 19562306a36Sopenharmony_civoid __init hv_common_free(void); 19662306a36Sopenharmony_ciint hv_common_cpu_init(unsigned int cpu); 19762306a36Sopenharmony_ciint hv_common_cpu_die(unsigned int cpu); 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_civoid *hv_alloc_hyperv_page(void); 20062306a36Sopenharmony_civoid *hv_alloc_hyperv_zeroed_page(void); 20162306a36Sopenharmony_civoid hv_free_hyperv_page(void *addr); 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci/** 20462306a36Sopenharmony_ci * hv_cpu_number_to_vp_number() - Map CPU to VP. 20562306a36Sopenharmony_ci * @cpu_number: CPU number in Linux terms 20662306a36Sopenharmony_ci * 20762306a36Sopenharmony_ci * This function returns the mapping between the Linux processor 20862306a36Sopenharmony_ci * number and the hypervisor's virtual processor number, useful 20962306a36Sopenharmony_ci * in making hypercalls and such that talk about specific 21062306a36Sopenharmony_ci * processors. 21162306a36Sopenharmony_ci * 21262306a36Sopenharmony_ci * Return: Virtual processor number in Hyper-V terms 21362306a36Sopenharmony_ci */ 21462306a36Sopenharmony_cistatic inline int hv_cpu_number_to_vp_number(int cpu_number) 21562306a36Sopenharmony_ci{ 21662306a36Sopenharmony_ci return hv_vp_index[cpu_number]; 21762306a36Sopenharmony_ci} 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_cistatic inline int __cpumask_to_vpset(struct hv_vpset *vpset, 22062306a36Sopenharmony_ci const struct cpumask *cpus, 22162306a36Sopenharmony_ci bool (*func)(int cpu)) 22262306a36Sopenharmony_ci{ 22362306a36Sopenharmony_ci int cpu, vcpu, vcpu_bank, vcpu_offset, nr_bank = 1; 22462306a36Sopenharmony_ci int max_vcpu_bank = hv_max_vp_index / HV_VCPUS_PER_SPARSE_BANK; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci /* vpset.valid_bank_mask can represent up to HV_MAX_SPARSE_VCPU_BANKS banks */ 22762306a36Sopenharmony_ci if (max_vcpu_bank >= HV_MAX_SPARSE_VCPU_BANKS) 22862306a36Sopenharmony_ci return 0; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci /* 23162306a36Sopenharmony_ci * Clear all banks up to the maximum possible bank as hv_tlb_flush_ex 23262306a36Sopenharmony_ci * structs are not cleared between calls, we risk flushing unneeded 23362306a36Sopenharmony_ci * vCPUs otherwise. 23462306a36Sopenharmony_ci */ 23562306a36Sopenharmony_ci for (vcpu_bank = 0; vcpu_bank <= max_vcpu_bank; vcpu_bank++) 23662306a36Sopenharmony_ci vpset->bank_contents[vcpu_bank] = 0; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci /* 23962306a36Sopenharmony_ci * Some banks may end up being empty but this is acceptable. 24062306a36Sopenharmony_ci */ 24162306a36Sopenharmony_ci for_each_cpu(cpu, cpus) { 24262306a36Sopenharmony_ci if (func && func(cpu)) 24362306a36Sopenharmony_ci continue; 24462306a36Sopenharmony_ci vcpu = hv_cpu_number_to_vp_number(cpu); 24562306a36Sopenharmony_ci if (vcpu == VP_INVAL) 24662306a36Sopenharmony_ci return -1; 24762306a36Sopenharmony_ci vcpu_bank = vcpu / HV_VCPUS_PER_SPARSE_BANK; 24862306a36Sopenharmony_ci vcpu_offset = vcpu % HV_VCPUS_PER_SPARSE_BANK; 24962306a36Sopenharmony_ci __set_bit(vcpu_offset, (unsigned long *) 25062306a36Sopenharmony_ci &vpset->bank_contents[vcpu_bank]); 25162306a36Sopenharmony_ci if (vcpu_bank >= nr_bank) 25262306a36Sopenharmony_ci nr_bank = vcpu_bank + 1; 25362306a36Sopenharmony_ci } 25462306a36Sopenharmony_ci vpset->valid_bank_mask = GENMASK_ULL(nr_bank - 1, 0); 25562306a36Sopenharmony_ci return nr_bank; 25662306a36Sopenharmony_ci} 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci/* 25962306a36Sopenharmony_ci * Convert a Linux cpumask into a Hyper-V VPset. In the _skip variant, 26062306a36Sopenharmony_ci * 'func' is called for each CPU present in cpumask. If 'func' returns 26162306a36Sopenharmony_ci * true, that CPU is skipped -- i.e., that CPU from cpumask is *not* 26262306a36Sopenharmony_ci * added to the Hyper-V VPset. If 'func' is NULL, no CPUs are 26362306a36Sopenharmony_ci * skipped. 26462306a36Sopenharmony_ci */ 26562306a36Sopenharmony_cistatic inline int cpumask_to_vpset(struct hv_vpset *vpset, 26662306a36Sopenharmony_ci const struct cpumask *cpus) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci return __cpumask_to_vpset(vpset, cpus, NULL); 26962306a36Sopenharmony_ci} 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_cistatic inline int cpumask_to_vpset_skip(struct hv_vpset *vpset, 27262306a36Sopenharmony_ci const struct cpumask *cpus, 27362306a36Sopenharmony_ci bool (*func)(int cpu)) 27462306a36Sopenharmony_ci{ 27562306a36Sopenharmony_ci return __cpumask_to_vpset(vpset, cpus, func); 27662306a36Sopenharmony_ci} 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_civoid hyperv_report_panic(struct pt_regs *regs, long err, bool in_die); 27962306a36Sopenharmony_cibool hv_is_hyperv_initialized(void); 28062306a36Sopenharmony_cibool hv_is_hibernation_supported(void); 28162306a36Sopenharmony_cienum hv_isolation_type hv_get_isolation_type(void); 28262306a36Sopenharmony_cibool hv_is_isolation_supported(void); 28362306a36Sopenharmony_cibool hv_isolation_type_snp(void); 28462306a36Sopenharmony_ciu64 hv_ghcb_hypercall(u64 control, void *input, void *output, u32 input_size); 28562306a36Sopenharmony_ciu64 hv_tdx_hypercall(u64 control, u64 param1, u64 param2); 28662306a36Sopenharmony_civoid hyperv_cleanup(void); 28762306a36Sopenharmony_cibool hv_query_ext_cap(u64 cap_query); 28862306a36Sopenharmony_civoid hv_setup_dma_ops(struct device *dev, bool coherent); 28962306a36Sopenharmony_ci#else /* CONFIG_HYPERV */ 29062306a36Sopenharmony_cistatic inline bool hv_is_hyperv_initialized(void) { return false; } 29162306a36Sopenharmony_cistatic inline bool hv_is_hibernation_supported(void) { return false; } 29262306a36Sopenharmony_cistatic inline void hyperv_cleanup(void) {} 29362306a36Sopenharmony_cistatic inline bool hv_is_isolation_supported(void) { return false; } 29462306a36Sopenharmony_cistatic inline enum hv_isolation_type hv_get_isolation_type(void) 29562306a36Sopenharmony_ci{ 29662306a36Sopenharmony_ci return HV_ISOLATION_TYPE_NONE; 29762306a36Sopenharmony_ci} 29862306a36Sopenharmony_ci#endif /* CONFIG_HYPERV */ 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci#endif 301