• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /*
3  * Implementation of the memory encryption/decryption API.
4  *
5  * Amusingly, no crypto is actually performed. Rather, we call into the
6  * hypervisor component of KVM to expose pages selectively to the host
7  * for virtio "DMA" operations. In other words, "encrypted" pages are
8  * not accessible to the host, whereas "decrypted" pages are.
9  *
10  * Author: Will Deacon <will@kernel.org>
11  */
12 #include <linux/arm-smccc.h>
13 #include <linux/mem_encrypt.h>
14 #include <linux/memory.h>
15 #include <linux/mm.h>
16 #include <linux/set_memory.h>
17 #include <linux/types.h>
18 
19 #include <asm/hypervisor.h>
20 
21 static unsigned long memshare_granule_sz;
22 
mem_encrypt_active(void)23 bool mem_encrypt_active(void)
24 {
25 	return memshare_granule_sz;
26 }
27 EXPORT_SYMBOL(mem_encrypt_active);
28 
kvm_init_memshare_services(void)29 void kvm_init_memshare_services(void)
30 {
31 	int i;
32 	struct arm_smccc_res res;
33 	const u32 funcs[] = {
34 		ARM_SMCCC_KVM_FUNC_HYP_MEMINFO,
35 		ARM_SMCCC_KVM_FUNC_MEM_SHARE,
36 		ARM_SMCCC_KVM_FUNC_MEM_UNSHARE,
37 	};
38 
39 	for (i = 0; i < ARRAY_SIZE(funcs); ++i) {
40 		if (!kvm_arm_hyp_service_available(funcs[i]))
41 			return;
42 	}
43 
44 	arm_smccc_1_1_invoke(ARM_SMCCC_VENDOR_HYP_KVM_HYP_MEMINFO_FUNC_ID,
45 			     0, 0, 0, &res);
46 	if (res.a0 > PAGE_SIZE) /* Includes error codes */
47 		return;
48 
49 	memshare_granule_sz = res.a0;
50 }
51 
arm_smccc_share_unshare_page(u32 func_id,phys_addr_t phys)52 static int arm_smccc_share_unshare_page(u32 func_id, phys_addr_t phys)
53 {
54 	phys_addr_t end = phys + PAGE_SIZE;
55 
56 	while (phys < end) {
57 		struct arm_smccc_res res;
58 
59 		arm_smccc_1_1_invoke(func_id, phys, 0, 0, &res);
60 		if (res.a0 != SMCCC_RET_SUCCESS)
61 			return -EPERM;
62 
63 		phys += memshare_granule_sz;
64 	}
65 
66 	return 0;
67 }
68 
set_memory_xcrypted(u32 func_id,unsigned long start,int numpages)69 static int set_memory_xcrypted(u32 func_id, unsigned long start, int numpages)
70 {
71 	void *addr = (void *)start, *end = addr + numpages * PAGE_SIZE;
72 
73 	while (addr < end) {
74 		int err;
75 
76 		err = arm_smccc_share_unshare_page(func_id, virt_to_phys(addr));
77 		if (err)
78 			return err;
79 
80 		addr += PAGE_SIZE;
81 	}
82 
83 	return 0;
84 }
85 
set_memory_encrypted(unsigned long addr,int numpages)86 int set_memory_encrypted(unsigned long addr, int numpages)
87 {
88 	if (!memshare_granule_sz || WARN_ON(!PAGE_ALIGNED(addr)))
89 		return 0;
90 
91 	return set_memory_xcrypted(ARM_SMCCC_VENDOR_HYP_KVM_MEM_UNSHARE_FUNC_ID,
92 				   addr, numpages);
93 }
94 
set_memory_decrypted(unsigned long addr,int numpages)95 int set_memory_decrypted(unsigned long addr, int numpages)
96 {
97 	if (!memshare_granule_sz || WARN_ON(!PAGE_ALIGNED(addr)))
98 		return 0;
99 
100 	return set_memory_xcrypted(ARM_SMCCC_VENDOR_HYP_KVM_MEM_SHARE_FUNC_ID,
101 				   addr, numpages);
102 }
103