mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
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


  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®