brintos

brintos / linux-shallow public Read only

0
0
Text · 9.1 KiB · 8fe7aaa Raw
319 lines · c
1/* SPDX-License-Identifier: GPL-2.0 */2 3/*4 * Linux-specific definitions for managing interactions with Microsoft's5 * Hyper-V hypervisor. The definitions in this file are architecture6 * independent. See arch/<arch>/include/asm/mshyperv.h for definitions7 * that are specific to architecture <arch>.8 *9 * Definitions that are specified in the Hyper-V Top Level Functional10 * Spec (TLFS) should not go in this file, but should instead go in11 * hyperv-tlfs.h.12 *13 * Copyright (C) 2019, Microsoft, Inc.14 *15 * Author : Michael Kelley <mikelley@microsoft.com>16 */17 18#ifndef _ASM_GENERIC_MSHYPERV_H19#define _ASM_GENERIC_MSHYPERV_H20 21#include <linux/types.h>22#include <linux/atomic.h>23#include <linux/bitops.h>24#include <acpi/acpi_numa.h>25#include <linux/cpumask.h>26#include <linux/nmi.h>27#include <asm/ptrace.h>28#include <asm/hyperv-tlfs.h>29 30#define VTPM_BASE_ADDRESS 0xfed4000031 32struct ms_hyperv_info {33	u32 features;34	u32 priv_high;35	u32 misc_features;36	u32 hints;37	u32 nested_features;38	u32 max_vp_index;39	u32 max_lp_index;40	u8 vtl;41	union {42		u32 isolation_config_a;43		struct {44			u32 paravisor_present : 1;45			u32 reserved_a1 : 31;46		};47	};48	union {49		u32 isolation_config_b;50		struct {51			u32 cvm_type : 4;52			u32 reserved_b1 : 1;53			u32 shared_gpa_boundary_active : 1;54			u32 shared_gpa_boundary_bits : 6;55			u32 reserved_b2 : 20;56		};57	};58	u64 shared_gpa_boundary;59};60extern struct ms_hyperv_info ms_hyperv;61extern bool hv_nested;62 63extern void * __percpu *hyperv_pcpu_input_arg;64extern void * __percpu *hyperv_pcpu_output_arg;65 66extern u64 hv_do_hypercall(u64 control, void *inputaddr, void *outputaddr);67extern u64 hv_do_fast_hypercall8(u16 control, u64 input8);68bool hv_isolation_type_snp(void);69bool hv_isolation_type_tdx(void);70 71static inline struct hv_proximity_domain_info hv_numa_node_to_pxm_info(int node)72{73	struct hv_proximity_domain_info pxm_info = {};74 75	if (node != NUMA_NO_NODE) {76		pxm_info.domain_id = node_to_pxm(node);77		pxm_info.flags.proximity_info_valid = 1;78		pxm_info.flags.proximity_preferred = 1;79	}80 81	return pxm_info;82}83 84/* Helper functions that provide a consistent pattern for checking Hyper-V hypercall status. */85static inline int hv_result(u64 status)86{87	return status & HV_HYPERCALL_RESULT_MASK;88}89 90static inline bool hv_result_success(u64 status)91{92	return hv_result(status) == HV_STATUS_SUCCESS;93}94 95static inline unsigned int hv_repcomp(u64 status)96{97	/* Bits [43:32] of status have 'Reps completed' data. */98	return (status & HV_HYPERCALL_REP_COMP_MASK) >>99			 HV_HYPERCALL_REP_COMP_OFFSET;100}101 102/*103 * Rep hypercalls. Callers of this functions are supposed to ensure that104 * rep_count and varhead_size comply with Hyper-V hypercall definition.105 */106static inline u64 hv_do_rep_hypercall(u16 code, u16 rep_count, u16 varhead_size,107				      void *input, void *output)108{109	u64 control = code;110	u64 status;111	u16 rep_comp;112 113	control |= (u64)varhead_size << HV_HYPERCALL_VARHEAD_OFFSET;114	control |= (u64)rep_count << HV_HYPERCALL_REP_COMP_OFFSET;115 116	do {117		status = hv_do_hypercall(control, input, output);118		if (!hv_result_success(status))119			return status;120 121		rep_comp = hv_repcomp(status);122 123		control &= ~HV_HYPERCALL_REP_START_MASK;124		control |= (u64)rep_comp << HV_HYPERCALL_REP_START_OFFSET;125 126		touch_nmi_watchdog();127	} while (rep_comp < rep_count);128 129	return status;130}131 132/* Generate the guest OS identifier as described in the Hyper-V TLFS */133static inline u64 hv_generate_guest_id(u64 kernel_version)134{135	u64 guest_id;136 137	guest_id = (((u64)HV_LINUX_VENDOR_ID) << 48);138	guest_id |= (kernel_version << 16);139 140	return guest_id;141}142 143/* Free the message slot and signal end-of-message if required */144static inline void vmbus_signal_eom(struct hv_message *msg, u32 old_msg_type)145{146	/*147	 * On crash we're reading some other CPU's message page and we need148	 * to be careful: this other CPU may already had cleared the header149	 * and the host may already had delivered some other message there.150	 * In case we blindly write msg->header.message_type we're going151	 * to lose it. We can still lose a message of the same type but152	 * we count on the fact that there can only be one153	 * CHANNELMSG_UNLOAD_RESPONSE and we don't care about other messages154	 * on crash.155	 */156	if (cmpxchg(&msg->header.message_type, old_msg_type,157		    HVMSG_NONE) != old_msg_type)158		return;159 160	/*161	 * The cmxchg() above does an implicit memory barrier to162	 * ensure the write to MessageType (ie set to163	 * HVMSG_NONE) happens before we read the164	 * MessagePending and EOMing. Otherwise, the EOMing165	 * will not deliver any more messages since there is166	 * no empty slot167	 */168	if (msg->header.message_flags.msg_pending) {169		/*170		 * This will cause message queue rescan to171		 * possibly deliver another msg from the172		 * hypervisor173		 */174		hv_set_msr(HV_MSR_EOM, 0);175	}176}177 178int hv_get_hypervisor_version(union hv_hypervisor_version_info *info);179 180void hv_setup_vmbus_handler(void (*handler)(void));181void hv_remove_vmbus_handler(void);182void hv_setup_stimer0_handler(void (*handler)(void));183void hv_remove_stimer0_handler(void);184 185void hv_setup_kexec_handler(void (*handler)(void));186void hv_remove_kexec_handler(void);187void hv_setup_crash_handler(void (*handler)(struct pt_regs *regs));188void hv_remove_crash_handler(void);189 190extern int vmbus_interrupt;191extern int vmbus_irq;192 193extern bool hv_root_partition;194 195#if IS_ENABLED(CONFIG_HYPERV)196/*197 * Hypervisor's notion of virtual processor ID is different from198 * Linux' notion of CPU ID. This information can only be retrieved199 * in the context of the calling CPU. Setup a map for easy access200 * to this information.201 */202extern u32 *hv_vp_index;203extern u32 hv_max_vp_index;204 205extern u64 (*hv_read_reference_counter)(void);206 207/* Sentinel value for an uninitialized entry in hv_vp_index array */208#define VP_INVAL	U32_MAX209 210int __init hv_common_init(void);211void __init hv_common_free(void);212void __init ms_hyperv_late_init(void);213int hv_common_cpu_init(unsigned int cpu);214int hv_common_cpu_die(unsigned int cpu);215 216void *hv_alloc_hyperv_page(void);217void *hv_alloc_hyperv_zeroed_page(void);218void hv_free_hyperv_page(void *addr);219 220/**221 * hv_cpu_number_to_vp_number() - Map CPU to VP.222 * @cpu_number: CPU number in Linux terms223 *224 * This function returns the mapping between the Linux processor225 * number and the hypervisor's virtual processor number, useful226 * in making hypercalls and such that talk about specific227 * processors.228 *229 * Return: Virtual processor number in Hyper-V terms230 */231static inline int hv_cpu_number_to_vp_number(int cpu_number)232{233	return hv_vp_index[cpu_number];234}235 236static inline int __cpumask_to_vpset(struct hv_vpset *vpset,237				    const struct cpumask *cpus,238				    bool (*func)(int cpu))239{240	int cpu, vcpu, vcpu_bank, vcpu_offset, nr_bank = 1;241	int max_vcpu_bank = hv_max_vp_index / HV_VCPUS_PER_SPARSE_BANK;242 243	/* vpset.valid_bank_mask can represent up to HV_MAX_SPARSE_VCPU_BANKS banks */244	if (max_vcpu_bank >= HV_MAX_SPARSE_VCPU_BANKS)245		return 0;246 247	/*248	 * Clear all banks up to the maximum possible bank as hv_tlb_flush_ex249	 * structs are not cleared between calls, we risk flushing unneeded250	 * vCPUs otherwise.251	 */252	for (vcpu_bank = 0; vcpu_bank <= max_vcpu_bank; vcpu_bank++)253		vpset->bank_contents[vcpu_bank] = 0;254 255	/*256	 * Some banks may end up being empty but this is acceptable.257	 */258	for_each_cpu(cpu, cpus) {259		if (func && func(cpu))260			continue;261		vcpu = hv_cpu_number_to_vp_number(cpu);262		if (vcpu == VP_INVAL)263			return -1;264		vcpu_bank = vcpu / HV_VCPUS_PER_SPARSE_BANK;265		vcpu_offset = vcpu % HV_VCPUS_PER_SPARSE_BANK;266		__set_bit(vcpu_offset, (unsigned long *)267			  &vpset->bank_contents[vcpu_bank]);268		if (vcpu_bank >= nr_bank)269			nr_bank = vcpu_bank + 1;270	}271	vpset->valid_bank_mask = GENMASK_ULL(nr_bank - 1, 0);272	return nr_bank;273}274 275/*276 * Convert a Linux cpumask into a Hyper-V VPset. In the _skip variant,277 * 'func' is called for each CPU present in cpumask.  If 'func' returns278 * true, that CPU is skipped -- i.e., that CPU from cpumask is *not*279 * added to the Hyper-V VPset. If 'func' is NULL, no CPUs are280 * skipped.281 */282static inline int cpumask_to_vpset(struct hv_vpset *vpset,283				    const struct cpumask *cpus)284{285	return __cpumask_to_vpset(vpset, cpus, NULL);286}287 288static inline int cpumask_to_vpset_skip(struct hv_vpset *vpset,289				    const struct cpumask *cpus,290				    bool (*func)(int cpu))291{292	return __cpumask_to_vpset(vpset, cpus, func);293}294 295void hyperv_report_panic(struct pt_regs *regs, long err, bool in_die);296bool hv_is_hyperv_initialized(void);297bool hv_is_hibernation_supported(void);298enum hv_isolation_type hv_get_isolation_type(void);299bool hv_is_isolation_supported(void);300bool hv_isolation_type_snp(void);301u64 hv_ghcb_hypercall(u64 control, void *input, void *output, u32 input_size);302u64 hv_tdx_hypercall(u64 control, u64 param1, u64 param2);303void hyperv_cleanup(void);304bool hv_query_ext_cap(u64 cap_query);305void hv_setup_dma_ops(struct device *dev, bool coherent);306#else /* CONFIG_HYPERV */307static inline bool hv_is_hyperv_initialized(void) { return false; }308static inline bool hv_is_hibernation_supported(void) { return false; }309static inline void hyperv_cleanup(void) {}310static inline void ms_hyperv_late_init(void) {}311static inline bool hv_is_isolation_supported(void) { return false; }312static inline enum hv_isolation_type hv_get_isolation_type(void)313{314	return HV_ISOLATION_TYPE_NONE;315}316#endif /* CONFIG_HYPERV */317 318#endif319