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