xref: /linux/drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c (revision 0f12694958001c96bda811473fdb23f333c6d3ca)
1a06c3fadSWill Deacon // SPDX-License-Identifier: GPL-2.0-only
2a06c3fadSWill Deacon /*
3a06c3fadSWill Deacon  * Support for the hypercall interface exposed to protected guests by
4a06c3fadSWill Deacon  * pKVM.
5a06c3fadSWill Deacon  *
6a06c3fadSWill Deacon  * Author: Will Deacon <will@kernel.org>
7a06c3fadSWill Deacon  * Copyright (C) 2024 Google LLC
8a06c3fadSWill Deacon  */
9a06c3fadSWill Deacon 
10a06c3fadSWill Deacon #include <linux/arm-smccc.h>
11a06c3fadSWill Deacon #include <linux/array_size.h>
12*0f126949SWill Deacon #include <linux/io.h>
13ebc59b12SWill Deacon #include <linux/mem_encrypt.h>
14a06c3fadSWill Deacon #include <linux/mm.h>
15*0f126949SWill Deacon #include <linux/pgtable.h>
16a06c3fadSWill Deacon 
17a06c3fadSWill Deacon #include <asm/hypervisor.h>
18a06c3fadSWill Deacon 
19a06c3fadSWill Deacon static size_t pkvm_granule;
20a06c3fadSWill Deacon 
21ebc59b12SWill Deacon static int arm_smccc_do_one_page(u32 func_id, phys_addr_t phys)
22ebc59b12SWill Deacon {
23ebc59b12SWill Deacon 	phys_addr_t end = phys + PAGE_SIZE;
24ebc59b12SWill Deacon 
25ebc59b12SWill Deacon 	while (phys < end) {
26ebc59b12SWill Deacon 		struct arm_smccc_res res;
27ebc59b12SWill Deacon 
28ebc59b12SWill Deacon 		arm_smccc_1_1_invoke(func_id, phys, 0, 0, &res);
29ebc59b12SWill Deacon 		if (res.a0 != SMCCC_RET_SUCCESS)
30ebc59b12SWill Deacon 			return -EPERM;
31ebc59b12SWill Deacon 
32ebc59b12SWill Deacon 		phys += pkvm_granule;
33ebc59b12SWill Deacon 	}
34ebc59b12SWill Deacon 
35ebc59b12SWill Deacon 	return 0;
36ebc59b12SWill Deacon }
37ebc59b12SWill Deacon 
38ebc59b12SWill Deacon static int __set_memory_range(u32 func_id, unsigned long start, int numpages)
39ebc59b12SWill Deacon {
40ebc59b12SWill Deacon 	void *addr = (void *)start, *end = addr + numpages * PAGE_SIZE;
41ebc59b12SWill Deacon 
42ebc59b12SWill Deacon 	while (addr < end) {
43ebc59b12SWill Deacon 		int err;
44ebc59b12SWill Deacon 
45ebc59b12SWill Deacon 		err = arm_smccc_do_one_page(func_id, virt_to_phys(addr));
46ebc59b12SWill Deacon 		if (err)
47ebc59b12SWill Deacon 			return err;
48ebc59b12SWill Deacon 
49ebc59b12SWill Deacon 		addr += PAGE_SIZE;
50ebc59b12SWill Deacon 	}
51ebc59b12SWill Deacon 
52ebc59b12SWill Deacon 	return 0;
53ebc59b12SWill Deacon }
54ebc59b12SWill Deacon 
55ebc59b12SWill Deacon static int pkvm_set_memory_encrypted(unsigned long addr, int numpages)
56ebc59b12SWill Deacon {
57ebc59b12SWill Deacon 	return __set_memory_range(ARM_SMCCC_VENDOR_HYP_KVM_MEM_UNSHARE_FUNC_ID,
58ebc59b12SWill Deacon 				  addr, numpages);
59ebc59b12SWill Deacon }
60ebc59b12SWill Deacon 
61ebc59b12SWill Deacon static int pkvm_set_memory_decrypted(unsigned long addr, int numpages)
62ebc59b12SWill Deacon {
63ebc59b12SWill Deacon 	return __set_memory_range(ARM_SMCCC_VENDOR_HYP_KVM_MEM_SHARE_FUNC_ID,
64ebc59b12SWill Deacon 				  addr, numpages);
65ebc59b12SWill Deacon }
66ebc59b12SWill Deacon 
67ebc59b12SWill Deacon static const struct arm64_mem_crypt_ops pkvm_crypt_ops = {
68ebc59b12SWill Deacon 	.encrypt	= pkvm_set_memory_encrypted,
69ebc59b12SWill Deacon 	.decrypt	= pkvm_set_memory_decrypted,
70ebc59b12SWill Deacon };
71ebc59b12SWill Deacon 
72*0f126949SWill Deacon static int mmio_guard_ioremap_hook(phys_addr_t phys, size_t size,
73*0f126949SWill Deacon 				   pgprot_t *prot)
74*0f126949SWill Deacon {
75*0f126949SWill Deacon 	phys_addr_t end;
76*0f126949SWill Deacon 	pteval_t protval = pgprot_val(*prot);
77*0f126949SWill Deacon 
78*0f126949SWill Deacon 	/*
79*0f126949SWill Deacon 	 * We only expect MMIO emulation for regions mapped with device
80*0f126949SWill Deacon 	 * attributes.
81*0f126949SWill Deacon 	 */
82*0f126949SWill Deacon 	if (protval != PROT_DEVICE_nGnRE && protval != PROT_DEVICE_nGnRnE)
83*0f126949SWill Deacon 		return 0;
84*0f126949SWill Deacon 
85*0f126949SWill Deacon 	phys = PAGE_ALIGN_DOWN(phys);
86*0f126949SWill Deacon 	end = phys + PAGE_ALIGN(size);
87*0f126949SWill Deacon 
88*0f126949SWill Deacon 	while (phys < end) {
89*0f126949SWill Deacon 		const int func_id = ARM_SMCCC_VENDOR_HYP_KVM_MMIO_GUARD_FUNC_ID;
90*0f126949SWill Deacon 		int err;
91*0f126949SWill Deacon 
92*0f126949SWill Deacon 		err = arm_smccc_do_one_page(func_id, phys);
93*0f126949SWill Deacon 		if (err)
94*0f126949SWill Deacon 			return err;
95*0f126949SWill Deacon 
96*0f126949SWill Deacon 		phys += PAGE_SIZE;
97*0f126949SWill Deacon 	}
98*0f126949SWill Deacon 
99*0f126949SWill Deacon 	return 0;
100*0f126949SWill Deacon }
101*0f126949SWill Deacon 
102a06c3fadSWill Deacon void pkvm_init_hyp_services(void)
103a06c3fadSWill Deacon {
104a06c3fadSWill Deacon 	int i;
105a06c3fadSWill Deacon 	struct arm_smccc_res res;
106a06c3fadSWill Deacon 	const u32 funcs[] = {
107a06c3fadSWill Deacon 		ARM_SMCCC_KVM_FUNC_HYP_MEMINFO,
108ebc59b12SWill Deacon 		ARM_SMCCC_KVM_FUNC_MEM_SHARE,
109ebc59b12SWill Deacon 		ARM_SMCCC_KVM_FUNC_MEM_UNSHARE,
110a06c3fadSWill Deacon 	};
111a06c3fadSWill Deacon 
112a06c3fadSWill Deacon 	for (i = 0; i < ARRAY_SIZE(funcs); ++i) {
113a06c3fadSWill Deacon 		if (!kvm_arm_hyp_service_available(funcs[i]))
114a06c3fadSWill Deacon 			return;
115a06c3fadSWill Deacon 	}
116a06c3fadSWill Deacon 
117a06c3fadSWill Deacon 	arm_smccc_1_1_invoke(ARM_SMCCC_VENDOR_HYP_KVM_HYP_MEMINFO_FUNC_ID,
118a06c3fadSWill Deacon 			     0, 0, 0, &res);
119a06c3fadSWill Deacon 	if (res.a0 > PAGE_SIZE) /* Includes error codes */
120a06c3fadSWill Deacon 		return;
121a06c3fadSWill Deacon 
122a06c3fadSWill Deacon 	pkvm_granule = res.a0;
123ebc59b12SWill Deacon 	arm64_mem_crypt_ops_register(&pkvm_crypt_ops);
124*0f126949SWill Deacon 
125*0f126949SWill Deacon 	if (kvm_arm_hyp_service_available(ARM_SMCCC_KVM_FUNC_MMIO_GUARD))
126*0f126949SWill Deacon 		arm64_ioremap_prot_hook_register(&mmio_guard_ioremap_hook);
127a06c3fadSWill Deacon }
128