Skip to content

Instantly share code, notes, and snippets.

@zhangyoufu
Created November 17, 2024 18:24
Show Gist options
  • Select an option

  • Save zhangyoufu/7b114ae82de824adf86bea6acf6ce4f4 to your computer and use it in GitHub Desktop.

Select an option

Save zhangyoufu/7b114ae82de824adf86bea6acf6ce4f4 to your computer and use it in GitHub Desktop.
check enabled Hyper-V Enlightenment inside VM
#include <intrin.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
/******************************************************************************/
// include/qemu/bitops.h
#define BIT(nr) (1UL << (nr))
/******************************************************************************/
// target/i386/kvm/hyperv-proto.h
#define HV_CPUID_VENDOR_AND_MAX_FUNCTIONS 0x40000000
#define HV_CPUID_INTERFACE 0x40000001
#define HV_CPUID_VERSION 0x40000002
#define HV_CPUID_FEATURES 0x40000003
#define HV_CPUID_ENLIGHTMENT_INFO 0x40000004
#define HV_CPUID_IMPLEMENT_LIMITS 0x40000005
#define HV_CPUID_NESTED_FEATURES 0x4000000A
#define HV_CPUID_SYNDBG_VENDOR_AND_MAX_FUNCTIONS 0x40000080
#define HV_CPUID_SYNDBG_INTERFACE 0x40000081
#define HV_CPUID_SYNDBG_PLATFORM_CAPABILITIES 0x40000082
#define HV_CPUID_MIN 0x40000005
#define HV_CPUID_MAX 0x4000ffff
#define HV_HYPERVISOR_PRESENT_BIT 0x80000000
/*
* HV_CPUID_FEATURES.EAX bits
*/
#define HV_VP_RUNTIME_AVAILABLE (1u << 0)
#define HV_TIME_REF_COUNT_AVAILABLE (1u << 1)
#define HV_SYNIC_AVAILABLE (1u << 2)
#define HV_SYNTIMERS_AVAILABLE (1u << 3)
#define HV_APIC_ACCESS_AVAILABLE (1u << 4)
#define HV_HYPERCALL_AVAILABLE (1u << 5)
#define HV_VP_INDEX_AVAILABLE (1u << 6)
#define HV_RESET_AVAILABLE (1u << 7)
#define HV_REFERENCE_TSC_AVAILABLE (1u << 9)
#define HV_ACCESS_FREQUENCY_MSRS (1u << 11)
#define HV_ACCESS_REENLIGHTENMENTS_CONTROL (1u << 13)
/*
* HV_CPUID_FEATURES.EBX bits
*/
#define HV_POST_MESSAGES (1u << 4)
#define HV_SIGNAL_EVENTS (1u << 5)
/*
* HV_CPUID_FEATURES.EDX bits
*/
#define HV_MWAIT_AVAILABLE (1u << 0)
#define HV_GUEST_DEBUGGING_AVAILABLE (1u << 1)
#define HV_PERF_MONITOR_AVAILABLE (1u << 2)
#define HV_CPU_DYNAMIC_PARTITIONING_AVAILABLE (1u << 3)
#define HV_HYPERCALL_XMM_INPUT_AVAILABLE (1u << 4)
#define HV_GUEST_IDLE_STATE_AVAILABLE (1u << 5)
#define HV_FREQUENCY_MSRS_AVAILABLE (1u << 8)
#define HV_GUEST_CRASH_MSR_AVAILABLE (1u << 10)
#define HV_FEATURE_DEBUG_MSRS_AVAILABLE (1u << 11)
#define HV_EXT_GVA_RANGES_FLUSH_AVAILABLE (1u << 14)
#define HV_STIMER_DIRECT_MODE_AVAILABLE (1u << 19)
/*
* HV_CPUID_FEATURES.EBX bits
*/
#define HV_PARTITION_DEBUGGING_ALLOWED (1u << 12)
/*
* HV_CPUID_ENLIGHTMENT_INFO.EAX bits
*/
#define HV_AS_SWITCH_RECOMMENDED (1u << 0)
#define HV_LOCAL_TLB_FLUSH_RECOMMENDED (1u << 1)
#define HV_REMOTE_TLB_FLUSH_RECOMMENDED (1u << 2)
#define HV_APIC_ACCESS_RECOMMENDED (1u << 3)
#define HV_SYSTEM_RESET_RECOMMENDED (1u << 4)
#define HV_RELAXED_TIMING_RECOMMENDED (1u << 5)
#define HV_DEPRECATING_AEOI_RECOMMENDED (1u << 9)
#define HV_CLUSTER_IPI_RECOMMENDED (1u << 10)
#define HV_EX_PROCESSOR_MASKS_RECOMMENDED (1u << 11)
#define HV_ENLIGHTENED_VMCS_RECOMMENDED (1u << 14)
#define HV_NO_NONARCH_CORESHARING (1u << 18)
/*
* HV_CPUID_SYNDBG_PLATFORM_CAPABILITIES.EAX bits
*/
#define HV_SYNDBG_CAP_ALLOW_KERNEL_DEBUGGING (1u << 1)
/*
* HV_CPUID_NESTED_FEATURES.EAX bits
*/
#define HV_NESTED_DIRECT_FLUSH (1u << 17)
#define HV_NESTED_MSR_BITMAP (1u << 19)
/******************************************************************************/
// target/i386/cpu.h
/* Supported Hyper-V Enlightenments */
#define HYPERV_FEAT_RELAXED 0
#define HYPERV_FEAT_VAPIC 1
#define HYPERV_FEAT_TIME 2
#define HYPERV_FEAT_CRASH 3
#define HYPERV_FEAT_RESET 4
#define HYPERV_FEAT_VPINDEX 5
#define HYPERV_FEAT_RUNTIME 6
#define HYPERV_FEAT_SYNIC 7
#define HYPERV_FEAT_STIMER 8
#define HYPERV_FEAT_FREQUENCIES 9
#define HYPERV_FEAT_REENLIGHTENMENT 10
#define HYPERV_FEAT_TLBFLUSH 11
#define HYPERV_FEAT_EVMCS 12
#define HYPERV_FEAT_IPI 13
#define HYPERV_FEAT_STIMER_DIRECT 14
#define HYPERV_FEAT_AVIC 15
#define HYPERV_FEAT_SYNDBG 16
#define HYPERV_FEAT_MSR_BITMAP 17
#define HYPERV_FEAT_XMM_INPUT 18
#define HYPERV_FEAT_TLBFLUSH_EXT 19
#define HYPERV_FEAT_TLBFLUSH_DIRECT 20
/******************************************************************************/
// modified
enum {
R_EAX = 0,
R_EBX = 1,
R_ECX = 2,
R_EDX = 3,
};
/******************************************************************************/
// target/i386/kvm/kvm.c
static struct {
const char* desc;
struct {
uint32_t func;
int reg;
uint32_t bits;
} flags[2];
uint64_t dependencies;
bool skip_passthrough;
} kvm_hyperv_properties[] = {
[HYPERV_FEAT_RELAXED] = {
.desc = "relaxed timing (hv-relaxed)",
.flags = {
{.func = HV_CPUID_ENLIGHTMENT_INFO, .reg = R_EAX,
.bits = HV_RELAXED_TIMING_RECOMMENDED}
}
},
[HYPERV_FEAT_VAPIC] = {
.desc = "virtual APIC (hv-vapic)",
.flags = {
{.func = HV_CPUID_FEATURES, .reg = R_EAX,
.bits = HV_APIC_ACCESS_AVAILABLE}
}
},
[HYPERV_FEAT_TIME] = {
.desc = "clocksources (hv-time)",
.flags = {
{.func = HV_CPUID_FEATURES, .reg = R_EAX,
.bits = HV_TIME_REF_COUNT_AVAILABLE | HV_REFERENCE_TSC_AVAILABLE}
}
},
[HYPERV_FEAT_CRASH] = {
.desc = "crash MSRs (hv-crash)",
.flags = {
{.func = HV_CPUID_FEATURES, .reg = R_EDX,
.bits = HV_GUEST_CRASH_MSR_AVAILABLE}
}
},
[HYPERV_FEAT_RESET] = {
.desc = "reset MSR (hv-reset)",
.flags = {
{.func = HV_CPUID_FEATURES, .reg = R_EAX,
.bits = HV_RESET_AVAILABLE}
}
},
[HYPERV_FEAT_VPINDEX] = {
.desc = "VP_INDEX MSR (hv-vpindex)",
.flags = {
{.func = HV_CPUID_FEATURES, .reg = R_EAX,
.bits = HV_VP_INDEX_AVAILABLE}
}
},
[HYPERV_FEAT_RUNTIME] = {
.desc = "VP_RUNTIME MSR (hv-runtime)",
.flags = {
{.func = HV_CPUID_FEATURES, .reg = R_EAX,
.bits = HV_VP_RUNTIME_AVAILABLE}
}
},
[HYPERV_FEAT_SYNIC] = {
.desc = "synthetic interrupt controller (hv-synic)",
.flags = {
{.func = HV_CPUID_FEATURES, .reg = R_EAX,
.bits = HV_SYNIC_AVAILABLE}
}
},
[HYPERV_FEAT_STIMER] = {
.desc = "synthetic timers (hv-stimer)",
.flags = {
{.func = HV_CPUID_FEATURES, .reg = R_EAX,
.bits = HV_SYNTIMERS_AVAILABLE}
},
.dependencies = BIT(HYPERV_FEAT_SYNIC) | BIT(HYPERV_FEAT_TIME)
},
[HYPERV_FEAT_FREQUENCIES] = {
.desc = "frequency MSRs (hv-frequencies)",
.flags = {
{.func = HV_CPUID_FEATURES, .reg = R_EAX,
.bits = HV_ACCESS_FREQUENCY_MSRS},
{.func = HV_CPUID_FEATURES, .reg = R_EDX,
.bits = HV_FREQUENCY_MSRS_AVAILABLE}
}
},
[HYPERV_FEAT_REENLIGHTENMENT] = {
.desc = "reenlightenment MSRs (hv-reenlightenment)",
.flags = {
{.func = HV_CPUID_FEATURES, .reg = R_EAX,
.bits = HV_ACCESS_REENLIGHTENMENTS_CONTROL}
}
},
[HYPERV_FEAT_TLBFLUSH] = {
.desc = "paravirtualized TLB flush (hv-tlbflush)",
.flags = {
{.func = HV_CPUID_ENLIGHTMENT_INFO, .reg = R_EAX,
.bits = HV_REMOTE_TLB_FLUSH_RECOMMENDED |
HV_EX_PROCESSOR_MASKS_RECOMMENDED}
},
.dependencies = BIT(HYPERV_FEAT_VPINDEX)
},
[HYPERV_FEAT_EVMCS] = {
.desc = "enlightened VMCS (hv-evmcs)",
.flags = {
{.func = HV_CPUID_ENLIGHTMENT_INFO, .reg = R_EAX,
.bits = HV_ENLIGHTENED_VMCS_RECOMMENDED}
},
.dependencies = BIT(HYPERV_FEAT_VAPIC)
},
[HYPERV_FEAT_IPI] = {
.desc = "paravirtualized IPI (hv-ipi)",
.flags = {
{.func = HV_CPUID_ENLIGHTMENT_INFO, .reg = R_EAX,
.bits = HV_CLUSTER_IPI_RECOMMENDED |
HV_EX_PROCESSOR_MASKS_RECOMMENDED}
},
.dependencies = BIT(HYPERV_FEAT_VPINDEX)
},
[HYPERV_FEAT_STIMER_DIRECT] = {
.desc = "direct mode synthetic timers (hv-stimer-direct)",
.flags = {
{.func = HV_CPUID_FEATURES, .reg = R_EDX,
.bits = HV_STIMER_DIRECT_MODE_AVAILABLE}
},
.dependencies = BIT(HYPERV_FEAT_STIMER)
},
[HYPERV_FEAT_AVIC] = {
.desc = "AVIC/APICv support (hv-avic/hv-apicv)",
.flags = {
{.func = HV_CPUID_ENLIGHTMENT_INFO, .reg = R_EAX,
.bits = HV_DEPRECATING_AEOI_RECOMMENDED}
}
},
[HYPERV_FEAT_SYNDBG] = {
.desc = "Enable synthetic kernel debugger channel (hv-syndbg)",
.flags = {
{.func = HV_CPUID_FEATURES, .reg = R_EDX,
.bits = HV_FEATURE_DEBUG_MSRS_AVAILABLE}
},
.dependencies = BIT(HYPERV_FEAT_SYNIC) | BIT(HYPERV_FEAT_RELAXED),
.skip_passthrough = true,
},
[HYPERV_FEAT_MSR_BITMAP] = {
.desc = "enlightened MSR-Bitmap (hv-emsr-bitmap)",
.flags = {
{.func = HV_CPUID_NESTED_FEATURES, .reg = R_EAX,
.bits = HV_NESTED_MSR_BITMAP}
}
},
[HYPERV_FEAT_XMM_INPUT] = {
.desc = "XMM fast hypercall input (hv-xmm-input)",
.flags = {
{.func = HV_CPUID_FEATURES, .reg = R_EDX,
.bits = HV_HYPERCALL_XMM_INPUT_AVAILABLE}
}
},
[HYPERV_FEAT_TLBFLUSH_EXT] = {
.desc = "Extended gva ranges for TLB flush hypercalls (hv-tlbflush-ext)",
.flags = {
{.func = HV_CPUID_FEATURES, .reg = R_EDX,
.bits = HV_EXT_GVA_RANGES_FLUSH_AVAILABLE}
},
.dependencies = BIT(HYPERV_FEAT_TLBFLUSH)
},
[HYPERV_FEAT_TLBFLUSH_DIRECT] = {
.desc = "direct TLB flush (hv-tlbflush-direct)",
.flags = {
{.func = HV_CPUID_NESTED_FEATURES, .reg = R_EAX,
.bits = HV_NESTED_DIRECT_FLUSH}
},
.dependencies = BIT(HYPERV_FEAT_VAPIC)
},
};
/******************************************************************************/
const char* hyperv_feature_macro[] = {
"HYPERV_FEAT_RELAXED",
"HYPERV_FEAT_VAPIC",
"HYPERV_FEAT_TIME",
"HYPERV_FEAT_CRASH",
"HYPERV_FEAT_RESET",
"HYPERV_FEAT_VPINDEX",
"HYPERV_FEAT_RUNTIME",
"HYPERV_FEAT_SYNIC",
"HYPERV_FEAT_STIMER",
"HYPERV_FEAT_FREQUENCIES",
"HYPERV_FEAT_REENLIGHTENMENT",
"HYPERV_FEAT_TLBFLUSH",
"HYPERV_FEAT_EVMCS",
"HYPERV_FEAT_IPI",
"HYPERV_FEAT_STIMER_DIRECT",
"HYPERV_FEAT_AVIC",
"HYPERV_FEAT_SYNDBG",
"HYPERV_FEAT_MSR_BITMAP",
"HYPERV_FEAT_XMM_INPUT",
"HYPERV_FEAT_TLBFLUSH_EXT",
"HYPERV_FEAT_TLBFLUSH_DIRECT",
};
int main(void) {
for (int i = 0; i < sizeof(hyperv_feature_macro) / sizeof(hyperv_feature_macro[0]); ++i) {
bool feature = true;
for (int j = 0; j < 2; ++j) {
int gpr[4];
if (kvm_hyperv_properties[i].flags[j].func == 0) break;
__cpuid(gpr, kvm_hyperv_properties[i].flags[j].func);
if ((gpr[kvm_hyperv_properties[i].flags[j].reg] & kvm_hyperv_properties[i].flags[j].bits) != kvm_hyperv_properties[i].flags[j].bits) {
feature = false;
break;
}
}
printf("%c %-27s %s\n", feature ? '+' : '-', hyperv_feature_macro[i], kvm_hyperv_properties[i].desc);
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment