linux/include/asm-generic/mshyperv.h
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0 */
   2
   3/*
   4 * Linux-specific definitions for managing interactions with Microsoft's
   5 * Hyper-V hypervisor. The definitions in this file are architecture
   6 * independent. See arch/<arch>/include/asm/mshyperv.h for definitions
   7 * that are specific to architecture <arch>.
   8 *
   9 * Definitions that are specified in the Hyper-V Top Level Functional
  10 * Spec (TLFS) should not go in this file, but should instead go in
  11 * 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_H
  19#define _ASM_GENERIC_MSHYPERV_H
  20
  21#include <linux/types.h>
  22#include <linux/atomic.h>
  23#include <linux/bitops.h>
  24#include <linux/cpumask.h>
  25#include <linux/nmi.h>
  26#include <asm/ptrace.h>
  27#include <asm/hyperv-tlfs.h>
  28
  29struct ms_hyperv_info {
  30        u32 features;
  31        u32 priv_high;
  32        u32 misc_features;
  33        u32 hints;
  34        u32 nested_features;
  35        u32 max_vp_index;
  36        u32 max_lp_index;
  37        u32 isolation_config_a;
  38        u32 isolation_config_b;
  39};
  40extern struct ms_hyperv_info ms_hyperv;
  41
  42extern void  __percpu  **hyperv_pcpu_input_arg;
  43extern void  __percpu  **hyperv_pcpu_output_arg;
  44
  45extern u64 hv_do_hypercall(u64 control, void *inputaddr, void *outputaddr);
  46extern u64 hv_do_fast_hypercall8(u16 control, u64 input8);
  47
  48/* Helper functions that provide a consistent pattern for checking Hyper-V hypercall status. */
  49static inline int hv_result(u64 status)
  50{
  51        return status & HV_HYPERCALL_RESULT_MASK;
  52}
  53
  54static inline bool hv_result_success(u64 status)
  55{
  56        return hv_result(status) == HV_STATUS_SUCCESS;
  57}
  58
  59static inline unsigned int hv_repcomp(u64 status)
  60{
  61        /* Bits [43:32] of status have 'Reps completed' data. */
  62        return (status & HV_HYPERCALL_REP_COMP_MASK) >>
  63                         HV_HYPERCALL_REP_COMP_OFFSET;
  64}
  65
  66/*
  67 * Rep hypercalls. Callers of this functions are supposed to ensure that
  68 * rep_count and varhead_size comply with Hyper-V hypercall definition.
  69 */
  70static inline u64 hv_do_rep_hypercall(u16 code, u16 rep_count, u16 varhead_size,
  71                                      void *input, void *output)
  72{
  73        u64 control = code;
  74        u64 status;
  75        u16 rep_comp;
  76
  77        control |= (u64)varhead_size << HV_HYPERCALL_VARHEAD_OFFSET;
  78        control |= (u64)rep_count << HV_HYPERCALL_REP_COMP_OFFSET;
  79
  80        do {
  81                status = hv_do_hypercall(control, input, output);
  82                if (!hv_result_success(status))
  83                        return status;
  84
  85                rep_comp = hv_repcomp(status);
  86
  87                control &= ~HV_HYPERCALL_REP_START_MASK;
  88                control |= (u64)rep_comp << HV_HYPERCALL_REP_START_OFFSET;
  89
  90                touch_nmi_watchdog();
  91        } while (rep_comp < rep_count);
  92
  93        return status;
  94}
  95
  96/* Generate the guest OS identifier as described in the Hyper-V TLFS */
  97static inline  __u64 generate_guest_id(__u64 d_info1, __u64 kernel_version,
  98                                       __u64 d_info2)
  99{
 100        __u64 guest_id = 0;
 101
 102        guest_id = (((__u64)HV_LINUX_VENDOR_ID) << 48);
 103        guest_id |= (d_info1 << 48);
 104        guest_id |= (kernel_version << 16);
 105        guest_id |= d_info2;
 106
 107        return guest_id;
 108}
 109
 110/* Free the message slot and signal end-of-message if required */
 111static inline void vmbus_signal_eom(struct hv_message *msg, u32 old_msg_type)
 112{
 113        /*
 114         * On crash we're reading some other CPU's message page and we need
 115         * to be careful: this other CPU may already had cleared the header
 116         * and the host may already had delivered some other message there.
 117         * In case we blindly write msg->header.message_type we're going
 118         * to lose it. We can still lose a message of the same type but
 119         * we count on the fact that there can only be one
 120         * CHANNELMSG_UNLOAD_RESPONSE and we don't care about other messages
 121         * on crash.
 122         */
 123        if (cmpxchg(&msg->header.message_type, old_msg_type,
 124                    HVMSG_NONE) != old_msg_type)
 125                return;
 126
 127        /*
 128         * The cmxchg() above does an implicit memory barrier to
 129         * ensure the write to MessageType (ie set to
 130         * HVMSG_NONE) happens before we read the
 131         * MessagePending and EOMing. Otherwise, the EOMing
 132         * will not deliver any more messages since there is
 133         * no empty slot
 134         */
 135        if (msg->header.message_flags.msg_pending) {
 136                /*
 137                 * This will cause message queue rescan to
 138                 * possibly deliver another msg from the
 139                 * hypervisor
 140                 */
 141                hv_set_register(HV_REGISTER_EOM, 0);
 142        }
 143}
 144
 145void hv_setup_vmbus_handler(void (*handler)(void));
 146void hv_remove_vmbus_handler(void);
 147void hv_setup_stimer0_handler(void (*handler)(void));
 148void hv_remove_stimer0_handler(void);
 149
 150void hv_setup_kexec_handler(void (*handler)(void));
 151void hv_remove_kexec_handler(void);
 152void hv_setup_crash_handler(void (*handler)(struct pt_regs *regs));
 153void hv_remove_crash_handler(void);
 154
 155extern int vmbus_interrupt;
 156extern int vmbus_irq;
 157
 158extern bool hv_root_partition;
 159
 160#if IS_ENABLED(CONFIG_HYPERV)
 161/*
 162 * Hypervisor's notion of virtual processor ID is different from
 163 * Linux' notion of CPU ID. This information can only be retrieved
 164 * in the context of the calling CPU. Setup a map for easy access
 165 * to this information.
 166 */
 167extern u32 *hv_vp_index;
 168extern u32 hv_max_vp_index;
 169
 170extern u64 (*hv_read_reference_counter)(void);
 171
 172/* Sentinel value for an uninitialized entry in hv_vp_index array */
 173#define VP_INVAL        U32_MAX
 174
 175int __init hv_common_init(void);
 176void __init hv_common_free(void);
 177int hv_common_cpu_init(unsigned int cpu);
 178int hv_common_cpu_die(unsigned int cpu);
 179
 180void *hv_alloc_hyperv_page(void);
 181void *hv_alloc_hyperv_zeroed_page(void);
 182void hv_free_hyperv_page(unsigned long addr);
 183
 184/**
 185 * hv_cpu_number_to_vp_number() - Map CPU to VP.
 186 * @cpu_number: CPU number in Linux terms
 187 *
 188 * This function returns the mapping between the Linux processor
 189 * number and the hypervisor's virtual processor number, useful
 190 * in making hypercalls and such that talk about specific
 191 * processors.
 192 *
 193 * Return: Virtual processor number in Hyper-V terms
 194 */
 195static inline int hv_cpu_number_to_vp_number(int cpu_number)
 196{
 197        return hv_vp_index[cpu_number];
 198}
 199
 200static inline int __cpumask_to_vpset(struct hv_vpset *vpset,
 201                                    const struct cpumask *cpus,
 202                                    bool exclude_self)
 203{
 204        int cpu, vcpu, vcpu_bank, vcpu_offset, nr_bank = 1;
 205        int this_cpu = smp_processor_id();
 206
 207        /* valid_bank_mask can represent up to 64 banks */
 208        if (hv_max_vp_index / 64 >= 64)
 209                return 0;
 210
 211        /*
 212         * Clear all banks up to the maximum possible bank as hv_tlb_flush_ex
 213         * structs are not cleared between calls, we risk flushing unneeded
 214         * vCPUs otherwise.
 215         */
 216        for (vcpu_bank = 0; vcpu_bank <= hv_max_vp_index / 64; vcpu_bank++)
 217                vpset->bank_contents[vcpu_bank] = 0;
 218
 219        /*
 220         * Some banks may end up being empty but this is acceptable.
 221         */
 222        for_each_cpu(cpu, cpus) {
 223                if (exclude_self && cpu == this_cpu)
 224                        continue;
 225                vcpu = hv_cpu_number_to_vp_number(cpu);
 226                if (vcpu == VP_INVAL)
 227                        return -1;
 228                vcpu_bank = vcpu / 64;
 229                vcpu_offset = vcpu % 64;
 230                __set_bit(vcpu_offset, (unsigned long *)
 231                          &vpset->bank_contents[vcpu_bank]);
 232                if (vcpu_bank >= nr_bank)
 233                        nr_bank = vcpu_bank + 1;
 234        }
 235        vpset->valid_bank_mask = GENMASK_ULL(nr_bank - 1, 0);
 236        return nr_bank;
 237}
 238
 239static inline int cpumask_to_vpset(struct hv_vpset *vpset,
 240                                    const struct cpumask *cpus)
 241{
 242        return __cpumask_to_vpset(vpset, cpus, false);
 243}
 244
 245static inline int cpumask_to_vpset_noself(struct hv_vpset *vpset,
 246                                    const struct cpumask *cpus)
 247{
 248        WARN_ON_ONCE(preemptible());
 249        return __cpumask_to_vpset(vpset, cpus, true);
 250}
 251
 252void hyperv_report_panic(struct pt_regs *regs, long err, bool in_die);
 253bool hv_is_hyperv_initialized(void);
 254bool hv_is_hibernation_supported(void);
 255enum hv_isolation_type hv_get_isolation_type(void);
 256bool hv_is_isolation_supported(void);
 257void hyperv_cleanup(void);
 258bool hv_query_ext_cap(u64 cap_query);
 259#else /* CONFIG_HYPERV */
 260static inline bool hv_is_hyperv_initialized(void) { return false; }
 261static inline bool hv_is_hibernation_supported(void) { return false; }
 262static inline void hyperv_cleanup(void) {}
 263#endif /* CONFIG_HYPERV */
 264
 265#endif
 266