brintos

brintos / linux-shallow public Read only

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