From e9f270f15d3ff7f23646ef6059d2106dd015dfae Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Wed, 5 Mar 2025 15:04:31 +0000 Subject: [PATCH] ANDROID: KVM: arm64: Fix loading pvmfw into a protected VM We cannot stash a pointer into the OF driver's reserved_mem table because this is now sorted *after* init functions are called. Hence we can end up with a pointer to an arbitrary rmem region. Instead copy out the required base and size fields. Bug: 400034937 Bug: 357781595 Change-Id: I2e04e8400ba1ec59def7b73d0a97cc83a9e39873 Signed-off-by: Keir Fraser --- arch/arm64/kvm/pkvm.c | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/arch/arm64/kvm/pkvm.c b/arch/arm64/kvm/pkvm.c index ba5cb05e2c34..77e48fd1cfba 100644 --- a/arch/arm64/kvm/pkvm.c +++ b/arch/arm64/kvm/pkvm.c @@ -41,9 +41,8 @@ DEFINE_STATIC_KEY_FALSE(kvm_protected_mode_initialized); -static struct reserved_mem *pkvm_firmware_mem; -static phys_addr_t *pvmfw_base = &kvm_nvhe_sym(pvmfw_base); -static phys_addr_t *pvmfw_size = &kvm_nvhe_sym(pvmfw_size); +static phys_addr_t pvmfw_base; +static phys_addr_t pvmfw_size; static struct pkvm_moveable_reg *moveable_regs = kvm_nvhe_sym(pkvm_moveable_regs); static struct memblock_region *hyp_memory = kvm_nvhe_sym(hyp_memory); @@ -741,7 +740,7 @@ static int __init pkvm_firmware_rmem_init(struct reserved_mem *rmem) { unsigned long node = rmem->fdt_node; - if (pkvm_firmware_mem) + if (pvmfw_size) return pkvm_firmware_rmem_err(rmem, "duplicate reservation"); if (!of_get_flat_dt_prop(node, "no-map", NULL)) @@ -756,9 +755,8 @@ static int __init pkvm_firmware_rmem_init(struct reserved_mem *rmem) if (!PAGE_ALIGNED(rmem->size)) return pkvm_firmware_rmem_err(rmem, "size is not page-aligned"); - *pvmfw_size = rmem->size; - *pvmfw_base = rmem->base; - pkvm_firmware_mem = rmem; + pvmfw_size = kvm_nvhe_sym(pvmfw_size) = rmem->size; + pvmfw_base = kvm_nvhe_sym(pvmfw_base) = rmem->base; return 0; } RESERVEDMEM_OF_DECLARE(pkvm_firmware, "linux,pkvm-guest-firmware-memory", @@ -769,12 +767,12 @@ static int __init pkvm_firmware_rmem_clear(void) void *addr; phys_addr_t size; - if (likely(!pkvm_firmware_mem)) + if (likely(!pvmfw_size)) return 0; kvm_info("Clearing pKVM firmware memory\n"); - size = pkvm_firmware_mem->size; - addr = memremap(pkvm_firmware_mem->base, size, MEMREMAP_WB); + size = pvmfw_size; + addr = memremap(pvmfw_base, size, MEMREMAP_WB); if (!addr) return -EINVAL; @@ -788,7 +786,7 @@ static int pkvm_vm_ioctl_set_fw_ipa(struct kvm *kvm, u64 ipa) { int ret = 0; - if (!pkvm_firmware_mem) + if (!pvmfw_size) return -EINVAL; mutex_lock(&kvm->lock); @@ -807,9 +805,7 @@ static int pkvm_vm_ioctl_info(struct kvm *kvm, struct kvm_protected_vm_info __user *info) { struct kvm_protected_vm_info kinfo = { - .firmware_size = pkvm_firmware_mem ? - pkvm_firmware_mem->size : - 0, + .firmware_size = pvmfw_size, }; return copy_to_user(info, &kinfo, sizeof(kinfo)) ? -EFAULT : 0;