qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

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 
     23 static void update_irq(NRF51RNGState *s)
     24 {
     25     bool irq = s->interrupt_enabled && s->event_valrdy;
     26     qemu_set_irq(s->irq, irq);
     27 }
     28 
     29 static 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 
     62 static 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 
     75 static 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 
     85 static 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 
    140 static 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 
    148 static 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 
    165 static 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 
    175 static 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 
    186 static 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 
    207 static 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 
    222 static 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 
    230 static 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 
    244 static 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 
    253 static 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 
    261 static void nrf51_rng_register_types(void)
    262 {
    263     type_register_static(&nrf51_rng_info);
    264 }
    265 
    266 type_init(nrf51_rng_register_types)