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
arm_smccc_do_one_page(u32 func_id,phys_addr_t phys)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
__set_memory_range(u32 func_id,unsigned long start,int numpages)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
pkvm_set_memory_encrypted(unsigned long addr,int numpages)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
pkvm_set_memory_decrypted(unsigned long addr,int numpages)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
mmio_guard_ioremap_hook(phys_addr_t phys,size_t size,pgprot_t * prot)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
pkvm_init_hyp_services(void)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