1 /*
2 * QTests for the Xilinx Versal True Random Number Generator device
3 *
4 * Copyright (c) 2023 Advanced Micro Devices, Inc.
5 *
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
8
9 #include "qemu/osdep.h"
10 #include "libqtest-single.h"
11
12 /* Base Address */
13 #define TRNG_BASEADDR (0xf1230000)
14
15 /* TRNG_INT_CTRL */
16 #define R_TRNG_INT_CTRL (0x0000)
17 #define TRNG_INT_CTRL_CERTF_RST_MASK (1 << 5)
18 #define TRNG_INT_CTRL_DTF_RST_MASK (1 << 4)
19 #define TRNG_INT_CTRL_DONE_RST_MASK (1 << 3)
20 #define TRNG_INT_CTRL_CERTF_EN_MASK (1 << 2)
21 #define TRNG_INT_CTRL_DTF_EN_MASK (1 << 1)
22 #define TRNG_INT_CTRL_DONE_EN_MASK (1)
23
24 /* TRNG_STATUS */
25 #define R_TRNG_STATUS (0x0004)
26 #define TRNG_STATUS_QCNT_SHIFT (9)
27 #define TRNG_STATUS_QCNT_MASK (7 << TRNG_STATUS_QCNT_SHIFT)
28 #define TRNG_STATUS_CERTF_MASK (1 << 3)
29 #define TRNG_STATUS_DTF_MASK (1 << 1)
30 #define TRNG_STATUS_DONE_MASK (1)
31
32 /* TRNG_CTRL */
33 #define R_TRNG_CTRL (0x0008)
34 #define TRNG_CTRL_PERSODISABLE_MASK (1 << 10)
35 #define TRNG_CTRL_SINGLEGENMODE_MASK (1 << 9)
36 #define TRNG_CTRL_PRNGMODE_MASK (1 << 7)
37 #define TRNG_CTRL_TSTMODE_MASK (1 << 6)
38 #define TRNG_CTRL_PRNGSTART_MASK (1 << 5)
39 #define TRNG_CTRL_PRNGXS_MASK (1 << 3)
40 #define TRNG_CTRL_TRSSEN_MASK (1 << 2)
41 #define TRNG_CTRL_QERTUEN_MASK (1 << 1)
42 #define TRNG_CTRL_PRNGSRST_MASK (1)
43
44 /* TRNG_EXT_SEED_0 ... _11 */
45 #define R_TRNG_EXT_SEED_0 (0x0040)
46 #define R_TRNG_EXT_SEED_11 (R_TRNG_EXT_SEED_0 + 4 * 11)
47
48 /* TRNG_PER_STRNG_0 ... 11 */
49 #define R_TRNG_PER_STRNG_0 (0x0080)
50 #define R_TRNG_PER_STRNG_11 (R_TRNG_PER_STRNG_0 + 4 * 11)
51
52 /* TRNG_CORE_OUTPUT */
53 #define R_TRNG_CORE_OUTPUT (0x00c0)
54
55 /* TRNG_RESET */
56 #define R_TRNG_RESET (0x00d0)
57 #define TRNG_RESET_VAL_MASK (1)
58
59 /* TRNG_OSC_EN */
60 #define R_TRNG_OSC_EN (0x00d4)
61 #define TRNG_OSC_EN_VAL_MASK (1)
62
63 /* TRNG_TRNG_ISR, _IMR, _IER, _IDR */
64 #define R_TRNG_ISR (0x00e0)
65 #define R_TRNG_IMR (0x00e4)
66 #define R_TRNG_IER (0x00e8)
67 #define R_TRNG_IDR (0x00ec)
68 #define TRNG_IRQ_SLVERR_MASK (1 << 1)
69 #define TRNG_IRQ_CORE_INT_MASK (1)
70
71 /*
72 * End test with a formatted error message, by embedding the message
73 * in a GError.
74 */
75 #define TRNG_FAILED(FMT, ...) \
76 do { \
77 g_autoptr(GError) err = g_error_new( \
78 g_quark_from_static_string(trng_qname), 0, \
79 FMT, ## __VA_ARGS__); \
80 g_assert_no_error(err); \
81 } while (0)
82
83 static const gchar trng_qname[] = "xlnx-versal-trng-test";
84
85 static const uint32_t prng_seed[12] = {
86 0x01234567, 0x12345678, 0x23456789, 0x3456789a, 0x456789ab, 0x56789abc,
87 0x76543210, 0x87654321, 0x98765432, 0xa9876543, 0xba987654, 0xfedcba98,
88 };
89
90 static const uint32_t pers_str[12] = {
91 0x76543210, 0x87654321, 0x98765432, 0xa9876543, 0xba987654, 0xfedcba98,
92 0x01234567, 0x12345678, 0x23456789, 0x3456789a, 0x456789ab, 0x56789abc,
93 };
94
trng_test_start(void)95 static void trng_test_start(void)
96 {
97 qtest_start("-machine xlnx-versal-virt");
98 }
99
trng_test_stop(void)100 static void trng_test_stop(void)
101 {
102 qtest_end();
103 }
104
trng_test_set_uint_prop(const char * name,uint64_t value)105 static void trng_test_set_uint_prop(const char *name, uint64_t value)
106 {
107 const char *path = "/machine/xlnx-versal/trng";
108 QDict *response;
109
110 response = qmp("{ 'execute': 'qom-set',"
111 " 'arguments': {"
112 " 'path': %s,"
113 " 'property': %s,"
114 " 'value': %llu"
115 "} }", path,
116 name, (unsigned long long)value);
117 g_assert(qdict_haskey(response, "return"));
118 qobject_unref(response);
119 }
120
trng_write(unsigned ra,uint32_t val)121 static void trng_write(unsigned ra, uint32_t val)
122 {
123 writel(TRNG_BASEADDR + ra, val);
124 }
125
trng_read(unsigned ra)126 static uint32_t trng_read(unsigned ra)
127 {
128 return readl(TRNG_BASEADDR + ra);
129 }
130
trng_bit_set(unsigned ra,uint32_t bits)131 static void trng_bit_set(unsigned ra, uint32_t bits)
132 {
133 trng_write(ra, (trng_read(ra) | bits));
134 }
135
trng_bit_clr(unsigned ra,uint32_t bits)136 static void trng_bit_clr(unsigned ra, uint32_t bits)
137 {
138 trng_write(ra, (trng_read(ra) & ~bits));
139 }
140
trng_ctrl_set(uint32_t bits)141 static void trng_ctrl_set(uint32_t bits)
142 {
143 trng_bit_set(R_TRNG_CTRL, bits);
144 }
145
trng_ctrl_clr(uint32_t bits)146 static void trng_ctrl_clr(uint32_t bits)
147 {
148 trng_bit_clr(R_TRNG_CTRL, bits);
149 }
150
trng_status(void)151 static uint32_t trng_status(void)
152 {
153 return trng_read(R_TRNG_STATUS);
154 }
155
trng_qcnt(void)156 static unsigned trng_qcnt(void)
157 {
158 uint32_t sta = trng_status();
159
160 return (sta & TRNG_STATUS_QCNT_MASK) >> TRNG_STATUS_QCNT_SHIFT;
161 }
162
trng_info(void)163 static const char *trng_info(void)
164 {
165 uint32_t sta = trng_status();
166 uint32_t ctl = trng_read(R_TRNG_CTRL);
167
168 static char info[64];
169
170 snprintf(info, sizeof(info), "; status=0x%x, ctrl=0x%x", sta, ctl);
171 return info;
172 }
173
trng_check_status(uint32_t status_mask,const char * act)174 static void trng_check_status(uint32_t status_mask, const char *act)
175 {
176 uint32_t clear_mask = 0;
177 uint32_t status;
178
179 /*
180 * Only selected bits are events in R_TRNG_STATUS, and
181 * clear them needs to go through R_INT_CTRL.
182 */
183 if (status_mask & TRNG_STATUS_CERTF_MASK) {
184 clear_mask |= TRNG_INT_CTRL_CERTF_RST_MASK;
185 }
186 if (status_mask & TRNG_STATUS_DTF_MASK) {
187 clear_mask |= TRNG_INT_CTRL_DTF_RST_MASK;
188 }
189 if (status_mask & TRNG_STATUS_DONE_MASK) {
190 clear_mask |= TRNG_INT_CTRL_DONE_RST_MASK;
191 }
192
193 status = trng_status();
194 if ((status & status_mask) != status_mask) {
195 TRNG_FAILED("%s: Status bitmask 0x%x failed to be 1%s",
196 act, status_mask, trng_info());
197 }
198
199 /* Remove event */
200 trng_bit_set(R_TRNG_INT_CTRL, clear_mask);
201
202 if (!!(trng_read(R_TRNG_STATUS) & status_mask)) {
203 TRNG_FAILED("%s: Event 0x%0x stuck at 1 after clear: %s",
204 act, status_mask, trng_info());
205 }
206 }
207
trng_check_done_status(const char * act)208 static void trng_check_done_status(const char *act)
209 {
210 trng_check_status(TRNG_STATUS_DONE_MASK, act);
211 }
212
trng_check_dtf_status(void)213 static void trng_check_dtf_status(void)
214 {
215 trng_check_status(TRNG_STATUS_DTF_MASK, "DTF injection");
216 }
217
trng_check_certf_status(void)218 static void trng_check_certf_status(void)
219 {
220 trng_check_status(TRNG_STATUS_CERTF_MASK, "CERTF injection");
221 }
222
trng_reset(void)223 static void trng_reset(void)
224 {
225 trng_write(R_TRNG_RESET, TRNG_RESET_VAL_MASK);
226 trng_write(R_TRNG_RESET, 0);
227 }
228
trng_load(unsigned r0,const uint32_t * b384)229 static void trng_load(unsigned r0, const uint32_t *b384)
230 {
231 static const uint32_t zero[12] = { 0 };
232 unsigned k;
233
234 if (!b384) {
235 b384 = zero;
236 }
237
238 for (k = 0; k < 12; k++) {
239 trng_write(r0 + 4 * k, b384[k]);
240 }
241 }
242
trng_reseed(const uint32_t * seed)243 static void trng_reseed(const uint32_t *seed)
244 {
245 const char *act;
246 uint32_t ctl;
247
248 ctl = TRNG_CTRL_PRNGSTART_MASK |
249 TRNG_CTRL_PRNGXS_MASK |
250 TRNG_CTRL_TRSSEN_MASK;
251
252 trng_ctrl_clr(ctl | TRNG_CTRL_PRNGMODE_MASK);
253
254 if (seed) {
255 trng_load(R_TRNG_EXT_SEED_0, seed);
256 act = "Reseed PRNG";
257 ctl &= ~TRNG_CTRL_TRSSEN_MASK;
258 } else {
259 trng_write(R_TRNG_OSC_EN, TRNG_OSC_EN_VAL_MASK);
260 act = "Reseed TRNG";
261 ctl &= ~TRNG_CTRL_PRNGXS_MASK;
262 }
263
264 trng_ctrl_set(ctl);
265 trng_check_done_status(act);
266 trng_ctrl_clr(TRNG_CTRL_PRNGSTART_MASK);
267 }
268
trng_generate(bool auto_enb)269 static void trng_generate(bool auto_enb)
270 {
271 uint32_t ctl;
272
273 ctl = TRNG_CTRL_PRNGSTART_MASK | TRNG_CTRL_SINGLEGENMODE_MASK;
274 trng_ctrl_clr(ctl);
275
276 if (auto_enb) {
277 ctl &= ~TRNG_CTRL_SINGLEGENMODE_MASK;
278 }
279
280 trng_ctrl_set(ctl | TRNG_CTRL_PRNGMODE_MASK);
281
282 trng_check_done_status("Generate");
283 g_assert(trng_qcnt() != 7);
284 }
285
trng_collect(uint32_t * rnd,size_t cnt)286 static size_t trng_collect(uint32_t *rnd, size_t cnt)
287 {
288 size_t i;
289
290 for (i = 0; i < cnt; i++) {
291 if (trng_qcnt() == 0) {
292 return i;
293 }
294
295 rnd[i] = trng_read(R_TRNG_CORE_OUTPUT);
296 }
297
298 return i;
299 }
300
301 /* These tests all generate 512 bits of random data with the device */
302 #define TEST_DATA_WORDS (512 / 32)
303
trng_test_autogen(void)304 static void trng_test_autogen(void)
305 {
306 const size_t cnt = TEST_DATA_WORDS;
307 uint32_t rng[TEST_DATA_WORDS], prng[TEST_DATA_WORDS];
308 size_t n;
309
310 trng_reset();
311
312 /* PRNG run #1 */
313 trng_reseed(prng_seed);
314 trng_generate(true);
315
316 n = trng_collect(prng, cnt);
317 if (n != cnt) {
318 TRNG_FAILED("PRNG_1 Auto-gen test failed: expected = %u, got = %u",
319 (unsigned)cnt, (unsigned)n);
320 }
321
322 /* TRNG, should not match PRNG */
323 trng_reseed(NULL);
324 trng_generate(true);
325
326 n = trng_collect(rng, cnt);
327 if (n != cnt) {
328 TRNG_FAILED("TRNG Auto-gen test failed: expected = %u, got = %u",
329 (unsigned)cnt, (unsigned)n);
330 }
331
332 /* PRNG #2: should matches run #1 */
333 trng_reseed(prng_seed);
334 trng_generate(true);
335
336 n = trng_collect(rng, cnt);
337 if (n != cnt) {
338 TRNG_FAILED("PRNG_2 Auto-gen test failed: expected = %u, got = %u",
339 (unsigned)cnt, (unsigned)n);
340 }
341
342 if (memcmp(rng, prng, sizeof(rng))) {
343 TRNG_FAILED("PRNG_2 Auto-gen test failed: does not match PRNG_1");
344 }
345 }
346
trng_test_oneshot(void)347 static void trng_test_oneshot(void)
348 {
349 const size_t cnt = TEST_DATA_WORDS;
350 uint32_t rng[TEST_DATA_WORDS];
351 size_t n;
352
353 trng_reset();
354
355 /* PRNG run #1 */
356 trng_reseed(prng_seed);
357 trng_generate(false);
358
359 n = trng_collect(rng, cnt);
360 if (n == cnt) {
361 TRNG_FAILED("PRNG_1 One-shot gen test failed");
362 }
363
364 /* TRNG, should not match PRNG */
365 trng_reseed(NULL);
366 trng_generate(false);
367
368 n = trng_collect(rng, cnt);
369 if (n == cnt) {
370 TRNG_FAILED("TRNG One-shot test failed");
371 }
372 }
373
trng_test_per_str(void)374 static void trng_test_per_str(void)
375 {
376 const size_t cnt = TEST_DATA_WORDS;
377 uint32_t rng[TEST_DATA_WORDS], prng[TEST_DATA_WORDS];
378 size_t n;
379
380 trng_reset();
381
382 /* #1: disabled */
383 trng_ctrl_set(TRNG_CTRL_PERSODISABLE_MASK);
384 trng_reseed(prng_seed);
385 trng_ctrl_clr(TRNG_CTRL_PERSODISABLE_MASK);
386
387 trng_generate(true);
388 n = trng_collect(prng, cnt);
389 g_assert_cmpuint(n, ==, cnt);
390
391 /* #2: zero string should match personalization disabled */
392 trng_load(R_TRNG_PER_STRNG_0, NULL);
393 trng_reseed(prng_seed);
394
395 trng_generate(true);
396 n = trng_collect(rng, cnt);
397 g_assert_cmpuint(n, ==, cnt);
398
399 if (memcmp(rng, prng, sizeof(rng))) {
400 TRNG_FAILED("Failed: PER_DISABLE != PER_STRNG_ALL_ZERO");
401 }
402
403 /* #3: non-zero string should not match personalization disabled */
404 trng_load(R_TRNG_PER_STRNG_0, pers_str);
405 trng_reseed(prng_seed);
406
407 trng_generate(true);
408 n = trng_collect(rng, cnt);
409 g_assert_cmpuint(n, ==, cnt);
410
411 if (!memcmp(rng, prng, sizeof(rng))) {
412 TRNG_FAILED("Failed: PER_DISABLE == PER_STRNG_NON_ZERO");
413 }
414 }
415
trng_test_forced_prng(void)416 static void trng_test_forced_prng(void)
417 {
418 const char *prop = "forced-prng";
419 const uint64_t seed = 0xdeadbeefbad1bad0ULL;
420
421 const size_t cnt = TEST_DATA_WORDS;
422 uint32_t rng[TEST_DATA_WORDS], prng[TEST_DATA_WORDS];
423 size_t n;
424
425 trng_reset();
426 trng_test_set_uint_prop(prop, seed);
427
428 /* TRNG run #1 */
429 trng_reset();
430 trng_reseed(NULL);
431 trng_generate(true);
432
433 n = trng_collect(prng, cnt);
434 g_assert_cmpuint(n, ==, cnt);
435
436 /* TRNG run #2 should match run #1 */
437 trng_reset();
438 trng_reseed(NULL);
439 trng_generate(true);
440
441 n = trng_collect(rng, cnt);
442 g_assert_cmpuint(n, ==, cnt);
443
444 if (memcmp(rng, prng, sizeof(rng))) {
445 TRNG_FAILED("Forced-prng test failed: results do not match");
446 }
447 }
448
trng_test_fault_events(void)449 static void trng_test_fault_events(void)
450 {
451 const char *prop = "fips-fault-events";
452
453 trng_reset();
454
455 /* Fault events only when TRSS is enabled */
456 trng_write(R_TRNG_OSC_EN, TRNG_OSC_EN_VAL_MASK);
457 trng_ctrl_set(TRNG_CTRL_TRSSEN_MASK);
458
459 trng_test_set_uint_prop(prop, TRNG_STATUS_CERTF_MASK);
460 trng_check_certf_status();
461
462 trng_test_set_uint_prop(prop, TRNG_STATUS_DTF_MASK);
463 trng_check_dtf_status();
464
465 trng_reset();
466 }
467
main(int argc,char ** argv)468 int main(int argc, char **argv)
469 {
470 int rc;
471
472 g_test_init(&argc, &argv, NULL);
473
474 #define TRNG_TEST_ADD(n) \
475 qtest_add_func("/hw/misc/xlnx-versal-trng/" #n, trng_test_ ## n);
476 TRNG_TEST_ADD(autogen);
477 TRNG_TEST_ADD(oneshot);
478 TRNG_TEST_ADD(per_str);
479 TRNG_TEST_ADD(forced_prng);
480 TRNG_TEST_ADD(fault_events);
481 #undef TRNG_TEST_ADD
482
483 trng_test_start();
484 rc = g_test_run();
485 trng_test_stop();
486
487 return rc;
488 }
489