1
2
3
4
5
6
7
8
9
10#include "qemu/osdep.h"
11#include "qemu/log.h"
12#include "qapi/error.h"
13#include "crypto/random.h"
14#include "hw/misc/bcm2835_rng.h"
15
16static uint32_t get_random_bytes(void)
17{
18 uint32_t res;
19 Error *err = NULL;
20
21 if (qcrypto_random_bytes((uint8_t *)&res, sizeof(res), &err) < 0) {
22
23
24
25
26
27
28
29
30
31
32
33 error_report_err(err);
34 exit(1);
35 }
36 return res;
37}
38
39static uint64_t bcm2835_rng_read(void *opaque, hwaddr offset,
40 unsigned size)
41{
42 BCM2835RngState *s = (BCM2835RngState *)opaque;
43 uint32_t res = 0;
44
45 assert(size == 4);
46
47 switch (offset) {
48 case 0x0:
49 res = s->rng_ctrl;
50 break;
51 case 0x4:
52 res = s->rng_status | (1 << 24);
53 break;
54 case 0x8:
55 res = get_random_bytes();
56 break;
57
58 default:
59 qemu_log_mask(LOG_GUEST_ERROR,
60 "bcm2835_rng_read: Bad offset %x\n",
61 (int)offset);
62 res = 0;
63 break;
64 }
65
66 return res;
67}
68
69static void bcm2835_rng_write(void *opaque, hwaddr offset,
70 uint64_t value, unsigned size)
71{
72 BCM2835RngState *s = (BCM2835RngState *)opaque;
73
74 assert(size == 4);
75
76 switch (offset) {
77 case 0x0:
78 s->rng_ctrl = value;
79 break;
80 case 0x4:
81
82 s->rng_status &= ~0xFFFFF;
83 s->rng_status |= value & 0xFFFFF;
84 break;
85
86 default:
87 qemu_log_mask(LOG_GUEST_ERROR,
88 "bcm2835_rng_write: Bad offset %x\n",
89 (int)offset);
90 break;
91 }
92}
93
94static const MemoryRegionOps bcm2835_rng_ops = {
95 .read = bcm2835_rng_read,
96 .write = bcm2835_rng_write,
97 .endianness = DEVICE_NATIVE_ENDIAN,
98};
99
100static const VMStateDescription vmstate_bcm2835_rng = {
101 .name = TYPE_BCM2835_RNG,
102 .version_id = 1,
103 .minimum_version_id = 1,
104 .fields = (VMStateField[]) {
105 VMSTATE_UINT32(rng_ctrl, BCM2835RngState),
106 VMSTATE_UINT32(rng_status, BCM2835RngState),
107 VMSTATE_END_OF_LIST()
108 }
109};
110
111static void bcm2835_rng_init(Object *obj)
112{
113 BCM2835RngState *s = BCM2835_RNG(obj);
114
115 memory_region_init_io(&s->iomem, obj, &bcm2835_rng_ops, s,
116 TYPE_BCM2835_RNG, 0x10);
117 sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
118}
119
120static void bcm2835_rng_reset(DeviceState *dev)
121{
122 BCM2835RngState *s = BCM2835_RNG(dev);
123
124 s->rng_ctrl = 0;
125 s->rng_status = 0;
126}
127
128static void bcm2835_rng_class_init(ObjectClass *klass, void *data)
129{
130 DeviceClass *dc = DEVICE_CLASS(klass);
131
132 dc->reset = bcm2835_rng_reset;
133 dc->vmsd = &vmstate_bcm2835_rng;
134}
135
136static TypeInfo bcm2835_rng_info = {
137 .name = TYPE_BCM2835_RNG,
138 .parent = TYPE_SYS_BUS_DEVICE,
139 .instance_size = sizeof(BCM2835RngState),
140 .class_init = bcm2835_rng_class_init,
141 .instance_init = bcm2835_rng_init,
142};
143
144static void bcm2835_rng_register_types(void)
145{
146 type_register_static(&bcm2835_rng_info);
147}
148
149type_init(bcm2835_rng_register_types)
150