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