xref: /qemu/hw/misc/nrf51_rng.c (revision 90c58941f6ce05d03364de253902008299d3f9e8)
1*90c58941SSteffen Görtz /*
2*90c58941SSteffen Görtz  * nRF51 Random Number Generator
3*90c58941SSteffen Görtz  *
4*90c58941SSteffen Görtz  * Reference Manual: http://infocenter.nordicsemi.com/pdf/nRF51_RM_v3.0.1.pdf
5*90c58941SSteffen Görtz  *
6*90c58941SSteffen Görtz  * Copyright 2018 Steffen Görtz <contrib@steffen-goertz.de>
7*90c58941SSteffen Görtz  *
8*90c58941SSteffen Görtz  * This code is licensed under the GPL version 2 or later.  See
9*90c58941SSteffen Görtz  * the COPYING file in the top-level directory.
10*90c58941SSteffen Görtz  */
11*90c58941SSteffen Görtz 
12*90c58941SSteffen Görtz #include "qemu/osdep.h"
13*90c58941SSteffen Görtz #include "qemu/log.h"
14*90c58941SSteffen Görtz #include "qapi/error.h"
15*90c58941SSteffen Görtz #include "hw/arm/nrf51.h"
16*90c58941SSteffen Görtz #include "hw/misc/nrf51_rng.h"
17*90c58941SSteffen Görtz #include "crypto/random.h"
18*90c58941SSteffen Görtz 
19*90c58941SSteffen Görtz static void update_irq(NRF51RNGState *s)
20*90c58941SSteffen Görtz {
21*90c58941SSteffen Görtz     bool irq = s->interrupt_enabled && s->event_valrdy;
22*90c58941SSteffen Görtz     qemu_set_irq(s->irq, irq);
23*90c58941SSteffen Görtz }
24*90c58941SSteffen Görtz 
25*90c58941SSteffen Görtz static uint64_t rng_read(void *opaque, hwaddr offset, unsigned int size)
26*90c58941SSteffen Görtz {
27*90c58941SSteffen Görtz     NRF51RNGState *s = NRF51_RNG(opaque);
28*90c58941SSteffen Görtz     uint64_t r = 0;
29*90c58941SSteffen Görtz 
30*90c58941SSteffen Görtz     switch (offset) {
31*90c58941SSteffen Görtz     case NRF51_RNG_EVENT_VALRDY:
32*90c58941SSteffen Görtz         r = s->event_valrdy;
33*90c58941SSteffen Görtz         break;
34*90c58941SSteffen Görtz     case NRF51_RNG_REG_SHORTS:
35*90c58941SSteffen Görtz         r = s->shortcut_stop_on_valrdy;
36*90c58941SSteffen Görtz         break;
37*90c58941SSteffen Görtz     case NRF51_RNG_REG_INTEN:
38*90c58941SSteffen Görtz     case NRF51_RNG_REG_INTENSET:
39*90c58941SSteffen Görtz     case NRF51_RNG_REG_INTENCLR:
40*90c58941SSteffen Görtz         r = s->interrupt_enabled;
41*90c58941SSteffen Görtz         break;
42*90c58941SSteffen Görtz     case NRF51_RNG_REG_CONFIG:
43*90c58941SSteffen Görtz         r = s->filter_enabled;
44*90c58941SSteffen Görtz         break;
45*90c58941SSteffen Görtz     case NRF51_RNG_REG_VALUE:
46*90c58941SSteffen Görtz         r = s->value;
47*90c58941SSteffen Görtz         break;
48*90c58941SSteffen Görtz 
49*90c58941SSteffen Görtz     default:
50*90c58941SSteffen Görtz         qemu_log_mask(LOG_GUEST_ERROR,
51*90c58941SSteffen Görtz                       "%s: bad read offset 0x%" HWADDR_PRIx "\n",
52*90c58941SSteffen Görtz                       __func__, offset);
53*90c58941SSteffen Görtz     }
54*90c58941SSteffen Görtz 
55*90c58941SSteffen Görtz     return r;
56*90c58941SSteffen Görtz }
57*90c58941SSteffen Görtz 
58*90c58941SSteffen Görtz static int64_t calc_next_timeout(NRF51RNGState *s)
59*90c58941SSteffen Görtz {
60*90c58941SSteffen Görtz     int64_t timeout = qemu_clock_get_us(QEMU_CLOCK_VIRTUAL);
61*90c58941SSteffen Görtz     if (s->filter_enabled) {
62*90c58941SSteffen Görtz         timeout += s->period_filtered_us;
63*90c58941SSteffen Görtz     } else {
64*90c58941SSteffen Görtz         timeout += s->period_unfiltered_us;
65*90c58941SSteffen Görtz     }
66*90c58941SSteffen Görtz 
67*90c58941SSteffen Görtz     return timeout;
68*90c58941SSteffen Görtz }
69*90c58941SSteffen Görtz 
70*90c58941SSteffen Görtz 
71*90c58941SSteffen Görtz static void rng_update_timer(NRF51RNGState *s)
72*90c58941SSteffen Görtz {
73*90c58941SSteffen Görtz     if (s->active) {
74*90c58941SSteffen Görtz         timer_mod(&s->timer, calc_next_timeout(s));
75*90c58941SSteffen Görtz     } else {
76*90c58941SSteffen Görtz         timer_del(&s->timer);
77*90c58941SSteffen Görtz     }
78*90c58941SSteffen Görtz }
79*90c58941SSteffen Görtz 
80*90c58941SSteffen Görtz 
81*90c58941SSteffen Görtz static void rng_write(void *opaque, hwaddr offset,
82*90c58941SSteffen Görtz                        uint64_t value, unsigned int size)
83*90c58941SSteffen Görtz {
84*90c58941SSteffen Görtz     NRF51RNGState *s = NRF51_RNG(opaque);
85*90c58941SSteffen Görtz 
86*90c58941SSteffen Görtz     switch (offset) {
87*90c58941SSteffen Görtz     case NRF51_RNG_TASK_START:
88*90c58941SSteffen Görtz         if (value == NRF51_TRIGGER_TASK) {
89*90c58941SSteffen Görtz             s->active = 1;
90*90c58941SSteffen Görtz             rng_update_timer(s);
91*90c58941SSteffen Görtz         }
92*90c58941SSteffen Görtz         break;
93*90c58941SSteffen Görtz     case NRF51_RNG_TASK_STOP:
94*90c58941SSteffen Görtz         if (value == NRF51_TRIGGER_TASK) {
95*90c58941SSteffen Görtz             s->active = 0;
96*90c58941SSteffen Görtz             rng_update_timer(s);
97*90c58941SSteffen Görtz         }
98*90c58941SSteffen Görtz         break;
99*90c58941SSteffen Görtz     case NRF51_RNG_EVENT_VALRDY:
100*90c58941SSteffen Görtz         if (value == NRF51_EVENT_CLEAR) {
101*90c58941SSteffen Görtz             s->event_valrdy = 0;
102*90c58941SSteffen Görtz         }
103*90c58941SSteffen Görtz         break;
104*90c58941SSteffen Görtz     case NRF51_RNG_REG_SHORTS:
105*90c58941SSteffen Görtz         s->shortcut_stop_on_valrdy =
106*90c58941SSteffen Görtz                 (value & BIT_MASK(NRF51_RNG_REG_SHORTS_VALRDY_STOP)) ? 1 : 0;
107*90c58941SSteffen Görtz         break;
108*90c58941SSteffen Görtz     case NRF51_RNG_REG_INTEN:
109*90c58941SSteffen Görtz         s->interrupt_enabled =
110*90c58941SSteffen Görtz                 (value & BIT_MASK(NRF51_RNG_REG_INTEN_VALRDY)) ? 1 : 0;
111*90c58941SSteffen Görtz         break;
112*90c58941SSteffen Görtz     case NRF51_RNG_REG_INTENSET:
113*90c58941SSteffen Görtz         if (value & BIT_MASK(NRF51_RNG_REG_INTEN_VALRDY)) {
114*90c58941SSteffen Görtz             s->interrupt_enabled = 1;
115*90c58941SSteffen Görtz         }
116*90c58941SSteffen Görtz         break;
117*90c58941SSteffen Görtz     case NRF51_RNG_REG_INTENCLR:
118*90c58941SSteffen Görtz         if (value & BIT_MASK(NRF51_RNG_REG_INTEN_VALRDY)) {
119*90c58941SSteffen Görtz             s->interrupt_enabled = 0;
120*90c58941SSteffen Görtz         }
121*90c58941SSteffen Görtz         break;
122*90c58941SSteffen Görtz     case NRF51_RNG_REG_CONFIG:
123*90c58941SSteffen Görtz         s->filter_enabled =
124*90c58941SSteffen Görtz                       (value & BIT_MASK(NRF51_RNG_REG_CONFIG_DECEN)) ? 1 : 0;
125*90c58941SSteffen Görtz         break;
126*90c58941SSteffen Görtz 
127*90c58941SSteffen Görtz     default:
128*90c58941SSteffen Görtz         qemu_log_mask(LOG_GUEST_ERROR,
129*90c58941SSteffen Görtz                       "%s: bad write offset 0x%" HWADDR_PRIx "\n",
130*90c58941SSteffen Görtz                       __func__, offset);
131*90c58941SSteffen Görtz     }
132*90c58941SSteffen Görtz 
133*90c58941SSteffen Görtz     update_irq(s);
134*90c58941SSteffen Görtz }
135*90c58941SSteffen Görtz 
136*90c58941SSteffen Görtz static const MemoryRegionOps rng_ops = {
137*90c58941SSteffen Görtz     .read =  rng_read,
138*90c58941SSteffen Görtz     .write = rng_write,
139*90c58941SSteffen Görtz     .endianness = DEVICE_LITTLE_ENDIAN,
140*90c58941SSteffen Görtz     .impl.min_access_size = 4,
141*90c58941SSteffen Görtz     .impl.max_access_size = 4
142*90c58941SSteffen Görtz };
143*90c58941SSteffen Görtz 
144*90c58941SSteffen Görtz static void nrf51_rng_timer_expire(void *opaque)
145*90c58941SSteffen Görtz {
146*90c58941SSteffen Görtz     NRF51RNGState *s = NRF51_RNG(opaque);
147*90c58941SSteffen Görtz 
148*90c58941SSteffen Görtz     qcrypto_random_bytes(&s->value, 1, &error_abort);
149*90c58941SSteffen Görtz 
150*90c58941SSteffen Görtz     s->event_valrdy = 1;
151*90c58941SSteffen Görtz     qemu_set_irq(s->eep_valrdy, 1);
152*90c58941SSteffen Görtz 
153*90c58941SSteffen Görtz     if (s->shortcut_stop_on_valrdy) {
154*90c58941SSteffen Görtz         s->active = 0;
155*90c58941SSteffen Görtz     }
156*90c58941SSteffen Görtz 
157*90c58941SSteffen Görtz     rng_update_timer(s);
158*90c58941SSteffen Görtz     update_irq(s);
159*90c58941SSteffen Görtz }
160*90c58941SSteffen Görtz 
161*90c58941SSteffen Görtz static void nrf51_rng_tep_start(void *opaque, int n, int level)
162*90c58941SSteffen Görtz {
163*90c58941SSteffen Görtz     NRF51RNGState *s = NRF51_RNG(opaque);
164*90c58941SSteffen Görtz 
165*90c58941SSteffen Görtz     if (level) {
166*90c58941SSteffen Görtz         s->active = 1;
167*90c58941SSteffen Görtz         rng_update_timer(s);
168*90c58941SSteffen Görtz     }
169*90c58941SSteffen Görtz }
170*90c58941SSteffen Görtz 
171*90c58941SSteffen Görtz static void nrf51_rng_tep_stop(void *opaque, int n, int level)
172*90c58941SSteffen Görtz {
173*90c58941SSteffen Görtz     NRF51RNGState *s = NRF51_RNG(opaque);
174*90c58941SSteffen Görtz 
175*90c58941SSteffen Görtz     if (level) {
176*90c58941SSteffen Görtz         s->active = 0;
177*90c58941SSteffen Görtz         rng_update_timer(s);
178*90c58941SSteffen Görtz     }
179*90c58941SSteffen Görtz }
180*90c58941SSteffen Görtz 
181*90c58941SSteffen Görtz 
182*90c58941SSteffen Görtz static void nrf51_rng_init(Object *obj)
183*90c58941SSteffen Görtz {
184*90c58941SSteffen Görtz     NRF51RNGState *s = NRF51_RNG(obj);
185*90c58941SSteffen Görtz     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
186*90c58941SSteffen Görtz 
187*90c58941SSteffen Görtz     memory_region_init_io(&s->mmio, obj, &rng_ops, s,
188*90c58941SSteffen Görtz             TYPE_NRF51_RNG, NRF51_RNG_SIZE);
189*90c58941SSteffen Görtz     sysbus_init_mmio(sbd, &s->mmio);
190*90c58941SSteffen Görtz 
191*90c58941SSteffen Görtz     timer_init_us(&s->timer, QEMU_CLOCK_VIRTUAL, nrf51_rng_timer_expire, s);
192*90c58941SSteffen Görtz 
193*90c58941SSteffen Görtz     sysbus_init_irq(sbd, &s->irq);
194*90c58941SSteffen Görtz 
195*90c58941SSteffen Görtz     /* Tasks */
196*90c58941SSteffen Görtz     qdev_init_gpio_in_named(DEVICE(s), nrf51_rng_tep_start, "tep_start", 1);
197*90c58941SSteffen Görtz     qdev_init_gpio_in_named(DEVICE(s), nrf51_rng_tep_stop, "tep_stop", 1);
198*90c58941SSteffen Görtz 
199*90c58941SSteffen Görtz     /* Events */
200*90c58941SSteffen Görtz     qdev_init_gpio_out_named(DEVICE(s), &s->eep_valrdy, "eep_valrdy", 1);
201*90c58941SSteffen Görtz }
202*90c58941SSteffen Görtz 
203*90c58941SSteffen Görtz static void nrf51_rng_reset(DeviceState *dev)
204*90c58941SSteffen Görtz {
205*90c58941SSteffen Görtz     NRF51RNGState *s = NRF51_RNG(dev);
206*90c58941SSteffen Görtz 
207*90c58941SSteffen Görtz     s->value = 0;
208*90c58941SSteffen Görtz     s->active = 0;
209*90c58941SSteffen Görtz     s->event_valrdy = 0;
210*90c58941SSteffen Görtz     s->shortcut_stop_on_valrdy = 0;
211*90c58941SSteffen Görtz     s->interrupt_enabled = 0;
212*90c58941SSteffen Görtz     s->filter_enabled = 0;
213*90c58941SSteffen Görtz 
214*90c58941SSteffen Görtz     rng_update_timer(s);
215*90c58941SSteffen Görtz }
216*90c58941SSteffen Görtz 
217*90c58941SSteffen Görtz 
218*90c58941SSteffen Görtz static Property nrf51_rng_properties[] = {
219*90c58941SSteffen Görtz     DEFINE_PROP_UINT16("period_unfiltered_us", NRF51RNGState,
220*90c58941SSteffen Görtz             period_unfiltered_us, 167),
221*90c58941SSteffen Görtz     DEFINE_PROP_UINT16("period_filtered_us", NRF51RNGState,
222*90c58941SSteffen Görtz             period_filtered_us, 660),
223*90c58941SSteffen Görtz     DEFINE_PROP_END_OF_LIST(),
224*90c58941SSteffen Görtz };
225*90c58941SSteffen Görtz 
226*90c58941SSteffen Görtz static const VMStateDescription vmstate_rng = {
227*90c58941SSteffen Görtz     .name = "nrf51_soc.rng",
228*90c58941SSteffen Görtz     .version_id = 1,
229*90c58941SSteffen Görtz     .minimum_version_id = 1,
230*90c58941SSteffen Görtz     .fields = (VMStateField[]) {
231*90c58941SSteffen Görtz         VMSTATE_UINT32(active, NRF51RNGState),
232*90c58941SSteffen Görtz         VMSTATE_UINT32(event_valrdy, NRF51RNGState),
233*90c58941SSteffen Görtz         VMSTATE_UINT32(shortcut_stop_on_valrdy, NRF51RNGState),
234*90c58941SSteffen Görtz         VMSTATE_UINT32(interrupt_enabled, NRF51RNGState),
235*90c58941SSteffen Görtz         VMSTATE_UINT32(filter_enabled, NRF51RNGState),
236*90c58941SSteffen Görtz         VMSTATE_END_OF_LIST()
237*90c58941SSteffen Görtz     }
238*90c58941SSteffen Görtz };
239*90c58941SSteffen Görtz 
240*90c58941SSteffen Görtz static void nrf51_rng_class_init(ObjectClass *klass, void *data)
241*90c58941SSteffen Görtz {
242*90c58941SSteffen Görtz     DeviceClass *dc = DEVICE_CLASS(klass);
243*90c58941SSteffen Görtz 
244*90c58941SSteffen Görtz     dc->props = nrf51_rng_properties;
245*90c58941SSteffen Görtz     dc->vmsd = &vmstate_rng;
246*90c58941SSteffen Görtz     dc->reset = nrf51_rng_reset;
247*90c58941SSteffen Görtz }
248*90c58941SSteffen Görtz 
249*90c58941SSteffen Görtz static const TypeInfo nrf51_rng_info = {
250*90c58941SSteffen Görtz     .name = TYPE_NRF51_RNG,
251*90c58941SSteffen Görtz     .parent = TYPE_SYS_BUS_DEVICE,
252*90c58941SSteffen Görtz     .instance_size = sizeof(NRF51RNGState),
253*90c58941SSteffen Görtz     .instance_init = nrf51_rng_init,
254*90c58941SSteffen Görtz     .class_init = nrf51_rng_class_init
255*90c58941SSteffen Görtz };
256*90c58941SSteffen Görtz 
257*90c58941SSteffen Görtz static void nrf51_rng_register_types(void)
258*90c58941SSteffen Görtz {
259*90c58941SSteffen Görtz     type_register_static(&nrf51_rng_info);
260*90c58941SSteffen Görtz }
261*90c58941SSteffen Görtz 
262*90c58941SSteffen Görtz type_init(nrf51_rng_register_types)
263