* [PATCH 0/5] drivers/virt: pkvm: Protected VMs with PAGE_SIZE smaller than the hypervisor granule
@ 2026-10-07 15:02 Vincent Donnefort
2026-10-07 15:02 ` [PATCH 1/5] drivers/virt: pkvm: Make pkvm_init_hyp_services() __init Vincent Donnefort
` (4 more replies)
0 siblings, 5 replies; 6+ messages in thread
From: Vincent Donnefort @ 2026-10-07 15:02 UTC (permalink / raw)
To: catalin.marinas, will
Cc: mark.rutland, linux-arm-kernel, linux-kernel, kernel-team,
fuad.tabba, Vincent Donnefort
This series allows a protected VM to boot with a hypervisor whose
protection granule is larger than the guest's PAGE_SIZE (e.g. a 4K guest
on a 16K host).
This is best-effort: non-granule-aligned sharing requests are rejected.
In practice this works because only the swiotlb is shared with the host,
which is allocated early and large enough to be aligned with the
granule.
Tested with a 4K protected guest on both upstream and android17-6.18 16K
hosts (with MMIO guard auto-enrollment forced).
Fuad Tabba (1):
drivers/virt: pkvm: Handle a granule larger than PAGE_SIZE for
MEM_SHARE
Vincent Donnefort (4):
drivers/virt: pkvm: Make pkvm_init_hyp_services() __init
drivers/virt: pkvm: Make pkvm_granule __ro_after_init
drivers/virt: pkvm: Handle a granule larger than PAGE_SIZE for
MMIO_GUARD
drivers/virt: pkvm: Allow granule larger than PAGE_SIZE
drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c | 102 +++++++++++-------
1 file changed, 63 insertions(+), 39 deletions(-)
base-commit: a90ee4305c4a5df72c11b31dacfdc76e00fcf78a
--
2.56.0.rc1.315.gc6ed9934b7-goog
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 1/5] drivers/virt: pkvm: Make pkvm_init_hyp_services() __init
2026-10-07 15:02 [PATCH 0/5] drivers/virt: pkvm: Protected VMs with PAGE_SIZE smaller than the hypervisor granule Vincent Donnefort
@ 2026-10-07 15:02 ` Vincent Donnefort
2026-10-07 15:02 ` [PATCH 2/5] drivers/virt: pkvm: Make pkvm_granule __ro_after_init Vincent Donnefort
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Vincent Donnefort @ 2026-10-07 15:02 UTC (permalink / raw)
To: catalin.marinas, will
Cc: mark.rutland, linux-arm-kernel, linux-kernel, kernel-team,
fuad.tabba, Vincent Donnefort
pkvm_init_hyp_services() is only called from kvm_init_hyp_services(),
which is already marked __init. Mark pkvm_init_hyp_services() as __init
too.
Signed-off-by: Vincent Donnefort <vdonnefort@google.com>
---
drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c b/drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c
index 26fe9c3f22e3..e7d7cedf7f6f 100644
--- a/drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c
+++ b/drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c
@@ -9,6 +9,7 @@
#include <linux/arm-smccc.h>
#include <linux/array_size.h>
+#include <linux/init.h>
#include <linux/io.h>
#include <linux/mem_encrypt.h>
#include <linux/mm.h>
@@ -96,7 +97,7 @@ static int mmio_guard_ioremap_hook(phys_addr_t phys, size_t size,
return 0;
}
-void pkvm_init_hyp_services(void)
+void __init pkvm_init_hyp_services(void)
{
int i;
struct arm_smccc_res res;
--
2.56.0.rc1.315.gc6ed9934b7-goog
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 2/5] drivers/virt: pkvm: Make pkvm_granule __ro_after_init
2026-10-07 15:02 [PATCH 0/5] drivers/virt: pkvm: Protected VMs with PAGE_SIZE smaller than the hypervisor granule Vincent Donnefort
2026-10-07 15:02 ` [PATCH 1/5] drivers/virt: pkvm: Make pkvm_init_hyp_services() __init Vincent Donnefort
@ 2026-10-07 15:02 ` Vincent Donnefort
2026-10-07 15:02 ` [PATCH 3/5] drivers/virt: pkvm: Handle a granule larger than PAGE_SIZE for MEM_SHARE Vincent Donnefort
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Vincent Donnefort @ 2026-10-07 15:02 UTC (permalink / raw)
To: catalin.marinas, will
Cc: mark.rutland, linux-arm-kernel, linux-kernel, kernel-team,
fuad.tabba, Vincent Donnefort
pkvm_granule is only written once during init in
pkvm_init_hyp_services(). Mark it as __ro_after_init.
Signed-off-by: Vincent Donnefort <vdonnefort@google.com>
---
drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c b/drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c
index e7d7cedf7f6f..fbcb57c31186 100644
--- a/drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c
+++ b/drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c
@@ -17,7 +17,7 @@
#include <asm/hypervisor.h>
-static size_t pkvm_granule;
+static size_t __ro_after_init pkvm_granule;
DEFINE_STATIC_KEY_FALSE_RO(pkvm_guest);
static int arm_smccc_do_one_page(u32 func_id, phys_addr_t phys)
--
2.56.0.rc1.315.gc6ed9934b7-goog
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 3/5] drivers/virt: pkvm: Handle a granule larger than PAGE_SIZE for MEM_SHARE
2026-10-07 15:02 [PATCH 0/5] drivers/virt: pkvm: Protected VMs with PAGE_SIZE smaller than the hypervisor granule Vincent Donnefort
2026-10-07 15:02 ` [PATCH 1/5] drivers/virt: pkvm: Make pkvm_init_hyp_services() __init Vincent Donnefort
2026-10-07 15:02 ` [PATCH 2/5] drivers/virt: pkvm: Make pkvm_granule __ro_after_init Vincent Donnefort
@ 2026-10-07 15:02 ` Vincent Donnefort
2026-10-07 15:02 ` [PATCH 4/5] drivers/virt: pkvm: Handle a granule larger than PAGE_SIZE for MMIO_GUARD Vincent Donnefort
2026-10-07 15:02 ` [PATCH 5/5] drivers/virt: pkvm: Allow granule larger than PAGE_SIZE Vincent Donnefort
4 siblings, 0 replies; 6+ messages in thread
From: Vincent Donnefort @ 2026-10-07 15:02 UTC (permalink / raw)
To: catalin.marinas, will
Cc: mark.rutland, linux-arm-kernel, linux-kernel, kernel-team,
fuad.tabba, Vincent Donnefort
From: Fuad Tabba <fuad.tabba@linux.dev>
In preparation for allowing protected VMs to run on a system where the
granule is bigger than their PAGE_SIZE, allow the encryption/decryption
callbacks to work with the hypervisor granule increment instead of
PAGE_SIZE.
Reject requests which are not aligned with the granule.
Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
Co-developed-by: Vincent Donnefort <vdonnefort@google.com>
Signed-off-by: Vincent Donnefort <vdonnefort@google.com>
---
drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c | 42 +++++++------------
1 file changed, 15 insertions(+), 27 deletions(-)
diff --git a/drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c b/drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c
index fbcb57c31186..98b1026cf68b 100644
--- a/drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c
+++ b/drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c
@@ -20,35 +20,19 @@
static size_t __ro_after_init pkvm_granule;
DEFINE_STATIC_KEY_FALSE_RO(pkvm_guest);
-static int arm_smccc_do_one_page(u32 func_id, phys_addr_t phys)
+static int arm_smccc_do_range(u32 func_id, phys_addr_t phys, size_t size)
{
- phys_addr_t end = phys + PAGE_SIZE;
+ phys_addr_t end = phys + size;
- while (phys < end) {
+ if (!IS_ALIGNED(phys | size, pkvm_granule))
+ return -EINVAL;
+
+ for (; phys < end; phys += pkvm_granule) {
struct arm_smccc_res res;
arm_smccc_1_1_invoke(func_id, phys, 0, 0, &res);
if (res.a0 != SMCCC_RET_SUCCESS)
return -EPERM;
-
- phys += pkvm_granule;
- }
-
- return 0;
-}
-
-static int __set_memory_range(u32 func_id, unsigned long start, int numpages)
-{
- void *addr = (void *)start, *end = addr + numpages * PAGE_SIZE;
-
- while (addr < end) {
- int err;
-
- err = arm_smccc_do_one_page(func_id, virt_to_phys(addr));
- if (err)
- return err;
-
- addr += PAGE_SIZE;
}
return 0;
@@ -56,14 +40,16 @@ static int __set_memory_range(u32 func_id, unsigned long start, int numpages)
static int pkvm_set_memory_encrypted(unsigned long addr, int numpages)
{
- return __set_memory_range(ARM_SMCCC_VENDOR_HYP_KVM_MEM_UNSHARE_FUNC_ID,
- addr, numpages);
+ return arm_smccc_do_range(ARM_SMCCC_VENDOR_HYP_KVM_MEM_UNSHARE_FUNC_ID,
+ virt_to_phys((void *)addr),
+ numpages * PAGE_SIZE);
}
static int pkvm_set_memory_decrypted(unsigned long addr, int numpages)
{
- return __set_memory_range(ARM_SMCCC_VENDOR_HYP_KVM_MEM_SHARE_FUNC_ID,
- addr, numpages);
+ return arm_smccc_do_range(ARM_SMCCC_VENDOR_HYP_KVM_MEM_SHARE_FUNC_ID,
+ virt_to_phys((void *)addr),
+ numpages * PAGE_SIZE);
}
static const struct arm64_mem_crypt_ops pkvm_crypt_ops = {
@@ -90,7 +76,7 @@ static int mmio_guard_ioremap_hook(phys_addr_t phys, size_t size,
while (phys < end) {
const int func_id = ARM_SMCCC_VENDOR_HYP_KVM_MMIO_GUARD_FUNC_ID;
- WARN_ON_ONCE(arm_smccc_do_one_page(func_id, phys));
+ WARN_ON_ONCE(arm_smccc_do_range(func_id, phys, PAGE_SIZE));
phys += PAGE_SIZE;
}
@@ -118,6 +104,8 @@ void __init pkvm_init_hyp_services(void)
return;
pkvm_granule = res.a0;
+ if (pkvm_granule > PAGE_SIZE)
+ pr_info("pKVM: sharing memory in %zu-byte granules\n", pkvm_granule);
arm64_mem_crypt_ops_register(&pkvm_crypt_ops);
if (kvm_arm_hyp_service_available(ARM_SMCCC_KVM_FUNC_MMIO_GUARD))
--
2.56.0.rc1.315.gc6ed9934b7-goog
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 4/5] drivers/virt: pkvm: Handle a granule larger than PAGE_SIZE for MMIO_GUARD
2026-10-07 15:02 [PATCH 0/5] drivers/virt: pkvm: Protected VMs with PAGE_SIZE smaller than the hypervisor granule Vincent Donnefort
` (2 preceding siblings ...)
2026-10-07 15:02 ` [PATCH 3/5] drivers/virt: pkvm: Handle a granule larger than PAGE_SIZE for MEM_SHARE Vincent Donnefort
@ 2026-10-07 15:02 ` Vincent Donnefort
2026-10-07 15:02 ` [PATCH 5/5] drivers/virt: pkvm: Allow granule larger than PAGE_SIZE Vincent Donnefort
4 siblings, 0 replies; 6+ messages in thread
From: Vincent Donnefort @ 2026-10-07 15:02 UTC (permalink / raw)
To: catalin.marinas, will
Cc: mark.rutland, linux-arm-kernel, linux-kernel, kernel-team,
fuad.tabba, Vincent Donnefort
In preparation for allowing protected VMs to run on a system where the
granule is bigger than their PAGE_SIZE, allow MMIO_GUARD requests to
overshoot.
Validate the memory regions are aligned with the hypervisor granule
before enabling the MMIO_GUARD support. If aligned, then the MMIO
regions are and overshooting is safe as MMIO_GUARD is solely here to
indicate to the hypervisor where the MMIO regions are.
It is possible to add new memory regions with memory hotplug later.
However the alignment requirement is way more conservative than the
maximum granule size of 64K. Nonetheless, add a test to document the
limitation.
Signed-off-by: Vincent Donnefort <vdonnefort@google.com>
---
drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c | 51 ++++++++++++++++---
1 file changed, 43 insertions(+), 8 deletions(-)
diff --git a/drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c b/drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c
index 98b1026cf68b..3852be6bd16b 100644
--- a/drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c
+++ b/drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c
@@ -12,6 +12,8 @@
#include <linux/init.h>
#include <linux/io.h>
#include <linux/mem_encrypt.h>
+#include <linux/memblock.h>
+#include <linux/memory.h>
#include <linux/mm.h>
#include <linux/pgtable.h>
@@ -70,17 +72,50 @@ static int mmio_guard_ioremap_hook(phys_addr_t phys, size_t size,
if (protval != PROT_DEVICE_nGnRE && protval != PROT_DEVICE_nGnRnE)
return 0;
- end = PAGE_ALIGN(phys + size);
- phys = PAGE_ALIGN_DOWN(phys);
+ /*
+ * It is fine to overshoot MMIO_GUARD requests. Its sole purpose is to
+ * indicate to the hypervisor where the MMIO regions are and we have
+ * validated the alignment of the memory regions beforehand.
+ */
+ end = ALIGN(phys + size, max(pkvm_granule, PAGE_SIZE));
+ phys = ALIGN_DOWN(phys, max(pkvm_granule, PAGE_SIZE));
- while (phys < end) {
- const int func_id = ARM_SMCCC_VENDOR_HYP_KVM_MMIO_GUARD_FUNC_ID;
+ WARN_ON_ONCE(arm_smccc_do_range(ARM_SMCCC_VENDOR_HYP_KVM_MMIO_GUARD_FUNC_ID,
+ phys, end - phys));
+ return 0;
+}
- WARN_ON_ONCE(arm_smccc_do_range(func_id, phys, PAGE_SIZE));
- phys += PAGE_SIZE;
+/*
+ * Return true if the MMIO_GUARD service is available and if overshooting is
+ * safe, which it is if the memory regions are aligned with pkvm_granule.
+ */
+static bool __init mmio_guard_available(void)
+{
+ struct memblock_region *region;
+ phys_addr_t prev_end = 0;
+
+ if (!kvm_arm_hyp_service_available(ARM_SMCCC_KVM_FUNC_MMIO_GUARD))
+ return false;
+
+ if (pkvm_granule <= PAGE_SIZE)
+ return true;
+
+ if (IS_ENABLED(CONFIG_MEMORY_HOTPLUG) &&
+ pkvm_granule > memory_block_size_bytes())
+ return false;
+
+ for_each_mem_region(region) {
+ if (prev_end == region->base)
+ goto contiguous;
+
+ if (!IS_ALIGNED(prev_end | region->base, pkvm_granule))
+ return false;
+
+contiguous:
+ prev_end = region->base + region->size;
}
- return 0;
+ return IS_ALIGNED(prev_end, pkvm_granule);
}
void __init pkvm_init_hyp_services(void)
@@ -108,7 +143,7 @@ void __init pkvm_init_hyp_services(void)
pr_info("pKVM: sharing memory in %zu-byte granules\n", pkvm_granule);
arm64_mem_crypt_ops_register(&pkvm_crypt_ops);
- if (kvm_arm_hyp_service_available(ARM_SMCCC_KVM_FUNC_MMIO_GUARD))
+ if (mmio_guard_available())
arm64_ioremap_prot_hook_register(&mmio_guard_ioremap_hook);
static_branch_enable(&pkvm_guest);
--
2.56.0.rc1.315.gc6ed9934b7-goog
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 5/5] drivers/virt: pkvm: Allow granule larger than PAGE_SIZE
2026-10-07 15:02 [PATCH 0/5] drivers/virt: pkvm: Protected VMs with PAGE_SIZE smaller than the hypervisor granule Vincent Donnefort
` (3 preceding siblings ...)
2026-10-07 15:02 ` [PATCH 4/5] drivers/virt: pkvm: Handle a granule larger than PAGE_SIZE for MMIO_GUARD Vincent Donnefort
@ 2026-10-07 15:02 ` Vincent Donnefort
4 siblings, 0 replies; 6+ messages in thread
From: Vincent Donnefort @ 2026-10-07 15:02 UTC (permalink / raw)
To: catalin.marinas, will
Cc: mark.rutland, linux-arm-kernel, linux-kernel, kernel-team,
fuad.tabba, Vincent Donnefort
Both MEM_SHARE and MMIO_GUARD now support a PAGE_SIZE smaller than the
hypervisor granule. We can relax this restriction.
Signed-off-by: Vincent Donnefort <vdonnefort@google.com>
---
drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c b/drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c
index 3852be6bd16b..e3363a69a7eb 100644
--- a/drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c
+++ b/drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c
@@ -135,7 +135,7 @@ void __init pkvm_init_hyp_services(void)
arm_smccc_1_1_invoke(ARM_SMCCC_VENDOR_HYP_KVM_HYP_MEMINFO_FUNC_ID,
0, 0, 0, &res);
- if (res.a0 > PAGE_SIZE) /* Includes error codes */
+ if ((long)res.a0 <= 0)
return;
pkvm_granule = res.a0;
--
2.56.0.rc1.315.gc6ed9934b7-goog
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-10-07 15:03 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-07 15:02 [PATCH 0/5] drivers/virt: pkvm: Protected VMs with PAGE_SIZE smaller than the hypervisor granule Vincent Donnefort
2026-10-07 15:02 ` [PATCH 1/5] drivers/virt: pkvm: Make pkvm_init_hyp_services() __init Vincent Donnefort
2026-10-07 15:02 ` [PATCH 2/5] drivers/virt: pkvm: Make pkvm_granule __ro_after_init Vincent Donnefort
2026-10-07 15:02 ` [PATCH 3/5] drivers/virt: pkvm: Handle a granule larger than PAGE_SIZE for MEM_SHARE Vincent Donnefort
2026-10-07 15:02 ` [PATCH 4/5] drivers/virt: pkvm: Handle a granule larger than PAGE_SIZE for MMIO_GUARD Vincent Donnefort
2026-10-07 15:02 ` [PATCH 5/5] drivers/virt: pkvm: Allow granule larger than PAGE_SIZE Vincent Donnefort
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®