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