Kernel KVM virtualization development
 help / color / mirror / Atom feed
From: Sriram Nambakam <snambakam@linux.microsoft.com>
To: kvm@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Subject: [RFC PATCH v2 4/8] security/vbs: add KVM software planes backend
Date: Mon, 10 Aug 2026 18:52:39 -0700	[thread overview]
Message-ID: <20260811015243.188486-5-snambakam@linux.microsoft.com> (raw)
In-Reply-To: <20260811015243.188486-1-snambakam@linux.microsoft.com>

Add the KVM software-planes VBS backend.  It uses a synchronous
shared-memory calling area and the KVM_HC_VBS_VTL_CALL paravirt hypercall
(handled by the host) to reach plane-1.

Only the plane lifecycle is implemented: init() allocates the calling
area and issues VBS_CALL_INIT to load (connect to) the secure plane;
shutdown() issues VBS_CALL_SHUTDOWN to unload it.  The BSP-pinned
work_on_cpu() ensures the plane switch always lands on CPU0.

Gated by CONFIG_VBS_KVM_PLANES.
---
 security/vbs/Kconfig      |  15 ++++
 security/vbs/Makefile     |   2 +
 security/vbs/kvm_planes.c | 177 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 194 insertions(+)
 create mode 100644 security/vbs/kvm_planes.c

diff --git a/security/vbs/Kconfig b/security/vbs/Kconfig
index 0e482196c5b7..e21f4f30b6cf 100644
--- a/security/vbs/Kconfig
+++ b/security/vbs/Kconfig
@@ -14,3 +14,18 @@ config VBS
 	  later).  Hardware confidential-compute is out of scope.
 
 	  If unsure, say N.
+
+config VBS_KVM_PLANES
+	bool "VBS backend: KVM software planes"
+	depends on VBS && KVM_GUEST
+	help
+	  VBS backend that uses a KVM paravirt hypercall to communicate
+	  between plane-0 (the normal guest kernel) and plane-1 (a secure
+	  kernel running in a separate KVM VM plane managed by QEMU).
+
+	  This minimal backend supports loading (connecting to) and
+	  unloading the secure plane via a shared-memory calling area.
+
+	  Select this if you are running under KVM with VM planes support.
+
+	  If unsure, say N.
diff --git a/security/vbs/Makefile b/security/vbs/Makefile
index 0fcbb6640ec1..3a161e7cc279 100644
--- a/security/vbs/Makefile
+++ b/security/vbs/Makefile
@@ -3,3 +3,5 @@ obj-$(CONFIG_VBS) += vbs.o
 # probe.o links before core.o so the backend is registered (vbs_probe_init)
 # early in the rootfs_initcall level.
 vbs-y := probe.o core.o
+
+obj-$(CONFIG_VBS_KVM_PLANES)	+= kvm_planes.o
diff --git a/security/vbs/kvm_planes.c b/security/vbs/kvm_planes.c
new file mode 100644
index 000000000000..af9118c6e74f
--- /dev/null
+++ b/security/vbs/kvm_planes.c
@@ -0,0 +1,177 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * VBS backend — KVM software planes
+ *
+ * Uses a KVM paravirt hypercall to communicate between plane-0 (the normal
+ * guest kernel) and plane-1 (a secure kernel running in a separate KVM plane
+ * managed by QEMU).
+ *
+ * Transport: kvm_hypercall1(KVM_HC_VBS_VTL_CALL, gpa) -> KVM_EXIT_HYPERCALL.
+ *
+ * The shared-memory VTL-call protocol is synchronous:
+ *   1. Plane-0 fills the request buffer in the shared calling area.
+ *   2. Plane-0 issues the hypercall carrying the physical address of the area.
+ *   3. Plane-1 processes the request and writes a response.
+ *   4. Plane-0 reads the response from the same page.
+ *
+ * This minimal backend implements only the plane lifecycle: init() loads
+ * (connects to) the secure plane, shutdown() unloads it.
+ */
+
+#include "internal.h"
+
+#include <linux/mm.h>
+#include <linux/gfp.h>
+#include <linux/io.h>
+#include <linux/string.h>
+#include <linux/workqueue.h>
+#include <linux/kvm_para.h>
+#include <asm/kvm_para.h>
+
+/* ── shared-memory calling area ────────────────────────────────────────── */
+
+/*
+ * Single shared page used for both request and response data.  The protocol
+ * is synchronous, so no concurrent access is possible.
+ *
+ * Layout (within one 4 KiB page):
+ *   [ call_pending | call_id | status | arg_size | resp_size | buffer ]
+ */
+struct vbs_kvm_ca {
+	__u8	call_pending;	/* 1 while call is in flight            */
+	__u8	rsvd[3];
+	__u32	call_id;	/* enum vbs_call_id (set by caller)     */
+	__s32	status;		/* return code (set by responder)       */
+	__u32	arg_size;	/* request payload size                 */
+	__u32	resp_size;	/* response payload size                */
+	__u8	buffer[];	/* request data in, response data out   */
+} __packed;
+
+#define VBS_CA_BUF_SIZE (PAGE_SIZE - sizeof(struct vbs_kvm_ca))
+
+static void *kvm_ca_page;	/* single calling-area page             */
+
+/* ── low-level VTL call ────────────────────────────────────────────────── */
+
+struct kvm_vtl_call_ctx {
+	enum vbs_call_id id;
+	const void	*arg;
+	size_t		arg_size;
+	void		*resp;
+	size_t		resp_size;
+};
+
+/*
+ * Issue the VTL-call hypercall.  MUST run on the BSP (CPU0): KVM switches
+ * planes per logical CPU and the secure plane boots only on CPU0's sibling.
+ * Driven via work_on_cpu() so the hypercall always lands on CPU0.
+ */
+static long kvm_planes_vtl_call_on_cpu(void *data)
+{
+	struct kvm_vtl_call_ctx *ctx = data;
+	struct vbs_kvm_ca *ca = kvm_ca_page;
+	long hc_ret;
+
+	ca->call_id   = ctx->id;
+	ca->arg_size  = ctx->arg_size;
+	ca->status    = 0;
+	ca->resp_size = 0;
+	if (ctx->arg_size && ctx->arg)
+		memcpy(ca->buffer, ctx->arg, ctx->arg_size);
+	ca->call_pending = 1;
+
+	hc_ret = kvm_hypercall1(KVM_HC_VBS_VTL_CALL, virt_to_phys(kvm_ca_page));
+	ca->call_pending = 0;
+
+	if (hc_ret) {
+		pr_err_ratelimited("vbs-kvm: hypercall failed (%ld)\n", hc_ret);
+		return -EIO;
+	}
+
+	if (ca->status)
+		return ca->status;
+
+	if (ctx->resp && ctx->resp_size && ca->resp_size) {
+		size_t copy = min_t(size_t, ctx->resp_size, ca->resp_size);
+
+		memcpy(ctx->resp, ca->buffer, copy);
+	}
+	return 0;
+}
+
+static int kvm_planes_vtl_call(enum vbs_call_id id,
+			       const void *arg, size_t arg_size,
+			       void *resp, size_t resp_size)
+{
+	struct kvm_vtl_call_ctx ctx = {
+		.id        = id,
+		.arg       = arg,
+		.arg_size  = arg_size,
+		.resp      = resp,
+		.resp_size = resp_size,
+	};
+
+	if (!kvm_ca_page)
+		return -ENOMEM;
+
+	if (arg_size > VBS_CA_BUF_SIZE)
+		return -E2BIG;
+
+	/* Pin the plane switch to CPU0's secure sibling. */
+	return work_on_cpu(0, kvm_planes_vtl_call_on_cpu, &ctx);
+}
+
+/* ── lifecycle: load / unload the secure plane ─────────────────────────── */
+
+static int kvm_planes_init(void)
+{
+	int ret;
+
+	kvm_ca_page = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO);
+	if (!kvm_ca_page)
+		return -ENOMEM;
+
+	ret = kvm_planes_vtl_call(VBS_CALL_INIT, NULL, 0, NULL, 0);
+	if (ret) {
+		pr_err("vbs-kvm: plane-1 INIT call failed (%d)\n", ret);
+		free_page((unsigned long)kvm_ca_page);
+		kvm_ca_page = NULL;
+		return ret;
+	}
+
+	pr_info("vbs-kvm: connected to plane-1 secure kernel\n");
+	return 0;
+}
+
+static void kvm_planes_shutdown(void)
+{
+	if (!kvm_ca_page)
+		return;
+
+	kvm_planes_vtl_call(VBS_CALL_SHUTDOWN, NULL, 0, NULL, 0);
+	free_page((unsigned long)kvm_ca_page);
+	kvm_ca_page = NULL;
+}
+
+/* ── ops table & registration ──────────────────────────────────────────── */
+
+static const struct vbs_ops kvm_planes_ops = {
+	.name     = "kvm-planes",
+	.init     = kvm_planes_init,
+	.shutdown = kvm_planes_shutdown,
+	.vtl_call = kvm_planes_vtl_call,
+};
+
+bool __init vbs_kvm_planes_detect(void)
+{
+	if (!kvm_para_available()) {
+		pr_debug("vbs-kvm: KVM paravirt not available\n");
+		return false;
+	}
+	return true;
+}
+
+const struct vbs_ops *vbs_kvm_planes_get_ops(void)
+{
+	return &kvm_planes_ops;
+}
-- 
2.55.0


  parent reply	other threads:[~2026-08-11  1:53 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-11  1:52 [RFC PATCH v2 0/8] VBS/VSM-on-KVM: guest support using VM Planes Sriram Nambakam
2026-08-11  1:52 ` [RFC PATCH v2 1/8] KVM: x86: raise the default maximum planes to two Sriram Nambakam
2026-08-11  1:52 ` [RFC PATCH v2 2/8] security/vbs: introduce core VBS framework Sriram Nambakam
2026-08-11  1:52 ` [RFC PATCH v2 3/8] security/vbs: add platform probe and backend registration Sriram Nambakam
2026-08-11  1:52 ` Sriram Nambakam [this message]
2026-08-11  1:52 ` [RFC PATCH v2 5/8] security/vbs: enable the backend after driver init Sriram Nambakam
2026-08-11  1:52 ` [RFC PATCH v2 6/8] vm_planes: add hypervisor-assisted plane bootstrap Sriram Nambakam
2026-08-11  1:52 ` [RFC PATCH v2 7/8] security/vbs: bootstrap the plane from the enable path Sriram Nambakam
2026-08-11  1:52 ` [RFC PATCH v2 8/8] drivers/virt: add KVM VM-planes secure-plane monitor Sriram Nambakam

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=20260811015243.188486-5-snambakam@linux.microsoft.com \
    --to=snambakam@linux.microsoft.com \
    --cc=kvm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    /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