diff options
author | Will Deacon <will@kernel.org> | 2024-08-30 14:01:47 +0100 |
---|---|---|
committer | Will Deacon <will@kernel.org> | 2024-08-30 16:30:41 +0100 |
commit | ebc59b120c588156feb7ce194a9636584ced18ba (patch) | |
tree | 920ef10082f63326dfbe0d19c81286930773f5ad /drivers/virt/coco | |
parent | e7bafbf7177750e6643941473b343ed72fc5a100 (diff) | |
download | lwn-ebc59b120c588156feb7ce194a9636584ced18ba.tar.gz lwn-ebc59b120c588156feb7ce194a9636584ced18ba.zip |
drivers/virt: pkvm: Hook up mem_encrypt API using pKVM hypercalls
If we detect the presence of pKVM's SHARE and UNSHARE hypercalls, then
register a backend implementation of the mem_encrypt API so that things
like DMA buffers can be shared appropriately with the host.
Acked-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20240830130150.8568-5-will@kernel.org
Signed-off-by: Will Deacon <will@kernel.org>
Diffstat (limited to 'drivers/virt/coco')
-rw-r--r-- | drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c | 55 |
1 files changed, 55 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 a5148701d2f1..8256cf68fd76 100644 --- a/drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c +++ b/drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c @@ -9,18 +9,72 @@ #include <linux/arm-smccc.h> #include <linux/array_size.h> +#include <linux/mem_encrypt.h> #include <linux/mm.h> #include <asm/hypervisor.h> static size_t pkvm_granule; +static int arm_smccc_do_one_page(u32 func_id, phys_addr_t phys) +{ + phys_addr_t end = phys + PAGE_SIZE; + + while (phys < end) { + 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; +} + +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); +} + +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); +} + +static const struct arm64_mem_crypt_ops pkvm_crypt_ops = { + .encrypt = pkvm_set_memory_encrypted, + .decrypt = pkvm_set_memory_decrypted, +}; + void pkvm_init_hyp_services(void) { int i; struct arm_smccc_res res; const u32 funcs[] = { ARM_SMCCC_KVM_FUNC_HYP_MEMINFO, + ARM_SMCCC_KVM_FUNC_MEM_SHARE, + ARM_SMCCC_KVM_FUNC_MEM_UNSHARE, }; for (i = 0; i < ARRAY_SIZE(funcs); ++i) { @@ -34,4 +88,5 @@ void pkvm_init_hyp_services(void) return; pkvm_granule = res.a0; + arm64_mem_crypt_ops_register(&pkvm_crypt_ops); } |