qemu/hw/misc/nrf51_rng.c
<<
>>
Prefs
   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
  20static void update_irq(NRF51RNGState *s)
  21{
  22    bool irq = s->interrupt_enabled && s->event_valrdy;
  23    qemu_set_irq(s->irq, irq);
  24}
  25
  26static 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
  59static 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
  72static 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
  82static 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
 137static 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
 145static 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
 162static 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
 172static 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
 183static 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
 204static 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
 219static 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
 227static 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
 241static 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
 250static 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
 258static void nrf51_rng_register_types(void)
 259{
 260    type_register_static(&nrf51_rng_info);
 261}
 262
 263type_init(nrf51_rng_register_types)
 264