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