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