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 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.