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
next prev 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.