From: Fuad Tabba <fuad.tabba@linux.dev>
To: kvm@vger.kernel.org
Cc: kvmarm@lists.linux.dev, Will Deacon <will@kernel.org>,
Alexandru Elisei <alexandru.elisei@arm.com>,
Suzuki K Poulose <suzuki.poulose@arm.com>,
Andre Przywara <andre.przywara@arm.com>,
Oliver Upton <oliver.upton@linux.dev>,
Marc Zyngier <maz@kernel.org>, Fuad Tabba <tabba@google.com>
Subject: [PATCH kvmtool v1 5/5] arm64: Add --guest-memfd option to back guest RAM with guest_memfd
Date: Mon, 6 Jul 2026 09:35:55 +0100 [thread overview]
Message-ID: <20260706083555.302972-6-fuad.tabba@linux.dev> (raw)
In-Reply-To: <20260706083555.302972-1-fuad.tabba@linux.dev>
Back guest RAM with a guest_memfd created with GUEST_MEMFD_FLAG_MMAP
and GUEST_MEMFD_FLAG_INIT_SHARED, mmapped MAP_SHARED to provide the
userspace mapping.
Protected VMs need in-place shared/private conversion of guest_memfd,
which the kernel does not support yet, so reject the combination of
--protected and --guest-memfd.
Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
---
arm64/include/kvm/kvm-config-arch.h | 5 +++-
arm64/kvm.c | 38 +++++++++++++++++++++++------
include/kvm/kvm.h | 1 +
include/kvm/util.h | 1 +
kvm.c | 1 +
util/util.c | 34 ++++++++++++++++++++++++++
6 files changed, 71 insertions(+), 9 deletions(-)
diff --git a/arm64/include/kvm/kvm-config-arch.h b/arm64/include/kvm/kvm-config-arch.h
index c2702d5..d8a8ef7 100644
--- a/arm64/include/kvm/kvm-config-arch.h
+++ b/arm64/include/kvm/kvm-config-arch.h
@@ -20,6 +20,7 @@ struct kvm_config_arch {
bool no_pvtime;
bool psci;
bool protected;
+ bool guest_memfd;
};
int irqchip_parser(const struct option *opt, const char *arg, int unset);
@@ -73,6 +74,8 @@ int sve_vl_parser(const struct option *opt, const char *arg, int unset);
OPT_BOOLEAN('\0', "e2h0", &(cfg)->e2h0, \
"Create guest without VHE support"), \
OPT_BOOLEAN('\0', "protected", &(cfg)->protected, \
- "Create a protected VM when pKVM is enabled"),
+ "Create a protected VM when pKVM is enabled"), \
+ OPT_BOOLEAN('\0', "guest-memfd", &(cfg)->guest_memfd, \
+ "Use guest_memfd to back guest RAM"),
#endif /* ARM_COMMON__KVM_CONFIG_ARCH_H */
diff --git a/arm64/kvm.c b/arm64/kvm.c
index fb0b98d..b594578 100644
--- a/arm64/kvm.c
+++ b/arm64/kvm.c
@@ -49,9 +49,14 @@ void kvm__init_ram(struct kvm *kvm)
kvm->arch.ram_alloc_size = kvm->ram_size;
if (!kvm->cfg.hugetlbfs_path)
kvm->arch.ram_alloc_size += SZ_2M;
- kvm->arch.ram_alloc_start = mmap_anon_or_hugetlbfs(kvm,
- kvm->cfg.hugetlbfs_path,
- kvm->arch.ram_alloc_size);
+
+ if (kvm->cfg.arch.guest_memfd)
+ kvm->arch.ram_alloc_start =
+ mmap_guest_memfd(kvm, kvm->arch.ram_alloc_size);
+ else
+ kvm->arch.ram_alloc_start =
+ mmap_anon_or_hugetlbfs(kvm, kvm->cfg.hugetlbfs_path,
+ kvm->arch.ram_alloc_size);
if (kvm->arch.ram_alloc_start == MAP_FAILED)
die("Failed to map %lld bytes for guest memory (%d)",
@@ -60,17 +65,25 @@ void kvm__init_ram(struct kvm *kvm)
kvm->ram_start = (void *)ALIGN((unsigned long)kvm->arch.ram_alloc_start,
SZ_2M);
- madvise(kvm->arch.ram_alloc_start, kvm->arch.ram_alloc_size,
- MADV_MERGEABLE);
+ if (!kvm->cfg.arch.guest_memfd) {
+ madvise(kvm->arch.ram_alloc_start, kvm->arch.ram_alloc_size,
+ MADV_MERGEABLE);
- madvise(kvm->arch.ram_alloc_start, kvm->arch.ram_alloc_size,
- MADV_HUGEPAGE);
+ madvise(kvm->arch.ram_alloc_start, kvm->arch.ram_alloc_size,
+ MADV_HUGEPAGE);
+ }
phys_start = kvm->cfg.ram_addr;
phys_size = kvm->ram_size;
host_mem = kvm->ram_start;
- err = kvm__register_ram(kvm, phys_start, phys_size, host_mem);
+ if (kvm->cfg.arch.guest_memfd)
+ err = kvm__register_ram_guest_memfd(kvm, phys_start,
+ phys_size, host_mem,
+ kvm->ram_guest_memfd,
+ host_mem - kvm->arch.ram_alloc_start);
+ else
+ err = kvm__register_ram(kvm, phys_start, phys_size, host_mem);
if (err)
die("Failed to register %lld bytes of memory at physical "
"address 0x%llx [err %d]", phys_size, phys_start, err);
@@ -468,6 +481,15 @@ void kvm__arch_validate_cfg(struct kvm *kvm)
if (kvm->cfg.arch.e2h0 && !kvm->cfg.arch.nested_virt)
pr_warning("--e2h0 requires --nested, ignoring");
+ if (kvm->cfg.arch.guest_memfd) {
+ /* Requires in-place shared/private conversion of guest_memfd. */
+ if (kvm->cfg.arch.protected)
+ die("Protected VMs do not yet support guest_memfd");
+
+ if (kvm->cfg.hugetlbfs_path)
+ die("guest_memfd cannot be backed by hugetlbfs");
+ }
+
if (kvm->cfg.arch.protected) {
if (kvm->cfg.ram_size &&
kvm->cfg.ram_size < DMA_MEM_REGION_SIZE) {
diff --git a/include/kvm/kvm.h b/include/kvm/kvm.h
index 5e7b5eb..95dc52f 100644
--- a/include/kvm/kvm.h
+++ b/include/kvm/kvm.h
@@ -90,6 +90,7 @@ struct kvm {
u64 ram_size; /* Guest memory size, in bytes */
void *ram_start;
u64 ram_pagesize;
+ int ram_guest_memfd; /* guest_memfd backing RAM, -1 if none */
struct mutex mem_banks_lock;
struct list_head mem_banks;
diff --git a/include/kvm/util.h b/include/kvm/util.h
index a6dba11..9e23431 100644
--- a/include/kvm/util.h
+++ b/include/kvm/util.h
@@ -148,5 +148,6 @@ static inline int pow2_size(unsigned long x)
struct kvm;
void *mmap_hugetlbfs(struct kvm *kvm, const char *htlbfs_path, u64 size);
void *mmap_anon_or_hugetlbfs(struct kvm *kvm, const char *hugetlbfs_path, u64 size);
+void *mmap_guest_memfd(struct kvm *kvm, u64 size);
#endif /* KVM__UTIL_H */
diff --git a/kvm.c b/kvm.c
index 3d05756..a400dd2 100644
--- a/kvm.c
+++ b/kvm.c
@@ -162,6 +162,7 @@ struct kvm *kvm__new(void)
mutex_init(&kvm->mem_banks_lock);
kvm->sys_fd = -1;
kvm->vm_fd = -1;
+ kvm->ram_guest_memfd = -1;
#ifdef KVM_BRLOCK_DEBUG
kvm->brlock_sem = (pthread_rwlock_t) PTHREAD_RWLOCK_INITIALIZER;
diff --git a/util/util.c b/util/util.c
index 05d49c4..c60fe02 100644
--- a/util/util.c
+++ b/util/util.c
@@ -6,7 +6,9 @@
#include "kvm/util.h"
#include <kvm/kvm.h>
+#include <linux/kvm.h>
#include <linux/magic.h> /* For HUGETLBFS_MAGIC */
+#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/statfs.h>
@@ -169,3 +171,35 @@ void *mmap_anon_or_hugetlbfs(struct kvm *kvm, const char *hugetlbfs_path, u64 si
return mmap(NULL, size, PROT_RW, MAP_ANON_NORESERVE, -1, 0);
}
}
+
+/*
+ * Map guest RAM backed by a guest_memfd. The file descriptor must stay open
+ * for the lifetime of the VM: closing it invalidates the memslot bindings.
+ */
+void *mmap_guest_memfd(struct kvm *kvm, u64 size)
+{
+ u64 flags = GUEST_MEMFD_FLAG_MMAP | GUEST_MEMFD_FLAG_INIT_SHARED;
+ struct kvm_create_guest_memfd gmem = {
+ .size = size,
+ .flags = flags,
+ };
+ void *addr;
+ int ret;
+
+ ret = ioctl(kvm->vm_fd, KVM_CHECK_EXTENSION, KVM_CAP_GUEST_MEMFD_FLAGS);
+ if (ret < 0 || ((u64)ret & flags) != flags)
+ die("kernel does not support guest_memfd with mmap");
+
+ ret = ioctl(kvm->vm_fd, KVM_CREATE_GUEST_MEMFD, &gmem);
+ if (ret < 0)
+ die_perror("KVM_CREATE_GUEST_MEMFD");
+
+ addr = mmap(NULL, size, PROT_RW, MAP_SHARED, ret, 0);
+ if (addr == MAP_FAILED)
+ die_perror("guest_memfd mmap");
+
+ kvm->ram_guest_memfd = ret;
+ kvm->ram_pagesize = getpagesize();
+
+ return addr;
+}
--
2.39.5
next prev parent reply other threads:[~2026-07-06 8:36 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-06 8:35 [PATCH kvmtool v1 0/5] Add guest_memfd support for arm64 Fuad Tabba
2026-07-06 8:35 ` [PATCH kvmtool v1 1/5] Initialize the return value in kvm__for_each_mem_bank() Fuad Tabba
2026-07-06 8:35 ` [PATCH kvmtool v1 2/5] Remove newline from end of die() aborts Fuad Tabba
2026-07-06 10:53 ` Suzuki K Poulose
2026-07-06 10:57 ` Fuad Tabba
2026-07-06 8:35 ` [PATCH kvmtool v1 3/5] Use kvm_userspace_memory_region2 for all memory registration Fuad Tabba
2026-07-06 10:23 ` Suzuki K Poulose
2026-07-06 10:41 ` Fuad Tabba
2026-07-06 10:46 ` Will Deacon
2026-07-06 10:47 ` Fuad Tabba
2026-07-06 10:57 ` Alexandru Elisei
2026-07-06 10:59 ` Fuad Tabba
2026-07-06 8:35 ` [PATCH kvmtool v1 4/5] Add guest_memfd support to kvm__register_mem() Fuad Tabba
2026-07-06 11:00 ` Suzuki K Poulose
2026-07-06 11:13 ` Suzuki K Poulose
2026-07-06 11:25 ` Fuad Tabba
2026-07-06 12:34 ` Suzuki K Poulose
2026-07-06 8:35 ` Fuad Tabba [this message]
2026-07-06 11:18 ` [PATCH kvmtool v1 5/5] arm64: Add --guest-memfd option to back guest RAM with guest_memfd Suzuki K Poulose
2026-07-06 11:24 ` Fuad Tabba
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=20260706083555.302972-6-fuad.tabba@linux.dev \
--to=fuad.tabba@linux.dev \
--cc=alexandru.elisei@arm.com \
--cc=andre.przywara@arm.com \
--cc=kvm@vger.kernel.org \
--cc=kvmarm@lists.linux.dev \
--cc=maz@kernel.org \
--cc=oliver.upton@linux.dev \
--cc=suzuki.poulose@arm.com \
--cc=tabba@google.com \
--cc=will@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