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