summaryrefslogtreecommitdiffstats
path: root/drivers/virt
diff options
context:
space:
mode:
authorWill Deacon <will@kernel.org>2024-08-30 15:01:47 +0200
committerWill Deacon <will@kernel.org>2024-08-30 17:30:41 +0200
commitebc59b120c588156feb7ce194a9636584ced18ba (patch)
tree920ef10082f63326dfbe0d19c81286930773f5ad /drivers/virt
parentarm64: mm: Add top-level dispatcher for internal mem_encrypt API (diff)
downloadlinux-ebc59b120c588156feb7ce194a9636584ced18ba.tar.xz
linux-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')
-rw-r--r--drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c55
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);
}