xref: /optee_os/core/drivers/versal_trng.c (revision cc672e1f1ce0dd40e0421704502470eff1c7fc28)
1*cc672e1fSJorge Ramirez-Ortiz // SPDX-License-Identifier: MIT
2*cc672e1fSJorge Ramirez-Ortiz /*
3*cc672e1fSJorge Ramirez-Ortiz  * Copyright (C) 2022 Xilinx, Inc.  All rights reserved.
4*cc672e1fSJorge Ramirez-Ortiz  * Copyright (C) 2022 Foundries Ltd.
5*cc672e1fSJorge Ramirez-Ortiz  *
6*cc672e1fSJorge Ramirez-Ortiz  * Driver port from Xilinx's FSBL implementation, jorge@foundries.io
7*cc672e1fSJorge Ramirez-Ortiz  *
8*cc672e1fSJorge Ramirez-Ortiz  * The Xilinx True Random Number Generator(TRNG) module in Versal - PMC TRNG
9*cc672e1fSJorge Ramirez-Ortiz  * consists of an entropy source, a deterministic random bit generator (DRBG)
10*cc672e1fSJorge Ramirez-Ortiz  * and health test logic, which tests the randomness of the generated data.
11*cc672e1fSJorge Ramirez-Ortiz  * The entropy source for the unit is an array of Ring Oscillators.
12*cc672e1fSJorge Ramirez-Ortiz  *
13*cc672e1fSJorge Ramirez-Ortiz  * The Versal PMC TRNG is envisaged to operate in three basic modes: DRNG, PTRNG
14*cc672e1fSJorge Ramirez-Ortiz  * and HRNG . Each of these can be operated with or without Derivative Function
15*cc672e1fSJorge Ramirez-Ortiz  * (DF), resulting in a total of 6 different modes of operation.
16*cc672e1fSJorge Ramirez-Ortiz  *
17*cc672e1fSJorge Ramirez-Ortiz  * NIST SP-800-90A practically requires the true random generators based on
18*cc672e1fSJorge Ramirez-Ortiz  * CTR_DRBG to include a derivation function (DF). This is expected to be
19*cc672e1fSJorge Ramirez-Ortiz  * implemented inside the Silicon (TRNG IP). However, the version of the IP used
20*cc672e1fSJorge Ramirez-Ortiz  * in Versal PMC does not have this capability. Hence, a software
21*cc672e1fSJorge Ramirez-Ortiz  * implementation of the DF is done in this driver.
22*cc672e1fSJorge Ramirez-Ortiz  *
23*cc672e1fSJorge Ramirez-Ortiz  * DRNG mode: Deterministic Random Number Generator mode.
24*cc672e1fSJorge Ramirez-Ortiz  *            In this mode, the DRBG portion of the TRNG is used. User provides
25*cc672e1fSJorge Ramirez-Ortiz  *            the (external) seed.
26*cc672e1fSJorge Ramirez-Ortiz  * PTRNG mode: Physical True Random Number Generator mode (aka Entropy mode).
27*cc672e1fSJorge Ramirez-Ortiz  *            In this mode digitized Entropy source is output as random number.
28*cc672e1fSJorge Ramirez-Ortiz  * HRNG mode: Hybrid Random Number Generator mode.
29*cc672e1fSJorge Ramirez-Ortiz  *            This is combination of above two modes in which the Entropy source
30*cc672e1fSJorge Ramirez-Ortiz  *            is used to provide the seed, which is fed to the DRBG, which in
31*cc672e1fSJorge Ramirez-Ortiz  *            turn generates the random number.
32*cc672e1fSJorge Ramirez-Ortiz  *
33*cc672e1fSJorge Ramirez-Ortiz  * DRNG mode with DF: It may not be common usecase to use the DF with DRNG as
34*cc672e1fSJorge Ramirez-Ortiz  * the general expectation would be that the seed would have sufficient entropy.
35*cc672e1fSJorge Ramirez-Ortiz  * However, the below guideline from section 10.2.1 of NIST SP-800-90A implies
36*cc672e1fSJorge Ramirez-Ortiz  * that need for DF for DRNG mode too: "..the DRBG mechanism is specified to
37*cc672e1fSJorge Ramirez-Ortiz  * allow an implementation tradeoff with respect to the use of this derivation
38*cc672e1fSJorge Ramirez-Ortiz  * function. The use of the derivation function is optional if either an
39*cc672e1fSJorge Ramirez-Ortiz  * approved RBG or an entropy source provides full entropy output when entropy
40*cc672e1fSJorge Ramirez-Ortiz  * input is requested by the DRBG mechanism. Otherwise, the derivation function
41*cc672e1fSJorge Ramirez-Ortiz  * shall be used". Sufficient large entropy data from user is fed to DF to
42*cc672e1fSJorge Ramirez-Ortiz  * generate the seed which will be loaded into the external seed registers.
43*cc672e1fSJorge Ramirez-Ortiz  * From here, it is similar to regular DRNG mode.
44*cc672e1fSJorge Ramirez-Ortiz  *
45*cc672e1fSJorge Ramirez-Ortiz  * PTRNG mode with DF: This mode is similar to PTRNG mode, however, the entropy
46*cc672e1fSJorge Ramirez-Ortiz  * data from the core output registers are accumulated and fed to the DF
47*cc672e1fSJorge Ramirez-Ortiz  * (instead of directly consuming it). The output of the DF would be final
48*cc672e1fSJorge Ramirez-Ortiz  * random data. In this mode, the output of DF is not seed but the random data.
49*cc672e1fSJorge Ramirez-Ortiz  *
50*cc672e1fSJorge Ramirez-Ortiz  * HRNG mode with DF: This mode is the combination of the above two modes.
51*cc672e1fSJorge Ramirez-Ortiz  * The entropy data is fed to the DF to produce seed. This seed is loaded to the
52*cc672e1fSJorge Ramirez-Ortiz  * external seed registers which provide seed to the DRBG.
53*cc672e1fSJorge Ramirez-Ortiz  */
54*cc672e1fSJorge Ramirez-Ortiz #include <arm.h>
55*cc672e1fSJorge Ramirez-Ortiz #include <crypto/crypto.h>
56*cc672e1fSJorge Ramirez-Ortiz #include <initcall.h>
57*cc672e1fSJorge Ramirez-Ortiz #include <io.h>
58*cc672e1fSJorge Ramirez-Ortiz #include <kernel/delay.h>
59*cc672e1fSJorge Ramirez-Ortiz #include <kernel/panic.h>
60*cc672e1fSJorge Ramirez-Ortiz #include <mm/core_mmu.h>
61*cc672e1fSJorge Ramirez-Ortiz #include <platform_config.h>
62*cc672e1fSJorge Ramirez-Ortiz #include <rng_support.h>
63*cc672e1fSJorge Ramirez-Ortiz #include <stdlib.h>
64*cc672e1fSJorge Ramirez-Ortiz #include <string.h>
65*cc672e1fSJorge Ramirez-Ortiz #include <tee/tee_cryp_utl.h>
66*cc672e1fSJorge Ramirez-Ortiz #include <trace.h>
67*cc672e1fSJorge Ramirez-Ortiz 
68*cc672e1fSJorge Ramirez-Ortiz #define TRNG_BASE            0xF1230000
69*cc672e1fSJorge Ramirez-Ortiz #define TRNG_SIZE            0x10000
70*cc672e1fSJorge Ramirez-Ortiz 
71*cc672e1fSJorge Ramirez-Ortiz #define TRNG_STATUS			0x04
72*cc672e1fSJorge Ramirez-Ortiz #define TRNG_STATUS_QCNT_SHIFT		9
73*cc672e1fSJorge Ramirez-Ortiz #define TRNG_STATUS_QCNT_MASK		(BIT(9) | BIT(10) | BIT(11))
74*cc672e1fSJorge Ramirez-Ortiz #define TRNG_STATUS_CERTF_MASK		BIT(3)
75*cc672e1fSJorge Ramirez-Ortiz #define TRNG_STATUS_DTF_MASK		BIT(1)
76*cc672e1fSJorge Ramirez-Ortiz #define TRNG_STATUS_DONE_MASK		BIT(0)
77*cc672e1fSJorge Ramirez-Ortiz #define TRNG_CTRL			0x08
78*cc672e1fSJorge Ramirez-Ortiz #define TRNG_CTRL_EUMODE_MASK		BIT(8)
79*cc672e1fSJorge Ramirez-Ortiz #define TRNG_CTRL_PRNGMODE_MASK		BIT(7)
80*cc672e1fSJorge Ramirez-Ortiz #define TRNG_CTRL_PRNGSTART_MASK	BIT(5)
81*cc672e1fSJorge Ramirez-Ortiz #define TRNG_CTRL_PRNGXS_MASK		BIT(3)
82*cc672e1fSJorge Ramirez-Ortiz #define TRNG_CTRL_TRSSEN_MASK		BIT(2)
83*cc672e1fSJorge Ramirez-Ortiz #define TRNG_CTRL_PRNGSRST_MASK		BIT(0)
84*cc672e1fSJorge Ramirez-Ortiz #define TRNG_EXT_SEED_0			0x40
85*cc672e1fSJorge Ramirez-Ortiz /*
86*cc672e1fSJorge Ramirez-Ortiz  * Below registers are not directly referenced in driver but are accessed
87*cc672e1fSJorge Ramirez-Ortiz  * with offset from TRNG_EXT_SEED_0
88*cc672e1fSJorge Ramirez-Ortiz  * Register: TRNG_EXT_SEED_1		0x00000044
89*cc672e1fSJorge Ramirez-Ortiz  * Register: TRNG_EXT_SEED_2		0x00000048
90*cc672e1fSJorge Ramirez-Ortiz  * Register: TRNG_EXT_SEED_3		0x0000004C
91*cc672e1fSJorge Ramirez-Ortiz  * Register: TRNG_EXT_SEED_4		0x00000050
92*cc672e1fSJorge Ramirez-Ortiz  * Register: TRNG_EXT_SEED_5		0x00000054
93*cc672e1fSJorge Ramirez-Ortiz  * Register: TRNG_EXT_SEED_6		0x00000058
94*cc672e1fSJorge Ramirez-Ortiz  * Register: TRNG_EXT_SEED_7		0x0000005C
95*cc672e1fSJorge Ramirez-Ortiz  * Register: TRNG_EXT_SEED_8		0x00000060
96*cc672e1fSJorge Ramirez-Ortiz  * Register: TRNG_EXT_SEED_9		0x00000064
97*cc672e1fSJorge Ramirez-Ortiz  * Register: TRNG_EXT_SEED_10		0x00000068
98*cc672e1fSJorge Ramirez-Ortiz  * Register: TRNG_EXT_SEED_11		0x0000006C
99*cc672e1fSJorge Ramirez-Ortiz  */
100*cc672e1fSJorge Ramirez-Ortiz #define TRNG_PER_STRING_0		0x80
101*cc672e1fSJorge Ramirez-Ortiz /*
102*cc672e1fSJorge Ramirez-Ortiz  * Below registers are not directly referenced in driver but are accessed
103*cc672e1fSJorge Ramirez-Ortiz  * with offset from TRNG_PER_STRING_0
104*cc672e1fSJorge Ramirez-Ortiz  * Register: TRNG_PER_STRING_1		0x00000084
105*cc672e1fSJorge Ramirez-Ortiz  * Register: TRNG_PER_STRING_2		0x00000088
106*cc672e1fSJorge Ramirez-Ortiz  * Register: TRNG_PER_STRING_3		0x0000008C
107*cc672e1fSJorge Ramirez-Ortiz  * Register: TRNG_PER_STRING_4		0x00000090
108*cc672e1fSJorge Ramirez-Ortiz  * Register: TRNG_PER_STRING_5		0x00000094
109*cc672e1fSJorge Ramirez-Ortiz  * Register: TRNG_PER_STRING_6		0x00000098
110*cc672e1fSJorge Ramirez-Ortiz  * Register: TRNG_PER_STRING_7		0x0000009C
111*cc672e1fSJorge Ramirez-Ortiz  * Register: TRNG_PER_STRING_8		0x000000A0
112*cc672e1fSJorge Ramirez-Ortiz  * Register: TRNG_PER_STRING_9		0x000000A4
113*cc672e1fSJorge Ramirez-Ortiz  * Register: TRNG_PER_STRING_10		0x000000A8
114*cc672e1fSJorge Ramirez-Ortiz  * Register: TRNG_PER_STRING_11		0x000000AC
115*cc672e1fSJorge Ramirez-Ortiz  */
116*cc672e1fSJorge Ramirez-Ortiz #define TRNG_CORE_OUTPUT		0xC0
117*cc672e1fSJorge Ramirez-Ortiz #define TRNG_RESET			0xD0
118*cc672e1fSJorge Ramirez-Ortiz #define TRNG_RESET_VAL_MASK		BIT(0)
119*cc672e1fSJorge Ramirez-Ortiz #define TRNG_OSC_EN			0xD4
120*cc672e1fSJorge Ramirez-Ortiz #define TRNG_OSC_EN_VAL_MASK		BIT(0)
121*cc672e1fSJorge Ramirez-Ortiz 
122*cc672e1fSJorge Ramirez-Ortiz /* TRNG configuration  */
123*cc672e1fSJorge Ramirez-Ortiz #define TRNG_BURST_SIZE		16
124*cc672e1fSJorge Ramirez-Ortiz #define TRNG_BURST_SIZE_BITS	128
125*cc672e1fSJorge Ramirez-Ortiz #define TRNG_NUM_INIT_REGS	12
126*cc672e1fSJorge Ramirez-Ortiz #define TRNG_REG_SIZE		32
127*cc672e1fSJorge Ramirez-Ortiz #define TRNG_BYTES_PER_REG	4
128*cc672e1fSJorge Ramirez-Ortiz #define TRNG_MAX_QCNT		4
129*cc672e1fSJorge Ramirez-Ortiz #define TRNG_RESEED_TIMEOUT	15000
130*cc672e1fSJorge Ramirez-Ortiz #define TRNG_GENERATE_TIMEOUT	8000
131*cc672e1fSJorge Ramirez-Ortiz #define TRNG_MIN_DFLENMULT	2
132*cc672e1fSJorge Ramirez-Ortiz #define TRNG_MAX_DFLENMULT	9
133*cc672e1fSJorge Ramirez-Ortiz #define PRNGMODE_RESEED		0
134*cc672e1fSJorge Ramirez-Ortiz #define PRNGMODE_GEN		TRNG_CTRL_PRNGMODE_MASK
135*cc672e1fSJorge Ramirez-Ortiz #define RESET_DELAY		10
136*cc672e1fSJorge Ramirez-Ortiz #define TRNG_SEC_STRENGTH_LEN	32
137*cc672e1fSJorge Ramirez-Ortiz #define TRNG_PERS_STR_REGS	12
138*cc672e1fSJorge Ramirez-Ortiz #define TRNG_PERS_STR_LEN	48
139*cc672e1fSJorge Ramirez-Ortiz #define TRNG_SEED_REGS		12
140*cc672e1fSJorge Ramirez-Ortiz #define TRNG_SEED_LEN		48
141*cc672e1fSJorge Ramirez-Ortiz #define TRNG_GEN_LEN		32
142*cc672e1fSJorge Ramirez-Ortiz #define RAND_BUF_LEN		4
143*cc672e1fSJorge Ramirez-Ortiz #define BYTES_PER_BLOCK		16
144*cc672e1fSJorge Ramirez-Ortiz #define ALL_A_PATTERN_32	0xAAAAAAAA
145*cc672e1fSJorge Ramirez-Ortiz #define ALL_5_PATTERN_32	0x55555555
146*cc672e1fSJorge Ramirez-Ortiz 
147*cc672e1fSJorge Ramirez-Ortiz /* Derivative function helper macros */
148*cc672e1fSJorge Ramirez-Ortiz #define DF_SEED			0
149*cc672e1fSJorge Ramirez-Ortiz #define DF_RAND			1
150*cc672e1fSJorge Ramirez-Ortiz #define DF_IP_IV_LEN		4
151*cc672e1fSJorge Ramirez-Ortiz #define DF_PAD_DATA_LEN		8
152*cc672e1fSJorge Ramirez-Ortiz #define MAX_PRE_DF_LEN		160
153*cc672e1fSJorge Ramirez-Ortiz #define MAX_PRE_DF_LEN_WORDS	40
154*cc672e1fSJorge Ramirez-Ortiz #define DF_PERS_STR_LEN		TRNG_PERS_STR_LEN
155*cc672e1fSJorge Ramirez-Ortiz #define DF_PAD_VAL		0x80
156*cc672e1fSJorge Ramirez-Ortiz #define DF_KEY_LEN		32
157*cc672e1fSJorge Ramirez-Ortiz #define BLK_SIZE		16
158*cc672e1fSJorge Ramirez-Ortiz #define MAX_ROUNDS		14
159*cc672e1fSJorge Ramirez-Ortiz 
160*cc672e1fSJorge Ramirez-Ortiz enum trng_status {
161*cc672e1fSJorge Ramirez-Ortiz 	TRNG_UNINITIALIZED = 0,
162*cc672e1fSJorge Ramirez-Ortiz 	TRNG_HEALTHY,
163*cc672e1fSJorge Ramirez-Ortiz 	TRNG_ERROR,
164*cc672e1fSJorge Ramirez-Ortiz 	TRNG_CATASTROPHIC
165*cc672e1fSJorge Ramirez-Ortiz };
166*cc672e1fSJorge Ramirez-Ortiz 
167*cc672e1fSJorge Ramirez-Ortiz enum trng_mode {
168*cc672e1fSJorge Ramirez-Ortiz 	TRNG_HRNG = 0,
169*cc672e1fSJorge Ramirez-Ortiz 	TRNG_DRNG,
170*cc672e1fSJorge Ramirez-Ortiz 	TRNG_PTRNG
171*cc672e1fSJorge Ramirez-Ortiz };
172*cc672e1fSJorge Ramirez-Ortiz 
173*cc672e1fSJorge Ramirez-Ortiz struct trng_cfg {
174*cc672e1fSJorge Ramirez-Ortiz 	paddr_t base;
175*cc672e1fSJorge Ramirez-Ortiz 	vaddr_t addr;
176*cc672e1fSJorge Ramirez-Ortiz 	size_t len;
177*cc672e1fSJorge Ramirez-Ortiz };
178*cc672e1fSJorge Ramirez-Ortiz 
179*cc672e1fSJorge Ramirez-Ortiz struct trng_usr_cfg {
180*cc672e1fSJorge Ramirez-Ortiz 	enum trng_mode mode;
181*cc672e1fSJorge Ramirez-Ortiz 	uint64_t seed_life;      /* number of TRNG requests per seed */
182*cc672e1fSJorge Ramirez-Ortiz 	bool predict_en;         /* enable prediction resistance     */
183*cc672e1fSJorge Ramirez-Ortiz 	bool pstr_en;            /* enable personalization string    */
184*cc672e1fSJorge Ramirez-Ortiz 	uint32_t pstr[TRNG_PERS_STR_REGS];
185*cc672e1fSJorge Ramirez-Ortiz 	bool iseed_en;           /* enable an initial seed           */
186*cc672e1fSJorge Ramirez-Ortiz 	uint32_t init_seed[MAX_PRE_DF_LEN_WORDS];
187*cc672e1fSJorge Ramirez-Ortiz 	uint32_t df_disable;     /* disable the derivative function  */
188*cc672e1fSJorge Ramirez-Ortiz 	uint32_t dfmul;          /* derivative function multiplier   */
189*cc672e1fSJorge Ramirez-Ortiz };
190*cc672e1fSJorge Ramirez-Ortiz 
191*cc672e1fSJorge Ramirez-Ortiz struct trng_stats {
192*cc672e1fSJorge Ramirez-Ortiz 	uint64_t bytes;
193*cc672e1fSJorge Ramirez-Ortiz 	uint64_t bytes_reseed;
194*cc672e1fSJorge Ramirez-Ortiz 	uint64_t elapsed_seed_life;
195*cc672e1fSJorge Ramirez-Ortiz };
196*cc672e1fSJorge Ramirez-Ortiz 
197*cc672e1fSJorge Ramirez-Ortiz /* block cipher derivative function algorithm */
198*cc672e1fSJorge Ramirez-Ortiz struct trng_dfin {
199*cc672e1fSJorge Ramirez-Ortiz 	uint32_t ivc[DF_IP_IV_LEN];
200*cc672e1fSJorge Ramirez-Ortiz 	uint32_t val1;
201*cc672e1fSJorge Ramirez-Ortiz 	uint32_t val2;
202*cc672e1fSJorge Ramirez-Ortiz 	uint8_t entropy[MAX_PRE_DF_LEN];    /* input entropy                */
203*cc672e1fSJorge Ramirez-Ortiz 	uint8_t pstr[DF_PERS_STR_LEN];      /* personalization string       */
204*cc672e1fSJorge Ramirez-Ortiz 	uint8_t pad_data[DF_PAD_DATA_LEN];  /* pad to multiples of 16 bytes*/
205*cc672e1fSJorge Ramirez-Ortiz };
206*cc672e1fSJorge Ramirez-Ortiz 
207*cc672e1fSJorge Ramirez-Ortiz struct versal_trng {
208*cc672e1fSJorge Ramirez-Ortiz 	struct trng_cfg cfg;
209*cc672e1fSJorge Ramirez-Ortiz 	struct trng_usr_cfg usr_cfg;
210*cc672e1fSJorge Ramirez-Ortiz 	struct trng_stats stats;
211*cc672e1fSJorge Ramirez-Ortiz 	enum trng_status status;
212*cc672e1fSJorge Ramirez-Ortiz 	uint32_t buf[RAND_BUF_LEN];   /* buffer of random bits      */
213*cc672e1fSJorge Ramirez-Ortiz 	size_t len;
214*cc672e1fSJorge Ramirez-Ortiz 	struct trng_dfin dfin;
215*cc672e1fSJorge Ramirez-Ortiz 	uint8_t dfout[TRNG_SEED_LEN]; /* output of the DF operation */
216*cc672e1fSJorge Ramirez-Ortiz };
217*cc672e1fSJorge Ramirez-Ortiz 
218*cc672e1fSJorge Ramirez-Ortiz /* Derivative function variables */
219*cc672e1fSJorge Ramirez-Ortiz static unsigned char sbx1[256];
220*cc672e1fSJorge Ramirez-Ortiz static unsigned char sbx2[256];
221*cc672e1fSJorge Ramirez-Ortiz static unsigned char sbx3[256];
222*cc672e1fSJorge Ramirez-Ortiz static unsigned char schedule[BLK_SIZE * (MAX_ROUNDS + 1)];
223*cc672e1fSJorge Ramirez-Ortiz static unsigned int rounds;
224*cc672e1fSJorge Ramirez-Ortiz 
rota4(uint8_t * a,uint8_t * b,uint8_t * c,uint8_t * d)225*cc672e1fSJorge Ramirez-Ortiz static void rota4(uint8_t *a, uint8_t *b, uint8_t *c, uint8_t *d)
226*cc672e1fSJorge Ramirez-Ortiz {
227*cc672e1fSJorge Ramirez-Ortiz 	uint8_t t = *a;
228*cc672e1fSJorge Ramirez-Ortiz 
229*cc672e1fSJorge Ramirez-Ortiz 	*a = sbx1[*b];
230*cc672e1fSJorge Ramirez-Ortiz 	*b = sbx1[*c];
231*cc672e1fSJorge Ramirez-Ortiz 	*c = sbx1[*d];
232*cc672e1fSJorge Ramirez-Ortiz 	*d = sbx1[t];
233*cc672e1fSJorge Ramirez-Ortiz }
234*cc672e1fSJorge Ramirez-Ortiz 
rota2(uint8_t * a,uint8_t * b)235*cc672e1fSJorge Ramirez-Ortiz static void rota2(uint8_t *a, uint8_t *b)
236*cc672e1fSJorge Ramirez-Ortiz {
237*cc672e1fSJorge Ramirez-Ortiz 	uint8_t t = *a;
238*cc672e1fSJorge Ramirez-Ortiz 
239*cc672e1fSJorge Ramirez-Ortiz 	*a = sbx1[*b];
240*cc672e1fSJorge Ramirez-Ortiz 	*b = sbx1[t];
241*cc672e1fSJorge Ramirez-Ortiz }
242*cc672e1fSJorge Ramirez-Ortiz 
sbox4(uint8_t * a,uint8_t * b,uint8_t * c,uint8_t * d)243*cc672e1fSJorge Ramirez-Ortiz static void sbox4(uint8_t *a, uint8_t *b, uint8_t *c, uint8_t *d)
244*cc672e1fSJorge Ramirez-Ortiz {
245*cc672e1fSJorge Ramirez-Ortiz 	*a = sbx1[*a];
246*cc672e1fSJorge Ramirez-Ortiz 	*b = sbx1[*b];
247*cc672e1fSJorge Ramirez-Ortiz 	*c = sbx1[*c];
248*cc672e1fSJorge Ramirez-Ortiz 	*d = sbx1[*d];
249*cc672e1fSJorge Ramirez-Ortiz }
250*cc672e1fSJorge Ramirez-Ortiz 
xorb(uint8_t * res,const uint8_t * in)251*cc672e1fSJorge Ramirez-Ortiz static void xorb(uint8_t *res,  const uint8_t *in)
252*cc672e1fSJorge Ramirez-Ortiz {
253*cc672e1fSJorge Ramirez-Ortiz 	size_t i = 0;
254*cc672e1fSJorge Ramirez-Ortiz 
255*cc672e1fSJorge Ramirez-Ortiz 	for (i = 0; i < BLK_SIZE; ++i)
256*cc672e1fSJorge Ramirez-Ortiz 		res[i] ^= in[i];
257*cc672e1fSJorge Ramirez-Ortiz }
258*cc672e1fSJorge Ramirez-Ortiz 
set_key(uint8_t * res,const uint8_t * src,unsigned int roundval)259*cc672e1fSJorge Ramirez-Ortiz static void set_key(uint8_t *res, const uint8_t *src, unsigned int roundval)
260*cc672e1fSJorge Ramirez-Ortiz {
261*cc672e1fSJorge Ramirez-Ortiz 	memcpy(res, src, BLK_SIZE);
262*cc672e1fSJorge Ramirez-Ortiz 	xorb(res, schedule + roundval * BLK_SIZE);
263*cc672e1fSJorge Ramirez-Ortiz }
264*cc672e1fSJorge Ramirez-Ortiz 
mix_column_sbox(uint8_t * dst,const uint8_t * f)265*cc672e1fSJorge Ramirez-Ortiz static void mix_column_sbox(uint8_t *dst, const uint8_t *f)
266*cc672e1fSJorge Ramirez-Ortiz {
267*cc672e1fSJorge Ramirez-Ortiz 	size_t i = 0;
268*cc672e1fSJorge Ramirez-Ortiz 	size_t a = 0;
269*cc672e1fSJorge Ramirez-Ortiz 	size_t b = 0;
270*cc672e1fSJorge Ramirez-Ortiz 	size_t c = 0;
271*cc672e1fSJorge Ramirez-Ortiz 	size_t d = 0;
272*cc672e1fSJorge Ramirez-Ortiz 
273*cc672e1fSJorge Ramirez-Ortiz 	for (i = 0; i < 4; i++) {
274*cc672e1fSJorge Ramirez-Ortiz 		a = 4 * i;
275*cc672e1fSJorge Ramirez-Ortiz 		b = (0x5 + a) % 16;
276*cc672e1fSJorge Ramirez-Ortiz 		c = (0xa + a) % 16;
277*cc672e1fSJorge Ramirez-Ortiz 		d = (0xf + a) % 16;
278*cc672e1fSJorge Ramirez-Ortiz 		dst[0 + a] = sbx2[f[a]] ^ sbx3[f[b]] ^ sbx1[f[c]] ^ sbx1[f[d]];
279*cc672e1fSJorge Ramirez-Ortiz 		dst[1 + a] = sbx1[f[a]] ^ sbx2[f[b]] ^ sbx3[f[c]] ^ sbx1[f[d]];
280*cc672e1fSJorge Ramirez-Ortiz 		dst[2 + a] = sbx1[f[a]] ^ sbx1[f[b]] ^ sbx2[f[c]] ^ sbx3[f[d]];
281*cc672e1fSJorge Ramirez-Ortiz 		dst[3 + a] = sbx3[f[a]] ^ sbx1[f[b]] ^ sbx1[f[c]] ^ sbx2[f[d]];
282*cc672e1fSJorge Ramirez-Ortiz 	}
283*cc672e1fSJorge Ramirez-Ortiz }
284*cc672e1fSJorge Ramirez-Ortiz 
shift_row_sbox(uint8_t * f)285*cc672e1fSJorge Ramirez-Ortiz static void shift_row_sbox(uint8_t *f)
286*cc672e1fSJorge Ramirez-Ortiz {
287*cc672e1fSJorge Ramirez-Ortiz 	sbox4(&f[0], &f[4], &f[8], &f[12]);
288*cc672e1fSJorge Ramirez-Ortiz 	rota4(&f[1], &f[5], &f[9], &f[13]);
289*cc672e1fSJorge Ramirez-Ortiz 	rota2(&f[2], &f[10]);
290*cc672e1fSJorge Ramirez-Ortiz 	rota2(&f[6], &f[14]);
291*cc672e1fSJorge Ramirez-Ortiz 	rota4(&f[15], &f[11], &f[7], &f[3]);
292*cc672e1fSJorge Ramirez-Ortiz }
293*cc672e1fSJorge Ramirez-Ortiz 
encrypt(uint8_t * in,uint8_t * out)294*cc672e1fSJorge Ramirez-Ortiz static void encrypt(uint8_t *in, uint8_t *out)
295*cc672e1fSJorge Ramirez-Ortiz {
296*cc672e1fSJorge Ramirez-Ortiz 	uint8_t fa[BLK_SIZE] = { 0 };
297*cc672e1fSJorge Ramirez-Ortiz 	uint8_t fb[BLK_SIZE] = { 0 };
298*cc672e1fSJorge Ramirez-Ortiz 	size_t roundval = 0;
299*cc672e1fSJorge Ramirez-Ortiz 
300*cc672e1fSJorge Ramirez-Ortiz 	set_key(fa, in, 0);
301*cc672e1fSJorge Ramirez-Ortiz 	for (roundval = 1; roundval < rounds; ++roundval) {
302*cc672e1fSJorge Ramirez-Ortiz 		mix_column_sbox(fb, fa);
303*cc672e1fSJorge Ramirez-Ortiz 		set_key(fa, fb, roundval);
304*cc672e1fSJorge Ramirez-Ortiz 	}
305*cc672e1fSJorge Ramirez-Ortiz 
306*cc672e1fSJorge Ramirez-Ortiz 	shift_row_sbox(fa);
307*cc672e1fSJorge Ramirez-Ortiz 	set_key(out, fa, roundval);
308*cc672e1fSJorge Ramirez-Ortiz }
309*cc672e1fSJorge Ramirez-Ortiz 
checksum(unsigned char * in,uint8_t * iv,int max_blk)310*cc672e1fSJorge Ramirez-Ortiz static void checksum(unsigned char *in, uint8_t *iv, int max_blk)
311*cc672e1fSJorge Ramirez-Ortiz {
312*cc672e1fSJorge Ramirez-Ortiz 	while (max_blk > 0) {
313*cc672e1fSJorge Ramirez-Ortiz 		xorb(iv, in);
314*cc672e1fSJorge Ramirez-Ortiz 		encrypt(iv, iv);
315*cc672e1fSJorge Ramirez-Ortiz 		in += BLK_SIZE;
316*cc672e1fSJorge Ramirez-Ortiz 		max_blk -= 1;
317*cc672e1fSJorge Ramirez-Ortiz 	}
318*cc672e1fSJorge Ramirez-Ortiz }
319*cc672e1fSJorge Ramirez-Ortiz 
setup_key(const unsigned char * k,size_t klen)320*cc672e1fSJorge Ramirez-Ortiz static void setup_key(const unsigned char *k, size_t klen)
321*cc672e1fSJorge Ramirez-Ortiz {
322*cc672e1fSJorge Ramirez-Ortiz 	unsigned char rcon = 1;
323*cc672e1fSJorge Ramirez-Ortiz 	size_t sch_size = 240;
324*cc672e1fSJorge Ramirez-Ortiz 	size_t i = 0;
325*cc672e1fSJorge Ramirez-Ortiz 
326*cc672e1fSJorge Ramirez-Ortiz 	rounds = MAX_ROUNDS;
327*cc672e1fSJorge Ramirez-Ortiz 	memcpy(schedule, k, klen);
328*cc672e1fSJorge Ramirez-Ortiz 	for (i = klen; i < sch_size; i += 4) {
329*cc672e1fSJorge Ramirez-Ortiz 		unsigned char t0 = 0;
330*cc672e1fSJorge Ramirez-Ortiz 		unsigned char t1 = 0;
331*cc672e1fSJorge Ramirez-Ortiz 		unsigned char t2 = 0;
332*cc672e1fSJorge Ramirez-Ortiz 		unsigned char t3 = 0;
333*cc672e1fSJorge Ramirez-Ortiz 		int ik = 0;
334*cc672e1fSJorge Ramirez-Ortiz 
335*cc672e1fSJorge Ramirez-Ortiz 		t0 = schedule[i - 4];
336*cc672e1fSJorge Ramirez-Ortiz 		t1 = schedule[i - 3];
337*cc672e1fSJorge Ramirez-Ortiz 		t2 = schedule[i - 2];
338*cc672e1fSJorge Ramirez-Ortiz 		t3 = schedule[i - 1];
339*cc672e1fSJorge Ramirez-Ortiz 		if (i % klen == 0) {
340*cc672e1fSJorge Ramirez-Ortiz 			rota4(&t0, &t1, &t2, &t3);
341*cc672e1fSJorge Ramirez-Ortiz 			t0 ^= rcon;
342*cc672e1fSJorge Ramirez-Ortiz 			rcon = (rcon << 1) ^ (((rcon >> 7) & 1) * 0x1B);
343*cc672e1fSJorge Ramirez-Ortiz 		} else if (i % klen == 16) {
344*cc672e1fSJorge Ramirez-Ortiz 			sbox4(&t0, &t1, &t2, &t3);
345*cc672e1fSJorge Ramirez-Ortiz 		}
346*cc672e1fSJorge Ramirez-Ortiz 		ik = i - klen;
347*cc672e1fSJorge Ramirez-Ortiz 		schedule[i + 0] = schedule[ik + 0] ^ t0;
348*cc672e1fSJorge Ramirez-Ortiz 		schedule[i + 1] = schedule[ik + 1] ^ t1;
349*cc672e1fSJorge Ramirez-Ortiz 		schedule[i + 2] = schedule[ik + 2] ^ t2;
350*cc672e1fSJorge Ramirez-Ortiz 		schedule[i + 3] = schedule[ik + 3] ^ t3;
351*cc672e1fSJorge Ramirez-Ortiz 	}
352*cc672e1fSJorge Ramirez-Ortiz }
353*cc672e1fSJorge Ramirez-Ortiz 
trng_df_init(void)354*cc672e1fSJorge Ramirez-Ortiz static void trng_df_init(void)
355*cc672e1fSJorge Ramirez-Ortiz {
356*cc672e1fSJorge Ramirez-Ortiz 	const uint8_t sb[] = {
357*cc672e1fSJorge Ramirez-Ortiz 		0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01,
358*cc672e1fSJorge Ramirez-Ortiz 		0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d,
359*cc672e1fSJorge Ramirez-Ortiz 		0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4,
360*cc672e1fSJorge Ramirez-Ortiz 		0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc,
361*cc672e1fSJorge Ramirez-Ortiz 		0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7,
362*cc672e1fSJorge Ramirez-Ortiz 		0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2,
363*cc672e1fSJorge Ramirez-Ortiz 		0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e,
364*cc672e1fSJorge Ramirez-Ortiz 		0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
365*cc672e1fSJorge Ramirez-Ortiz 		0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb,
366*cc672e1fSJorge Ramirez-Ortiz 		0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb,
367*cc672e1fSJorge Ramirez-Ortiz 		0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c,
368*cc672e1fSJorge Ramirez-Ortiz 		0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
369*cc672e1fSJorge Ramirez-Ortiz 		0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c,
370*cc672e1fSJorge Ramirez-Ortiz 		0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d,
371*cc672e1fSJorge Ramirez-Ortiz 		0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a,
372*cc672e1fSJorge Ramirez-Ortiz 		0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
373*cc672e1fSJorge Ramirez-Ortiz 		0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3,
374*cc672e1fSJorge Ramirez-Ortiz 		0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d,
375*cc672e1fSJorge Ramirez-Ortiz 		0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a,
376*cc672e1fSJorge Ramirez-Ortiz 		0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6,
377*cc672e1fSJorge Ramirez-Ortiz 		0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e,
378*cc672e1fSJorge Ramirez-Ortiz 		0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9,
379*cc672e1fSJorge Ramirez-Ortiz 		0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9,
380*cc672e1fSJorge Ramirez-Ortiz 		0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
381*cc672e1fSJorge Ramirez-Ortiz 		0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99,
382*cc672e1fSJorge Ramirez-Ortiz 		0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16,
383*cc672e1fSJorge Ramirez-Ortiz 	};
384*cc672e1fSJorge Ramirez-Ortiz 	size_t i = 0;
385*cc672e1fSJorge Ramirez-Ortiz 
386*cc672e1fSJorge Ramirez-Ortiz 	memcpy(sbx1, sb, sizeof(sb));
387*cc672e1fSJorge Ramirez-Ortiz 	for (i = 0; i < sizeof(sb); i++) {
388*cc672e1fSJorge Ramirez-Ortiz 		sbx2[i] = (sb[i] << 1) ^ (((sb[i] >> 7) & 1) * 0x1B);
389*cc672e1fSJorge Ramirez-Ortiz 		sbx3[i] = sbx2[i] ^ sb[i];
390*cc672e1fSJorge Ramirez-Ortiz 	}
391*cc672e1fSJorge Ramirez-Ortiz }
392*cc672e1fSJorge Ramirez-Ortiz 
393*cc672e1fSJorge Ramirez-Ortiz /*
394*cc672e1fSJorge Ramirez-Ortiz  * This function implements the Derivative Function by distilling the entropy
395*cc672e1fSJorge Ramirez-Ortiz  * available in its input into a smaller number of bits on the output.
396*cc672e1fSJorge Ramirez-Ortiz  * - per NIST SP80090A.
397*cc672e1fSJorge Ramirez-Ortiz  *
398*cc672e1fSJorge Ramirez-Ortiz  * The Block Cipher algorithm follows sections 10.3.2 and 10.3.3 of the
399*cc672e1fSJorge Ramirez-Ortiz  * NIST.SP.800-90Ar1 document
400*cc672e1fSJorge Ramirez-Ortiz  */
trng_df_algorithm(struct versal_trng * trng,uint8_t * dfout,uint32_t flag,const uint8_t * pstr)401*cc672e1fSJorge Ramirez-Ortiz static void trng_df_algorithm(struct versal_trng *trng, uint8_t *dfout,
402*cc672e1fSJorge Ramirez-Ortiz 			      uint32_t flag, const uint8_t *pstr)
403*cc672e1fSJorge Ramirez-Ortiz {
404*cc672e1fSJorge Ramirez-Ortiz 	static bool df_init;
405*cc672e1fSJorge Ramirez-Ortiz 	const uint8_t df_key[DF_KEY_LEN] = {
406*cc672e1fSJorge Ramirez-Ortiz 		0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
407*cc672e1fSJorge Ramirez-Ortiz 		17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
408*cc672e1fSJorge Ramirez-Ortiz 	};
409*cc672e1fSJorge Ramirez-Ortiz 	size_t dfin_len = sizeof(struct trng_dfin) + trng->len;
410*cc672e1fSJorge Ramirez-Ortiz 	uint8_t *inp_blk = NULL;
411*cc672e1fSJorge Ramirez-Ortiz 	uint8_t *out_blk = NULL;
412*cc672e1fSJorge Ramirez-Ortiz 	uintptr_t reminder = 0;
413*cc672e1fSJorge Ramirez-Ortiz 	size_t xfer_len = 0;
414*cc672e1fSJorge Ramirez-Ortiz 	uint32_t index = 0;
415*cc672e1fSJorge Ramirez-Ortiz 	uintptr_t src = 0;
416*cc672e1fSJorge Ramirez-Ortiz 	uintptr_t dst = 0;
417*cc672e1fSJorge Ramirez-Ortiz 	size_t offset = 0;
418*cc672e1fSJorge Ramirez-Ortiz 
419*cc672e1fSJorge Ramirez-Ortiz 	if (!df_init) {
420*cc672e1fSJorge Ramirez-Ortiz 		trng_df_init();
421*cc672e1fSJorge Ramirez-Ortiz 		df_init = true;
422*cc672e1fSJorge Ramirez-Ortiz 	}
423*cc672e1fSJorge Ramirez-Ortiz 
424*cc672e1fSJorge Ramirez-Ortiz 	if (flag == DF_SEED)
425*cc672e1fSJorge Ramirez-Ortiz 		trng->dfin.val2 = TEE_U32_TO_BIG_ENDIAN(TRNG_PERS_STR_LEN);
426*cc672e1fSJorge Ramirez-Ortiz 	else
427*cc672e1fSJorge Ramirez-Ortiz 		trng->dfin.val2 = TEE_U32_TO_BIG_ENDIAN(TRNG_GEN_LEN);
428*cc672e1fSJorge Ramirez-Ortiz 
429*cc672e1fSJorge Ramirez-Ortiz 	trng->dfin.pad_data[0] = DF_PAD_VAL;
430*cc672e1fSJorge Ramirez-Ortiz 
431*cc672e1fSJorge Ramirez-Ortiz 	if (!pstr) {
432*cc672e1fSJorge Ramirez-Ortiz 		if (trng->len > (MAX_PRE_DF_LEN + TRNG_PERS_STR_LEN))
433*cc672e1fSJorge Ramirez-Ortiz 			panic();
434*cc672e1fSJorge Ramirez-Ortiz 
435*cc672e1fSJorge Ramirez-Ortiz 		dfin_len = dfin_len - TRNG_PERS_STR_LEN - MAX_PRE_DF_LEN;
436*cc672e1fSJorge Ramirez-Ortiz 		trng->dfin.val1 = TEE_U32_TO_BIG_ENDIAN(trng->len);
437*cc672e1fSJorge Ramirez-Ortiz 
438*cc672e1fSJorge Ramirez-Ortiz 		xfer_len = DF_PAD_DATA_LEN;
439*cc672e1fSJorge Ramirez-Ortiz 		src = (uintptr_t)trng->dfin.pad_data;
440*cc672e1fSJorge Ramirez-Ortiz 		offset = MAX_PRE_DF_LEN + TRNG_PERS_STR_LEN - trng->len;
441*cc672e1fSJorge Ramirez-Ortiz 	} else {
442*cc672e1fSJorge Ramirez-Ortiz 		if (trng->len > MAX_PRE_DF_LEN)
443*cc672e1fSJorge Ramirez-Ortiz 			panic();
444*cc672e1fSJorge Ramirez-Ortiz 
445*cc672e1fSJorge Ramirez-Ortiz 		memcpy(trng->dfin.pstr, pstr, TRNG_PERS_STR_LEN);
446*cc672e1fSJorge Ramirez-Ortiz 		dfin_len = dfin_len - MAX_PRE_DF_LEN;
447*cc672e1fSJorge Ramirez-Ortiz 		trng->dfin.val1 = TEE_U32_TO_BIG_ENDIAN(trng->len +
448*cc672e1fSJorge Ramirez-Ortiz 							TRNG_PERS_STR_LEN);
449*cc672e1fSJorge Ramirez-Ortiz 		xfer_len = DF_PAD_DATA_LEN + TRNG_PERS_STR_LEN;
450*cc672e1fSJorge Ramirez-Ortiz 		src = (uintptr_t)trng->dfin.pstr;
451*cc672e1fSJorge Ramirez-Ortiz 		offset = MAX_PRE_DF_LEN - trng->len;
452*cc672e1fSJorge Ramirez-Ortiz 	}
453*cc672e1fSJorge Ramirez-Ortiz 
454*cc672e1fSJorge Ramirez-Ortiz 	/* Move back into the dfin structure */
455*cc672e1fSJorge Ramirez-Ortiz 	dst = src - offset;
456*cc672e1fSJorge Ramirez-Ortiz 	reminder = (uintptr_t)&trng->dfin + sizeof(trng->dfin) - offset;
457*cc672e1fSJorge Ramirez-Ortiz 	if (offset) {
458*cc672e1fSJorge Ramirez-Ortiz 		if (xfer_len > offset)
459*cc672e1fSJorge Ramirez-Ortiz 			panic("Overlapping data");
460*cc672e1fSJorge Ramirez-Ortiz 
461*cc672e1fSJorge Ramirez-Ortiz 		memcpy((void *)dst, (void *)src, xfer_len);
462*cc672e1fSJorge Ramirez-Ortiz 		memset((void *)reminder, 0, offset);
463*cc672e1fSJorge Ramirez-Ortiz 	}
464*cc672e1fSJorge Ramirez-Ortiz 
465*cc672e1fSJorge Ramirez-Ortiz 	/* DF algorithm - step 1 */
466*cc672e1fSJorge Ramirez-Ortiz 	setup_key(df_key, DF_KEY_LEN);
467*cc672e1fSJorge Ramirez-Ortiz 	for (index = 0; index < TRNG_SEED_LEN; index += BLK_SIZE) {
468*cc672e1fSJorge Ramirez-Ortiz 		memset((void *)(trng->dfout + index), 0, BLK_SIZE);
469*cc672e1fSJorge Ramirez-Ortiz 		trng->dfin.ivc[0] = TEE_U32_TO_BIG_ENDIAN(index / BLK_SIZE);
470*cc672e1fSJorge Ramirez-Ortiz 		checksum((unsigned char *)&trng->dfin,
471*cc672e1fSJorge Ramirez-Ortiz 			 trng->dfout + index, dfin_len / BLK_SIZE);
472*cc672e1fSJorge Ramirez-Ortiz 	}
473*cc672e1fSJorge Ramirez-Ortiz 
474*cc672e1fSJorge Ramirez-Ortiz 	/* DF algorithm - step 2 */
475*cc672e1fSJorge Ramirez-Ortiz 	setup_key(trng->dfout, DF_KEY_LEN);
476*cc672e1fSJorge Ramirez-Ortiz 	for (index = 0; index < TRNG_SEED_LEN; index += BLK_SIZE) {
477*cc672e1fSJorge Ramirez-Ortiz 		if (!index)
478*cc672e1fSJorge Ramirez-Ortiz 			inp_blk = &dfout[TRNG_SEC_STRENGTH_LEN];
479*cc672e1fSJorge Ramirez-Ortiz 		else
480*cc672e1fSJorge Ramirez-Ortiz 			inp_blk = &dfout[index - BLK_SIZE];
481*cc672e1fSJorge Ramirez-Ortiz 
482*cc672e1fSJorge Ramirez-Ortiz 		out_blk = &dfout[index];
483*cc672e1fSJorge Ramirez-Ortiz 		encrypt(inp_blk, out_blk);
484*cc672e1fSJorge Ramirez-Ortiz 	}
485*cc672e1fSJorge Ramirez-Ortiz }
486*cc672e1fSJorge Ramirez-Ortiz 
trng_read32(vaddr_t addr,size_t off)487*cc672e1fSJorge Ramirez-Ortiz static uint32_t trng_read32(vaddr_t addr, size_t off)
488*cc672e1fSJorge Ramirez-Ortiz {
489*cc672e1fSJorge Ramirez-Ortiz 	return io_read32(addr + off);
490*cc672e1fSJorge Ramirez-Ortiz }
491*cc672e1fSJorge Ramirez-Ortiz 
trng_write32(vaddr_t addr,size_t off,uint32_t val)492*cc672e1fSJorge Ramirez-Ortiz static void trng_write32(vaddr_t addr, size_t off, uint32_t val)
493*cc672e1fSJorge Ramirez-Ortiz {
494*cc672e1fSJorge Ramirez-Ortiz 	io_write32(addr + off, val);
495*cc672e1fSJorge Ramirez-Ortiz }
496*cc672e1fSJorge Ramirez-Ortiz 
trng_clrset32(vaddr_t addr,size_t off,uint32_t mask,uint32_t val)497*cc672e1fSJorge Ramirez-Ortiz static void trng_clrset32(vaddr_t addr, size_t off, uint32_t mask, uint32_t val)
498*cc672e1fSJorge Ramirez-Ortiz {
499*cc672e1fSJorge Ramirez-Ortiz 	io_clrsetbits32(addr + off, mask, mask & val);
500*cc672e1fSJorge Ramirez-Ortiz }
501*cc672e1fSJorge Ramirez-Ortiz 
trng_write32_range(const struct versal_trng * trng,uint32_t start,uint32_t num_regs,const uint8_t * buf)502*cc672e1fSJorge Ramirez-Ortiz static void trng_write32_range(const struct versal_trng *trng, uint32_t start,
503*cc672e1fSJorge Ramirez-Ortiz 			       uint32_t num_regs, const uint8_t *buf)
504*cc672e1fSJorge Ramirez-Ortiz {
505*cc672e1fSJorge Ramirez-Ortiz 	size_t off = 0;
506*cc672e1fSJorge Ramirez-Ortiz 	uint32_t val = 0;
507*cc672e1fSJorge Ramirez-Ortiz 	size_t cnt = 0;
508*cc672e1fSJorge Ramirez-Ortiz 	size_t i = 0;
509*cc672e1fSJorge Ramirez-Ortiz 
510*cc672e1fSJorge Ramirez-Ortiz 	for (i = 0; i < num_regs; ++i) {
511*cc672e1fSJorge Ramirez-Ortiz 		if (!buf) {
512*cc672e1fSJorge Ramirez-Ortiz 			off = start + i * TRNG_BYTES_PER_REG;
513*cc672e1fSJorge Ramirez-Ortiz 			trng_write32(trng->cfg.addr, off, 0);
514*cc672e1fSJorge Ramirez-Ortiz 			continue;
515*cc672e1fSJorge Ramirez-Ortiz 		}
516*cc672e1fSJorge Ramirez-Ortiz 
517*cc672e1fSJorge Ramirez-Ortiz 		val = 0;
518*cc672e1fSJorge Ramirez-Ortiz 		for (cnt = 0; cnt < TRNG_BYTES_PER_REG; ++cnt)
519*cc672e1fSJorge Ramirez-Ortiz 			val = (val << 8) | buf[i * TRNG_BYTES_PER_REG + cnt];
520*cc672e1fSJorge Ramirez-Ortiz 
521*cc672e1fSJorge Ramirez-Ortiz 		off = start + (TRNG_NUM_INIT_REGS - 1 - i) * TRNG_BYTES_PER_REG;
522*cc672e1fSJorge Ramirez-Ortiz 		trng_write32(trng->cfg.addr, off, val);
523*cc672e1fSJorge Ramirez-Ortiz 	}
524*cc672e1fSJorge Ramirez-Ortiz }
525*cc672e1fSJorge Ramirez-Ortiz 
trng_wait_for_event(vaddr_t addr,size_t off,uint32_t mask,uint32_t event,uint32_t time_out)526*cc672e1fSJorge Ramirez-Ortiz static TEE_Result trng_wait_for_event(vaddr_t addr, size_t off, uint32_t mask,
527*cc672e1fSJorge Ramirez-Ortiz 				      uint32_t event, uint32_t time_out)
528*cc672e1fSJorge Ramirez-Ortiz {
529*cc672e1fSJorge Ramirez-Ortiz 	uint64_t tref = timeout_init_us(time_out);
530*cc672e1fSJorge Ramirez-Ortiz 
531*cc672e1fSJorge Ramirez-Ortiz 	do {
532*cc672e1fSJorge Ramirez-Ortiz 		if (timeout_elapsed(tref))
533*cc672e1fSJorge Ramirez-Ortiz 			break;
534*cc672e1fSJorge Ramirez-Ortiz 	} while ((io_read32(addr + off) & mask) != event);
535*cc672e1fSJorge Ramirez-Ortiz 
536*cc672e1fSJorge Ramirez-Ortiz 	/* Normal world might have suspended the OP-TEE thread, check again  */
537*cc672e1fSJorge Ramirez-Ortiz 	if ((io_read32(addr + off) & mask) != event)
538*cc672e1fSJorge Ramirez-Ortiz 		return TEE_ERROR_GENERIC;
539*cc672e1fSJorge Ramirez-Ortiz 
540*cc672e1fSJorge Ramirez-Ortiz 	return TEE_SUCCESS;
541*cc672e1fSJorge Ramirez-Ortiz }
542*cc672e1fSJorge Ramirez-Ortiz 
trng_soft_reset(const struct versal_trng * trng)543*cc672e1fSJorge Ramirez-Ortiz static void trng_soft_reset(const struct versal_trng *trng)
544*cc672e1fSJorge Ramirez-Ortiz {
545*cc672e1fSJorge Ramirez-Ortiz 	trng_clrset32(trng->cfg.addr, TRNG_CTRL, TRNG_CTRL_PRNGSRST_MASK,
546*cc672e1fSJorge Ramirez-Ortiz 		      TRNG_CTRL_PRNGSRST_MASK);
547*cc672e1fSJorge Ramirez-Ortiz 	udelay(RESET_DELAY);
548*cc672e1fSJorge Ramirez-Ortiz 	trng_clrset32(trng->cfg.addr, TRNG_CTRL, TRNG_CTRL_PRNGSRST_MASK, 0);
549*cc672e1fSJorge Ramirez-Ortiz }
550*cc672e1fSJorge Ramirez-Ortiz 
trng_reset(const struct versal_trng * trng)551*cc672e1fSJorge Ramirez-Ortiz static void trng_reset(const struct versal_trng *trng)
552*cc672e1fSJorge Ramirez-Ortiz {
553*cc672e1fSJorge Ramirez-Ortiz 	trng_write32(trng->cfg.addr, TRNG_RESET, TRNG_RESET_VAL_MASK);
554*cc672e1fSJorge Ramirez-Ortiz 	udelay(RESET_DELAY);
555*cc672e1fSJorge Ramirez-Ortiz 	trng_write32(trng->cfg.addr, TRNG_RESET, 0);
556*cc672e1fSJorge Ramirez-Ortiz 	trng_soft_reset(trng);
557*cc672e1fSJorge Ramirez-Ortiz }
558*cc672e1fSJorge Ramirez-Ortiz 
trng_hold_reset(const struct versal_trng * trng)559*cc672e1fSJorge Ramirez-Ortiz static void trng_hold_reset(const struct versal_trng *trng)
560*cc672e1fSJorge Ramirez-Ortiz {
561*cc672e1fSJorge Ramirez-Ortiz 	trng_clrset32(trng->cfg.addr, TRNG_CTRL,
562*cc672e1fSJorge Ramirez-Ortiz 		      TRNG_CTRL_PRNGSRST_MASK, TRNG_CTRL_PRNGSRST_MASK);
563*cc672e1fSJorge Ramirez-Ortiz 	trng_write32(trng->cfg.addr, TRNG_RESET, TRNG_RESET_VAL_MASK);
564*cc672e1fSJorge Ramirez-Ortiz 	udelay(RESET_DELAY);
565*cc672e1fSJorge Ramirez-Ortiz }
566*cc672e1fSJorge Ramirez-Ortiz 
trng_check_seed(uint8_t * entropy,uint32_t len)567*cc672e1fSJorge Ramirez-Ortiz static TEE_Result trng_check_seed(uint8_t *entropy, uint32_t len)
568*cc672e1fSJorge Ramirez-Ortiz {
569*cc672e1fSJorge Ramirez-Ortiz 	uint32_t *p = (void *)entropy;
570*cc672e1fSJorge Ramirez-Ortiz 	size_t i = 0;
571*cc672e1fSJorge Ramirez-Ortiz 
572*cc672e1fSJorge Ramirez-Ortiz 	for (i = 0; i < len / sizeof(*p); i++) {
573*cc672e1fSJorge Ramirez-Ortiz 		if (p[i] == ALL_A_PATTERN_32)
574*cc672e1fSJorge Ramirez-Ortiz 			return TEE_ERROR_GENERIC;
575*cc672e1fSJorge Ramirez-Ortiz 
576*cc672e1fSJorge Ramirez-Ortiz 		if (p[i] == ALL_5_PATTERN_32)
577*cc672e1fSJorge Ramirez-Ortiz 			return TEE_ERROR_GENERIC;
578*cc672e1fSJorge Ramirez-Ortiz 	}
579*cc672e1fSJorge Ramirez-Ortiz 
580*cc672e1fSJorge Ramirez-Ortiz 	return TEE_SUCCESS;
581*cc672e1fSJorge Ramirez-Ortiz }
582*cc672e1fSJorge Ramirez-Ortiz 
trng_collect_random(struct versal_trng * trng,uint8_t * dst,size_t len)583*cc672e1fSJorge Ramirez-Ortiz static TEE_Result trng_collect_random(struct versal_trng *trng, uint8_t *dst,
584*cc672e1fSJorge Ramirez-Ortiz 				      size_t len)
585*cc672e1fSJorge Ramirez-Ortiz {
586*cc672e1fSJorge Ramirez-Ortiz 	const size_t bursts = len / TRNG_BURST_SIZE;
587*cc672e1fSJorge Ramirez-Ortiz 	const size_t words = TRNG_BURST_SIZE_BITS / TRNG_REG_SIZE;
588*cc672e1fSJorge Ramirez-Ortiz 	uint32_t *p = (void *)dst;
589*cc672e1fSJorge Ramirez-Ortiz 	size_t bcnt = 0;
590*cc672e1fSJorge Ramirez-Ortiz 	size_t wcnt = 0;
591*cc672e1fSJorge Ramirez-Ortiz 	size_t index = 0;
592*cc672e1fSJorge Ramirez-Ortiz 	uint32_t val = 0;
593*cc672e1fSJorge Ramirez-Ortiz 	bool match = false;
594*cc672e1fSJorge Ramirez-Ortiz 
595*cc672e1fSJorge Ramirez-Ortiz 	trng_clrset32(trng->cfg.addr, TRNG_CTRL,
596*cc672e1fSJorge Ramirez-Ortiz 		      TRNG_CTRL_PRNGSTART_MASK, TRNG_CTRL_PRNGSTART_MASK);
597*cc672e1fSJorge Ramirez-Ortiz 
598*cc672e1fSJorge Ramirez-Ortiz 	/*
599*cc672e1fSJorge Ramirez-Ortiz 	 * Loop as many times based on len requested. In each burst 128 bits
600*cc672e1fSJorge Ramirez-Ortiz 	 * are generated, which is reflected in QCNT value of 4 by hardware.
601*cc672e1fSJorge Ramirez-Ortiz 	 */
602*cc672e1fSJorge Ramirez-Ortiz 	for (bcnt = 0; bcnt < bursts; bcnt++) {
603*cc672e1fSJorge Ramirez-Ortiz 		if (trng_wait_for_event(trng->cfg.addr,
604*cc672e1fSJorge Ramirez-Ortiz 					TRNG_STATUS, TRNG_STATUS_QCNT_MASK,
605*cc672e1fSJorge Ramirez-Ortiz 					TRNG_MAX_QCNT << TRNG_STATUS_QCNT_SHIFT,
606*cc672e1fSJorge Ramirez-Ortiz 					TRNG_GENERATE_TIMEOUT)) {
607*cc672e1fSJorge Ramirez-Ortiz 			EMSG("Timeout waiting for randomness");
608*cc672e1fSJorge Ramirez-Ortiz 			return TEE_ERROR_GENERIC;
609*cc672e1fSJorge Ramirez-Ortiz 		}
610*cc672e1fSJorge Ramirez-Ortiz 
611*cc672e1fSJorge Ramirez-Ortiz 		/*
612*cc672e1fSJorge Ramirez-Ortiz 		 * DTF flag set during generate indicates catastrophic
613*cc672e1fSJorge Ramirez-Ortiz 		 * condition, which needs to be checked for every time unless we
614*cc672e1fSJorge Ramirez-Ortiz 		 * are in PTRNG mode
615*cc672e1fSJorge Ramirez-Ortiz 		 */
616*cc672e1fSJorge Ramirez-Ortiz 		if (trng->usr_cfg.mode != TRNG_PTRNG) {
617*cc672e1fSJorge Ramirez-Ortiz 			val = trng_read32(trng->cfg.addr, TRNG_STATUS);
618*cc672e1fSJorge Ramirez-Ortiz 			if (val & TRNG_STATUS_DTF_MASK) {
619*cc672e1fSJorge Ramirez-Ortiz 				EMSG("Catastrophic DFT error");
620*cc672e1fSJorge Ramirez-Ortiz 				trng->status = TRNG_CATASTROPHIC;
621*cc672e1fSJorge Ramirez-Ortiz 
622*cc672e1fSJorge Ramirez-Ortiz 				return TEE_ERROR_GENERIC;
623*cc672e1fSJorge Ramirez-Ortiz 			}
624*cc672e1fSJorge Ramirez-Ortiz 		}
625*cc672e1fSJorge Ramirez-Ortiz 		/*
626*cc672e1fSJorge Ramirez-Ortiz 		 * Read the core output register 4 times to consume the random
627*cc672e1fSJorge Ramirez-Ortiz 		 * data generated for every burst.
628*cc672e1fSJorge Ramirez-Ortiz 		 */
629*cc672e1fSJorge Ramirez-Ortiz 		match = true;
630*cc672e1fSJorge Ramirez-Ortiz 		for (wcnt = 0; wcnt < words; wcnt++) {
631*cc672e1fSJorge Ramirez-Ortiz 			val = trng_read32(trng->cfg.addr, TRNG_CORE_OUTPUT);
632*cc672e1fSJorge Ramirez-Ortiz 
633*cc672e1fSJorge Ramirez-Ortiz 			if (bcnt > 0 && trng->buf[wcnt] != val)
634*cc672e1fSJorge Ramirez-Ortiz 				match = false;
635*cc672e1fSJorge Ramirez-Ortiz 
636*cc672e1fSJorge Ramirez-Ortiz 			trng->buf[wcnt] = val;
637*cc672e1fSJorge Ramirez-Ortiz 
638*cc672e1fSJorge Ramirez-Ortiz 			if (dst) {
639*cc672e1fSJorge Ramirez-Ortiz 				p[index] = TEE_U32_TO_BIG_ENDIAN(val);
640*cc672e1fSJorge Ramirez-Ortiz 				index++;
641*cc672e1fSJorge Ramirez-Ortiz 			}
642*cc672e1fSJorge Ramirez-Ortiz 		}
643*cc672e1fSJorge Ramirez-Ortiz 
644*cc672e1fSJorge Ramirez-Ortiz 		if (bursts > 1 && bcnt > 0 && match) {
645*cc672e1fSJorge Ramirez-Ortiz 			EMSG("Catastrophic software error");
646*cc672e1fSJorge Ramirez-Ortiz 			trng->status = TRNG_CATASTROPHIC;
647*cc672e1fSJorge Ramirez-Ortiz 			return TEE_ERROR_GENERIC;
648*cc672e1fSJorge Ramirez-Ortiz 		}
649*cc672e1fSJorge Ramirez-Ortiz 	}
650*cc672e1fSJorge Ramirez-Ortiz 
651*cc672e1fSJorge Ramirez-Ortiz 	return TEE_SUCCESS;
652*cc672e1fSJorge Ramirez-Ortiz }
653*cc672e1fSJorge Ramirez-Ortiz 
trng_reseed_internal_nodf(struct versal_trng * trng,uint8_t * eseed,uint8_t * str)654*cc672e1fSJorge Ramirez-Ortiz static TEE_Result trng_reseed_internal_nodf(struct versal_trng *trng,
655*cc672e1fSJorge Ramirez-Ortiz 					    uint8_t *eseed, uint8_t *str)
656*cc672e1fSJorge Ramirez-Ortiz {
657*cc672e1fSJorge Ramirez-Ortiz 	uint8_t entropy[TRNG_SEED_LEN] = { 0 };
658*cc672e1fSJorge Ramirez-Ortiz 	uint8_t *seed = NULL;
659*cc672e1fSJorge Ramirez-Ortiz 
660*cc672e1fSJorge Ramirez-Ortiz 	switch (trng->usr_cfg.mode) {
661*cc672e1fSJorge Ramirez-Ortiz 	case TRNG_HRNG:
662*cc672e1fSJorge Ramirez-Ortiz 		trng_write32(trng->cfg.addr, TRNG_OSC_EN, TRNG_OSC_EN_VAL_MASK);
663*cc672e1fSJorge Ramirez-Ortiz 		trng_soft_reset(trng);
664*cc672e1fSJorge Ramirez-Ortiz 		trng_write32(trng->cfg.addr, TRNG_CTRL,
665*cc672e1fSJorge Ramirez-Ortiz 			     TRNG_CTRL_EUMODE_MASK | TRNG_CTRL_TRSSEN_MASK);
666*cc672e1fSJorge Ramirez-Ortiz 
667*cc672e1fSJorge Ramirez-Ortiz 		if (trng_collect_random(trng, entropy, TRNG_SEED_LEN))
668*cc672e1fSJorge Ramirez-Ortiz 			return TEE_ERROR_GENERIC;
669*cc672e1fSJorge Ramirez-Ortiz 
670*cc672e1fSJorge Ramirez-Ortiz 		if (trng_check_seed(entropy, TRNG_SEED_LEN))
671*cc672e1fSJorge Ramirez-Ortiz 			return TEE_ERROR_GENERIC;
672*cc672e1fSJorge Ramirez-Ortiz 
673*cc672e1fSJorge Ramirez-Ortiz 		seed = entropy;
674*cc672e1fSJorge Ramirez-Ortiz 		break;
675*cc672e1fSJorge Ramirez-Ortiz 	case TRNG_DRNG:
676*cc672e1fSJorge Ramirez-Ortiz 		seed = eseed;
677*cc672e1fSJorge Ramirez-Ortiz 		break;
678*cc672e1fSJorge Ramirez-Ortiz 	default:
679*cc672e1fSJorge Ramirez-Ortiz 		seed = NULL;
680*cc672e1fSJorge Ramirez-Ortiz 		break;
681*cc672e1fSJorge Ramirez-Ortiz 	}
682*cc672e1fSJorge Ramirez-Ortiz 
683*cc672e1fSJorge Ramirez-Ortiz 	trng_write32_range(trng, TRNG_EXT_SEED_0, TRNG_SEED_REGS, seed);
684*cc672e1fSJorge Ramirez-Ortiz 	if (str)
685*cc672e1fSJorge Ramirez-Ortiz 		trng_write32_range(trng, TRNG_PER_STRING_0, TRNG_PERS_STR_REGS,
686*cc672e1fSJorge Ramirez-Ortiz 				   str);
687*cc672e1fSJorge Ramirez-Ortiz 
688*cc672e1fSJorge Ramirez-Ortiz 	return TEE_SUCCESS;
689*cc672e1fSJorge Ramirez-Ortiz }
690*cc672e1fSJorge Ramirez-Ortiz 
trng_reseed_internal_df(struct versal_trng * trng,uint8_t * eseed,uint8_t * str)691*cc672e1fSJorge Ramirez-Ortiz static TEE_Result trng_reseed_internal_df(struct versal_trng *trng,
692*cc672e1fSJorge Ramirez-Ortiz 					  uint8_t *eseed, uint8_t *str)
693*cc672e1fSJorge Ramirez-Ortiz {
694*cc672e1fSJorge Ramirez-Ortiz 	memset(&trng->dfin, 0, sizeof(trng->dfin));
695*cc672e1fSJorge Ramirez-Ortiz 
696*cc672e1fSJorge Ramirez-Ortiz 	switch (trng->usr_cfg.mode) {
697*cc672e1fSJorge Ramirez-Ortiz 	case TRNG_HRNG:
698*cc672e1fSJorge Ramirez-Ortiz 		trng_write32(trng->cfg.addr, TRNG_OSC_EN, TRNG_OSC_EN_VAL_MASK);
699*cc672e1fSJorge Ramirez-Ortiz 		trng_soft_reset(trng);
700*cc672e1fSJorge Ramirez-Ortiz 		trng_write32(trng->cfg.addr, TRNG_CTRL,
701*cc672e1fSJorge Ramirez-Ortiz 			     TRNG_CTRL_EUMODE_MASK | TRNG_CTRL_TRSSEN_MASK);
702*cc672e1fSJorge Ramirez-Ortiz 
703*cc672e1fSJorge Ramirez-Ortiz 		if (trng_collect_random(trng, trng->dfin.entropy, trng->len))
704*cc672e1fSJorge Ramirez-Ortiz 			return TEE_ERROR_GENERIC;
705*cc672e1fSJorge Ramirez-Ortiz 
706*cc672e1fSJorge Ramirez-Ortiz 		if (trng_check_seed(trng->dfin.entropy, trng->len))
707*cc672e1fSJorge Ramirez-Ortiz 			return TEE_ERROR_GENERIC;
708*cc672e1fSJorge Ramirez-Ortiz 		break;
709*cc672e1fSJorge Ramirez-Ortiz 	case TRNG_DRNG:
710*cc672e1fSJorge Ramirez-Ortiz 		memcpy(trng->dfin.entropy, eseed, trng->len);
711*cc672e1fSJorge Ramirez-Ortiz 		break;
712*cc672e1fSJorge Ramirez-Ortiz 	default:
713*cc672e1fSJorge Ramirez-Ortiz 		break;
714*cc672e1fSJorge Ramirez-Ortiz 	}
715*cc672e1fSJorge Ramirez-Ortiz 
716*cc672e1fSJorge Ramirez-Ortiz 	trng_df_algorithm(trng, trng->dfout, DF_SEED, str);
717*cc672e1fSJorge Ramirez-Ortiz 	trng_write32_range(trng, TRNG_EXT_SEED_0, TRNG_SEED_REGS, trng->dfout);
718*cc672e1fSJorge Ramirez-Ortiz 
719*cc672e1fSJorge Ramirez-Ortiz 	return TEE_SUCCESS;
720*cc672e1fSJorge Ramirez-Ortiz }
721*cc672e1fSJorge Ramirez-Ortiz 
trng_reseed_internal(struct versal_trng * trng,uint8_t * eseed,uint8_t * str,uint32_t mul)722*cc672e1fSJorge Ramirez-Ortiz static TEE_Result trng_reseed_internal(struct versal_trng *trng,
723*cc672e1fSJorge Ramirez-Ortiz 				       uint8_t *eseed, uint8_t *str,
724*cc672e1fSJorge Ramirez-Ortiz 				       uint32_t mul)
725*cc672e1fSJorge Ramirez-Ortiz {
726*cc672e1fSJorge Ramirez-Ortiz 	uint32_t val = 0;
727*cc672e1fSJorge Ramirez-Ortiz 
728*cc672e1fSJorge Ramirez-Ortiz 	trng->stats.bytes_reseed = 0;
729*cc672e1fSJorge Ramirez-Ortiz 	trng->stats.elapsed_seed_life = 0;
730*cc672e1fSJorge Ramirez-Ortiz 
731*cc672e1fSJorge Ramirez-Ortiz 	if (trng->usr_cfg.df_disable)
732*cc672e1fSJorge Ramirez-Ortiz 		trng->len = TRNG_SEED_LEN;
733*cc672e1fSJorge Ramirez-Ortiz 	else
734*cc672e1fSJorge Ramirez-Ortiz 		trng->len = (mul + 1) * BYTES_PER_BLOCK;
735*cc672e1fSJorge Ramirez-Ortiz 
736*cc672e1fSJorge Ramirez-Ortiz 	if (trng->usr_cfg.df_disable) {
737*cc672e1fSJorge Ramirez-Ortiz 		if (trng_reseed_internal_nodf(trng, eseed, str))
738*cc672e1fSJorge Ramirez-Ortiz 			goto error;
739*cc672e1fSJorge Ramirez-Ortiz 	} else {
740*cc672e1fSJorge Ramirez-Ortiz 		if (trng_reseed_internal_df(trng, eseed, str))
741*cc672e1fSJorge Ramirez-Ortiz 			goto error;
742*cc672e1fSJorge Ramirez-Ortiz 	}
743*cc672e1fSJorge Ramirez-Ortiz 
744*cc672e1fSJorge Ramirez-Ortiz 	trng_write32(trng->cfg.addr, TRNG_CTRL,
745*cc672e1fSJorge Ramirez-Ortiz 		     PRNGMODE_RESEED | TRNG_CTRL_PRNGXS_MASK);
746*cc672e1fSJorge Ramirez-Ortiz 
747*cc672e1fSJorge Ramirez-Ortiz 	/* Start the reseed operation */
748*cc672e1fSJorge Ramirez-Ortiz 	trng_clrset32(trng->cfg.addr, TRNG_CTRL, TRNG_CTRL_PRNGSTART_MASK,
749*cc672e1fSJorge Ramirez-Ortiz 		      TRNG_CTRL_PRNGSTART_MASK);
750*cc672e1fSJorge Ramirez-Ortiz 
751*cc672e1fSJorge Ramirez-Ortiz 	if (trng_wait_for_event(trng->cfg.addr, TRNG_STATUS,
752*cc672e1fSJorge Ramirez-Ortiz 				TRNG_STATUS_DONE_MASK, TRNG_STATUS_DONE_MASK,
753*cc672e1fSJorge Ramirez-Ortiz 				TRNG_RESEED_TIMEOUT))
754*cc672e1fSJorge Ramirez-Ortiz 		goto error;
755*cc672e1fSJorge Ramirez-Ortiz 
756*cc672e1fSJorge Ramirez-Ortiz 	/* Check SP800 - 90B (entropy health test error) */
757*cc672e1fSJorge Ramirez-Ortiz 	val = trng_read32(trng->cfg.addr, TRNG_STATUS) & TRNG_STATUS_CERTF_MASK;
758*cc672e1fSJorge Ramirez-Ortiz 	if (val == TRNG_STATUS_CERTF_MASK)
759*cc672e1fSJorge Ramirez-Ortiz 		goto error;
760*cc672e1fSJorge Ramirez-Ortiz 
761*cc672e1fSJorge Ramirez-Ortiz 	trng_clrset32(trng->cfg.addr, TRNG_CTRL, TRNG_CTRL_PRNGSTART_MASK, 0);
762*cc672e1fSJorge Ramirez-Ortiz 	return TEE_SUCCESS;
763*cc672e1fSJorge Ramirez-Ortiz error:
764*cc672e1fSJorge Ramirez-Ortiz 	trng->status = TRNG_ERROR;
765*cc672e1fSJorge Ramirez-Ortiz 	return TEE_ERROR_GENERIC;
766*cc672e1fSJorge Ramirez-Ortiz }
767*cc672e1fSJorge Ramirez-Ortiz 
trng_instantiate(struct versal_trng * trng,const struct trng_usr_cfg * usr_cfg)768*cc672e1fSJorge Ramirez-Ortiz static TEE_Result trng_instantiate(struct versal_trng *trng,
769*cc672e1fSJorge Ramirez-Ortiz 				   const struct trng_usr_cfg *usr_cfg)
770*cc672e1fSJorge Ramirez-Ortiz {
771*cc672e1fSJorge Ramirez-Ortiz 	uint8_t *seed = NULL;
772*cc672e1fSJorge Ramirez-Ortiz 	uint8_t *pers = NULL;
773*cc672e1fSJorge Ramirez-Ortiz 
774*cc672e1fSJorge Ramirez-Ortiz 	if (!trng)
775*cc672e1fSJorge Ramirez-Ortiz 		return TEE_ERROR_GENERIC;
776*cc672e1fSJorge Ramirez-Ortiz 
777*cc672e1fSJorge Ramirez-Ortiz 	if (!usr_cfg)
778*cc672e1fSJorge Ramirez-Ortiz 		goto error;
779*cc672e1fSJorge Ramirez-Ortiz 
780*cc672e1fSJorge Ramirez-Ortiz 	if (trng->status != TRNG_UNINITIALIZED)
781*cc672e1fSJorge Ramirez-Ortiz 		goto error;
782*cc672e1fSJorge Ramirez-Ortiz 
783*cc672e1fSJorge Ramirez-Ortiz 	if (usr_cfg->mode != TRNG_HRNG && usr_cfg->mode != TRNG_DRNG &&
784*cc672e1fSJorge Ramirez-Ortiz 	    usr_cfg->mode != TRNG_PTRNG)
785*cc672e1fSJorge Ramirez-Ortiz 		goto error;
786*cc672e1fSJorge Ramirez-Ortiz 
787*cc672e1fSJorge Ramirez-Ortiz 	if (usr_cfg->mode != TRNG_PTRNG && !usr_cfg->seed_life)
788*cc672e1fSJorge Ramirez-Ortiz 		goto error;
789*cc672e1fSJorge Ramirez-Ortiz 
790*cc672e1fSJorge Ramirez-Ortiz 	if (!usr_cfg->iseed_en && usr_cfg->mode == TRNG_DRNG)
791*cc672e1fSJorge Ramirez-Ortiz 		goto error;
792*cc672e1fSJorge Ramirez-Ortiz 
793*cc672e1fSJorge Ramirez-Ortiz 	if (usr_cfg->iseed_en && usr_cfg->mode == TRNG_HRNG)
794*cc672e1fSJorge Ramirez-Ortiz 		goto error;
795*cc672e1fSJorge Ramirez-Ortiz 
796*cc672e1fSJorge Ramirez-Ortiz 	if (!usr_cfg->df_disable &&
797*cc672e1fSJorge Ramirez-Ortiz 	    (usr_cfg->dfmul < TRNG_MIN_DFLENMULT ||
798*cc672e1fSJorge Ramirez-Ortiz 	     usr_cfg->dfmul > TRNG_MAX_DFLENMULT))
799*cc672e1fSJorge Ramirez-Ortiz 		goto error;
800*cc672e1fSJorge Ramirez-Ortiz 
801*cc672e1fSJorge Ramirez-Ortiz 	if (usr_cfg->df_disable && usr_cfg->dfmul)
802*cc672e1fSJorge Ramirez-Ortiz 		goto error;
803*cc672e1fSJorge Ramirez-Ortiz 
804*cc672e1fSJorge Ramirez-Ortiz 	if (usr_cfg->mode == TRNG_PTRNG &&
805*cc672e1fSJorge Ramirez-Ortiz 	    (usr_cfg->iseed_en || usr_cfg->pstr_en ||
806*cc672e1fSJorge Ramirez-Ortiz 	     usr_cfg->predict_en || usr_cfg->seed_life))
807*cc672e1fSJorge Ramirez-Ortiz 		goto error;
808*cc672e1fSJorge Ramirez-Ortiz 
809*cc672e1fSJorge Ramirez-Ortiz 	memcpy(&trng->usr_cfg, usr_cfg, sizeof(struct trng_usr_cfg));
810*cc672e1fSJorge Ramirez-Ortiz 	trng_reset(trng);
811*cc672e1fSJorge Ramirez-Ortiz 
812*cc672e1fSJorge Ramirez-Ortiz 	if (trng->usr_cfg.iseed_en)
813*cc672e1fSJorge Ramirez-Ortiz 		seed = (void *)trng->usr_cfg.init_seed;
814*cc672e1fSJorge Ramirez-Ortiz 
815*cc672e1fSJorge Ramirez-Ortiz 	if (trng->usr_cfg.pstr_en)
816*cc672e1fSJorge Ramirez-Ortiz 		pers = (void *)trng->usr_cfg.pstr;
817*cc672e1fSJorge Ramirez-Ortiz 
818*cc672e1fSJorge Ramirez-Ortiz 	if (trng->usr_cfg.mode != TRNG_PTRNG) {
819*cc672e1fSJorge Ramirez-Ortiz 		if (trng_reseed_internal(trng, seed, pers, trng->usr_cfg.dfmul))
820*cc672e1fSJorge Ramirez-Ortiz 			goto error;
821*cc672e1fSJorge Ramirez-Ortiz 	}
822*cc672e1fSJorge Ramirez-Ortiz 
823*cc672e1fSJorge Ramirez-Ortiz 	trng->status = TRNG_HEALTHY;
824*cc672e1fSJorge Ramirez-Ortiz 	return TEE_SUCCESS;
825*cc672e1fSJorge Ramirez-Ortiz error:
826*cc672e1fSJorge Ramirez-Ortiz 	trng->status = TRNG_ERROR;
827*cc672e1fSJorge Ramirez-Ortiz 	return TEE_ERROR_GENERIC;
828*cc672e1fSJorge Ramirez-Ortiz }
829*cc672e1fSJorge Ramirez-Ortiz 
trng_reseed(struct versal_trng * trng,uint8_t * eseed,uint32_t mul)830*cc672e1fSJorge Ramirez-Ortiz static TEE_Result trng_reseed(struct versal_trng *trng, uint8_t *eseed,
831*cc672e1fSJorge Ramirez-Ortiz 			      uint32_t mul)
832*cc672e1fSJorge Ramirez-Ortiz {
833*cc672e1fSJorge Ramirez-Ortiz 	if (!trng)
834*cc672e1fSJorge Ramirez-Ortiz 		return TEE_ERROR_GENERIC;
835*cc672e1fSJorge Ramirez-Ortiz 
836*cc672e1fSJorge Ramirez-Ortiz 	if (trng->status != TRNG_HEALTHY)
837*cc672e1fSJorge Ramirez-Ortiz 		goto error;
838*cc672e1fSJorge Ramirez-Ortiz 
839*cc672e1fSJorge Ramirez-Ortiz 	if (trng->usr_cfg.mode != TRNG_DRNG && trng->usr_cfg.mode != TRNG_HRNG)
840*cc672e1fSJorge Ramirez-Ortiz 		goto error;
841*cc672e1fSJorge Ramirez-Ortiz 
842*cc672e1fSJorge Ramirez-Ortiz 	if (trng->usr_cfg.mode == TRNG_DRNG && !eseed)
843*cc672e1fSJorge Ramirez-Ortiz 		goto error;
844*cc672e1fSJorge Ramirez-Ortiz 
845*cc672e1fSJorge Ramirez-Ortiz 	if (trng->usr_cfg.mode != TRNG_DRNG && eseed)
846*cc672e1fSJorge Ramirez-Ortiz 		goto error;
847*cc672e1fSJorge Ramirez-Ortiz 
848*cc672e1fSJorge Ramirez-Ortiz 	if (!trng->usr_cfg.df_disable) {
849*cc672e1fSJorge Ramirez-Ortiz 		if (mul < TRNG_MIN_DFLENMULT || mul > TRNG_MAX_DFLENMULT)
850*cc672e1fSJorge Ramirez-Ortiz 			goto error;
851*cc672e1fSJorge Ramirez-Ortiz 	}
852*cc672e1fSJorge Ramirez-Ortiz 
853*cc672e1fSJorge Ramirez-Ortiz 	if (trng->usr_cfg.df_disable && mul)
854*cc672e1fSJorge Ramirez-Ortiz 		goto error;
855*cc672e1fSJorge Ramirez-Ortiz 
856*cc672e1fSJorge Ramirez-Ortiz 	if (eseed && !memcmp(eseed, trng->usr_cfg.init_seed, trng->len))
857*cc672e1fSJorge Ramirez-Ortiz 		goto error;
858*cc672e1fSJorge Ramirez-Ortiz 
859*cc672e1fSJorge Ramirez-Ortiz 	if (trng_reseed_internal(trng, eseed, NULL, mul))
860*cc672e1fSJorge Ramirez-Ortiz 		goto error;
861*cc672e1fSJorge Ramirez-Ortiz 
862*cc672e1fSJorge Ramirez-Ortiz 	return TEE_SUCCESS;
863*cc672e1fSJorge Ramirez-Ortiz error:
864*cc672e1fSJorge Ramirez-Ortiz 	trng->status = TRNG_ERROR;
865*cc672e1fSJorge Ramirez-Ortiz 	return TEE_ERROR_GENERIC;
866*cc672e1fSJorge Ramirez-Ortiz }
867*cc672e1fSJorge Ramirez-Ortiz 
trng_generate(struct versal_trng * trng,uint8_t * buf,size_t blen,bool predict)868*cc672e1fSJorge Ramirez-Ortiz static TEE_Result trng_generate(struct versal_trng *trng, uint8_t *buf,
869*cc672e1fSJorge Ramirez-Ortiz 				size_t blen, bool predict)
870*cc672e1fSJorge Ramirez-Ortiz {
871*cc672e1fSJorge Ramirez-Ortiz 	uint32_t len = TRNG_SEC_STRENGTH_LEN;
872*cc672e1fSJorge Ramirez-Ortiz 	uint8_t *p = buf;
873*cc672e1fSJorge Ramirez-Ortiz 
874*cc672e1fSJorge Ramirez-Ortiz 	if (!trng)
875*cc672e1fSJorge Ramirez-Ortiz 		return TEE_ERROR_GENERIC;
876*cc672e1fSJorge Ramirez-Ortiz 
877*cc672e1fSJorge Ramirez-Ortiz 	if (!p)
878*cc672e1fSJorge Ramirez-Ortiz 		goto error;
879*cc672e1fSJorge Ramirez-Ortiz 
880*cc672e1fSJorge Ramirez-Ortiz 	if (blen < TRNG_SEC_STRENGTH_LEN)
881*cc672e1fSJorge Ramirez-Ortiz 		goto error;
882*cc672e1fSJorge Ramirez-Ortiz 
883*cc672e1fSJorge Ramirez-Ortiz 	if (trng->status != TRNG_HEALTHY)
884*cc672e1fSJorge Ramirez-Ortiz 		goto error;
885*cc672e1fSJorge Ramirez-Ortiz 
886*cc672e1fSJorge Ramirez-Ortiz 	if (trng->usr_cfg.mode == TRNG_PTRNG && predict)
887*cc672e1fSJorge Ramirez-Ortiz 		goto error;
888*cc672e1fSJorge Ramirez-Ortiz 
889*cc672e1fSJorge Ramirez-Ortiz 	if (!trng->usr_cfg.predict_en && predict)
890*cc672e1fSJorge Ramirez-Ortiz 		goto error;
891*cc672e1fSJorge Ramirez-Ortiz 
892*cc672e1fSJorge Ramirez-Ortiz 	switch (trng->usr_cfg.mode) {
893*cc672e1fSJorge Ramirez-Ortiz 	case TRNG_HRNG:
894*cc672e1fSJorge Ramirez-Ortiz 		if (trng->stats.elapsed_seed_life >= trng->usr_cfg.seed_life) {
895*cc672e1fSJorge Ramirez-Ortiz 			if (trng_reseed_internal(trng, NULL, NULL, 0))
896*cc672e1fSJorge Ramirez-Ortiz 				goto error;
897*cc672e1fSJorge Ramirez-Ortiz 		}
898*cc672e1fSJorge Ramirez-Ortiz 
899*cc672e1fSJorge Ramirez-Ortiz 		if (predict && trng->stats.elapsed_seed_life > 0) {
900*cc672e1fSJorge Ramirez-Ortiz 			if (trng_reseed_internal(trng, NULL, NULL, 0))
901*cc672e1fSJorge Ramirez-Ortiz 				goto error;
902*cc672e1fSJorge Ramirez-Ortiz 		}
903*cc672e1fSJorge Ramirez-Ortiz 
904*cc672e1fSJorge Ramirez-Ortiz 		trng_write32(trng->cfg.addr, TRNG_CTRL, PRNGMODE_GEN);
905*cc672e1fSJorge Ramirez-Ortiz 		break;
906*cc672e1fSJorge Ramirez-Ortiz 	case TRNG_DRNG:
907*cc672e1fSJorge Ramirez-Ortiz 		if (trng->stats.elapsed_seed_life > trng->usr_cfg.seed_life)
908*cc672e1fSJorge Ramirez-Ortiz 			goto error;
909*cc672e1fSJorge Ramirez-Ortiz 
910*cc672e1fSJorge Ramirez-Ortiz 		if (predict && trng->stats.elapsed_seed_life > 0)
911*cc672e1fSJorge Ramirez-Ortiz 			goto error;
912*cc672e1fSJorge Ramirez-Ortiz 
913*cc672e1fSJorge Ramirez-Ortiz 		trng_write32(trng->cfg.addr, TRNG_CTRL, PRNGMODE_GEN);
914*cc672e1fSJorge Ramirez-Ortiz 		break;
915*cc672e1fSJorge Ramirez-Ortiz 	default:
916*cc672e1fSJorge Ramirez-Ortiz 		if (!trng->usr_cfg.df_disable) {
917*cc672e1fSJorge Ramirez-Ortiz 			memset(&trng->dfin, 0, sizeof(trng->dfin));
918*cc672e1fSJorge Ramirez-Ortiz 			len = (trng->usr_cfg.dfmul + 1) * BYTES_PER_BLOCK;
919*cc672e1fSJorge Ramirez-Ortiz 			trng->len = len;
920*cc672e1fSJorge Ramirez-Ortiz 			p = trng->dfin.entropy;
921*cc672e1fSJorge Ramirez-Ortiz 		}
922*cc672e1fSJorge Ramirez-Ortiz 		/* Enable the 8 ring oscillators used for entropy source */
923*cc672e1fSJorge Ramirez-Ortiz 		trng_write32(trng->cfg.addr, TRNG_OSC_EN, TRNG_OSC_EN_VAL_MASK);
924*cc672e1fSJorge Ramirez-Ortiz 		trng_soft_reset(trng);
925*cc672e1fSJorge Ramirez-Ortiz 		trng_write32(trng->cfg.addr, TRNG_CTRL,
926*cc672e1fSJorge Ramirez-Ortiz 			     TRNG_CTRL_EUMODE_MASK | TRNG_CTRL_TRSSEN_MASK);
927*cc672e1fSJorge Ramirez-Ortiz 		break;
928*cc672e1fSJorge Ramirez-Ortiz 	}
929*cc672e1fSJorge Ramirez-Ortiz 
930*cc672e1fSJorge Ramirez-Ortiz 	if (trng_collect_random(trng, p, len))
931*cc672e1fSJorge Ramirez-Ortiz 		goto error;
932*cc672e1fSJorge Ramirez-Ortiz 
933*cc672e1fSJorge Ramirez-Ortiz 	trng->stats.bytes_reseed += len;
934*cc672e1fSJorge Ramirez-Ortiz 	trng->stats.bytes += len;
935*cc672e1fSJorge Ramirez-Ortiz 	trng->stats.elapsed_seed_life++;
936*cc672e1fSJorge Ramirez-Ortiz 
937*cc672e1fSJorge Ramirez-Ortiz 	if (!trng->usr_cfg.df_disable && trng->usr_cfg.mode == TRNG_PTRNG)
938*cc672e1fSJorge Ramirez-Ortiz 		trng_df_algorithm(trng, buf, DF_RAND, NULL);
939*cc672e1fSJorge Ramirez-Ortiz 
940*cc672e1fSJorge Ramirez-Ortiz 	return TEE_SUCCESS;
941*cc672e1fSJorge Ramirez-Ortiz error:
942*cc672e1fSJorge Ramirez-Ortiz 	if (trng->status != TRNG_CATASTROPHIC)
943*cc672e1fSJorge Ramirez-Ortiz 		trng->status = TRNG_ERROR;
944*cc672e1fSJorge Ramirez-Ortiz 
945*cc672e1fSJorge Ramirez-Ortiz 	return TEE_ERROR_GENERIC;
946*cc672e1fSJorge Ramirez-Ortiz }
947*cc672e1fSJorge Ramirez-Ortiz 
trng_release(struct versal_trng * trng)948*cc672e1fSJorge Ramirez-Ortiz static TEE_Result trng_release(struct versal_trng *trng)
949*cc672e1fSJorge Ramirez-Ortiz {
950*cc672e1fSJorge Ramirez-Ortiz 	if (!trng)
951*cc672e1fSJorge Ramirez-Ortiz 		return TEE_ERROR_GENERIC;
952*cc672e1fSJorge Ramirez-Ortiz 
953*cc672e1fSJorge Ramirez-Ortiz 	if (trng->status == TRNG_UNINITIALIZED)
954*cc672e1fSJorge Ramirez-Ortiz 		goto error;
955*cc672e1fSJorge Ramirez-Ortiz 
956*cc672e1fSJorge Ramirez-Ortiz 	trng_write32_range(trng, TRNG_EXT_SEED_0, TRNG_SEED_REGS, NULL);
957*cc672e1fSJorge Ramirez-Ortiz 	trng_write32_range(trng, TRNG_PER_STRING_0, TRNG_PERS_STR_REGS, NULL);
958*cc672e1fSJorge Ramirez-Ortiz 	trng_hold_reset(trng);
959*cc672e1fSJorge Ramirez-Ortiz 
960*cc672e1fSJorge Ramirez-Ortiz 	/* Clear the instance */
961*cc672e1fSJorge Ramirez-Ortiz 	memset(&trng->usr_cfg, 0, sizeof(trng->usr_cfg));
962*cc672e1fSJorge Ramirez-Ortiz 	memset(trng->buf, 0, sizeof(trng->buf));
963*cc672e1fSJorge Ramirez-Ortiz 	memset(trng->dfout, 0, sizeof(trng->dfout));
964*cc672e1fSJorge Ramirez-Ortiz 	trng->status = TRNG_UNINITIALIZED;
965*cc672e1fSJorge Ramirez-Ortiz 
966*cc672e1fSJorge Ramirez-Ortiz 	return TEE_SUCCESS;
967*cc672e1fSJorge Ramirez-Ortiz error:
968*cc672e1fSJorge Ramirez-Ortiz 	trng->status = TRNG_ERROR;
969*cc672e1fSJorge Ramirez-Ortiz 
970*cc672e1fSJorge Ramirez-Ortiz 	return TEE_ERROR_GENERIC;
971*cc672e1fSJorge Ramirez-Ortiz }
972*cc672e1fSJorge Ramirez-Ortiz 
973*cc672e1fSJorge Ramirez-Ortiz /* Health tests should be run when the configured mode is of PTRNG or HRNG */
trng_health_test(struct versal_trng * trng)974*cc672e1fSJorge Ramirez-Ortiz static TEE_Result trng_health_test(struct versal_trng *trng)
975*cc672e1fSJorge Ramirez-Ortiz {
976*cc672e1fSJorge Ramirez-Ortiz 	struct trng_usr_cfg tests = {
977*cc672e1fSJorge Ramirez-Ortiz 		.mode = TRNG_HRNG,
978*cc672e1fSJorge Ramirez-Ortiz 		.seed_life = 10,
979*cc672e1fSJorge Ramirez-Ortiz 		.dfmul = 7,
980*cc672e1fSJorge Ramirez-Ortiz 		.predict_en = false,
981*cc672e1fSJorge Ramirez-Ortiz 		.iseed_en = false,
982*cc672e1fSJorge Ramirez-Ortiz 		.pstr_en = false,
983*cc672e1fSJorge Ramirez-Ortiz 		.df_disable = false,
984*cc672e1fSJorge Ramirez-Ortiz 	};
985*cc672e1fSJorge Ramirez-Ortiz 
986*cc672e1fSJorge Ramirez-Ortiz 	if (trng_instantiate(trng, &tests))
987*cc672e1fSJorge Ramirez-Ortiz 		goto error;
988*cc672e1fSJorge Ramirez-Ortiz 
989*cc672e1fSJorge Ramirez-Ortiz 	if (trng_release(trng))
990*cc672e1fSJorge Ramirez-Ortiz 		goto error;
991*cc672e1fSJorge Ramirez-Ortiz 
992*cc672e1fSJorge Ramirez-Ortiz 	return TEE_SUCCESS;
993*cc672e1fSJorge Ramirez-Ortiz error:
994*cc672e1fSJorge Ramirez-Ortiz 	trng->status = TRNG_ERROR;
995*cc672e1fSJorge Ramirez-Ortiz 
996*cc672e1fSJorge Ramirez-Ortiz 	return TEE_ERROR_GENERIC;
997*cc672e1fSJorge Ramirez-Ortiz }
998*cc672e1fSJorge Ramirez-Ortiz 
999*cc672e1fSJorge Ramirez-Ortiz /*
1000*cc672e1fSJorge Ramirez-Ortiz  * The KAT test should be run when the TRNG is configured in DRNG or HRNG mode.
1001*cc672e1fSJorge Ramirez-Ortiz  * If KAT fails, the driver has to be put in error state.
1002*cc672e1fSJorge Ramirez-Ortiz  */
trng_kat_test(struct versal_trng * trng)1003*cc672e1fSJorge Ramirez-Ortiz static TEE_Result trng_kat_test(struct versal_trng *trng)
1004*cc672e1fSJorge Ramirez-Ortiz {
1005*cc672e1fSJorge Ramirez-Ortiz 	struct trng_usr_cfg tests = {
1006*cc672e1fSJorge Ramirez-Ortiz 		.mode = TRNG_DRNG,
1007*cc672e1fSJorge Ramirez-Ortiz 		.seed_life = 5,
1008*cc672e1fSJorge Ramirez-Ortiz 		.dfmul = 2,
1009*cc672e1fSJorge Ramirez-Ortiz 		.predict_en = false,
1010*cc672e1fSJorge Ramirez-Ortiz 		.iseed_en = true,
1011*cc672e1fSJorge Ramirez-Ortiz 		.pstr_en = true,
1012*cc672e1fSJorge Ramirez-Ortiz 		.df_disable = false,
1013*cc672e1fSJorge Ramirez-Ortiz 	};
1014*cc672e1fSJorge Ramirez-Ortiz 	const uint8_t ext_seed[TRNG_SEED_LEN] = {
1015*cc672e1fSJorge Ramirez-Ortiz 		0x3BU, 0xC3U, 0xEDU, 0x64U, 0xF4U, 0x80U, 0x1CU, 0xC7U,
1016*cc672e1fSJorge Ramirez-Ortiz 		0x14U, 0xCCU, 0x35U, 0xEDU, 0x57U, 0x01U, 0x2AU, 0xE4U,
1017*cc672e1fSJorge Ramirez-Ortiz 		0xBCU, 0xEFU, 0xDEU, 0xF6U, 0x7CU, 0x46U, 0xA6U, 0x34U,
1018*cc672e1fSJorge Ramirez-Ortiz 		0xC6U, 0x79U, 0xE8U, 0x91U, 0x5DU, 0xB1U, 0xDBU, 0xA7U,
1019*cc672e1fSJorge Ramirez-Ortiz 		0x49U, 0xA5U, 0xBBU, 0x4FU, 0xEDU, 0x30U, 0xB3U, 0x7BU,
1020*cc672e1fSJorge Ramirez-Ortiz 		0xA9U, 0x8BU, 0xF5U, 0x56U, 0x4DU, 0x40U, 0x18U, 0x9FU,
1021*cc672e1fSJorge Ramirez-Ortiz 	};
1022*cc672e1fSJorge Ramirez-Ortiz 	const uint8_t pers_str[TRNG_PERS_STR_LEN] = {
1023*cc672e1fSJorge Ramirez-Ortiz 		0xB2U, 0x80U, 0x7EU, 0x4CU, 0xD0U, 0xE4U, 0xE2U, 0xA9U,
1024*cc672e1fSJorge Ramirez-Ortiz 		0x2FU, 0x1FU, 0x5DU, 0xC1U, 0xA2U, 0x1FU, 0x40U, 0xFCU,
1025*cc672e1fSJorge Ramirez-Ortiz 		0x1FU, 0x24U, 0x5DU, 0x42U, 0x61U, 0x80U, 0xE6U, 0xE9U,
1026*cc672e1fSJorge Ramirez-Ortiz 		0x71U, 0x05U, 0x17U, 0x5BU, 0xAFU, 0x70U, 0x30U, 0x18U,
1027*cc672e1fSJorge Ramirez-Ortiz 		0xBCU, 0x23U, 0x18U, 0x15U, 0xCBU, 0xB8U, 0xA6U, 0x3EU,
1028*cc672e1fSJorge Ramirez-Ortiz 		0x83U, 0xB8U, 0x4AU, 0xFEU, 0x38U, 0xFCU, 0x25U, 0x87U,
1029*cc672e1fSJorge Ramirez-Ortiz 	};
1030*cc672e1fSJorge Ramirez-Ortiz 	const uint8_t expected_out[TRNG_GEN_LEN] = {
1031*cc672e1fSJorge Ramirez-Ortiz 		0x91U, 0x9AU, 0x6BU, 0x99U, 0xD5U, 0xBCU, 0x2CU, 0x11U,
1032*cc672e1fSJorge Ramirez-Ortiz 		0x5FU, 0x3AU, 0xFCU, 0x0BU, 0x0EU, 0x7BU, 0xC7U, 0x69U,
1033*cc672e1fSJorge Ramirez-Ortiz 		0x4DU, 0xE1U, 0xE5U, 0xFEU, 0x59U, 0x9EU, 0xAAU, 0x41U,
1034*cc672e1fSJorge Ramirez-Ortiz 		0xD3U, 0x48U, 0xFDU, 0x3DU, 0xD2U, 0xC4U, 0x50U, 0x1EU,
1035*cc672e1fSJorge Ramirez-Ortiz 	};
1036*cc672e1fSJorge Ramirez-Ortiz 	uint8_t out[TRNG_GEN_LEN] = { 0 };
1037*cc672e1fSJorge Ramirez-Ortiz 
1038*cc672e1fSJorge Ramirez-Ortiz 	if (!trng)
1039*cc672e1fSJorge Ramirez-Ortiz 		return TEE_ERROR_GENERIC;
1040*cc672e1fSJorge Ramirez-Ortiz 
1041*cc672e1fSJorge Ramirez-Ortiz 	memcpy(&tests.init_seed, ext_seed, sizeof(ext_seed));
1042*cc672e1fSJorge Ramirez-Ortiz 	memcpy(tests.pstr, pers_str, sizeof(pers_str));
1043*cc672e1fSJorge Ramirez-Ortiz 
1044*cc672e1fSJorge Ramirez-Ortiz 	if (trng_instantiate(trng, &tests))
1045*cc672e1fSJorge Ramirez-Ortiz 		goto error;
1046*cc672e1fSJorge Ramirez-Ortiz 
1047*cc672e1fSJorge Ramirez-Ortiz 	if (trng_generate(trng, out, sizeof(out), false))
1048*cc672e1fSJorge Ramirez-Ortiz 		goto error;
1049*cc672e1fSJorge Ramirez-Ortiz 
1050*cc672e1fSJorge Ramirez-Ortiz 	if (memcmp(out, expected_out, TRNG_GEN_LEN)) {
1051*cc672e1fSJorge Ramirez-Ortiz 		EMSG("K.A.T mismatch");
1052*cc672e1fSJorge Ramirez-Ortiz 		goto error;
1053*cc672e1fSJorge Ramirez-Ortiz 	}
1054*cc672e1fSJorge Ramirez-Ortiz 
1055*cc672e1fSJorge Ramirez-Ortiz 	if (trng_release(trng))
1056*cc672e1fSJorge Ramirez-Ortiz 		goto error;
1057*cc672e1fSJorge Ramirez-Ortiz 
1058*cc672e1fSJorge Ramirez-Ortiz 	return TEE_SUCCESS;
1059*cc672e1fSJorge Ramirez-Ortiz error:
1060*cc672e1fSJorge Ramirez-Ortiz 	trng->status = TRNG_ERROR;
1061*cc672e1fSJorge Ramirez-Ortiz 	return TEE_ERROR_GENERIC;
1062*cc672e1fSJorge Ramirez-Ortiz }
1063*cc672e1fSJorge Ramirez-Ortiz 
1064*cc672e1fSJorge Ramirez-Ortiz static struct versal_trng versal_trng = {
1065*cc672e1fSJorge Ramirez-Ortiz 	.cfg.base = TRNG_BASE,
1066*cc672e1fSJorge Ramirez-Ortiz 	.cfg.len = TRNG_SIZE,
1067*cc672e1fSJorge Ramirez-Ortiz };
1068*cc672e1fSJorge Ramirez-Ortiz 
hw_get_random_bytes(void * buf,size_t len)1069*cc672e1fSJorge Ramirez-Ortiz TEE_Result hw_get_random_bytes(void *buf, size_t len)
1070*cc672e1fSJorge Ramirez-Ortiz {
1071*cc672e1fSJorge Ramirez-Ortiz 	uint8_t random[TRNG_SEC_STRENGTH_LEN] = { 0 };
1072*cc672e1fSJorge Ramirez-Ortiz 	uint8_t *p = buf;
1073*cc672e1fSJorge Ramirez-Ortiz 	size_t i = 0;
1074*cc672e1fSJorge Ramirez-Ortiz 
1075*cc672e1fSJorge Ramirez-Ortiz 	for (i = 0; i < len / TRNG_SEC_STRENGTH_LEN; i++) {
1076*cc672e1fSJorge Ramirez-Ortiz 		if (trng_generate(&versal_trng, p + i * TRNG_SEC_STRENGTH_LEN,
1077*cc672e1fSJorge Ramirez-Ortiz 				  TRNG_SEC_STRENGTH_LEN, false))
1078*cc672e1fSJorge Ramirez-Ortiz 			panic();
1079*cc672e1fSJorge Ramirez-Ortiz 	}
1080*cc672e1fSJorge Ramirez-Ortiz 
1081*cc672e1fSJorge Ramirez-Ortiz 	if (len % TRNG_SEC_STRENGTH_LEN) {
1082*cc672e1fSJorge Ramirez-Ortiz 		if (trng_generate(&versal_trng, random, TRNG_SEC_STRENGTH_LEN,
1083*cc672e1fSJorge Ramirez-Ortiz 				  false))
1084*cc672e1fSJorge Ramirez-Ortiz 			panic();
1085*cc672e1fSJorge Ramirez-Ortiz 		memcpy(p + i * TRNG_SEC_STRENGTH_LEN, random,
1086*cc672e1fSJorge Ramirez-Ortiz 		       len % TRNG_SEC_STRENGTH_LEN);
1087*cc672e1fSJorge Ramirez-Ortiz 	}
1088*cc672e1fSJorge Ramirez-Ortiz 
1089*cc672e1fSJorge Ramirez-Ortiz 	return TEE_SUCCESS;
1090*cc672e1fSJorge Ramirez-Ortiz }
1091*cc672e1fSJorge Ramirez-Ortiz 
plat_rng_init(void)1092*cc672e1fSJorge Ramirez-Ortiz void plat_rng_init(void)
1093*cc672e1fSJorge Ramirez-Ortiz {
1094*cc672e1fSJorge Ramirez-Ortiz }
1095*cc672e1fSJorge Ramirez-Ortiz 
trng_hrng_mode_init(void)1096*cc672e1fSJorge Ramirez-Ortiz static TEE_Result trng_hrng_mode_init(void)
1097*cc672e1fSJorge Ramirez-Ortiz {
1098*cc672e1fSJorge Ramirez-Ortiz 	const uint8_t pers_str[TRNG_PERS_STR_LEN] = {
1099*cc672e1fSJorge Ramirez-Ortiz 		0xB2, 0x80, 0x7E, 0x4C, 0xD0, 0xE4, 0xE2, 0xA9,
1100*cc672e1fSJorge Ramirez-Ortiz 		0x2F, 0x1F, 0x5D, 0xC1, 0xA2, 0x1F, 0x40, 0xFC,
1101*cc672e1fSJorge Ramirez-Ortiz 		0x1F, 0x24, 0x5D, 0x42, 0x61, 0x80, 0xE6, 0xE9,
1102*cc672e1fSJorge Ramirez-Ortiz 		0x71, 0x05, 0x17, 0x5B, 0xAF, 0x70, 0x30, 0x18,
1103*cc672e1fSJorge Ramirez-Ortiz 		0xBC, 0x23, 0x18, 0x15, 0xCB, 0xB8, 0xA6, 0x3E,
1104*cc672e1fSJorge Ramirez-Ortiz 		0x83, 0xB8, 0x4A, 0xFE, 0x38, 0xFC, 0x25, 0x87,
1105*cc672e1fSJorge Ramirez-Ortiz 	};
1106*cc672e1fSJorge Ramirez-Ortiz 	/* configure in hybrid mode with derivative function enabled */
1107*cc672e1fSJorge Ramirez-Ortiz 	struct trng_usr_cfg usr_cfg = {
1108*cc672e1fSJorge Ramirez-Ortiz 		.mode = TRNG_HRNG,
1109*cc672e1fSJorge Ramirez-Ortiz 		.seed_life = CFG_VERSAL_TRNG_SEED_LIFE,
1110*cc672e1fSJorge Ramirez-Ortiz 		.predict_en = false,
1111*cc672e1fSJorge Ramirez-Ortiz 		.df_disable = false,
1112*cc672e1fSJorge Ramirez-Ortiz 		.dfmul = CFG_VERSAL_TRNG_DF_MUL,
1113*cc672e1fSJorge Ramirez-Ortiz 		.iseed_en =  false,
1114*cc672e1fSJorge Ramirez-Ortiz 		.pstr_en = true,
1115*cc672e1fSJorge Ramirez-Ortiz 	};
1116*cc672e1fSJorge Ramirez-Ortiz 
1117*cc672e1fSJorge Ramirez-Ortiz 	memcpy(usr_cfg.pstr, pers_str, TRNG_PERS_STR_LEN);
1118*cc672e1fSJorge Ramirez-Ortiz 	versal_trng.cfg.addr = (vaddr_t)core_mmu_add_mapping(MEM_AREA_IO_SEC,
1119*cc672e1fSJorge Ramirez-Ortiz 						     versal_trng.cfg.base,
1120*cc672e1fSJorge Ramirez-Ortiz 						     versal_trng.cfg.len);
1121*cc672e1fSJorge Ramirez-Ortiz 	if (!versal_trng.cfg.addr) {
1122*cc672e1fSJorge Ramirez-Ortiz 		EMSG("Failed to map TRNG");
1123*cc672e1fSJorge Ramirez-Ortiz 		panic();
1124*cc672e1fSJorge Ramirez-Ortiz 	}
1125*cc672e1fSJorge Ramirez-Ortiz 
1126*cc672e1fSJorge Ramirez-Ortiz 	if (trng_kat_test(&versal_trng)) {
1127*cc672e1fSJorge Ramirez-Ortiz 		EMSG("KAT Failed");
1128*cc672e1fSJorge Ramirez-Ortiz 		panic();
1129*cc672e1fSJorge Ramirez-Ortiz 	}
1130*cc672e1fSJorge Ramirez-Ortiz 
1131*cc672e1fSJorge Ramirez-Ortiz 	if (trng_health_test(&versal_trng)) {
1132*cc672e1fSJorge Ramirez-Ortiz 		EMSG("RunHealthTest Failed");
1133*cc672e1fSJorge Ramirez-Ortiz 		panic();
1134*cc672e1fSJorge Ramirez-Ortiz 	}
1135*cc672e1fSJorge Ramirez-Ortiz 
1136*cc672e1fSJorge Ramirez-Ortiz 	if (trng_instantiate(&versal_trng, &usr_cfg)) {
1137*cc672e1fSJorge Ramirez-Ortiz 		EMSG("Driver instantiation Failed");
1138*cc672e1fSJorge Ramirez-Ortiz 		panic();
1139*cc672e1fSJorge Ramirez-Ortiz 	}
1140*cc672e1fSJorge Ramirez-Ortiz 
1141*cc672e1fSJorge Ramirez-Ortiz 	if (trng_reseed(&versal_trng, NULL, usr_cfg.dfmul)) {
1142*cc672e1fSJorge Ramirez-Ortiz 		EMSG("Reseed Failed");
1143*cc672e1fSJorge Ramirez-Ortiz 		panic();
1144*cc672e1fSJorge Ramirez-Ortiz 	}
1145*cc672e1fSJorge Ramirez-Ortiz 
1146*cc672e1fSJorge Ramirez-Ortiz 	return TEE_SUCCESS;
1147*cc672e1fSJorge Ramirez-Ortiz }
1148*cc672e1fSJorge Ramirez-Ortiz 
1149*cc672e1fSJorge Ramirez-Ortiz driver_init(trng_hrng_mode_init);
1150