cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

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)