1*92192358STong Ho /* 2*92192358STong Ho * Non-crypto strength model of the True Random Number Generator 3*92192358STong Ho * in the AMD/Xilinx Versal device family. 4*92192358STong Ho * 5*92192358STong Ho * Copyright (c) 2017-2020 Xilinx Inc. 6*92192358STong Ho * Copyright (c) 2023 Advanced Micro Devices, Inc. 7*92192358STong Ho * 8*92192358STong Ho * Written by Edgar E. Iglesias <edgar.iglesias@xilinx.com> 9*92192358STong Ho * 10*92192358STong Ho * Permission is hereby granted, free of charge, to any person obtaining a copy 11*92192358STong Ho * of this software and associated documentation files (the "Software"), to deal 12*92192358STong Ho * in the Software without restriction, including without limitation the rights 13*92192358STong Ho * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14*92192358STong Ho * copies of the Software, and to permit persons to whom the Software is 15*92192358STong Ho * furnished to do so, subject to the following conditions: 16*92192358STong Ho * 17*92192358STong Ho * The above copyright notice and this permission notice shall be included in 18*92192358STong Ho * all copies or substantial portions of the Software. 19*92192358STong Ho * 20*92192358STong Ho * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21*92192358STong Ho * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22*92192358STong Ho * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 23*92192358STong Ho * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24*92192358STong Ho * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25*92192358STong Ho * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26*92192358STong Ho * THE SOFTWARE. 27*92192358STong Ho */ 28*92192358STong Ho #include "qemu/osdep.h" 29*92192358STong Ho #include "hw/misc/xlnx-versal-trng.h" 30*92192358STong Ho 31*92192358STong Ho #include "qemu/bitops.h" 32*92192358STong Ho #include "qemu/log.h" 33*92192358STong Ho #include "qemu/error-report.h" 34*92192358STong Ho #include "qemu/guest-random.h" 35*92192358STong Ho #include "qemu/timer.h" 36*92192358STong Ho #include "qapi/visitor.h" 37*92192358STong Ho #include "migration/vmstate.h" 38*92192358STong Ho #include "hw/qdev-properties.h" 39*92192358STong Ho 40*92192358STong Ho #ifndef XLNX_VERSAL_TRNG_ERR_DEBUG 41*92192358STong Ho #define XLNX_VERSAL_TRNG_ERR_DEBUG 0 42*92192358STong Ho #endif 43*92192358STong Ho 44*92192358STong Ho REG32(INT_CTRL, 0x0) 45*92192358STong Ho FIELD(INT_CTRL, CERTF_RST, 5, 1) 46*92192358STong Ho FIELD(INT_CTRL, DTF_RST, 4, 1) 47*92192358STong Ho FIELD(INT_CTRL, DONE_RST, 3, 1) 48*92192358STong Ho FIELD(INT_CTRL, CERTF_EN, 2, 1) 49*92192358STong Ho FIELD(INT_CTRL, DTF_EN, 1, 1) 50*92192358STong Ho FIELD(INT_CTRL, DONE_EN, 0, 1) 51*92192358STong Ho REG32(STATUS, 0x4) 52*92192358STong Ho FIELD(STATUS, QCNT, 9, 3) 53*92192358STong Ho FIELD(STATUS, EAT, 4, 5) 54*92192358STong Ho FIELD(STATUS, CERTF, 3, 1) 55*92192358STong Ho FIELD(STATUS, DTF, 1, 1) 56*92192358STong Ho FIELD(STATUS, DONE, 0, 1) 57*92192358STong Ho REG32(CTRL, 0x8) 58*92192358STong Ho FIELD(CTRL, PERSODISABLE, 10, 1) 59*92192358STong Ho FIELD(CTRL, SINGLEGENMODE, 9, 1) 60*92192358STong Ho FIELD(CTRL, EUMODE, 8, 1) 61*92192358STong Ho FIELD(CTRL, PRNGMODE, 7, 1) 62*92192358STong Ho FIELD(CTRL, TSTMODE, 6, 1) 63*92192358STong Ho FIELD(CTRL, PRNGSTART, 5, 1) 64*92192358STong Ho FIELD(CTRL, EATAU, 4, 1) 65*92192358STong Ho FIELD(CTRL, PRNGXS, 3, 1) 66*92192358STong Ho FIELD(CTRL, TRSSEN, 2, 1) 67*92192358STong Ho FIELD(CTRL, QERTUEN, 1, 1) 68*92192358STong Ho FIELD(CTRL, PRNGSRST, 0, 1) 69*92192358STong Ho REG32(CTRL_2, 0xc) 70*92192358STong Ho FIELD(CTRL_2, REPCOUNTTESTCUTOFF, 8, 9) 71*92192358STong Ho FIELD(CTRL_2, RESERVED_7_5, 5, 3) 72*92192358STong Ho FIELD(CTRL_2, DIT, 0, 5) 73*92192358STong Ho REG32(CTRL_3, 0x10) 74*92192358STong Ho FIELD(CTRL_3, ADAPTPROPTESTCUTOFF, 8, 10) 75*92192358STong Ho FIELD(CTRL_3, DLEN, 0, 8) 76*92192358STong Ho REG32(CTRL_4, 0x14) 77*92192358STong Ho FIELD(CTRL_4, SINGLEBITRAW, 0, 1) 78*92192358STong Ho REG32(EXT_SEED_0, 0x40) 79*92192358STong Ho REG32(EXT_SEED_1, 0x44) 80*92192358STong Ho REG32(EXT_SEED_2, 0x48) 81*92192358STong Ho REG32(EXT_SEED_3, 0x4c) 82*92192358STong Ho REG32(EXT_SEED_4, 0x50) 83*92192358STong Ho REG32(EXT_SEED_5, 0x54) 84*92192358STong Ho REG32(EXT_SEED_6, 0x58) 85*92192358STong Ho REG32(EXT_SEED_7, 0x5c) 86*92192358STong Ho REG32(EXT_SEED_8, 0x60) 87*92192358STong Ho REG32(EXT_SEED_9, 0x64) 88*92192358STong Ho REG32(EXT_SEED_10, 0x68) 89*92192358STong Ho REG32(EXT_SEED_11, 0x6c) 90*92192358STong Ho REG32(PER_STRNG_0, 0x80) 91*92192358STong Ho REG32(PER_STRNG_1, 0x84) 92*92192358STong Ho REG32(PER_STRNG_2, 0x88) 93*92192358STong Ho REG32(PER_STRNG_3, 0x8c) 94*92192358STong Ho REG32(PER_STRNG_4, 0x90) 95*92192358STong Ho REG32(PER_STRNG_5, 0x94) 96*92192358STong Ho REG32(PER_STRNG_6, 0x98) 97*92192358STong Ho REG32(PER_STRNG_7, 0x9c) 98*92192358STong Ho REG32(PER_STRNG_8, 0xa0) 99*92192358STong Ho REG32(PER_STRNG_9, 0xa4) 100*92192358STong Ho REG32(PER_STRNG_10, 0xa8) 101*92192358STong Ho REG32(PER_STRNG_11, 0xac) 102*92192358STong Ho REG32(CORE_OUTPUT, 0xc0) 103*92192358STong Ho REG32(RESET, 0xd0) 104*92192358STong Ho FIELD(RESET, VAL, 0, 1) 105*92192358STong Ho REG32(OSC_EN, 0xd4) 106*92192358STong Ho FIELD(OSC_EN, VAL, 0, 1) 107*92192358STong Ho REG32(TRNG_ISR, 0xe0) 108*92192358STong Ho FIELD(TRNG_ISR, SLVERR, 1, 1) 109*92192358STong Ho FIELD(TRNG_ISR, CORE_INT, 0, 1) 110*92192358STong Ho REG32(TRNG_IMR, 0xe4) 111*92192358STong Ho FIELD(TRNG_IMR, SLVERR, 1, 1) 112*92192358STong Ho FIELD(TRNG_IMR, CORE_INT, 0, 1) 113*92192358STong Ho REG32(TRNG_IER, 0xe8) 114*92192358STong Ho FIELD(TRNG_IER, SLVERR, 1, 1) 115*92192358STong Ho FIELD(TRNG_IER, CORE_INT, 0, 1) 116*92192358STong Ho REG32(TRNG_IDR, 0xec) 117*92192358STong Ho FIELD(TRNG_IDR, SLVERR, 1, 1) 118*92192358STong Ho FIELD(TRNG_IDR, CORE_INT, 0, 1) 119*92192358STong Ho REG32(SLV_ERR_CTRL, 0xf0) 120*92192358STong Ho FIELD(SLV_ERR_CTRL, ENABLE, 0, 1) 121*92192358STong Ho 122*92192358STong Ho #define R_MAX (R_SLV_ERR_CTRL + 1) 123*92192358STong Ho 124*92192358STong Ho QEMU_BUILD_BUG_ON(R_MAX * 4 != sizeof_field(XlnxVersalTRng, regs)); 125*92192358STong Ho 126*92192358STong Ho #define TRNG_GUEST_ERROR(D, FMT, ...) \ 127*92192358STong Ho do { \ 128*92192358STong Ho g_autofree char *p = object_get_canonical_path(OBJECT(D)); \ 129*92192358STong Ho qemu_log_mask(LOG_GUEST_ERROR, "%s: " FMT, p, ## __VA_ARGS__); \ 130*92192358STong Ho } while (0) 131*92192358STong Ho 132*92192358STong Ho #define TRNG_WARN(D, FMT, ...) \ 133*92192358STong Ho do { \ 134*92192358STong Ho g_autofree char *p = object_get_canonical_path(OBJECT(D)); \ 135*92192358STong Ho warn_report("%s: " FMT, p, ## __VA_ARGS__); \ 136*92192358STong Ho } while (0) 137*92192358STong Ho 138*92192358STong Ho static bool trng_older_than_v2(XlnxVersalTRng *s) 139*92192358STong Ho { 140*92192358STong Ho return s->hw_version < 0x0200; 141*92192358STong Ho } 142*92192358STong Ho 143*92192358STong Ho static bool trng_in_reset(XlnxVersalTRng *s) 144*92192358STong Ho { 145*92192358STong Ho if (ARRAY_FIELD_EX32(s->regs, RESET, VAL)) { 146*92192358STong Ho return true; 147*92192358STong Ho } 148*92192358STong Ho if (ARRAY_FIELD_EX32(s->regs, CTRL, PRNGSRST)) { 149*92192358STong Ho return true; 150*92192358STong Ho } 151*92192358STong Ho 152*92192358STong Ho return false; 153*92192358STong Ho } 154*92192358STong Ho 155*92192358STong Ho static bool trng_test_enabled(XlnxVersalTRng *s) 156*92192358STong Ho { 157*92192358STong Ho return ARRAY_FIELD_EX32(s->regs, CTRL, TSTMODE); 158*92192358STong Ho } 159*92192358STong Ho 160*92192358STong Ho static bool trng_trss_enabled(XlnxVersalTRng *s) 161*92192358STong Ho { 162*92192358STong Ho if (trng_in_reset(s)) { 163*92192358STong Ho return false; 164*92192358STong Ho } 165*92192358STong Ho if (!ARRAY_FIELD_EX32(s->regs, CTRL, TRSSEN)) { 166*92192358STong Ho return false; 167*92192358STong Ho } 168*92192358STong Ho if (!ARRAY_FIELD_EX32(s->regs, OSC_EN, VAL)) { 169*92192358STong Ho return false; 170*92192358STong Ho } 171*92192358STong Ho 172*92192358STong Ho return true; 173*92192358STong Ho } 174*92192358STong Ho 175*92192358STong Ho static void trng_seed_128(uint32_t *seed, uint64_t h00, uint64_t h64) 176*92192358STong Ho { 177*92192358STong Ho seed[0] = extract64(h00, 0, 32); 178*92192358STong Ho seed[1] = extract64(h00, 32, 32); 179*92192358STong Ho seed[2] = extract64(h64, 0, 32); 180*92192358STong Ho seed[3] = extract64(h64, 32, 32); 181*92192358STong Ho } 182*92192358STong Ho 183*92192358STong Ho static void trng_reseed(XlnxVersalTRng *s) 184*92192358STong Ho { 185*92192358STong Ho bool ext_seed = ARRAY_FIELD_EX32(s->regs, CTRL, PRNGXS); 186*92192358STong Ho bool pers_disabled = ARRAY_FIELD_EX32(s->regs, CTRL, PERSODISABLE); 187*92192358STong Ho 188*92192358STong Ho enum { 189*92192358STong Ho U384_U8 = 384 / 8, 190*92192358STong Ho U384_U32 = 384 / 32, 191*92192358STong Ho }; 192*92192358STong Ho 193*92192358STong Ho /* 194*92192358STong Ho * Maximum seed length is len(personalized string) + len(ext seed). 195*92192358STong Ho * 196*92192358STong Ho * g_rand_set_seed_array() takes array of uint32 in host endian. 197*92192358STong Ho */ 198*92192358STong Ho guint32 gs[U384_U32 * 2], *seed = &gs[U384_U32]; 199*92192358STong Ho 200*92192358STong Ho /* 201*92192358STong Ho * A disabled personalized string is the same as 202*92192358STong Ho * a string with all zeros. 203*92192358STong Ho * 204*92192358STong Ho * The device's hardware spec defines 3 modes (all selectable 205*92192358STong Ho * by guest at will and at anytime): 206*92192358STong Ho * 1) External seeding 207*92192358STong Ho * This is a PRNG mode, in which the produced sequence shall 208*92192358STong Ho * be reproducible if reseeded by the same 384-bit seed, as 209*92192358STong Ho * supplied by guest software. 210*92192358STong Ho * 2) Test seeding 211*92192358STong Ho * This is a PRNG mode, in which the produced sequence shall 212*92192358STong Ho * be reproducible if reseeded by a 128-bit test seed, as 213*92192358STong Ho * supplied by guest software. 214*92192358STong Ho * 3) Truly-random seeding 215*92192358STong Ho * This is the TRNG mode, in which the produced sequence is 216*92192358STong Ho * periodically reseeded by a crypto-strength entropy source. 217*92192358STong Ho * 218*92192358STong Ho * To assist debugging of certain classes of software defects, 219*92192358STong Ho * this QEMU model implements a 4th mode, 220*92192358STong Ho * 4) Forced PRNG 221*92192358STong Ho * When in this mode, a reproducible sequence is generated 222*92192358STong Ho * if software has selected the TRNG mode (mode 2). 223*92192358STong Ho * 224*92192358STong Ho * This emulation-only mode can only be selected by setting 225*92192358STong Ho * the uint64 property 'forced-prng' to a non-zero value. 226*92192358STong Ho * Guest software cannot select this mode. 227*92192358STong Ho */ 228*92192358STong Ho memset(gs, 0, sizeof(gs)); 229*92192358STong Ho 230*92192358STong Ho if (!pers_disabled) { 231*92192358STong Ho memcpy(gs, &s->regs[R_PER_STRNG_0], U384_U8); 232*92192358STong Ho } 233*92192358STong Ho 234*92192358STong Ho if (ext_seed) { 235*92192358STong Ho memcpy(seed, &s->regs[R_EXT_SEED_0], U384_U8); 236*92192358STong Ho } else if (trng_test_enabled(s)) { 237*92192358STong Ho trng_seed_128(seed, s->tst_seed[0], s->tst_seed[1]); 238*92192358STong Ho } else if (s->forced_prng_seed) { 239*92192358STong Ho s->forced_prng_count++; 240*92192358STong Ho trng_seed_128(seed, s->forced_prng_count, s->forced_prng_seed); 241*92192358STong Ho } else { 242*92192358STong Ho qemu_guest_getrandom_nofail(seed, U384_U8); 243*92192358STong Ho } 244*92192358STong Ho 245*92192358STong Ho g_rand_set_seed_array(s->prng, gs, ARRAY_SIZE(gs)); 246*92192358STong Ho 247*92192358STong Ho s->rand_count = 0; 248*92192358STong Ho s->rand_reseed = 1ULL << 48; 249*92192358STong Ho } 250*92192358STong Ho 251*92192358STong Ho static void trng_regen(XlnxVersalTRng *s) 252*92192358STong Ho { 253*92192358STong Ho if (s->rand_reseed == 0) { 254*92192358STong Ho TRNG_GUEST_ERROR(s, "Too many generations without a reseed"); 255*92192358STong Ho trng_reseed(s); 256*92192358STong Ho } 257*92192358STong Ho s->rand_reseed--; 258*92192358STong Ho 259*92192358STong Ho /* 260*92192358STong Ho * In real hardware, each regen creates 256 bits, but QCNT 261*92192358STong Ho * reports a max of 4. 262*92192358STong Ho */ 263*92192358STong Ho ARRAY_FIELD_DP32(s->regs, STATUS, QCNT, 4); 264*92192358STong Ho s->rand_count = 256 / 32; 265*92192358STong Ho } 266*92192358STong Ho 267*92192358STong Ho static uint32_t trng_rdout(XlnxVersalTRng *s) 268*92192358STong Ho { 269*92192358STong Ho assert(s->rand_count); 270*92192358STong Ho 271*92192358STong Ho s->rand_count--; 272*92192358STong Ho if (s->rand_count < 4) { 273*92192358STong Ho ARRAY_FIELD_DP32(s->regs, STATUS, QCNT, s->rand_count); 274*92192358STong Ho } 275*92192358STong Ho 276*92192358STong Ho return g_rand_int(s->prng); 277*92192358STong Ho } 278*92192358STong Ho 279*92192358STong Ho static void trng_irq_update(XlnxVersalTRng *s) 280*92192358STong Ho { 281*92192358STong Ho bool pending = s->regs[R_TRNG_ISR] & ~s->regs[R_TRNG_IMR]; 282*92192358STong Ho qemu_set_irq(s->irq, pending); 283*92192358STong Ho } 284*92192358STong Ho 285*92192358STong Ho static void trng_isr_postw(RegisterInfo *reg, uint64_t val64) 286*92192358STong Ho { 287*92192358STong Ho XlnxVersalTRng *s = XLNX_VERSAL_TRNG(reg->opaque); 288*92192358STong Ho trng_irq_update(s); 289*92192358STong Ho } 290*92192358STong Ho 291*92192358STong Ho static uint64_t trng_ier_prew(RegisterInfo *reg, uint64_t val64) 292*92192358STong Ho { 293*92192358STong Ho XlnxVersalTRng *s = XLNX_VERSAL_TRNG(reg->opaque); 294*92192358STong Ho uint32_t val = val64; 295*92192358STong Ho 296*92192358STong Ho s->regs[R_TRNG_IMR] &= ~val; 297*92192358STong Ho trng_irq_update(s); 298*92192358STong Ho return 0; 299*92192358STong Ho } 300*92192358STong Ho 301*92192358STong Ho static uint64_t trng_idr_prew(RegisterInfo *reg, uint64_t val64) 302*92192358STong Ho { 303*92192358STong Ho XlnxVersalTRng *s = XLNX_VERSAL_TRNG(reg->opaque); 304*92192358STong Ho uint32_t val = val64; 305*92192358STong Ho 306*92192358STong Ho s->regs[R_TRNG_IMR] |= val; 307*92192358STong Ho trng_irq_update(s); 308*92192358STong Ho return 0; 309*92192358STong Ho } 310*92192358STong Ho 311*92192358STong Ho static void trng_core_int_update(XlnxVersalTRng *s) 312*92192358STong Ho { 313*92192358STong Ho bool pending = false; 314*92192358STong Ho uint32_t st = s->regs[R_STATUS]; 315*92192358STong Ho uint32_t en = s->regs[R_INT_CTRL]; 316*92192358STong Ho 317*92192358STong Ho if (FIELD_EX32(st, STATUS, CERTF) && FIELD_EX32(en, INT_CTRL, CERTF_EN)) { 318*92192358STong Ho pending = true; 319*92192358STong Ho } 320*92192358STong Ho 321*92192358STong Ho if (FIELD_EX32(st, STATUS, DTF) && FIELD_EX32(en, INT_CTRL, DTF_EN)) { 322*92192358STong Ho pending = true; 323*92192358STong Ho } 324*92192358STong Ho 325*92192358STong Ho if (FIELD_EX32(st, STATUS, DONE) && FIELD_EX32(en, INT_CTRL, DONE_EN)) { 326*92192358STong Ho pending = true; 327*92192358STong Ho } 328*92192358STong Ho 329*92192358STong Ho ARRAY_FIELD_DP32(s->regs, TRNG_ISR, CORE_INT, pending); 330*92192358STong Ho trng_irq_update(s); 331*92192358STong Ho } 332*92192358STong Ho 333*92192358STong Ho static void trng_int_ctrl_postw(RegisterInfo *reg, uint64_t val64) 334*92192358STong Ho { 335*92192358STong Ho XlnxVersalTRng *s = XLNX_VERSAL_TRNG(reg->opaque); 336*92192358STong Ho uint32_t v32 = val64; 337*92192358STong Ho uint32_t clr_mask = 0; 338*92192358STong Ho 339*92192358STong Ho if (FIELD_EX32(v32, INT_CTRL, CERTF_RST)) { 340*92192358STong Ho clr_mask |= R_STATUS_CERTF_MASK; 341*92192358STong Ho } 342*92192358STong Ho if (FIELD_EX32(v32, INT_CTRL, DTF_RST)) { 343*92192358STong Ho clr_mask |= R_STATUS_DTF_MASK; 344*92192358STong Ho } 345*92192358STong Ho if (FIELD_EX32(v32, INT_CTRL, DONE_RST)) { 346*92192358STong Ho clr_mask |= R_STATUS_DONE_MASK; 347*92192358STong Ho } 348*92192358STong Ho 349*92192358STong Ho s->regs[R_STATUS] &= ~clr_mask; 350*92192358STong Ho trng_core_int_update(s); 351*92192358STong Ho } 352*92192358STong Ho 353*92192358STong Ho static void trng_done(XlnxVersalTRng *s) 354*92192358STong Ho { 355*92192358STong Ho ARRAY_FIELD_DP32(s->regs, STATUS, DONE, true); 356*92192358STong Ho trng_core_int_update(s); 357*92192358STong Ho } 358*92192358STong Ho 359*92192358STong Ho static void trng_fault_event_set(XlnxVersalTRng *s, uint32_t events) 360*92192358STong Ho { 361*92192358STong Ho bool pending = false; 362*92192358STong Ho 363*92192358STong Ho /* Disabled TRSS cannot generate any fault event */ 364*92192358STong Ho if (!trng_trss_enabled(s)) { 365*92192358STong Ho return; 366*92192358STong Ho } 367*92192358STong Ho 368*92192358STong Ho if (FIELD_EX32(events, STATUS, CERTF)) { 369*92192358STong Ho /* In older version, ERTU must be enabled explicitly to get CERTF */ 370*92192358STong Ho if (trng_older_than_v2(s) && 371*92192358STong Ho !ARRAY_FIELD_EX32(s->regs, CTRL, QERTUEN)) { 372*92192358STong Ho TRNG_WARN(s, "CERTF injection ignored: ERTU disabled"); 373*92192358STong Ho } else { 374*92192358STong Ho ARRAY_FIELD_DP32(s->regs, STATUS, CERTF, true); 375*92192358STong Ho pending = true; 376*92192358STong Ho } 377*92192358STong Ho } 378*92192358STong Ho 379*92192358STong Ho if (FIELD_EX32(events, STATUS, DTF)) { 380*92192358STong Ho ARRAY_FIELD_DP32(s->regs, STATUS, DTF, true); 381*92192358STong Ho pending = true; 382*92192358STong Ho } 383*92192358STong Ho 384*92192358STong Ho if (pending) { 385*92192358STong Ho trng_core_int_update(s); 386*92192358STong Ho } 387*92192358STong Ho } 388*92192358STong Ho 389*92192358STong Ho static void trng_soft_reset(XlnxVersalTRng *s) 390*92192358STong Ho { 391*92192358STong Ho s->rand_count = 0; 392*92192358STong Ho s->regs[R_STATUS] = 0; 393*92192358STong Ho 394*92192358STong Ho ARRAY_FIELD_DP32(s->regs, TRNG_ISR, CORE_INT, 0); 395*92192358STong Ho } 396*92192358STong Ho 397*92192358STong Ho static void trng_ctrl_postw(RegisterInfo *reg, uint64_t val64) 398*92192358STong Ho { 399*92192358STong Ho XlnxVersalTRng *s = XLNX_VERSAL_TRNG(reg->opaque); 400*92192358STong Ho 401*92192358STong Ho if (trng_in_reset(s)) { 402*92192358STong Ho return; 403*92192358STong Ho } 404*92192358STong Ho 405*92192358STong Ho if (FIELD_EX32(val64, CTRL, PRNGSRST)) { 406*92192358STong Ho trng_soft_reset(s); 407*92192358STong Ho trng_irq_update(s); 408*92192358STong Ho return; 409*92192358STong Ho } 410*92192358STong Ho 411*92192358STong Ho if (!FIELD_EX32(val64, CTRL, PRNGSTART)) { 412*92192358STong Ho return; 413*92192358STong Ho } 414*92192358STong Ho 415*92192358STong Ho if (FIELD_EX32(val64, CTRL, PRNGMODE)) { 416*92192358STong Ho trng_regen(s); 417*92192358STong Ho } else { 418*92192358STong Ho trng_reseed(s); 419*92192358STong Ho } 420*92192358STong Ho 421*92192358STong Ho trng_done(s); 422*92192358STong Ho } 423*92192358STong Ho 424*92192358STong Ho static void trng_ctrl4_postw(RegisterInfo *reg, uint64_t val64) 425*92192358STong Ho { 426*92192358STong Ho XlnxVersalTRng *s = XLNX_VERSAL_TRNG(reg->opaque); 427*92192358STong Ho 428*92192358STong Ho /* Only applies to test mode with TRSS enabled */ 429*92192358STong Ho if (!trng_test_enabled(s) || !trng_trss_enabled(s)) { 430*92192358STong Ho return; 431*92192358STong Ho } 432*92192358STong Ho 433*92192358STong Ho /* Shift in a single bit. */ 434*92192358STong Ho s->tst_seed[1] <<= 1; 435*92192358STong Ho s->tst_seed[1] |= s->tst_seed[0] >> 63; 436*92192358STong Ho s->tst_seed[0] <<= 1; 437*92192358STong Ho s->tst_seed[0] |= val64 & 1; 438*92192358STong Ho 439*92192358STong Ho trng_reseed(s); 440*92192358STong Ho trng_regen(s); 441*92192358STong Ho } 442*92192358STong Ho 443*92192358STong Ho static uint64_t trng_core_out_postr(RegisterInfo *reg, uint64_t val) 444*92192358STong Ho { 445*92192358STong Ho XlnxVersalTRng *s = XLNX_VERSAL_TRNG(reg->opaque); 446*92192358STong Ho bool oneshot = ARRAY_FIELD_EX32(s->regs, CTRL, SINGLEGENMODE); 447*92192358STong Ho bool start = ARRAY_FIELD_EX32(s->regs, CTRL, PRNGSTART); 448*92192358STong Ho uint32_t r = 0xbad; 449*92192358STong Ho 450*92192358STong Ho if (trng_in_reset(s)) { 451*92192358STong Ho TRNG_GUEST_ERROR(s, "Reading random number while in reset!"); 452*92192358STong Ho return r; 453*92192358STong Ho } 454*92192358STong Ho 455*92192358STong Ho if (s->rand_count == 0) { 456*92192358STong Ho TRNG_GUEST_ERROR(s, "Reading random number when unavailable!"); 457*92192358STong Ho return r; 458*92192358STong Ho } 459*92192358STong Ho 460*92192358STong Ho r = trng_rdout(s); 461*92192358STong Ho 462*92192358STong Ho /* Automatic mode regenerates when half the output reg is empty. */ 463*92192358STong Ho if (!oneshot && start && s->rand_count <= 3) { 464*92192358STong Ho trng_regen(s); 465*92192358STong Ho } 466*92192358STong Ho 467*92192358STong Ho return r; 468*92192358STong Ho } 469*92192358STong Ho 470*92192358STong Ho static void trng_reset(XlnxVersalTRng *s) 471*92192358STong Ho { 472*92192358STong Ho unsigned int i; 473*92192358STong Ho 474*92192358STong Ho s->forced_prng_count = 0; 475*92192358STong Ho 476*92192358STong Ho for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) { 477*92192358STong Ho register_reset(&s->regs_info[i]); 478*92192358STong Ho } 479*92192358STong Ho trng_soft_reset(s); 480*92192358STong Ho trng_irq_update(s); 481*92192358STong Ho } 482*92192358STong Ho 483*92192358STong Ho static uint64_t trng_reset_prew(RegisterInfo *reg, uint64_t val64) 484*92192358STong Ho { 485*92192358STong Ho XlnxVersalTRng *s = XLNX_VERSAL_TRNG(reg->opaque); 486*92192358STong Ho 487*92192358STong Ho if (!ARRAY_FIELD_EX32(s->regs, RESET, VAL) && 488*92192358STong Ho FIELD_EX32(val64, RESET, VAL)) { 489*92192358STong Ho trng_reset(s); 490*92192358STong Ho } 491*92192358STong Ho 492*92192358STong Ho return val64; 493*92192358STong Ho } 494*92192358STong Ho 495*92192358STong Ho static uint64_t trng_register_read(void *opaque, hwaddr addr, unsigned size) 496*92192358STong Ho { 497*92192358STong Ho /* 498*92192358STong Ho * Guest provided seed and personalized strings cannot be 499*92192358STong Ho * read back, and read attempts return value of A_STATUS. 500*92192358STong Ho */ 501*92192358STong Ho switch (addr) { 502*92192358STong Ho case A_EXT_SEED_0 ... A_PER_STRNG_11: 503*92192358STong Ho addr = A_STATUS; 504*92192358STong Ho break; 505*92192358STong Ho } 506*92192358STong Ho 507*92192358STong Ho return register_read_memory(opaque, addr, size); 508*92192358STong Ho } 509*92192358STong Ho 510*92192358STong Ho static void trng_register_write(void *opaque, hwaddr addr, 511*92192358STong Ho uint64_t value, unsigned size) 512*92192358STong Ho { 513*92192358STong Ho RegisterInfoArray *reg_array = opaque; 514*92192358STong Ho XlnxVersalTRng *s = XLNX_VERSAL_TRNG(reg_array->r[0]->opaque); 515*92192358STong Ho 516*92192358STong Ho if (trng_older_than_v2(s)) { 517*92192358STong Ho switch (addr) { 518*92192358STong Ho case A_CTRL: 519*92192358STong Ho value = FIELD_DP64(value, CTRL, PERSODISABLE, 0); 520*92192358STong Ho value = FIELD_DP64(value, CTRL, SINGLEGENMODE, 0); 521*92192358STong Ho break; 522*92192358STong Ho case A_CTRL_2: 523*92192358STong Ho case A_CTRL_3: 524*92192358STong Ho case A_CTRL_4: 525*92192358STong Ho return; 526*92192358STong Ho } 527*92192358STong Ho } else { 528*92192358STong Ho switch (addr) { 529*92192358STong Ho case A_CTRL: 530*92192358STong Ho value = FIELD_DP64(value, CTRL, EATAU, 0); 531*92192358STong Ho value = FIELD_DP64(value, CTRL, QERTUEN, 0); 532*92192358STong Ho break; 533*92192358STong Ho } 534*92192358STong Ho } 535*92192358STong Ho 536*92192358STong Ho register_write_memory(opaque, addr, value, size); 537*92192358STong Ho } 538*92192358STong Ho 539*92192358STong Ho static RegisterAccessInfo trng_regs_info[] = { 540*92192358STong Ho { .name = "INT_CTRL", .addr = A_INT_CTRL, 541*92192358STong Ho .post_write = trng_int_ctrl_postw, 542*92192358STong Ho },{ .name = "STATUS", .addr = A_STATUS, 543*92192358STong Ho .ro = 0xfff, 544*92192358STong Ho },{ .name = "CTRL", .addr = A_CTRL, 545*92192358STong Ho .post_write = trng_ctrl_postw, 546*92192358STong Ho },{ .name = "CTRL_2", .addr = A_CTRL_2, 547*92192358STong Ho .reset = 0x210c, 548*92192358STong Ho },{ .name = "CTRL_3", .addr = A_CTRL_3, 549*92192358STong Ho .reset = 0x26f09, 550*92192358STong Ho },{ .name = "CTRL_4", .addr = A_CTRL_4, 551*92192358STong Ho .post_write = trng_ctrl4_postw, 552*92192358STong Ho },{ .name = "EXT_SEED_0", .addr = A_EXT_SEED_0, 553*92192358STong Ho },{ .name = "EXT_SEED_1", .addr = A_EXT_SEED_1, 554*92192358STong Ho },{ .name = "EXT_SEED_2", .addr = A_EXT_SEED_2, 555*92192358STong Ho },{ .name = "EXT_SEED_3", .addr = A_EXT_SEED_3, 556*92192358STong Ho },{ .name = "EXT_SEED_4", .addr = A_EXT_SEED_4, 557*92192358STong Ho },{ .name = "EXT_SEED_5", .addr = A_EXT_SEED_5, 558*92192358STong Ho },{ .name = "EXT_SEED_6", .addr = A_EXT_SEED_6, 559*92192358STong Ho },{ .name = "EXT_SEED_7", .addr = A_EXT_SEED_7, 560*92192358STong Ho },{ .name = "EXT_SEED_8", .addr = A_EXT_SEED_8, 561*92192358STong Ho },{ .name = "EXT_SEED_9", .addr = A_EXT_SEED_9, 562*92192358STong Ho },{ .name = "EXT_SEED_10", .addr = A_EXT_SEED_10, 563*92192358STong Ho },{ .name = "EXT_SEED_11", .addr = A_EXT_SEED_11, 564*92192358STong Ho },{ .name = "PER_STRNG_0", .addr = A_PER_STRNG_0, 565*92192358STong Ho },{ .name = "PER_STRNG_1", .addr = A_PER_STRNG_1, 566*92192358STong Ho },{ .name = "PER_STRNG_2", .addr = A_PER_STRNG_2, 567*92192358STong Ho },{ .name = "PER_STRNG_3", .addr = A_PER_STRNG_3, 568*92192358STong Ho },{ .name = "PER_STRNG_4", .addr = A_PER_STRNG_4, 569*92192358STong Ho },{ .name = "PER_STRNG_5", .addr = A_PER_STRNG_5, 570*92192358STong Ho },{ .name = "PER_STRNG_6", .addr = A_PER_STRNG_6, 571*92192358STong Ho },{ .name = "PER_STRNG_7", .addr = A_PER_STRNG_7, 572*92192358STong Ho },{ .name = "PER_STRNG_8", .addr = A_PER_STRNG_8, 573*92192358STong Ho },{ .name = "PER_STRNG_9", .addr = A_PER_STRNG_9, 574*92192358STong Ho },{ .name = "PER_STRNG_10", .addr = A_PER_STRNG_10, 575*92192358STong Ho },{ .name = "PER_STRNG_11", .addr = A_PER_STRNG_11, 576*92192358STong Ho },{ .name = "CORE_OUTPUT", .addr = A_CORE_OUTPUT, 577*92192358STong Ho .ro = 0xffffffff, 578*92192358STong Ho .post_read = trng_core_out_postr, 579*92192358STong Ho },{ .name = "RESET", .addr = A_RESET, 580*92192358STong Ho .reset = 0x1, 581*92192358STong Ho .pre_write = trng_reset_prew, 582*92192358STong Ho },{ .name = "OSC_EN", .addr = A_OSC_EN, 583*92192358STong Ho },{ .name = "TRNG_ISR", .addr = A_TRNG_ISR, 584*92192358STong Ho .w1c = 0x3, 585*92192358STong Ho .post_write = trng_isr_postw, 586*92192358STong Ho },{ .name = "TRNG_IMR", .addr = A_TRNG_IMR, 587*92192358STong Ho .reset = 0x3, 588*92192358STong Ho .ro = 0x3, 589*92192358STong Ho },{ .name = "TRNG_IER", .addr = A_TRNG_IER, 590*92192358STong Ho .pre_write = trng_ier_prew, 591*92192358STong Ho },{ .name = "TRNG_IDR", .addr = A_TRNG_IDR, 592*92192358STong Ho .pre_write = trng_idr_prew, 593*92192358STong Ho },{ .name = "SLV_ERR_CTRL", .addr = A_SLV_ERR_CTRL, 594*92192358STong Ho } 595*92192358STong Ho }; 596*92192358STong Ho 597*92192358STong Ho static const MemoryRegionOps trng_ops = { 598*92192358STong Ho .read = trng_register_read, 599*92192358STong Ho .write = trng_register_write, 600*92192358STong Ho .endianness = DEVICE_LITTLE_ENDIAN, 601*92192358STong Ho .valid = { 602*92192358STong Ho .min_access_size = 4, 603*92192358STong Ho .max_access_size = 4, 604*92192358STong Ho }, 605*92192358STong Ho }; 606*92192358STong Ho 607*92192358STong Ho static void trng_init(Object *obj) 608*92192358STong Ho { 609*92192358STong Ho XlnxVersalTRng *s = XLNX_VERSAL_TRNG(obj); 610*92192358STong Ho SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 611*92192358STong Ho RegisterInfoArray *reg_array; 612*92192358STong Ho 613*92192358STong Ho reg_array = 614*92192358STong Ho register_init_block32(DEVICE(obj), trng_regs_info, 615*92192358STong Ho ARRAY_SIZE(trng_regs_info), 616*92192358STong Ho s->regs_info, s->regs, 617*92192358STong Ho &trng_ops, 618*92192358STong Ho XLNX_VERSAL_TRNG_ERR_DEBUG, 619*92192358STong Ho R_MAX * 4); 620*92192358STong Ho 621*92192358STong Ho sysbus_init_mmio(sbd, ®_array->mem); 622*92192358STong Ho sysbus_init_irq(sbd, &s->irq); 623*92192358STong Ho 624*92192358STong Ho s->prng = g_rand_new(); 625*92192358STong Ho } 626*92192358STong Ho 627*92192358STong Ho static void trng_unrealize(DeviceState *dev) 628*92192358STong Ho { 629*92192358STong Ho XlnxVersalTRng *s = XLNX_VERSAL_TRNG(dev); 630*92192358STong Ho 631*92192358STong Ho g_rand_free(s->prng); 632*92192358STong Ho s->prng = NULL; 633*92192358STong Ho } 634*92192358STong Ho 635*92192358STong Ho static void trng_reset_hold(Object *obj) 636*92192358STong Ho { 637*92192358STong Ho trng_reset(XLNX_VERSAL_TRNG(obj)); 638*92192358STong Ho } 639*92192358STong Ho 640*92192358STong Ho static void trng_prop_fault_event_set(Object *obj, Visitor *v, 641*92192358STong Ho const char *name, void *opaque, 642*92192358STong Ho Error **errp) 643*92192358STong Ho { 644*92192358STong Ho Property *prop = opaque; 645*92192358STong Ho uint32_t *events = object_field_prop_ptr(obj, prop); 646*92192358STong Ho 647*92192358STong Ho visit_type_uint32(v, name, events, errp); 648*92192358STong Ho if (*errp) { 649*92192358STong Ho return; 650*92192358STong Ho } 651*92192358STong Ho 652*92192358STong Ho trng_fault_event_set(XLNX_VERSAL_TRNG(obj), *events); 653*92192358STong Ho } 654*92192358STong Ho 655*92192358STong Ho static const PropertyInfo trng_prop_fault_events = { 656*92192358STong Ho .name = "uint32:bits", 657*92192358STong Ho .description = "Set to trigger TRNG fault events", 658*92192358STong Ho .set = trng_prop_fault_event_set, 659*92192358STong Ho .realized_set_allowed = true, 660*92192358STong Ho }; 661*92192358STong Ho 662*92192358STong Ho static PropertyInfo trng_prop_uint64; /* to extend qdev_prop_uint64 */ 663*92192358STong Ho 664*92192358STong Ho static Property trng_props[] = { 665*92192358STong Ho DEFINE_PROP_UINT64("forced-prng", XlnxVersalTRng, forced_prng_seed, 0), 666*92192358STong Ho DEFINE_PROP_UINT32("hw-version", XlnxVersalTRng, hw_version, 0x0200), 667*92192358STong Ho DEFINE_PROP("fips-fault-events", XlnxVersalTRng, forced_faults, 668*92192358STong Ho trng_prop_fault_events, uint32_t), 669*92192358STong Ho 670*92192358STong Ho DEFINE_PROP_END_OF_LIST(), 671*92192358STong Ho }; 672*92192358STong Ho 673*92192358STong Ho static const VMStateDescription vmstate_trng = { 674*92192358STong Ho .name = TYPE_XLNX_VERSAL_TRNG, 675*92192358STong Ho .version_id = 1, 676*92192358STong Ho .minimum_version_id = 1, 677*92192358STong Ho .fields = (VMStateField[]) { 678*92192358STong Ho VMSTATE_UINT32(rand_count, XlnxVersalTRng), 679*92192358STong Ho VMSTATE_UINT64(rand_reseed, XlnxVersalTRng), 680*92192358STong Ho VMSTATE_UINT64(forced_prng_count, XlnxVersalTRng), 681*92192358STong Ho VMSTATE_UINT64_ARRAY(tst_seed, XlnxVersalTRng, 2), 682*92192358STong Ho VMSTATE_UINT32_ARRAY(regs, XlnxVersalTRng, R_MAX), 683*92192358STong Ho VMSTATE_END_OF_LIST(), 684*92192358STong Ho } 685*92192358STong Ho }; 686*92192358STong Ho 687*92192358STong Ho static void trng_class_init(ObjectClass *klass, void *data) 688*92192358STong Ho { 689*92192358STong Ho DeviceClass *dc = DEVICE_CLASS(klass); 690*92192358STong Ho ResettableClass *rc = RESETTABLE_CLASS(klass); 691*92192358STong Ho 692*92192358STong Ho dc->vmsd = &vmstate_trng; 693*92192358STong Ho dc->unrealize = trng_unrealize; 694*92192358STong Ho rc->phases.hold = trng_reset_hold; 695*92192358STong Ho 696*92192358STong Ho /* Clone uint64 property with set allowed after realized */ 697*92192358STong Ho trng_prop_uint64 = qdev_prop_uint64; 698*92192358STong Ho trng_prop_uint64.realized_set_allowed = true; 699*92192358STong Ho trng_props[0].info = &trng_prop_uint64; 700*92192358STong Ho 701*92192358STong Ho device_class_set_props(dc, trng_props); 702*92192358STong Ho } 703*92192358STong Ho 704*92192358STong Ho static const TypeInfo trng_info = { 705*92192358STong Ho .name = TYPE_XLNX_VERSAL_TRNG, 706*92192358STong Ho .parent = TYPE_SYS_BUS_DEVICE, 707*92192358STong Ho .instance_size = sizeof(XlnxVersalTRng), 708*92192358STong Ho .class_init = trng_class_init, 709*92192358STong Ho .instance_init = trng_init, 710*92192358STong Ho }; 711*92192358STong Ho 712*92192358STong Ho static void trng_register_types(void) 713*92192358STong Ho { 714*92192358STong Ho type_register_static(&trng_info); 715*92192358STong Ho } 716*92192358STong Ho 717*92192358STong Ho type_init(trng_register_types) 718