xref: /qemu/tests/qtest/xlnx-versal-trng-test.c (revision 9c707525)
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 
95 static void trng_test_start(void)
96 {
97     qtest_start("-machine xlnx-versal-virt");
98 }
99 
100 static void trng_test_stop(void)
101 {
102     qtest_end();
103 }
104 
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 
121 static void trng_write(unsigned ra, uint32_t val)
122 {
123     writel(TRNG_BASEADDR + ra, val);
124 }
125 
126 static uint32_t trng_read(unsigned ra)
127 {
128     return readl(TRNG_BASEADDR + ra);
129 }
130 
131 static void trng_bit_set(unsigned ra, uint32_t bits)
132 {
133     trng_write(ra, (trng_read(ra) | bits));
134 }
135 
136 static void trng_bit_clr(unsigned ra, uint32_t bits)
137 {
138     trng_write(ra, (trng_read(ra) & ~bits));
139 }
140 
141 static void trng_ctrl_set(uint32_t bits)
142 {
143     trng_bit_set(R_TRNG_CTRL, bits);
144 }
145 
146 static void trng_ctrl_clr(uint32_t bits)
147 {
148     trng_bit_clr(R_TRNG_CTRL, bits);
149 }
150 
151 static uint32_t trng_status(void)
152 {
153     return trng_read(R_TRNG_STATUS);
154 }
155 
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 
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 
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 
208 static void trng_check_done_status(const char *act)
209 {
210     trng_check_status(TRNG_STATUS_DONE_MASK, act);
211 }
212 
213 static void trng_check_dtf_status(void)
214 {
215     trng_check_status(TRNG_STATUS_DTF_MASK, "DTF injection");
216 }
217 
218 static void trng_check_certf_status(void)
219 {
220     trng_check_status(TRNG_STATUS_CERTF_MASK, "CERTF injection");
221 }
222 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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