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 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 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 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 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 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 1870347e53fSEtienne Carriere DMSG("SMCCC TRNG v%u.%u, UUID %08lx-%04lx-%04lx-%04lx-%04lx%08lx\n", 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 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 216*23b77ea3SAndrew 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