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