1 /*
2 * MAX78000 True Random Number Generator
3 *
4 * Copyright (c) 2025 Jackson Donaldson <jcksn@duck.com>
5 *
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
8
9 #include "qemu/osdep.h"
10 #include "qemu/log.h"
11 #include "trace.h"
12 #include "hw/irq.h"
13 #include "migration/vmstate.h"
14 #include "hw/misc/max78000_trng.h"
15 #include "qemu/guest-random.h"
16
max78000_trng_read(void * opaque,hwaddr addr,unsigned int size)17 static uint64_t max78000_trng_read(void *opaque, hwaddr addr,
18 unsigned int size)
19 {
20 uint32_t data;
21
22 Max78000TrngState *s = opaque;
23 switch (addr) {
24 case CTRL:
25 return s->ctrl;
26
27 case STATUS:
28 return 1;
29
30 case DATA:
31 /*
32 * When interrupts are enabled, reading random data should cause a
33 * new interrupt to be generated; since there's always a random number
34 * available, we could qemu_set_irq(s->irq, s->ctrl & RND_IE). Because
35 * of how trng_write is set up, this is always a noop, so don't
36 */
37 qemu_guest_getrandom_nofail(&data, sizeof(data));
38 return data;
39
40 default:
41 qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"
42 HWADDR_PRIx "\n", __func__, addr);
43 break;
44 }
45 return 0;
46 }
47
max78000_trng_write(void * opaque,hwaddr addr,uint64_t val64,unsigned int size)48 static void max78000_trng_write(void *opaque, hwaddr addr,
49 uint64_t val64, unsigned int size)
50 {
51 Max78000TrngState *s = opaque;
52 uint32_t val = val64;
53 switch (addr) {
54 case CTRL:
55 /* TODO: implement AES keygen */
56 s->ctrl = val;
57
58 /*
59 * This device models random number generation as taking 0 time.
60 * A new random number is always available, so the condition for the
61 * RND interrupt is always fulfilled; we can just set irq to 1.
62 */
63 if (val & RND_IE) {
64 qemu_set_irq(s->irq, 1);
65 } else{
66 qemu_set_irq(s->irq, 0);
67 }
68 break;
69
70 default:
71 qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"
72 HWADDR_PRIx "\n", __func__, addr);
73 break;
74 }
75 }
76
max78000_trng_reset_hold(Object * obj,ResetType type)77 static void max78000_trng_reset_hold(Object *obj, ResetType type)
78 {
79 Max78000TrngState *s = MAX78000_TRNG(obj);
80 s->ctrl = 0;
81 s->status = 0;
82 s->data = 0;
83 }
84
85 static const MemoryRegionOps max78000_trng_ops = {
86 .read = max78000_trng_read,
87 .write = max78000_trng_write,
88 .endianness = DEVICE_LITTLE_ENDIAN,
89 .valid.min_access_size = 4,
90 .valid.max_access_size = 4,
91 };
92
93 static const VMStateDescription max78000_trng_vmstate = {
94 .name = TYPE_MAX78000_TRNG,
95 .version_id = 1,
96 .minimum_version_id = 1,
97 .fields = (const VMStateField[]) {
98 VMSTATE_UINT32(ctrl, Max78000TrngState),
99 VMSTATE_UINT32(status, Max78000TrngState),
100 VMSTATE_UINT32(data, Max78000TrngState),
101 VMSTATE_END_OF_LIST()
102 }
103 };
104
max78000_trng_init(Object * obj)105 static void max78000_trng_init(Object *obj)
106 {
107 Max78000TrngState *s = MAX78000_TRNG(obj);
108 sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
109
110 memory_region_init_io(&s->mmio, obj, &max78000_trng_ops, s,
111 TYPE_MAX78000_TRNG, 0x1000);
112 sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
113
114 }
115
max78000_trng_class_init(ObjectClass * klass,const void * data)116 static void max78000_trng_class_init(ObjectClass *klass, const void *data)
117 {
118 ResettableClass *rc = RESETTABLE_CLASS(klass);
119 DeviceClass *dc = DEVICE_CLASS(klass);
120
121 rc->phases.hold = max78000_trng_reset_hold;
122 dc->vmsd = &max78000_trng_vmstate;
123
124 }
125
126 static const TypeInfo max78000_trng_info = {
127 .name = TYPE_MAX78000_TRNG,
128 .parent = TYPE_SYS_BUS_DEVICE,
129 .instance_size = sizeof(Max78000TrngState),
130 .instance_init = max78000_trng_init,
131 .class_init = max78000_trng_class_init,
132 };
133
max78000_trng_register_types(void)134 static void max78000_trng_register_types(void)
135 {
136 type_register_static(&max78000_trng_info);
137 }
138
139 type_init(max78000_trng_register_types)
140