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