From: David Woodhouse <dwmw2@infradead.org>
To: kvm@vger.kernel.org
Cc: linux-kernel@vger.kernel.org, linux-hyperv@vger.kernel.org,
linux-kselftest@vger.kernel.org, linux-doc@vger.kernel.org,
"Paolo Bonzini" <pbonzini@redhat.com>,
"Sean Christopherson" <seanjc@google.com>,
"Vitaly Kuznetsov" <vkuznets@redhat.com>,
"Marcelo Tosatti" <mtosatti@redhat.com>,
"Joerg Roedel" <joro@8bytes.org>,
"Tom Lendacky" <thomas.lendacky@amd.com>,
"James Bottomley" <James.Bottomley@HansenPartnership.com>,
"Thara Gopinath" <tgopinath@linux.microsoft.com>,
"Wei Liu" <wei.liu@kernel.org>,
"Michael Kelley" <mhklinux@outlook.com>,
"Nicolas Saenz Julienne" <nsaenz@amazon.com>,
"Nikolas Wipper" <nik.wipper@gmx.de>,
"Mushahid Hussain" <hmushi@amazon.co.uk>,
"Sriram Nambakam" <snambakam@linux.microsoft.com>,
"Zack Rusin" <zack.rusin@broadcom.com>,
"Doug Covelli" <doug.covelli@broadcom.com>,
"Thomas Gleixner" <tglx@kernel.org>,
"Ingo Molnar" <mingo@redhat.com>,
"Borislav Petkov" <bp@alien8.de>,
"Dave Hansen" <dave.hansen@linux.intel.com>,
x86@kernel.org, "H . Peter Anvin" <hpa@zytor.com>,
"Jonathan Corbet" <corbet@lwn.net>,
"Randy Dunlap" <rdunlap@infradead.org>,
"Shuah Khan" <shuah@kernel.org>, "Paul Durrant" <paul@xen.org>,
"Xin Li" <xin@zytor.com>, "Francesco Lavra" <flavra@baylibre.com>,
"Radim Krčmář" <rkrcmar@ventanamicro.com>,
"Liran Alon" <liran.alon@oracle.com>,
"Arbel Moshe" <arbel.moshe@oracle.com>,
"David Woodhouse" <dwmw@amazon.co.uk>
Subject: [PATCH v2 1/4] KVM: x86: hyper-v: Add KVM_CAP_HYPERV_FORWARD_HCALL
Date: Fri, 13 Nov 2026 10:05:32 -0700 [thread overview]
Message-ID: <20261113170535.79246-2-dwmw2@infradead.org> (raw)
In-Reply-To: <20261113170535.79246-1-dwmw2@infradead.org>
From: David Woodhouse <dwmw@amazon.co.uk>
A VMM that implements Hyper-V hypercalls KVM does not know about has
no way to receive them. kvm_hv_hypercall() fails an unknown code with
HV_STATUS_INVALID_HYPERCALL_CODE, and only a fixed set (the synthetic
debugger, memory-based extended hypercalls, HvCallPostMessage and the
HvCallSignalEvent fallback) ever exits to userspace.
Add a VM capability whose KVM_CHECK_EXTENSION value is a bitmask of the
hypercall handling features the kernel implements, as KVM_CAP_XEN_HVM
and KVM_CAP_EXIT_HYPERCALL do. KVM_ENABLE_CAP takes the subset to
enable and rejects any bit the kernel does not report, so a VMM can
probe for exactly the behaviour it relies on.
The first feature, KVM_HYPERV_HCALL_FORWARD_UNKNOWN, sends a hypercall
KVM would have failed as unknown, and an extended hypercall in fast
form, out through the existing KVM_EXIT_HYPERV_HCALL. That exit already
carries the control value and both parameter registers, and XMM state
is reachable through the ordinary vCPU state ioctls, so no new exit
format is needed.
Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
---
Documentation/virt/kvm/api.rst | 49 +++++++++++++++++++++++++++++++++
arch/x86/include/asm/kvm_host.h | 2 ++
arch/x86/kvm/hyperv.c | 7 ++++-
arch/x86/kvm/hyperv.h | 8 ++++++
arch/x86/kvm/x86.c | 14 ++++++++++
include/uapi/linux/kvm.h | 4 +++
6 files changed, 83 insertions(+), 1 deletion(-)
diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
index e95c9cda085d..092f6f9ad8a0 100644
--- a/Documentation/virt/kvm/api.rst
+++ b/Documentation/virt/kvm/api.rst
@@ -7312,6 +7312,17 @@ Hyper-V SynIC state change. Notification is used to remap SynIC
event/message pages and to enable/disable SynIC messages/events processing
in userspace.
+ - KVM_EXIT_HYPERV_HCALL -- a hypercall for userspace to handle.
+
+'input' holds the hypercall control value and 'params' the two parameter
+registers. Userspace sets 'result' to the hypercall result value before
+resuming the vCPU; KVM then writes it to the guest and advances past the
+hypercall instruction. HvCallPostMessage, HvCallSignalEvent for a
+connection with no registered eventfd, the synthetic debugger hypercalls
+and memory-based extended hypercalls exit this way;
+KVM_CAP_HYPERV_FORWARD_HCALL (see section 7.48) adds the hypercalls KVM
+does not implement.
+
- KVM_EXIT_HYPERV_SYNDBG -- synchronously notify user-space about
Hyper-V Synthetic debugger state change. Notification is used to either update
@@ -9181,6 +9192,44 @@ enabled, cmma can't be enabled anymore and pfmfi and the storage key
interpretation are disabled. If cmma has already been enabled or the
hpage_2g module parameter is not set to 1, -EINVAL is returned.
+7.48 KVM_CAP_HYPERV_FORWARD_HCALL
+---------------------------------
+
+:Architectures: x86
+:Target: VM
+:Parameters: args[0] is a bitmask of KVM_HYPERV_HCALL_* features to enable
+:Returns: 0 on success, -EINVAL if args[0] contains an unsupported bit
+
+KVM_CHECK_EXTENSION for this capability returns a bitmask of the Hyper-V
+hypercall handling features that KVM implements. KVM_ENABLE_CAP takes
+the subset that userspace wants active and replaces the previously
+enabled set; it can be called at any time. A bit that KVM_CHECK_EXTENSION
+does not report is rejected with -EINVAL, so a VMM can enable exactly the
+features it was written for and learn which ones the kernel lacks.
+
+The defined bits are::
+
+ #define KVM_HYPERV_HCALL_FORWARD_UNKNOWN (1ULL << 0)
+
+KVM_HYPERV_HCALL_FORWARD_UNKNOWN: a hypercall that KVM would otherwise
+fail with HV_STATUS_INVALID_HYPERCALL_CODE exits to userspace with
+KVM_EXIT_HYPERV_HCALL instead, and an extended hypercall in fast form
+exits the same way instead of failing with HV_STATUS_INVALID_PARAMETER.
+The VMM can then implement hypercalls that KVM does not. The synthetic
+debugger hypercalls (HvCallResetDebugSession, HvCallPostDebugData,
+HvCallRetrieveDebugData) are an exception: while the synthetic debugger
+is not enabled they still fail in KVM, with HV_STATUS_INVALID_PARAMETER
+for the fast form of HvCallPostDebugData and HvCallRetrieveDebugData
+and with HV_STATUS_INVALID_HYPERCALL_CODE otherwise.
+
+For a fast hypercall, 'params' carries RDX and R8 from a 64-bit caller,
+or the EBX:ECX and EDI:ESI pairs from a 32-bit caller. XMM input and
+output registers of a fast hypercall are read and written with the
+ordinary vCPU state ioctls (KVM_GET_XSAVE/KVM_SET_XSAVE or
+KVM_GET_FPU/KVM_SET_FPU) before the vCPU is resumed. Hypercalls that
+KVM implements itself, and the CPUID-enforcement checks KVM applies
+before dispatching a hypercall, are unaffected.
+
8. Other capabilities.
======================
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 1ee4b127004d..fce46ae26137 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -1072,6 +1072,8 @@ struct kvm_hv {
struct mutex hv_lock;
u64 hv_guest_os_id;
u64 hv_hypercall;
+ /* KVM_HYPERV_HCALL_* features enabled by KVM_CAP_HYPERV_FORWARD_HCALL */
+ u64 hcall_features;
u64 hv_tsc_page;
enum hv_tsc_page_status hv_tsc_page_status;
diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c
index 5d2e3617c952..e72539f9acc9 100644
--- a/arch/x86/kvm/hyperv.c
+++ b/arch/x86/kvm/hyperv.c
@@ -2692,12 +2692,17 @@ int kvm_hv_hypercall(struct kvm_vcpu *vcpu)
goto hypercall_userspace_exit;
}
case HV_EXT_CALL_QUERY_CAPABILITIES ... HV_EXT_CALL_MAX:
- if (unlikely(hc.fast)) {
+ if (unlikely(hc.fast) &&
+ !kvm_hv_hcall_feature(vcpu->kvm,
+ KVM_HYPERV_HCALL_FORWARD_UNKNOWN)) {
ret = HV_STATUS_INVALID_PARAMETER;
break;
}
goto hypercall_userspace_exit;
default:
+ if (kvm_hv_hcall_feature(vcpu->kvm,
+ KVM_HYPERV_HCALL_FORWARD_UNKNOWN))
+ goto hypercall_userspace_exit;
ret = HV_STATUS_INVALID_HYPERCALL_CODE;
break;
}
diff --git a/arch/x86/kvm/hyperv.h b/arch/x86/kvm/hyperv.h
index 622a6553e9ac..20d40261c75b 100644
--- a/arch/x86/kvm/hyperv.h
+++ b/arch/x86/kvm/hyperv.h
@@ -205,6 +205,14 @@ static inline bool kvm_hv_hypercall_enabled(struct kvm_vcpu *vcpu)
return vcpu->arch.hyperv_enabled && to_kvm_hv(vcpu->kvm)->hv_guest_os_id;
}
+/* Features reported and accepted by KVM_CAP_HYPERV_FORWARD_HCALL. */
+#define KVM_HYPERV_HCALL_SUPPORTED KVM_HYPERV_HCALL_FORWARD_UNKNOWN
+
+static inline bool kvm_hv_hcall_feature(struct kvm *kvm, u64 feature)
+{
+ return READ_ONCE(to_kvm_hv(kvm)->hcall_features) & feature;
+}
+
int kvm_hv_hypercall(struct kvm_vcpu *vcpu);
void kvm_hv_irq_routing_update(struct kvm *kvm);
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 26e7beaff8a0..d8de7742a0da 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -2305,6 +2305,11 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
case KVM_CAP_EXIT_HYPERCALL:
r = KVM_EXIT_HYPERCALL_VALID_MASK;
break;
+#ifdef CONFIG_KVM_HYPERV
+ case KVM_CAP_HYPERV_FORWARD_HCALL:
+ r = KVM_HYPERV_HCALL_SUPPORTED;
+ break;
+#endif
case KVM_CAP_SET_GUEST_DEBUG2:
return KVM_GUESTDBG_VALID_MASK;
#ifdef CONFIG_KVM_XEN
@@ -4144,6 +4149,15 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
kvm->arch.hypercall_exit_enabled = cap->args[0];
r = 0;
break;
+#ifdef CONFIG_KVM_HYPERV
+ case KVM_CAP_HYPERV_FORWARD_HCALL:
+ r = -EINVAL;
+ if (cap->args[0] & ~KVM_HYPERV_HCALL_SUPPORTED)
+ break;
+ WRITE_ONCE(to_kvm_hv(kvm)->hcall_features, cap->args[0]);
+ r = 0;
+ break;
+#endif
case KVM_CAP_EXIT_ON_EMULATION_FAILURE:
r = -EINVAL;
if (cap->args[0] & ~1)
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 8dff2fc1972e..79f128958df5 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -126,6 +126,9 @@ struct kvm_hyperv_exit {
} u;
};
+/* KVM_CAP_HYPERV_FORWARD_HCALL feature bits */
+#define KVM_HYPERV_HCALL_FORWARD_UNKNOWN (1ULL << 0)
+
struct kvm_xen_exit {
#define KVM_EXIT_XEN_HCALL 1
__u32 type;
@@ -1000,6 +1003,7 @@ struct kvm_enable_cap {
#define KVM_CAP_PPC_COMPAT_CAPS 250
#define KVM_CAP_ARM_PMU_V3_STRICT 251
#define KVM_CAP_GUEST_MEMFD_MEMORY_ATTRIBUTES 252
+#define KVM_CAP_HYPERV_FORWARD_HCALL 255
struct kvm_irq_routing_irqchip {
__u32 irqchip;
--
2.50.1
next prev parent reply other threads:[~2026-11-13 17:05 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-13 17:05 [PATCH v2 0/4] KVM: x86: hyper-v: Forward unimplemented hypercalls to userspace David Woodhouse
2026-11-13 17:05 ` David Woodhouse [this message]
2026-11-13 17:05 ` [PATCH v2 2/4] KVM: x86: Let userspace cancel a pending hypercall completion David Woodhouse
2026-11-13 17:05 ` [PATCH v2 3/4] KVM: x86: hyper-v: Advertise XMM fast hypercall output David Woodhouse
2026-11-13 17:05 ` [PATCH v2 4/4] KVM: selftests: Add Hyper-V hypercall forwarding test David Woodhouse
2026-11-13 17:10 ` [PATCH v2 0/4] KVM: x86: hyper-v: Forward unimplemented hypercalls to userspace Sean Christopherson
2026-11-13 17:23 ` David Woodhouse
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261113170535.79246-2-dwmw2@infradead.org \
--to=dwmw2@infradead.org \
--cc=James.Bottomley@HansenPartnership.com \
--cc=arbel.moshe@oracle.com \
--cc=bp@alien8.de \
--cc=corbet@lwn.net \
--cc=dave.hansen@linux.intel.com \
--cc=doug.covelli@broadcom.com \
--cc=dwmw@amazon.co.uk \
--cc=flavra@baylibre.com \
--cc=hmushi@amazon.co.uk \
--cc=hpa@zytor.com \
--cc=joro@8bytes.org \
--cc=kvm@vger.kernel.org \
--cc=linux-doc@vger.kernel.org \
--cc=linux-hyperv@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=liran.alon@oracle.com \
--cc=mhklinux@outlook.com \
--cc=mingo@redhat.com \
--cc=mtosatti@redhat.com \
--cc=nik.wipper@gmx.de \
--cc=nsaenz@amazon.com \
--cc=paul@xen.org \
--cc=pbonzini@redhat.com \
--cc=rdunlap@infradead.org \
--cc=rkrcmar@ventanamicro.com \
--cc=seanjc@google.com \
--cc=shuah@kernel.org \
--cc=snambakam@linux.microsoft.com \
--cc=tglx@kernel.org \
--cc=tgopinath@linux.microsoft.com \
--cc=thomas.lendacky@amd.com \
--cc=vkuznets@redhat.com \
--cc=wei.liu@kernel.org \
--cc=x86@kernel.org \
--cc=xin@zytor.com \
--cc=zack.rusin@broadcom.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®