xref: /optee_os/core/drivers/smccc_trng.c (revision bce2f88ab347b28f4149dacef2ad48ac67a500b6)
10347e53fSEtienne Carriere // SPDX-License-Identifier: BSD-2-Clause
20347e53fSEtienne Carriere /*
30347e53fSEtienne Carriere  * Copyright (C) 2022 Linaro Limited
40347e53fSEtienne Carriere  */
50347e53fSEtienne Carriere 
60347e53fSEtienne Carriere #include <assert.h>
70347e53fSEtienne Carriere #include <config.h>
80347e53fSEtienne Carriere #include <crypto/crypto.h>
90347e53fSEtienne Carriere #include <kernel/panic.h>
100347e53fSEtienne Carriere #include <kernel/thread_arch.h>
110347e53fSEtienne Carriere #include <rng_support.h>
120347e53fSEtienne Carriere #include <sm/std_smc.h>
130347e53fSEtienne Carriere #include <stdbool.h>
140347e53fSEtienne Carriere #include <string.h>
150347e53fSEtienne Carriere #include <util.h>
160347e53fSEtienne Carriere #include <tee_api_types.h>
170347e53fSEtienne Carriere #include <tee/tee_cryp_utl.h>
180347e53fSEtienne Carriere #include <trace.h>
190347e53fSEtienne Carriere 
200347e53fSEtienne Carriere /*
210347e53fSEtienne Carriere  * Arm SMCCC TRNG firmware interface specification:
220347e53fSEtienne Carriere  * https://developer.arm.com/documentation/den0098/
230347e53fSEtienne Carriere  */
240347e53fSEtienne Carriere #define ARM_SMCCC_TRNG_VERSION		0x84000050
250347e53fSEtienne Carriere #define ARM_SMCCC_TRNG_FEATURES		0x84000051
260347e53fSEtienne Carriere #define ARM_SMCCC_TRNG_GET_UUID		0x84000052
270347e53fSEtienne Carriere #define ARM_SMCCC_TRNG_RND_32		0x84000053
280347e53fSEtienne Carriere #define ARM_SMCCC_TRNG_RND_64		0xc4000053
290347e53fSEtienne Carriere 
300347e53fSEtienne Carriere #define ARM_SMCCC_RET_TRNG_SUCCESS		U(0)
310347e53fSEtienne Carriere #define ARM_SMCCC_RET_TRNG_NOT_SUPPORTED	((unsigned long)-1)
320347e53fSEtienne Carriere #define ARM_SMCCC_RET_TRNG_INVALID_PARAMETER	((unsigned long)-2)
330347e53fSEtienne Carriere #define ARM_SMCCC_RET_TRNG_NO_ENTROPY		((unsigned long)-3)
340347e53fSEtienne Carriere 
350347e53fSEtienne Carriere #define TRNG_MAJOR_MASK		GENMASK_32(30, 16)
360347e53fSEtienne Carriere #define TRNG_MAJOR_SHIFT	16
370347e53fSEtienne Carriere #define TRNG_MINOR_MASK		GENMASK_32(15, 0)
380347e53fSEtienne Carriere #define TRNG_MINOR_SHIFT	0
390347e53fSEtienne Carriere #define TRNG_MAKE_VERSION(major, minor)	\
400347e53fSEtienne Carriere 	((SHIFT_U32(major, TRNG_MAJOR_SHIFT) & TRNG_MAJOR_MASK) | \
410347e53fSEtienne Carriere 	 (SHIFT_U32(minor, TRNG_MINOR_SHIFT) & TRNG_MINOR_MASK))
420347e53fSEtienne Carriere 
430347e53fSEtienne Carriere #define TRNG_VERSION_1_0	TRNG_MAKE_VERSION(1, 0)
440347e53fSEtienne Carriere 
450347e53fSEtienne Carriere #define TRNG_MAX_RND_64		(192 / 8)
460347e53fSEtienne Carriere #define TRNG_MAX_RND_32		(96 / 8)
470347e53fSEtienne Carriere 
480347e53fSEtienne Carriere /* Function ID discovered for getting random bytes or 0 if not supported */
490347e53fSEtienne Carriere static uint32_t trng_rnd_fid;
500347e53fSEtienne Carriere 
smccc_trng_is_supported(void)510347e53fSEtienne Carriere static bool smccc_trng_is_supported(void)
520347e53fSEtienne Carriere {
530347e53fSEtienne Carriere 	struct thread_smc_args args = { };
540347e53fSEtienne Carriere 	static bool inited;
550347e53fSEtienne Carriere 
560347e53fSEtienne Carriere 	if (inited)
570347e53fSEtienne Carriere 		return trng_rnd_fid != 0;
580347e53fSEtienne Carriere 
590347e53fSEtienne Carriere 	inited = true;
600347e53fSEtienne Carriere 
610347e53fSEtienne Carriere 	/*
620347e53fSEtienne Carriere 	 * TRNG ABI requires caller to check that Arm SMCCC version is
630347e53fSEtienne Carriere 	 * larger or equal to v1.1
640347e53fSEtienne Carriere 	 */
650347e53fSEtienne Carriere 	args.a0 = ARM_SMCCC_VERSION;
660347e53fSEtienne Carriere 	thread_smccc(&args);
670347e53fSEtienne Carriere 	if (args.a0 & BIT32(31) || args.a0 < SMCCC_V_1_1)
680347e53fSEtienne Carriere 		return false;
690347e53fSEtienne Carriere 
700347e53fSEtienne Carriere 	/*
710347e53fSEtienne Carriere 	 * Check TRNG version, if successful we're guaranteed to have at least
720347e53fSEtienne Carriere 	 * the ARM_SMCCC_TRNG_FEATURES fid.
730347e53fSEtienne Carriere 	 */
740347e53fSEtienne Carriere 	args.a0 = ARM_SMCCC_TRNG_VERSION;
750347e53fSEtienne Carriere 	thread_smccc(&args);
760347e53fSEtienne Carriere 	if (args.a0 & BIT32(31) || args.a0 < TRNG_VERSION_1_0)
770347e53fSEtienne Carriere 		return false;
780347e53fSEtienne Carriere 
790347e53fSEtienne Carriere #ifdef ARM64
800347e53fSEtienne Carriere 	args.a0 = ARM_SMCCC_TRNG_FEATURES;
810347e53fSEtienne Carriere 	args.a1 = ARM_SMCCC_TRNG_RND_64;
820347e53fSEtienne Carriere 	thread_smccc(&args);
830347e53fSEtienne Carriere 	if (args.a0 == ARM_SMCCC_RET_SUCCESS) {
840347e53fSEtienne Carriere 		trng_rnd_fid = ARM_SMCCC_TRNG_RND_64;
850347e53fSEtienne Carriere 		return true;
860347e53fSEtienne Carriere 	}
870347e53fSEtienne Carriere #endif
880347e53fSEtienne Carriere 
890347e53fSEtienne Carriere 	args.a0 = ARM_SMCCC_TRNG_FEATURES;
900347e53fSEtienne Carriere 	args.a1 = ARM_SMCCC_TRNG_RND_32;
910347e53fSEtienne Carriere 	thread_smccc(&args);
920347e53fSEtienne Carriere 	if (args.a0 == ARM_SMCCC_RET_TRNG_SUCCESS) {
930347e53fSEtienne Carriere 		trng_rnd_fid = ARM_SMCCC_TRNG_RND_32;
940347e53fSEtienne Carriere 		return true;
950347e53fSEtienne Carriere 	}
960347e53fSEtienne Carriere 
970347e53fSEtienne Carriere 	return false;
980347e53fSEtienne Carriere }
990347e53fSEtienne Carriere 
read_bytes(unsigned long val,size_t byte_count,uint8_t ** buf,size_t * rem)1000347e53fSEtienne Carriere static void read_bytes(unsigned long val, size_t byte_count, uint8_t **buf,
1010347e53fSEtienne Carriere 		       size_t *rem)
1020347e53fSEtienne Carriere {
1030347e53fSEtienne Carriere 	size_t count = MIN(byte_count, *rem);
1040347e53fSEtienne Carriere 	size_t n = 0;
1050347e53fSEtienne Carriere 
1060347e53fSEtienne Carriere 	for (n = 0; n < count; n++)
1070347e53fSEtienne Carriere 		(*buf)[n] = val >> (n * 8);
1080347e53fSEtienne Carriere 
1090347e53fSEtienne Carriere 	*buf += count;
1100347e53fSEtienne Carriere 	*rem -= count;
1110347e53fSEtienne Carriere }
1120347e53fSEtienne Carriere 
read_samples(struct thread_smc_args * args,uint8_t * buf,size_t len)1130347e53fSEtienne Carriere static void read_samples(struct thread_smc_args *args, uint8_t *buf, size_t len)
1140347e53fSEtienne Carriere {
1150347e53fSEtienne Carriere 	uint8_t *ptr = buf;
1160347e53fSEtienne Carriere 	size_t rem = len;
1170347e53fSEtienne Carriere 	size_t byte_count = 4;
1180347e53fSEtienne Carriere 
1190347e53fSEtienne Carriere #ifdef ARM64
1200347e53fSEtienne Carriere 	if (trng_rnd_fid == ARM_SMCCC_TRNG_RND_64)
1210347e53fSEtienne Carriere 		byte_count = 8;
1220347e53fSEtienne Carriere #endif
1230347e53fSEtienne Carriere 
1240347e53fSEtienne Carriere 	read_bytes(args->a3, byte_count, &ptr, &rem);
1250347e53fSEtienne Carriere 	read_bytes(args->a2, byte_count, &ptr, &rem);
1260347e53fSEtienne Carriere 	read_bytes(args->a1, byte_count, &ptr, &rem);
1270347e53fSEtienne Carriere }
1280347e53fSEtienne Carriere 
smccc_trng_read(void * buf,size_t len)1290347e53fSEtienne Carriere static TEE_Result __maybe_unused smccc_trng_read(void *buf, size_t len)
1300347e53fSEtienne Carriere {
1310347e53fSEtienne Carriere 	struct thread_smc_args args = { };
1320347e53fSEtienne Carriere 	uint8_t *ptr = buf;
1330347e53fSEtienne Carriere 	size_t rem = len;
1340347e53fSEtienne Carriere 	size_t max_burst = 0;
1350347e53fSEtienne Carriere 
1360347e53fSEtienne Carriere 	if (!smccc_trng_is_supported())
1370347e53fSEtienne Carriere 		return TEE_ERROR_NOT_SUPPORTED;
1380347e53fSEtienne Carriere 
1390347e53fSEtienne Carriere 	if (trng_rnd_fid == ARM_SMCCC_TRNG_RND_64)
1400347e53fSEtienne Carriere 		max_burst = TRNG_MAX_RND_64;
1410347e53fSEtienne Carriere 	else
1420347e53fSEtienne Carriere 		max_burst = TRNG_MAX_RND_32;
1430347e53fSEtienne Carriere 
1440347e53fSEtienne Carriere 	while (rem) {
1450347e53fSEtienne Carriere 		size_t burst = MIN(rem, max_burst);
1460347e53fSEtienne Carriere 
1470347e53fSEtienne Carriere 		args.a0 = trng_rnd_fid;
1480347e53fSEtienne Carriere 		args.a1 = burst * 8;
1490347e53fSEtienne Carriere 
1500347e53fSEtienne Carriere 		thread_smccc(&args);
1510347e53fSEtienne Carriere 
1520347e53fSEtienne Carriere 		switch (args.a0) {
1530347e53fSEtienne Carriere 		case ARM_SMCCC_RET_TRNG_SUCCESS:
1540347e53fSEtienne Carriere 			read_samples(&args, ptr, burst);
1550347e53fSEtienne Carriere 			rem -= burst;
1560347e53fSEtienne Carriere 			ptr += burst;
1570347e53fSEtienne Carriere 			break;
1580347e53fSEtienne Carriere 		case ARM_SMCCC_RET_TRNG_NO_ENTROPY:
1590347e53fSEtienne Carriere 			break;
1600347e53fSEtienne Carriere 		default:
1610347e53fSEtienne Carriere 			return TEE_ERROR_GENERIC;
1620347e53fSEtienne Carriere 		}
1630347e53fSEtienne Carriere 	}
1640347e53fSEtienne Carriere 
1650347e53fSEtienne Carriere 	return TEE_SUCCESS;
1660347e53fSEtienne Carriere }
1670347e53fSEtienne Carriere 
smccc_trng_print_info(void)1680347e53fSEtienne Carriere static void __maybe_unused smccc_trng_print_info(void)
1690347e53fSEtienne Carriere {
1700347e53fSEtienne Carriere 	struct thread_smc_args args = { };
1710347e53fSEtienne Carriere 	unsigned int __maybe_unused major = 0;
1720347e53fSEtienne Carriere 	unsigned int __maybe_unused minor = 0;
1730347e53fSEtienne Carriere 
1740347e53fSEtienne Carriere 	if (!IS_ENABLED(CFG_TEE_CORE_DEBUG))
1750347e53fSEtienne Carriere 		return;
1760347e53fSEtienne Carriere 
1770347e53fSEtienne Carriere 	args.a0 = ARM_SMCCC_TRNG_VERSION;
1780347e53fSEtienne Carriere 	thread_smccc(&args);
1790347e53fSEtienne Carriere 	assert((args.a0 & BIT32(31)) == 0);
1800347e53fSEtienne Carriere 	major = (args.a0 & TRNG_MAJOR_MASK) >> TRNG_MAJOR_SHIFT;
1810347e53fSEtienne Carriere 	minor = (args.a0 & TRNG_MINOR_MASK) >> TRNG_MINOR_SHIFT;
1820347e53fSEtienne Carriere 
1830347e53fSEtienne Carriere 	args.a0 = ARM_SMCCC_TRNG_GET_UUID;
1840347e53fSEtienne Carriere 	thread_smccc(&args);
1850347e53fSEtienne Carriere 	assert(args.a0 != ARM_SMCCC_RET_TRNG_NOT_SUPPORTED);
1860347e53fSEtienne Carriere 
187*bce2f88aSVincent Mailhol 	DMSG("SMCCC TRNG v%u.%u, UUID %08lx-%04lx-%04lx-%04lx-%04lx%08lx",
1880347e53fSEtienne Carriere 	     major, minor, (unsigned long)args.a0, (unsigned long)args.a1 >> 16,
1890347e53fSEtienne Carriere 	     (unsigned long)args.a1 & GENMASK_32(16, 0),
1900347e53fSEtienne Carriere 	     (unsigned long)args.a2 >> 16,
1910347e53fSEtienne Carriere 	     (unsigned long)args.a2 & GENMASK_32(16, 0),
1920347e53fSEtienne Carriere 	     (unsigned long)args.a3);
1930347e53fSEtienne Carriere }
1940347e53fSEtienne Carriere 
plat_rng_init(void)1950347e53fSEtienne Carriere void plat_rng_init(void)
1960347e53fSEtienne Carriere {
1970347e53fSEtienne Carriere 	if (!smccc_trng_is_supported())
1980347e53fSEtienne Carriere 		panic("SMCCC TRNG not supported");
1990347e53fSEtienne Carriere 
2000347e53fSEtienne Carriere 	smccc_trng_print_info();
2010347e53fSEtienne Carriere 
2020347e53fSEtienne Carriere 	if (IS_ENABLED(CFG_WITH_SOFTWARE_PRNG)) {
2030347e53fSEtienne Carriere 		/* If CFG_WITH_SOFTWARE_PRNG is enabled, seed PRNG with TRNG */
2040347e53fSEtienne Carriere 		uint8_t seed[32] = { 0 };
2050347e53fSEtienne Carriere 
2060347e53fSEtienne Carriere 		if (smccc_trng_read(seed, sizeof(seed)))
2070347e53fSEtienne Carriere 			panic("SMCCC TRNG not supported");
2080347e53fSEtienne Carriere 
2090347e53fSEtienne Carriere 		if (crypto_rng_init(seed, sizeof(seed)))
2100347e53fSEtienne Carriere 			panic();
2110347e53fSEtienne Carriere 	}
2120347e53fSEtienne Carriere }
2130347e53fSEtienne Carriere 
2140347e53fSEtienne Carriere /* If CFG_WITH_SOFTWARE_PRNG is disabled, TRNG is our HW RNG */
2150347e53fSEtienne Carriere #ifndef CFG_WITH_SOFTWARE_PRNG
hw_get_random_bytes(void * buf,size_t len)21623b77ea3SAndrew Davis TEE_Result hw_get_random_bytes(void *buf, size_t len)
2170347e53fSEtienne Carriere {
2180347e53fSEtienne Carriere 	return smccc_trng_read(buf, len);
2190347e53fSEtienne Carriere }
2200347e53fSEtienne Carriere #endif
221