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

arm_timer.c (11382B)


      1/*
      2 * ARM PrimeCell Timer modules.
      3 *
      4 * Copyright (c) 2005-2006 CodeSourcery.
      5 * Written by Paul Brook
      6 *
      7 * This code is licensed under the GPL.
      8 */
      9
     10#include "qemu/osdep.h"
     11#include "hw/sysbus.h"
     12#include "migration/vmstate.h"
     13#include "qemu/timer.h"
     14#include "hw/irq.h"
     15#include "hw/ptimer.h"
     16#include "hw/qdev-properties.h"
     17#include "qemu/module.h"
     18#include "qemu/log.h"
     19#include "qom/object.h"
     20
     21/* Common timer implementation.  */
     22
     23#define TIMER_CTRL_ONESHOT      (1 << 0)
     24#define TIMER_CTRL_32BIT        (1 << 1)
     25#define TIMER_CTRL_DIV1         (0 << 2)
     26#define TIMER_CTRL_DIV16        (1 << 2)
     27#define TIMER_CTRL_DIV256       (2 << 2)
     28#define TIMER_CTRL_IE           (1 << 5)
     29#define TIMER_CTRL_PERIODIC     (1 << 6)
     30#define TIMER_CTRL_ENABLE       (1 << 7)
     31
     32typedef struct {
     33    ptimer_state *timer;
     34    uint32_t control;
     35    uint32_t limit;
     36    int freq;
     37    int int_level;
     38    qemu_irq irq;
     39} arm_timer_state;
     40
     41/* Check all active timers, and schedule the next timer interrupt.  */
     42
     43static void arm_timer_update(arm_timer_state *s)
     44{
     45    /* Update interrupts.  */
     46    if (s->int_level && (s->control & TIMER_CTRL_IE)) {
     47        qemu_irq_raise(s->irq);
     48    } else {
     49        qemu_irq_lower(s->irq);
     50    }
     51}
     52
     53static uint32_t arm_timer_read(void *opaque, hwaddr offset)
     54{
     55    arm_timer_state *s = (arm_timer_state *)opaque;
     56
     57    switch (offset >> 2) {
     58    case 0: /* TimerLoad */
     59    case 6: /* TimerBGLoad */
     60        return s->limit;
     61    case 1: /* TimerValue */
     62        return ptimer_get_count(s->timer);
     63    case 2: /* TimerControl */
     64        return s->control;
     65    case 4: /* TimerRIS */
     66        return s->int_level;
     67    case 5: /* TimerMIS */
     68        if ((s->control & TIMER_CTRL_IE) == 0)
     69            return 0;
     70        return s->int_level;
     71    default:
     72        qemu_log_mask(LOG_GUEST_ERROR,
     73                      "%s: Bad offset %x\n", __func__, (int)offset);
     74        return 0;
     75    }
     76}
     77
     78/*
     79 * Reset the timer limit after settings have changed.
     80 * May only be called from inside a ptimer transaction block.
     81 */
     82static void arm_timer_recalibrate(arm_timer_state *s, int reload)
     83{
     84    uint32_t limit;
     85
     86    if ((s->control & (TIMER_CTRL_PERIODIC | TIMER_CTRL_ONESHOT)) == 0) {
     87        /* Free running.  */
     88        if (s->control & TIMER_CTRL_32BIT)
     89            limit = 0xffffffff;
     90        else
     91            limit = 0xffff;
     92    } else {
     93          /* Periodic.  */
     94          limit = s->limit;
     95    }
     96    ptimer_set_limit(s->timer, limit, reload);
     97}
     98
     99static void arm_timer_write(void *opaque, hwaddr offset,
    100                            uint32_t value)
    101{
    102    arm_timer_state *s = (arm_timer_state *)opaque;
    103    int freq;
    104
    105    switch (offset >> 2) {
    106    case 0: /* TimerLoad */
    107        s->limit = value;
    108        ptimer_transaction_begin(s->timer);
    109        arm_timer_recalibrate(s, 1);
    110        ptimer_transaction_commit(s->timer);
    111        break;
    112    case 1: /* TimerValue */
    113        /* ??? Linux seems to want to write to this readonly register.
    114           Ignore it.  */
    115        break;
    116    case 2: /* TimerControl */
    117        ptimer_transaction_begin(s->timer);
    118        if (s->control & TIMER_CTRL_ENABLE) {
    119            /* Pause the timer if it is running.  This may cause some
    120               inaccuracy dure to rounding, but avoids a whole lot of other
    121               messyness.  */
    122            ptimer_stop(s->timer);
    123        }
    124        s->control = value;
    125        freq = s->freq;
    126        /* ??? Need to recalculate expiry time after changing divisor.  */
    127        switch ((value >> 2) & 3) {
    128        case 1: freq >>= 4; break;
    129        case 2: freq >>= 8; break;
    130        }
    131        arm_timer_recalibrate(s, s->control & TIMER_CTRL_ENABLE);
    132        ptimer_set_freq(s->timer, freq);
    133        if (s->control & TIMER_CTRL_ENABLE) {
    134            /* Restart the timer if still enabled.  */
    135            ptimer_run(s->timer, (s->control & TIMER_CTRL_ONESHOT) != 0);
    136        }
    137        ptimer_transaction_commit(s->timer);
    138        break;
    139    case 3: /* TimerIntClr */
    140        s->int_level = 0;
    141        break;
    142    case 6: /* TimerBGLoad */
    143        s->limit = value;
    144        ptimer_transaction_begin(s->timer);
    145        arm_timer_recalibrate(s, 0);
    146        ptimer_transaction_commit(s->timer);
    147        break;
    148    default:
    149        qemu_log_mask(LOG_GUEST_ERROR,
    150                      "%s: Bad offset %x\n", __func__, (int)offset);
    151    }
    152    arm_timer_update(s);
    153}
    154
    155static void arm_timer_tick(void *opaque)
    156{
    157    arm_timer_state *s = (arm_timer_state *)opaque;
    158    s->int_level = 1;
    159    arm_timer_update(s);
    160}
    161
    162static const VMStateDescription vmstate_arm_timer = {
    163    .name = "arm_timer",
    164    .version_id = 1,
    165    .minimum_version_id = 1,
    166    .fields = (VMStateField[]) {
    167        VMSTATE_UINT32(control, arm_timer_state),
    168        VMSTATE_UINT32(limit, arm_timer_state),
    169        VMSTATE_INT32(int_level, arm_timer_state),
    170        VMSTATE_PTIMER(timer, arm_timer_state),
    171        VMSTATE_END_OF_LIST()
    172    }
    173};
    174
    175static arm_timer_state *arm_timer_init(uint32_t freq)
    176{
    177    arm_timer_state *s;
    178
    179    s = (arm_timer_state *)g_malloc0(sizeof(arm_timer_state));
    180    s->freq = freq;
    181    s->control = TIMER_CTRL_IE;
    182
    183    s->timer = ptimer_init(arm_timer_tick, s, PTIMER_POLICY_DEFAULT);
    184    vmstate_register(NULL, VMSTATE_INSTANCE_ID_ANY, &vmstate_arm_timer, s);
    185    return s;
    186}
    187
    188/*
    189 * ARM PrimeCell SP804 dual timer module.
    190 * Docs at
    191 * https://developer.arm.com/documentation/ddi0271/latest/
    192 */
    193
    194#define TYPE_SP804 "sp804"
    195OBJECT_DECLARE_SIMPLE_TYPE(SP804State, SP804)
    196
    197struct SP804State {
    198    SysBusDevice parent_obj;
    199
    200    MemoryRegion iomem;
    201    arm_timer_state *timer[2];
    202    uint32_t freq0, freq1;
    203    int level[2];
    204    qemu_irq irq;
    205};
    206
    207static const uint8_t sp804_ids[] = {
    208    /* Timer ID */
    209    0x04, 0x18, 0x14, 0,
    210    /* PrimeCell ID */
    211    0xd, 0xf0, 0x05, 0xb1
    212};
    213
    214/* Merge the IRQs from the two component devices.  */
    215static void sp804_set_irq(void *opaque, int irq, int level)
    216{
    217    SP804State *s = (SP804State *)opaque;
    218
    219    s->level[irq] = level;
    220    qemu_set_irq(s->irq, s->level[0] || s->level[1]);
    221}
    222
    223static uint64_t sp804_read(void *opaque, hwaddr offset,
    224                           unsigned size)
    225{
    226    SP804State *s = (SP804State *)opaque;
    227
    228    if (offset < 0x20) {
    229        return arm_timer_read(s->timer[0], offset);
    230    }
    231    if (offset < 0x40) {
    232        return arm_timer_read(s->timer[1], offset - 0x20);
    233    }
    234
    235    /* TimerPeriphID */
    236    if (offset >= 0xfe0 && offset <= 0xffc) {
    237        return sp804_ids[(offset - 0xfe0) >> 2];
    238    }
    239
    240    switch (offset) {
    241    /* Integration Test control registers, which we won't support */
    242    case 0xf00: /* TimerITCR */
    243    case 0xf04: /* TimerITOP (strictly write only but..) */
    244        qemu_log_mask(LOG_UNIMP,
    245                      "%s: integration test registers unimplemented\n",
    246                      __func__);
    247        return 0;
    248    }
    249
    250    qemu_log_mask(LOG_GUEST_ERROR,
    251                  "%s: Bad offset %x\n", __func__, (int)offset);
    252    return 0;
    253}
    254
    255static void sp804_write(void *opaque, hwaddr offset,
    256                        uint64_t value, unsigned size)
    257{
    258    SP804State *s = (SP804State *)opaque;
    259
    260    if (offset < 0x20) {
    261        arm_timer_write(s->timer[0], offset, value);
    262        return;
    263    }
    264
    265    if (offset < 0x40) {
    266        arm_timer_write(s->timer[1], offset - 0x20, value);
    267        return;
    268    }
    269
    270    /* Technically we could be writing to the Test Registers, but not likely */
    271    qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %x\n",
    272                  __func__, (int)offset);
    273}
    274
    275static const MemoryRegionOps sp804_ops = {
    276    .read = sp804_read,
    277    .write = sp804_write,
    278    .endianness = DEVICE_NATIVE_ENDIAN,
    279};
    280
    281static const VMStateDescription vmstate_sp804 = {
    282    .name = "sp804",
    283    .version_id = 1,
    284    .minimum_version_id = 1,
    285    .fields = (VMStateField[]) {
    286        VMSTATE_INT32_ARRAY(level, SP804State, 2),
    287        VMSTATE_END_OF_LIST()
    288    }
    289};
    290
    291static void sp804_init(Object *obj)
    292{
    293    SP804State *s = SP804(obj);
    294    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
    295
    296    sysbus_init_irq(sbd, &s->irq);
    297    memory_region_init_io(&s->iomem, obj, &sp804_ops, s,
    298                          "sp804", 0x1000);
    299    sysbus_init_mmio(sbd, &s->iomem);
    300}
    301
    302static void sp804_realize(DeviceState *dev, Error **errp)
    303{
    304    SP804State *s = SP804(dev);
    305
    306    s->timer[0] = arm_timer_init(s->freq0);
    307    s->timer[1] = arm_timer_init(s->freq1);
    308    s->timer[0]->irq = qemu_allocate_irq(sp804_set_irq, s, 0);
    309    s->timer[1]->irq = qemu_allocate_irq(sp804_set_irq, s, 1);
    310}
    311
    312/* Integrator/CP timer module.  */
    313
    314#define TYPE_INTEGRATOR_PIT "integrator_pit"
    315OBJECT_DECLARE_SIMPLE_TYPE(icp_pit_state, INTEGRATOR_PIT)
    316
    317struct icp_pit_state {
    318    SysBusDevice parent_obj;
    319
    320    MemoryRegion iomem;
    321    arm_timer_state *timer[3];
    322};
    323
    324static uint64_t icp_pit_read(void *opaque, hwaddr offset,
    325                             unsigned size)
    326{
    327    icp_pit_state *s = (icp_pit_state *)opaque;
    328    int n;
    329
    330    /* ??? Don't know the PrimeCell ID for this device.  */
    331    n = offset >> 8;
    332    if (n > 2) {
    333        qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad timer %d\n", __func__, n);
    334        return 0;
    335    }
    336
    337    return arm_timer_read(s->timer[n], offset & 0xff);
    338}
    339
    340static void icp_pit_write(void *opaque, hwaddr offset,
    341                          uint64_t value, unsigned size)
    342{
    343    icp_pit_state *s = (icp_pit_state *)opaque;
    344    int n;
    345
    346    n = offset >> 8;
    347    if (n > 2) {
    348        qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad timer %d\n", __func__, n);
    349        return;
    350    }
    351
    352    arm_timer_write(s->timer[n], offset & 0xff, value);
    353}
    354
    355static const MemoryRegionOps icp_pit_ops = {
    356    .read = icp_pit_read,
    357    .write = icp_pit_write,
    358    .endianness = DEVICE_NATIVE_ENDIAN,
    359};
    360
    361static void icp_pit_init(Object *obj)
    362{
    363    icp_pit_state *s = INTEGRATOR_PIT(obj);
    364    SysBusDevice *dev = SYS_BUS_DEVICE(obj);
    365
    366    /* Timer 0 runs at the system clock speed (40MHz).  */
    367    s->timer[0] = arm_timer_init(40000000);
    368    /* The other two timers run at 1MHz.  */
    369    s->timer[1] = arm_timer_init(1000000);
    370    s->timer[2] = arm_timer_init(1000000);
    371
    372    sysbus_init_irq(dev, &s->timer[0]->irq);
    373    sysbus_init_irq(dev, &s->timer[1]->irq);
    374    sysbus_init_irq(dev, &s->timer[2]->irq);
    375
    376    memory_region_init_io(&s->iomem, obj, &icp_pit_ops, s,
    377                          "icp_pit", 0x1000);
    378    sysbus_init_mmio(dev, &s->iomem);
    379    /* This device has no state to save/restore.  The component timers will
    380       save themselves.  */
    381}
    382
    383static const TypeInfo icp_pit_info = {
    384    .name          = TYPE_INTEGRATOR_PIT,
    385    .parent        = TYPE_SYS_BUS_DEVICE,
    386    .instance_size = sizeof(icp_pit_state),
    387    .instance_init = icp_pit_init,
    388};
    389
    390static Property sp804_properties[] = {
    391    DEFINE_PROP_UINT32("freq0", SP804State, freq0, 1000000),
    392    DEFINE_PROP_UINT32("freq1", SP804State, freq1, 1000000),
    393    DEFINE_PROP_END_OF_LIST(),
    394};
    395
    396static void sp804_class_init(ObjectClass *klass, void *data)
    397{
    398    DeviceClass *k = DEVICE_CLASS(klass);
    399
    400    k->realize = sp804_realize;
    401    device_class_set_props(k, sp804_properties);
    402    k->vmsd = &vmstate_sp804;
    403}
    404
    405static const TypeInfo sp804_info = {
    406    .name          = TYPE_SP804,
    407    .parent        = TYPE_SYS_BUS_DEVICE,
    408    .instance_size = sizeof(SP804State),
    409    .instance_init = sp804_init,
    410    .class_init    = sp804_class_init,
    411};
    412
    413static void arm_timer_register_types(void)
    414{
    415    type_register_static(&icp_pit_info);
    416    type_register_static(&sp804_info);
    417}
    418
    419type_init(arm_timer_register_types)