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