summaryrefslogtreecommitdiff
path: root/drivers/virt
diff options
context:
space:
mode:
authorWill Deacon <will@kernel.org>2024-08-30 14:01:49 +0100
committerWill Deacon <will@kernel.org>2024-08-30 16:30:41 +0100
commit0f12694958001c96bda811473fdb23f333c6d3ca (patch)
tree89427b8cf9699902c19ade73e40057f6bcaf7ce3 /drivers/virt
parentc86fa3470c1026e9f63a93e8885ea51ef99fae35 (diff)
drivers/virt: pkvm: Intercept ioremap using pKVM MMIO_GUARD hypercall
Hook up pKVM's MMIO_GUARD hypercall so that ioremap() and friends will register the target physical address as MMIO with the hypervisor, allowing guest exits to that page to be emulated by the host with full syndrome information. Acked-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20240830130150.8568-7-will@kernel.org Signed-off-by: Will Deacon <will@kernel.org>
Diffstat (limited to 'drivers/virt')
-rw-r--r--drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c35
1 files changed, 35 insertions, 0 deletions
diff --git a/drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c b/drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c
index 8256cf68fd76..56a3859dda8a 100644
--- a/drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c
+++ b/drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c
@@ -9,8 +9,10 @@
#include <linux/arm-smccc.h>
#include <linux/array_size.h>
+#include <linux/io.h>
#include <linux/mem_encrypt.h>
#include <linux/mm.h>
+#include <linux/pgtable.h>
#include <asm/hypervisor.h>
@@ -67,6 +69,36 @@ static const struct arm64_mem_crypt_ops pkvm_crypt_ops = {
.decrypt = pkvm_set_memory_decrypted,
};
+static int mmio_guard_ioremap_hook(phys_addr_t phys, size_t size,
+ pgprot_t *prot)
+{
+ phys_addr_t end;
+ pteval_t protval = pgprot_val(*prot);
+
+ /*
+ * We only expect MMIO emulation for regions mapped with device
+ * attributes.
+ */
+ if (protval != PROT_DEVICE_nGnRE && protval != PROT_DEVICE_nGnRnE)
+ return 0;
+
+ phys = PAGE_ALIGN_DOWN(phys);
+ end = phys + PAGE_ALIGN(size);
+
+ while (phys < end) {
+ const int func_id = ARM_SMCCC_VENDOR_HYP_KVM_MMIO_GUARD_FUNC_ID;
+ int err;
+
+ err = arm_smccc_do_one_page(func_id, phys);
+ if (err)
+ return err;
+
+ phys += PAGE_SIZE;
+ }
+
+ return 0;
+}
+
void pkvm_init_hyp_services(void)
{
int i;
@@ -89,4 +121,7 @@ void pkvm_init_hyp_services(void)
pkvm_granule = res.a0;
arm64_mem_crypt_ops_register(&pkvm_crypt_ops);
+
+ if (kvm_arm_hyp_service_available(ARM_SMCCC_KVM_FUNC_MMIO_GUARD))
+ arm64_ioremap_prot_hook_register(&mmio_guard_ioremap_hook);
}