xref: /optee_os/core/drivers/smccc_trng.c (revision d74bac2ab72c6f851804ff0faa29e1fe44b6db37)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (C) 2022 Linaro Limited
4  */
5 
6 #include <assert.h>
7 #include <config.h>
8 #include <crypto/crypto.h>
9 #include <kernel/panic.h>
10 #include <kernel/thread_arch.h>
11 #include <rng_support.h>
12 #include <sm/std_smc.h>
13 #include <initcall.h>
14 #include <stdbool.h>
15 #include <string.h>
16 #include <util.h>
17 #include <tee_api_types.h>
18 #include <tee/tee_cryp_utl.h>
19 #include <trace.h>
20 
21 /*
22  * Arm SMCCC TRNG firmware interface specification:
23  * https://developer.arm.com/documentation/den0098/
24  */
25 #define ARM_SMCCC_TRNG_VERSION		0x84000050
26 #define ARM_SMCCC_TRNG_FEATURES		0x84000051
27 #define ARM_SMCCC_TRNG_GET_UUID		0x84000052
28 #define ARM_SMCCC_TRNG_RND_32		0x84000053
29 #define ARM_SMCCC_TRNG_RND_64		0xc4000053
30 
31 #define ARM_SMCCC_RET_TRNG_SUCCESS		U(0)
32 #define ARM_SMCCC_RET_TRNG_NOT_SUPPORTED	((unsigned long)-1)
33 #define ARM_SMCCC_RET_TRNG_INVALID_PARAMETER	((unsigned long)-2)
34 #define ARM_SMCCC_RET_TRNG_NO_ENTROPY		((unsigned long)-3)
35 
36 #define TRNG_MAJOR_MASK		GENMASK_32(30, 16)
37 #define TRNG_MAJOR_SHIFT	16
38 #define TRNG_MINOR_MASK		GENMASK_32(15, 0)
39 #define TRNG_MINOR_SHIFT	0
40 #define TRNG_MAKE_VERSION(major, minor)	\
41 	((SHIFT_U32(major, TRNG_MAJOR_SHIFT) & TRNG_MAJOR_MASK) | \
42 	 (SHIFT_U32(minor, TRNG_MINOR_SHIFT) & TRNG_MINOR_MASK))
43 
44 #define TRNG_VERSION_1_0	TRNG_MAKE_VERSION(1, 0)
45 
46 #define TRNG_MAX_RND_64		(192 / 8)
47 #define TRNG_MAX_RND_32		(96 / 8)
48 
49 /* Function ID discovered for getting random bytes or 0 if not supported */
50 static uint32_t trng_rnd_fid;
51 
smccc_trng_is_supported(void)52 static bool smccc_trng_is_supported(void)
53 {
54 	struct thread_smc_args args = { };
55 	static bool inited;
56 
57 	if (inited)
58 		return trng_rnd_fid != 0;
59 
60 	inited = true;
61 
62 	/*
63 	 * TRNG ABI requires caller to check that Arm SMCCC version is
64 	 * larger or equal to v1.1
65 	 */
66 	args.a0 = ARM_SMCCC_VERSION;
67 	thread_smccc(&args);
68 	if (args.a0 & BIT32(31) || args.a0 < SMCCC_V_1_1)
69 		return false;
70 
71 	/*
72 	 * Check TRNG version, if successful we're guaranteed to have at least
73 	 * the ARM_SMCCC_TRNG_FEATURES fid.
74 	 */
75 	args.a0 = ARM_SMCCC_TRNG_VERSION;
76 	thread_smccc(&args);
77 	if (args.a0 & BIT32(31) || args.a0 < TRNG_VERSION_1_0)
78 		return false;
79 
80 #ifdef ARM64
81 	args.a0 = ARM_SMCCC_TRNG_FEATURES;
82 	args.a1 = ARM_SMCCC_TRNG_RND_64;
83 	thread_smccc(&args);
84 	if (args.a0 == ARM_SMCCC_RET_SUCCESS) {
85 		trng_rnd_fid = ARM_SMCCC_TRNG_RND_64;
86 		return true;
87 	}
88 #endif
89 
90 	args.a0 = ARM_SMCCC_TRNG_FEATURES;
91 	args.a1 = ARM_SMCCC_TRNG_RND_32;
92 	thread_smccc(&args);
93 	if (args.a0 == ARM_SMCCC_RET_TRNG_SUCCESS) {
94 		trng_rnd_fid = ARM_SMCCC_TRNG_RND_32;
95 		return true;
96 	}
97 
98 	return false;
99 }
100 
read_bytes(unsigned long val,size_t byte_count,uint8_t ** buf,size_t * rem)101 static void read_bytes(unsigned long val, size_t byte_count, uint8_t **buf,
102 		       size_t *rem)
103 {
104 	size_t count = MIN(byte_count, *rem);
105 	size_t n = 0;
106 
107 	for (n = 0; n < count; n++)
108 		(*buf)[n] = val >> (n * 8);
109 
110 	*buf += count;
111 	*rem -= count;
112 }
113 
read_samples(struct thread_smc_args * args,uint8_t * buf,size_t len)114 static void read_samples(struct thread_smc_args *args, uint8_t *buf, size_t len)
115 {
116 	uint8_t *ptr = buf;
117 	size_t rem = len;
118 	size_t byte_count = 4;
119 
120 #ifdef ARM64
121 	if (trng_rnd_fid == ARM_SMCCC_TRNG_RND_64)
122 		byte_count = 8;
123 #endif
124 
125 	read_bytes(args->a3, byte_count, &ptr, &rem);
126 	read_bytes(args->a2, byte_count, &ptr, &rem);
127 	read_bytes(args->a1, byte_count, &ptr, &rem);
128 }
129 
smccc_trng_read(void * buf,size_t len)130 static TEE_Result __maybe_unused smccc_trng_read(void *buf, size_t len)
131 {
132 	struct thread_smc_args args = { };
133 	uint8_t *ptr = buf;
134 	size_t rem = len;
135 	size_t max_burst = 0;
136 
137 	if (!smccc_trng_is_supported())
138 		return TEE_ERROR_NOT_SUPPORTED;
139 
140 	if (trng_rnd_fid == ARM_SMCCC_TRNG_RND_64)
141 		max_burst = TRNG_MAX_RND_64;
142 	else
143 		max_burst = TRNG_MAX_RND_32;
144 
145 	while (rem) {
146 		size_t burst = MIN(rem, max_burst);
147 
148 		args.a0 = trng_rnd_fid;
149 		args.a1 = burst * 8;
150 
151 		thread_smccc(&args);
152 
153 		switch (args.a0) {
154 		case ARM_SMCCC_RET_TRNG_SUCCESS:
155 			read_samples(&args, ptr, burst);
156 			rem -= burst;
157 			ptr += burst;
158 			break;
159 		case ARM_SMCCC_RET_TRNG_NO_ENTROPY:
160 			break;
161 		default:
162 			return TEE_ERROR_GENERIC;
163 		}
164 	}
165 
166 	return TEE_SUCCESS;
167 }
168 
smccc_trng_print_info(void)169 static void __maybe_unused smccc_trng_print_info(void)
170 {
171 	struct thread_smc_args args = { };
172 	unsigned int __maybe_unused major = 0;
173 	unsigned int __maybe_unused minor = 0;
174 
175 	if (!IS_ENABLED(CFG_TEE_CORE_DEBUG))
176 		return;
177 
178 	args.a0 = ARM_SMCCC_TRNG_VERSION;
179 	thread_smccc(&args);
180 	assert((args.a0 & BIT32(31)) == 0);
181 	major = (args.a0 & TRNG_MAJOR_MASK) >> TRNG_MAJOR_SHIFT;
182 	minor = (args.a0 & TRNG_MINOR_MASK) >> TRNG_MINOR_SHIFT;
183 
184 	args.a0 = ARM_SMCCC_TRNG_GET_UUID;
185 	thread_smccc(&args);
186 	assert(args.a0 != ARM_SMCCC_RET_TRNG_NOT_SUPPORTED);
187 
188 	DMSG("SMCCC TRNG v%u.%u, UUID %08lx-%04lx-%04lx-%04lx-%04lx%08lx",
189 	     major, minor, (unsigned long)args.a0, (unsigned long)args.a1 >> 16,
190 	     (unsigned long)args.a1 & GENMASK_32(16, 0),
191 	     (unsigned long)args.a2 >> 16,
192 	     (unsigned long)args.a2 & GENMASK_32(16, 0),
193 	     (unsigned long)args.a3);
194 }
195 
smcc_trng_init(void)196 static TEE_Result smcc_trng_init(void)
197 {
198 	if (!smccc_trng_is_supported())
199 		panic("SMCCC TRNG not supported");
200 
201 	smccc_trng_print_info();
202 
203 	return TEE_SUCCESS;
204 }
205 early_init(smcc_trng_init);
206 
207 #ifdef CFG_WITH_SOFTWARE_PRNG
plat_init_soft_prng(void)208 void plat_init_soft_prng(void)
209 {
210 	uint8_t seed[32] = { 0 };
211 
212 	if (smccc_trng_read(seed, sizeof(seed)))
213 		panic("SMCCC TRNG not supported");
214 
215 	if (crypto_rng_init(seed, sizeof(seed)))
216 		panic();
217 }
218 #else
hw_get_random_bytes(void * buf,size_t len)219 TEE_Result hw_get_random_bytes(void *buf, size_t len)
220 {
221 	return smccc_trng_read(buf, len);
222 }
223 #endif
224