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