2 * Non-crypto strength model of the True Random Number Generator
3 * in the AMD/Xilinx Versal device family.
5 * Copyright (c) 2017-2020 Xilinx Inc.
6 * Copyright (c) 2023 Advanced Micro Devices, Inc.
8 * Written by Edgar E. Iglesias <edgar.iglesias@xilinx.com>
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:
17 * The above copyright notice and this permission notice shall be included in
18 * all copies or substantial portions of the Software.
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
28 #include "qemu/osdep.h"
29 #include "hw/misc/xlnx-versal-trng.h"
31 #include "qemu/bitops.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"
40 #ifndef XLNX_VERSAL_TRNG_ERR_DEBUG
41 #define XLNX_VERSAL_TRNG_ERR_DEBUG 0
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)
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)
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)
70 FIELD(CTRL_2
, REPCOUNTTESTCUTOFF
, 8, 9)
71 FIELD(CTRL_2
, RESERVED_7_5
, 5, 3)
72 FIELD(CTRL_2
, DIT
, 0, 5)
74 FIELD(CTRL_3
, ADAPTPROPTESTCUTOFF
, 8, 10)
75 FIELD(CTRL_3
, DLEN
, 0, 8)
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)
104 FIELD(RESET
, VAL
, 0, 1)
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)
122 #define R_MAX (R_SLV_ERR_CTRL + 1)
124 QEMU_BUILD_BUG_ON(R_MAX
* 4 != sizeof_field(XlnxVersalTRng
, regs
));
126 #define TRNG_GUEST_ERROR(D, FMT, ...) \
128 g_autofree char *p = object_get_canonical_path(OBJECT(D)); \
129 qemu_log_mask(LOG_GUEST_ERROR, "%s: " FMT, p, ## __VA_ARGS__); \
132 #define TRNG_WARN(D, FMT, ...) \
134 g_autofree char *p = object_get_canonical_path(OBJECT(D)); \
135 warn_report("%s: " FMT, p, ## __VA_ARGS__); \
138 static bool trng_older_than_v2(XlnxVersalTRng
*s
)
140 return s
->hw_version
< 0x0200;
143 static bool trng_in_reset(XlnxVersalTRng
*s
)
145 if (ARRAY_FIELD_EX32(s
->regs
, RESET
, VAL
)) {
148 if (ARRAY_FIELD_EX32(s
->regs
, CTRL
, PRNGSRST
)) {
155 static bool trng_test_enabled(XlnxVersalTRng
*s
)
157 return ARRAY_FIELD_EX32(s
->regs
, CTRL
, TSTMODE
);
160 static bool trng_trss_enabled(XlnxVersalTRng
*s
)
162 if (trng_in_reset(s
)) {
165 if (!ARRAY_FIELD_EX32(s
->regs
, CTRL
, TRSSEN
)) {
168 if (!ARRAY_FIELD_EX32(s
->regs
, OSC_EN
, VAL
)) {
175 static void trng_seed_128(uint32_t *seed
, uint64_t h00
, uint64_t h64
)
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);
183 static void trng_reseed(XlnxVersalTRng
*s
)
185 bool ext_seed
= ARRAY_FIELD_EX32(s
->regs
, CTRL
, PRNGXS
);
186 bool pers_disabled
= ARRAY_FIELD_EX32(s
->regs
, CTRL
, PERSODISABLE
);
194 * Maximum seed length is len(personalized string) + len(ext seed).
196 * g_rand_set_seed_array() takes array of uint32 in host endian.
198 guint32 gs
[U384_U32
* 2], *seed
= &gs
[U384_U32
];
201 * A disabled personalized string is the same as
202 * a string with all zeros.
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.
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.
218 * To assist debugging of certain classes of software defects,
219 * this QEMU model implements a 4th mode,
221 * When in this mode, a reproducible sequence is generated
222 * if software has selected the TRNG mode (mode 2).
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.
228 memset(gs
, 0, sizeof(gs
));
230 if (!pers_disabled
) {
231 memcpy(gs
, &s
->regs
[R_PER_STRNG_0
], U384_U8
);
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
);
242 qemu_guest_getrandom_nofail(seed
, U384_U8
);
245 g_rand_set_seed_array(s
->prng
, gs
, ARRAY_SIZE(gs
));
248 s
->rand_reseed
= 1ULL << 48;
251 static void trng_regen(XlnxVersalTRng
*s
)
253 if (s
->rand_reseed
== 0) {
254 TRNG_GUEST_ERROR(s
, "Too many generations without a reseed");
260 * In real hardware, each regen creates 256 bits, but QCNT
261 * reports a max of 4.
263 ARRAY_FIELD_DP32(s
->regs
, STATUS
, QCNT
, 4);
264 s
->rand_count
= 256 / 32;
267 static uint32_t trng_rdout(XlnxVersalTRng
*s
)
269 assert(s
->rand_count
);
272 if (s
->rand_count
< 4) {
273 ARRAY_FIELD_DP32(s
->regs
, STATUS
, QCNT
, s
->rand_count
);
276 return g_rand_int(s
->prng
);
279 static void trng_irq_update(XlnxVersalTRng
*s
)
281 bool pending
= s
->regs
[R_TRNG_ISR
] & ~s
->regs
[R_TRNG_IMR
];
282 qemu_set_irq(s
->irq
, pending
);
285 static void trng_isr_postw(RegisterInfo
*reg
, uint64_t val64
)
287 XlnxVersalTRng
*s
= XLNX_VERSAL_TRNG(reg
->opaque
);
291 static uint64_t trng_ier_prew(RegisterInfo
*reg
, uint64_t val64
)
293 XlnxVersalTRng
*s
= XLNX_VERSAL_TRNG(reg
->opaque
);
294 uint32_t val
= val64
;
296 s
->regs
[R_TRNG_IMR
] &= ~val
;
301 static uint64_t trng_idr_prew(RegisterInfo
*reg
, uint64_t val64
)
303 XlnxVersalTRng
*s
= XLNX_VERSAL_TRNG(reg
->opaque
);
304 uint32_t val
= val64
;
306 s
->regs
[R_TRNG_IMR
] |= val
;
311 static void trng_core_int_update(XlnxVersalTRng
*s
)
313 bool pending
= false;
314 uint32_t st
= s
->regs
[R_STATUS
];
315 uint32_t en
= s
->regs
[R_INT_CTRL
];
317 if (FIELD_EX32(st
, STATUS
, CERTF
) && FIELD_EX32(en
, INT_CTRL
, CERTF_EN
)) {
321 if (FIELD_EX32(st
, STATUS
, DTF
) && FIELD_EX32(en
, INT_CTRL
, DTF_EN
)) {
325 if (FIELD_EX32(st
, STATUS
, DONE
) && FIELD_EX32(en
, INT_CTRL
, DONE_EN
)) {
329 ARRAY_FIELD_DP32(s
->regs
, TRNG_ISR
, CORE_INT
, pending
);
333 static void trng_int_ctrl_postw(RegisterInfo
*reg
, uint64_t val64
)
335 XlnxVersalTRng
*s
= XLNX_VERSAL_TRNG(reg
->opaque
);
336 uint32_t v32
= val64
;
337 uint32_t clr_mask
= 0;
339 if (FIELD_EX32(v32
, INT_CTRL
, CERTF_RST
)) {
340 clr_mask
|= R_STATUS_CERTF_MASK
;
342 if (FIELD_EX32(v32
, INT_CTRL
, DTF_RST
)) {
343 clr_mask
|= R_STATUS_DTF_MASK
;
345 if (FIELD_EX32(v32
, INT_CTRL
, DONE_RST
)) {
346 clr_mask
|= R_STATUS_DONE_MASK
;
349 s
->regs
[R_STATUS
] &= ~clr_mask
;
350 trng_core_int_update(s
);
353 static void trng_done(XlnxVersalTRng
*s
)
355 ARRAY_FIELD_DP32(s
->regs
, STATUS
, DONE
, true);
356 trng_core_int_update(s
);
359 static void trng_fault_event_set(XlnxVersalTRng
*s
, uint32_t events
)
361 bool pending
= false;
363 /* Disabled TRSS cannot generate any fault event */
364 if (!trng_trss_enabled(s
)) {
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");
374 ARRAY_FIELD_DP32(s
->regs
, STATUS
, CERTF
, true);
379 if (FIELD_EX32(events
, STATUS
, DTF
)) {
380 ARRAY_FIELD_DP32(s
->regs
, STATUS
, DTF
, true);
385 trng_core_int_update(s
);
389 static void trng_soft_reset(XlnxVersalTRng
*s
)
392 s
->regs
[R_STATUS
] = 0;
394 ARRAY_FIELD_DP32(s
->regs
, TRNG_ISR
, CORE_INT
, 0);
397 static void trng_ctrl_postw(RegisterInfo
*reg
, uint64_t val64
)
399 XlnxVersalTRng
*s
= XLNX_VERSAL_TRNG(reg
->opaque
);
401 if (trng_in_reset(s
)) {
405 if (FIELD_EX32(val64
, CTRL
, PRNGSRST
)) {
411 if (!FIELD_EX32(val64
, CTRL
, PRNGSTART
)) {
415 if (FIELD_EX32(val64
, CTRL
, PRNGMODE
)) {
424 static void trng_ctrl4_postw(RegisterInfo
*reg
, uint64_t val64
)
426 XlnxVersalTRng
*s
= XLNX_VERSAL_TRNG(reg
->opaque
);
428 /* Only applies to test mode with TRSS enabled */
429 if (!trng_test_enabled(s
) || !trng_trss_enabled(s
)) {
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;
443 static uint64_t trng_core_out_postr(RegisterInfo
*reg
, uint64_t val
)
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
);
450 if (trng_in_reset(s
)) {
451 TRNG_GUEST_ERROR(s
, "Reading random number while in reset!");
455 if (s
->rand_count
== 0) {
456 TRNG_GUEST_ERROR(s
, "Reading random number when unavailable!");
462 /* Automatic mode regenerates when half the output reg is empty. */
463 if (!oneshot
&& start
&& s
->rand_count
<= 3) {
470 static void trng_reset(XlnxVersalTRng
*s
)
474 s
->forced_prng_count
= 0;
476 for (i
= 0; i
< ARRAY_SIZE(s
->regs_info
); ++i
) {
477 register_reset(&s
->regs_info
[i
]);
483 static uint64_t trng_reset_prew(RegisterInfo
*reg
, uint64_t val64
)
485 XlnxVersalTRng
*s
= XLNX_VERSAL_TRNG(reg
->opaque
);
487 if (!ARRAY_FIELD_EX32(s
->regs
, RESET
, VAL
) &&
488 FIELD_EX32(val64
, RESET
, VAL
)) {
495 static uint64_t trng_register_read(void *opaque
, hwaddr addr
, unsigned size
)
498 * Guest provided seed and personalized strings cannot be
499 * read back, and read attempts return value of A_STATUS.
502 case A_EXT_SEED_0
... A_PER_STRNG_11
:
507 return register_read_memory(opaque
, addr
, size
);
510 static void trng_register_write(void *opaque
, hwaddr addr
,
511 uint64_t value
, unsigned size
)
513 RegisterInfoArray
*reg_array
= opaque
;
514 XlnxVersalTRng
*s
= XLNX_VERSAL_TRNG(reg_array
->r
[0]->opaque
);
516 if (trng_older_than_v2(s
)) {
519 value
= FIELD_DP64(value
, CTRL
, PERSODISABLE
, 0);
520 value
= FIELD_DP64(value
, CTRL
, SINGLEGENMODE
, 0);
530 value
= FIELD_DP64(value
, CTRL
, EATAU
, 0);
531 value
= FIELD_DP64(value
, CTRL
, QERTUEN
, 0);
536 register_write_memory(opaque
, addr
, value
, size
);
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
,
544 },{ .name
= "CTRL", .addr
= A_CTRL
,
545 .post_write
= trng_ctrl_postw
,
546 },{ .name
= "CTRL_2", .addr
= A_CTRL_2
,
548 },{ .name
= "CTRL_3", .addr
= A_CTRL_3
,
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
,
578 .post_read
= trng_core_out_postr
,
579 },{ .name
= "RESET", .addr
= A_RESET
,
581 .pre_write
= trng_reset_prew
,
582 },{ .name
= "OSC_EN", .addr
= A_OSC_EN
,
583 },{ .name
= "TRNG_ISR", .addr
= A_TRNG_ISR
,
585 .post_write
= trng_isr_postw
,
586 },{ .name
= "TRNG_IMR", .addr
= A_TRNG_IMR
,
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
,
597 static const MemoryRegionOps trng_ops
= {
598 .read
= trng_register_read
,
599 .write
= trng_register_write
,
600 .endianness
= DEVICE_LITTLE_ENDIAN
,
602 .min_access_size
= 4,
603 .max_access_size
= 4,
607 static void trng_init(Object
*obj
)
609 XlnxVersalTRng
*s
= XLNX_VERSAL_TRNG(obj
);
610 SysBusDevice
*sbd
= SYS_BUS_DEVICE(obj
);
611 RegisterInfoArray
*reg_array
;
614 register_init_block32(DEVICE(obj
), trng_regs_info
,
615 ARRAY_SIZE(trng_regs_info
),
616 s
->regs_info
, s
->regs
,
618 XLNX_VERSAL_TRNG_ERR_DEBUG
,
621 sysbus_init_mmio(sbd
, ®_array
->mem
);
622 sysbus_init_irq(sbd
, &s
->irq
);
624 s
->prng
= g_rand_new();
627 static void trng_unrealize(DeviceState
*dev
)
629 XlnxVersalTRng
*s
= XLNX_VERSAL_TRNG(dev
);
631 g_rand_free(s
->prng
);
635 static void trng_reset_hold(Object
*obj
)
637 trng_reset(XLNX_VERSAL_TRNG(obj
));
640 static void trng_prop_fault_event_set(Object
*obj
, Visitor
*v
,
641 const char *name
, void *opaque
,
644 Property
*prop
= opaque
;
645 uint32_t *events
= object_field_prop_ptr(obj
, prop
);
647 visit_type_uint32(v
, name
, events
, errp
);
652 trng_fault_event_set(XLNX_VERSAL_TRNG(obj
), *events
);
655 static const PropertyInfo trng_prop_fault_events
= {
656 .name
= "uint32:bits",
657 .description
= "Set to trigger TRNG fault events",
658 .set
= trng_prop_fault_event_set
,
659 .realized_set_allowed
= true,
662 static PropertyInfo trng_prop_uint64
; /* to extend qdev_prop_uint64 */
664 static Property trng_props
[] = {
665 DEFINE_PROP_UINT64("forced-prng", XlnxVersalTRng
, forced_prng_seed
, 0),
666 DEFINE_PROP_UINT32("hw-version", XlnxVersalTRng
, hw_version
, 0x0200),
667 DEFINE_PROP("fips-fault-events", XlnxVersalTRng
, forced_faults
,
668 trng_prop_fault_events
, uint32_t),
670 DEFINE_PROP_END_OF_LIST(),
673 static const VMStateDescription vmstate_trng
= {
674 .name
= TYPE_XLNX_VERSAL_TRNG
,
676 .minimum_version_id
= 1,
677 .fields
= (const VMStateField
[]) {
678 VMSTATE_UINT32(rand_count
, XlnxVersalTRng
),
679 VMSTATE_UINT64(rand_reseed
, XlnxVersalTRng
),
680 VMSTATE_UINT64(forced_prng_count
, XlnxVersalTRng
),
681 VMSTATE_UINT64_ARRAY(tst_seed
, XlnxVersalTRng
, 2),
682 VMSTATE_UINT32_ARRAY(regs
, XlnxVersalTRng
, R_MAX
),
683 VMSTATE_END_OF_LIST(),
687 static void trng_class_init(ObjectClass
*klass
, void *data
)
689 DeviceClass
*dc
= DEVICE_CLASS(klass
);
690 ResettableClass
*rc
= RESETTABLE_CLASS(klass
);
692 dc
->vmsd
= &vmstate_trng
;
693 dc
->unrealize
= trng_unrealize
;
694 rc
->phases
.hold
= trng_reset_hold
;
696 /* Clone uint64 property with set allowed after realized */
697 trng_prop_uint64
= qdev_prop_uint64
;
698 trng_prop_uint64
.realized_set_allowed
= true;
699 trng_props
[0].info
= &trng_prop_uint64
;
701 device_class_set_props(dc
, trng_props
);
704 static const TypeInfo trng_info
= {
705 .name
= TYPE_XLNX_VERSAL_TRNG
,
706 .parent
= TYPE_SYS_BUS_DEVICE
,
707 .instance_size
= sizeof(XlnxVersalTRng
),
708 .class_init
= trng_class_init
,
709 .instance_init
= trng_init
,
712 static void trng_register_types(void)
714 type_register_static(&trng_info
);
717 type_init(trng_register_types
)