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