On CPUID leaf 0x40000003, EBX bit 20 signals that we support
the HvExtCallQueryCapabilities hypercall. This returns a bit field which
signals which further extended hypercalls are supported (as a way to
conserve CPUID leaf bits).
For now, we don't support any extended hypercalls, but we'll add
HvExtCallGetBootZeroedMemory in a followup patch.
Signed-off-by: Florian Schmidt <flosch@nutanix.com>
---
hw/hyperv/hyperv.c | 28 ++++++++++++++++++++++++++++
include/hw/hyperv/hyperv-proto.h | 1 +
include/hw/hyperv/hyperv.h | 5 +++++
target/i386/kvm/hyperv-proto.h | 1 +
target/i386/kvm/hyperv.c | 14 ++++++++++++++
target/i386/kvm/kvm.c | 3 +++
6 files changed, 52 insertions(+)
diff --git a/hw/hyperv/hyperv.c b/hw/hyperv/hyperv.c
index 27e323a819..13a42a68b2 100644
--- a/hw/hyperv/hyperv.c
+++ b/hw/hyperv/hyperv.c
@@ -699,6 +699,34 @@ int hyperv_set_event_flag_handler(uint32_t conn_id, EventNotifier *notifier)
return set_event_flag_handler(conn_id, notifier);
}
+uint16_t hyperv_ext_hcall_query_caps(uint64_t sup, uint64_t outgpa, bool fast)
+{
+ uint16_t ret;
+ uint64_t *supported = NULL;
+ hwaddr len;
+
+ if (fast) {
+ ret = HV_STATUS_INVALID_HYPERCALL_CODE;
+ goto cleanup;
+ }
+
+ len = sizeof(*supported);
+ supported = cpu_physical_memory_map(outgpa, &len, 1);
+ if (!supported || len < sizeof(*supported)) {
+ ret = HV_STATUS_INSUFFICIENT_MEMORY;
+ goto cleanup;
+ }
+
+ *supported = sup;
+ ret = HV_STATUS_SUCCESS;
+
+cleanup:
+ if (supported) {
+ cpu_physical_memory_unmap(supported, sizeof(*supported), 1, len);
+ }
+ return ret;
+}
+
uint16_t hyperv_hcall_signal_event(uint64_t param, bool fast)
{
EventFlagHandler *handler;
diff --git a/include/hw/hyperv/hyperv-proto.h b/include/hw/hyperv/hyperv-proto.h
index fffc5ce342..f1d1d2eb26 100644
--- a/include/hw/hyperv/hyperv-proto.h
+++ b/include/hw/hyperv/hyperv-proto.h
@@ -35,6 +35,7 @@
#define HV_POST_DEBUG_DATA 0x0069
#define HV_RETRIEVE_DEBUG_DATA 0x006a
#define HV_RESET_DEBUG_SESSION 0x006b
+#define HV_EXT_CALL_QUERY_CAPABILITIES 0x8001
#define HV_HYPERCALL_FAST (1u << 16)
/*
diff --git a/include/hw/hyperv/hyperv.h b/include/hw/hyperv/hyperv.h
index 63a8b65278..921e1623f7 100644
--- a/include/hw/hyperv/hyperv.h
+++ b/include/hw/hyperv/hyperv.h
@@ -96,6 +96,11 @@ uint16_t hyperv_hcall_retreive_dbg_data(uint64_t ingpa, uint64_t outgpa,
*/
uint16_t hyperv_hcall_post_dbg_data(uint64_t ingpa, uint64_t outgpa, bool fast);
+/*
+ * Process HVCALL_EXT_QUERY_CAPABILITIES hypercall.
+ */
+uint16_t hyperv_ext_hcall_query_caps(uint64_t sup, uint64_t outgpa, bool fast);
+
uint32_t hyperv_syndbg_send(uint64_t ingpa, uint32_t count);
uint32_t hyperv_syndbg_recv(uint64_t ingpa, uint32_t count);
void hyperv_syndbg_set_pending_page(uint64_t ingpa);
diff --git a/target/i386/kvm/hyperv-proto.h b/target/i386/kvm/hyperv-proto.h
index a9f056f2f3..4eb2955ac5 100644
--- a/target/i386/kvm/hyperv-proto.h
+++ b/target/i386/kvm/hyperv-proto.h
@@ -46,6 +46,7 @@
*/
#define HV_POST_MESSAGES (1u << 4)
#define HV_SIGNAL_EVENTS (1u << 5)
+#define HV_ENABLE_EXT_HYPERCALLS (1u << 20)
/*
* HV_CPUID_FEATURES.EDX bits
diff --git a/target/i386/kvm/hyperv.c b/target/i386/kvm/hyperv.c
index f7a81bd270..1ac5c26799 100644
--- a/target/i386/kvm/hyperv.c
+++ b/target/i386/kvm/hyperv.c
@@ -51,6 +51,15 @@ static void async_synic_update(CPUState *cs, run_on_cpu_data data)
bql_unlock();
}
+static uint64_t calc_supported_ext_hypercalls(X86CPU *cpu)
+{
+ uint64_t ret = 0;
+
+ /* For now, no extended hypercalls are supported. */
+
+ return ret;
+}
+
int kvm_hv_handle_exit(X86CPU *cpu, struct kvm_hyperv_exit *exit)
{
CPUX86State *env = &cpu->env;
@@ -108,6 +117,11 @@ int kvm_hv_handle_exit(X86CPU *cpu, struct kvm_hyperv_exit *exit)
exit->u.hcall.result =
hyperv_hcall_reset_dbg_session(out_param);
break;
+ case HV_EXT_CALL_QUERY_CAPABILITIES:
+ exit->u.hcall.result =
+ hyperv_ext_hcall_query_caps(calc_supported_ext_hypercalls(cpu),
+ out_param, fast);
+ break;
default:
exit->u.hcall.result = HV_STATUS_INVALID_HYPERCALL_CODE;
}
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index 7b9b740a8e..5d8553ef0c 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -1594,6 +1594,9 @@ static int hyperv_fill_cpuids(CPUState *cs,
/* Unconditionally required with any Hyper-V enlightenment */
c->eax |= HV_HYPERCALL_AVAILABLE;
+ /* No reason to not always support HvExtCallQueryCapabilities (?) */
+ c->ebx |= HV_ENABLE_EXT_HYPERCALLS;
+
/* SynIC and Vmbus devices require messages/signals hypercalls */
if (hyperv_feat_enabled(cpu, HYPERV_FEAT_SYNIC) &&
!cpu->hyperv_synic_kvm_only) {
--
2.39.5
© 2016 - 2026 Red Hat, Inc.