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

cmsdk-apb-dualtimer.c (17675B)


      1/*
      2 * ARM CMSDK APB dual-timer emulation
      3 *
      4 * Copyright (c) 2018 Linaro Limited
      5 * Written by Peter Maydell
      6 *
      7 *  This program is free software; you can redistribute it and/or modify
      8 *  it under the terms of the GNU General Public License version 2 or
      9 *  (at your option) any later version.
     10 */
     11
     12/*
     13 * This is a model of the "APB dual-input timer" which is part of the Cortex-M
     14 * System Design Kit (CMSDK) and documented in the Cortex-M System
     15 * Design Kit Technical Reference Manual (ARM DDI0479C):
     16 * https://developer.arm.com/products/system-design/system-design-kits/cortex-m-system-design-kit
     17 */
     18
     19#include "qemu/osdep.h"
     20#include "qemu/log.h"
     21#include "trace.h"
     22#include "qapi/error.h"
     23#include "qemu/module.h"
     24#include "hw/sysbus.h"
     25#include "hw/irq.h"
     26#include "hw/qdev-properties.h"
     27#include "hw/registerfields.h"
     28#include "hw/qdev-clock.h"
     29#include "hw/timer/cmsdk-apb-dualtimer.h"
     30#include "migration/vmstate.h"
     31
     32REG32(TIMER1LOAD, 0x0)
     33REG32(TIMER1VALUE, 0x4)
     34REG32(TIMER1CONTROL, 0x8)
     35    FIELD(CONTROL, ONESHOT, 0, 1)
     36    FIELD(CONTROL, SIZE, 1, 1)
     37    FIELD(CONTROL, PRESCALE, 2, 2)
     38    FIELD(CONTROL, INTEN, 5, 1)
     39    FIELD(CONTROL, MODE, 6, 1)
     40    FIELD(CONTROL, ENABLE, 7, 1)
     41#define R_CONTROL_VALID_MASK (R_CONTROL_ONESHOT_MASK | R_CONTROL_SIZE_MASK | \
     42                              R_CONTROL_PRESCALE_MASK | R_CONTROL_INTEN_MASK | \
     43                              R_CONTROL_MODE_MASK | R_CONTROL_ENABLE_MASK)
     44REG32(TIMER1INTCLR, 0xc)
     45REG32(TIMER1RIS, 0x10)
     46REG32(TIMER1MIS, 0x14)
     47REG32(TIMER1BGLOAD, 0x18)
     48REG32(TIMER2LOAD, 0x20)
     49REG32(TIMER2VALUE, 0x24)
     50REG32(TIMER2CONTROL, 0x28)
     51REG32(TIMER2INTCLR, 0x2c)
     52REG32(TIMER2RIS, 0x30)
     53REG32(TIMER2MIS, 0x34)
     54REG32(TIMER2BGLOAD, 0x38)
     55REG32(TIMERITCR, 0xf00)
     56    FIELD(TIMERITCR, ENABLE, 0, 1)
     57#define R_TIMERITCR_VALID_MASK R_TIMERITCR_ENABLE_MASK
     58REG32(TIMERITOP, 0xf04)
     59    FIELD(TIMERITOP, TIMINT1, 0, 1)
     60    FIELD(TIMERITOP, TIMINT2, 1, 1)
     61#define R_TIMERITOP_VALID_MASK (R_TIMERITOP_TIMINT1_MASK | \
     62                                R_TIMERITOP_TIMINT2_MASK)
     63REG32(PID4, 0xfd0)
     64REG32(PID5, 0xfd4)
     65REG32(PID6, 0xfd8)
     66REG32(PID7, 0xfdc)
     67REG32(PID0, 0xfe0)
     68REG32(PID1, 0xfe4)
     69REG32(PID2, 0xfe8)
     70REG32(PID3, 0xfec)
     71REG32(CID0, 0xff0)
     72REG32(CID1, 0xff4)
     73REG32(CID2, 0xff8)
     74REG32(CID3, 0xffc)
     75
     76/* PID/CID values */
     77static const int timer_id[] = {
     78    0x04, 0x00, 0x00, 0x00, /* PID4..PID7 */
     79    0x23, 0xb8, 0x1b, 0x00, /* PID0..PID3 */
     80    0x0d, 0xf0, 0x05, 0xb1, /* CID0..CID3 */
     81};
     82
     83static bool cmsdk_dualtimermod_intstatus(CMSDKAPBDualTimerModule *m)
     84{
     85    /* Return masked interrupt status for the timer module */
     86    return m->intstatus && (m->control & R_CONTROL_INTEN_MASK);
     87}
     88
     89static void cmsdk_apb_dualtimer_update(CMSDKAPBDualTimer *s)
     90{
     91    bool timint1, timint2, timintc;
     92
     93    if (s->timeritcr) {
     94        /* Integration test mode: outputs driven directly from TIMERITOP bits */
     95        timint1 = s->timeritop & R_TIMERITOP_TIMINT1_MASK;
     96        timint2 = s->timeritop & R_TIMERITOP_TIMINT2_MASK;
     97    } else {
     98        timint1 = cmsdk_dualtimermod_intstatus(&s->timermod[0]);
     99        timint2 = cmsdk_dualtimermod_intstatus(&s->timermod[1]);
    100    }
    101
    102    timintc = timint1 || timint2;
    103
    104    qemu_set_irq(s->timermod[0].timerint, timint1);
    105    qemu_set_irq(s->timermod[1].timerint, timint2);
    106    qemu_set_irq(s->timerintc, timintc);
    107}
    108
    109static int cmsdk_dualtimermod_divisor(CMSDKAPBDualTimerModule *m)
    110{
    111    /* Return the divisor set by the current CONTROL.PRESCALE value */
    112    switch (FIELD_EX32(m->control, CONTROL, PRESCALE)) {
    113    case 0:
    114        return 1;
    115    case 1:
    116        return 16;
    117    case 2:
    118    case 3: /* UNDEFINED, we treat like 2 (and complained when it was set) */
    119        return 256;
    120    default:
    121        g_assert_not_reached();
    122    }
    123}
    124
    125static void cmsdk_dualtimermod_write_control(CMSDKAPBDualTimerModule *m,
    126                                             uint32_t newctrl)
    127{
    128    /* Handle a write to the CONTROL register */
    129    uint32_t changed;
    130
    131    ptimer_transaction_begin(m->timer);
    132
    133    newctrl &= R_CONTROL_VALID_MASK;
    134
    135    changed = m->control ^ newctrl;
    136
    137    if (changed & ~newctrl & R_CONTROL_ENABLE_MASK) {
    138        /* ENABLE cleared, stop timer before any further changes */
    139        ptimer_stop(m->timer);
    140    }
    141
    142    if (changed & R_CONTROL_PRESCALE_MASK) {
    143        int divisor;
    144
    145        switch (FIELD_EX32(newctrl, CONTROL, PRESCALE)) {
    146        case 0:
    147            divisor = 1;
    148            break;
    149        case 1:
    150            divisor = 16;
    151            break;
    152        case 2:
    153            divisor = 256;
    154            break;
    155        case 3:
    156            /* UNDEFINED; complain, and arbitrarily treat like 2 */
    157            qemu_log_mask(LOG_GUEST_ERROR,
    158                          "CMSDK APB dual-timer: CONTROL.PRESCALE==0b11"
    159                          " is undefined behaviour\n");
    160            divisor = 256;
    161            break;
    162        default:
    163            g_assert_not_reached();
    164        }
    165        ptimer_set_period_from_clock(m->timer, m->parent->timclk, divisor);
    166    }
    167
    168    if (changed & R_CONTROL_MODE_MASK) {
    169        uint32_t load;
    170        if (newctrl & R_CONTROL_MODE_MASK) {
    171            /* Periodic: the limit is the LOAD register value */
    172            load = m->load;
    173        } else {
    174            /* Free-running: counter wraps around */
    175            load = ptimer_get_limit(m->timer);
    176            if (!(m->control & R_CONTROL_SIZE_MASK)) {
    177                load = deposit32(m->load, 0, 16, load);
    178            }
    179            m->load = load;
    180            load = 0xffffffff;
    181        }
    182        if (!(m->control & R_CONTROL_SIZE_MASK)) {
    183            load &= 0xffff;
    184        }
    185        ptimer_set_limit(m->timer, load, 0);
    186    }
    187
    188    if (changed & R_CONTROL_SIZE_MASK) {
    189        /* Timer switched between 16 and 32 bit count */
    190        uint32_t value, load;
    191
    192        value = ptimer_get_count(m->timer);
    193        load = ptimer_get_limit(m->timer);
    194        if (newctrl & R_CONTROL_SIZE_MASK) {
    195            /* 16 -> 32, top half of VALUE is in struct field */
    196            value = deposit32(m->value, 0, 16, value);
    197        } else {
    198            /* 32 -> 16: save top half to struct field and truncate */
    199            m->value = value;
    200            value &= 0xffff;
    201        }
    202
    203        if (newctrl & R_CONTROL_MODE_MASK) {
    204            /* Periodic, timer limit has LOAD value */
    205            if (newctrl & R_CONTROL_SIZE_MASK) {
    206                load = deposit32(m->load, 0, 16, load);
    207            } else {
    208                m->load = load;
    209                load &= 0xffff;
    210            }
    211        } else {
    212            /* Free-running, timer limit is set to give wraparound */
    213            if (newctrl & R_CONTROL_SIZE_MASK) {
    214                load = 0xffffffff;
    215            } else {
    216                load = 0xffff;
    217            }
    218        }
    219        ptimer_set_count(m->timer, value);
    220        ptimer_set_limit(m->timer, load, 0);
    221    }
    222
    223    if (newctrl & R_CONTROL_ENABLE_MASK) {
    224        /*
    225         * ENABLE is set; start the timer after all other changes.
    226         * We start it even if the ENABLE bit didn't actually change,
    227         * in case the timer was an expired one-shot timer that has
    228         * now been changed into a free-running or periodic timer.
    229         */
    230        ptimer_run(m->timer, !!(newctrl & R_CONTROL_ONESHOT_MASK));
    231    }
    232
    233    m->control = newctrl;
    234
    235    ptimer_transaction_commit(m->timer);
    236}
    237
    238static uint64_t cmsdk_apb_dualtimer_read(void *opaque, hwaddr offset,
    239                                          unsigned size)
    240{
    241    CMSDKAPBDualTimer *s = CMSDK_APB_DUALTIMER(opaque);
    242    uint64_t r;
    243
    244    if (offset >= A_TIMERITCR) {
    245        switch (offset) {
    246        case A_TIMERITCR:
    247            r = s->timeritcr;
    248            break;
    249        case A_PID4 ... A_CID3:
    250            r = timer_id[(offset - A_PID4) / 4];
    251            break;
    252        default:
    253        bad_offset:
    254            qemu_log_mask(LOG_GUEST_ERROR,
    255                          "CMSDK APB dual-timer read: bad offset %x\n",
    256                          (int) offset);
    257            r = 0;
    258            break;
    259        }
    260    } else {
    261        int timer = offset >> 5;
    262        CMSDKAPBDualTimerModule *m;
    263
    264        if (timer >= ARRAY_SIZE(s->timermod)) {
    265            goto bad_offset;
    266        }
    267
    268        m = &s->timermod[timer];
    269
    270        switch (offset & 0x1F) {
    271        case A_TIMER1LOAD:
    272        case A_TIMER1BGLOAD:
    273            if (m->control & R_CONTROL_MODE_MASK) {
    274                /*
    275                 * Periodic: the ptimer limit is the LOAD register value, (or
    276                 * just the low 16 bits of it if the timer is in 16-bit mode)
    277                 */
    278                r = ptimer_get_limit(m->timer);
    279                if (!(m->control & R_CONTROL_SIZE_MASK)) {
    280                    r = deposit32(m->load, 0, 16, r);
    281                }
    282            } else {
    283                /* Free-running: LOAD register value is just in m->load */
    284                r = m->load;
    285            }
    286            break;
    287        case A_TIMER1VALUE:
    288            r = ptimer_get_count(m->timer);
    289            if (!(m->control & R_CONTROL_SIZE_MASK)) {
    290                r = deposit32(m->value, 0, 16, r);
    291            }
    292            break;
    293        case A_TIMER1CONTROL:
    294            r = m->control;
    295            break;
    296        case A_TIMER1RIS:
    297            r = m->intstatus;
    298            break;
    299        case A_TIMER1MIS:
    300            r = cmsdk_dualtimermod_intstatus(m);
    301            break;
    302        default:
    303            goto bad_offset;
    304        }
    305    }
    306
    307    trace_cmsdk_apb_dualtimer_read(offset, r, size);
    308    return r;
    309}
    310
    311static void cmsdk_apb_dualtimer_write(void *opaque, hwaddr offset,
    312                                       uint64_t value, unsigned size)
    313{
    314    CMSDKAPBDualTimer *s = CMSDK_APB_DUALTIMER(opaque);
    315
    316    trace_cmsdk_apb_dualtimer_write(offset, value, size);
    317
    318    if (offset >= A_TIMERITCR) {
    319        switch (offset) {
    320        case A_TIMERITCR:
    321            s->timeritcr = value & R_TIMERITCR_VALID_MASK;
    322            cmsdk_apb_dualtimer_update(s);
    323            break;
    324        case A_TIMERITOP:
    325            s->timeritop = value & R_TIMERITOP_VALID_MASK;
    326            cmsdk_apb_dualtimer_update(s);
    327            break;
    328        default:
    329        bad_offset:
    330            qemu_log_mask(LOG_GUEST_ERROR,
    331                          "CMSDK APB dual-timer write: bad offset %x\n",
    332                          (int) offset);
    333            break;
    334        }
    335    } else {
    336        int timer = offset >> 5;
    337        CMSDKAPBDualTimerModule *m;
    338
    339        if (timer >= ARRAY_SIZE(s->timermod)) {
    340            goto bad_offset;
    341        }
    342
    343        m = &s->timermod[timer];
    344
    345        switch (offset & 0x1F) {
    346        case A_TIMER1LOAD:
    347            /* Set the limit, and immediately reload the count from it */
    348            m->load = value;
    349            m->value = value;
    350            if (!(m->control & R_CONTROL_SIZE_MASK)) {
    351                value &= 0xffff;
    352            }
    353            ptimer_transaction_begin(m->timer);
    354            if (!(m->control & R_CONTROL_MODE_MASK)) {
    355                /*
    356                 * In free-running mode this won't set the limit but will
    357                 * still change the current count value.
    358                 */
    359                ptimer_set_count(m->timer, value);
    360            } else {
    361                if (!value) {
    362                    ptimer_stop(m->timer);
    363                }
    364                ptimer_set_limit(m->timer, value, 1);
    365                if (value && (m->control & R_CONTROL_ENABLE_MASK)) {
    366                    /* Force possibly-expired oneshot timer to restart */
    367                    ptimer_run(m->timer, 1);
    368                }
    369            }
    370            ptimer_transaction_commit(m->timer);
    371            break;
    372        case A_TIMER1BGLOAD:
    373            /* Set the limit, but not the current count */
    374            m->load = value;
    375            if (!(m->control & R_CONTROL_MODE_MASK)) {
    376                /* In free-running mode there is no limit */
    377                break;
    378            }
    379            if (!(m->control & R_CONTROL_SIZE_MASK)) {
    380                value &= 0xffff;
    381            }
    382            ptimer_transaction_begin(m->timer);
    383            ptimer_set_limit(m->timer, value, 0);
    384            ptimer_transaction_commit(m->timer);
    385            break;
    386        case A_TIMER1CONTROL:
    387            cmsdk_dualtimermod_write_control(m, value);
    388            cmsdk_apb_dualtimer_update(s);
    389            break;
    390        case A_TIMER1INTCLR:
    391            m->intstatus = 0;
    392            cmsdk_apb_dualtimer_update(s);
    393            break;
    394        default:
    395            goto bad_offset;
    396        }
    397    }
    398}
    399
    400static const MemoryRegionOps cmsdk_apb_dualtimer_ops = {
    401    .read = cmsdk_apb_dualtimer_read,
    402    .write = cmsdk_apb_dualtimer_write,
    403    .endianness = DEVICE_LITTLE_ENDIAN,
    404    /* byte/halfword accesses are just zero-padded on reads and writes */
    405    .impl.min_access_size = 4,
    406    .impl.max_access_size = 4,
    407    .valid.min_access_size = 1,
    408    .valid.max_access_size = 4,
    409};
    410
    411static void cmsdk_dualtimermod_tick(void *opaque)
    412{
    413    CMSDKAPBDualTimerModule *m = opaque;
    414
    415    m->intstatus = 1;
    416    cmsdk_apb_dualtimer_update(m->parent);
    417}
    418
    419static void cmsdk_dualtimermod_reset(CMSDKAPBDualTimerModule *m)
    420{
    421    m->control = R_CONTROL_INTEN_MASK;
    422    m->intstatus = 0;
    423    m->load = 0;
    424    m->value = 0xffffffff;
    425    ptimer_transaction_begin(m->timer);
    426    ptimer_stop(m->timer);
    427    /*
    428     * We start in free-running mode, with VALUE at 0xffffffff, and
    429     * in 16-bit counter mode. This means that the ptimer count and
    430     * limit must both be set to 0xffff, so we wrap at 16 bits.
    431     */
    432    ptimer_set_limit(m->timer, 0xffff, 1);
    433    ptimer_set_period_from_clock(m->timer, m->parent->timclk,
    434                                 cmsdk_dualtimermod_divisor(m));
    435    ptimer_transaction_commit(m->timer);
    436}
    437
    438static void cmsdk_apb_dualtimer_reset(DeviceState *dev)
    439{
    440    CMSDKAPBDualTimer *s = CMSDK_APB_DUALTIMER(dev);
    441    int i;
    442
    443    trace_cmsdk_apb_dualtimer_reset();
    444
    445    for (i = 0; i < ARRAY_SIZE(s->timermod); i++) {
    446        cmsdk_dualtimermod_reset(&s->timermod[i]);
    447    }
    448    s->timeritcr = 0;
    449    s->timeritop = 0;
    450}
    451
    452static void cmsdk_apb_dualtimer_clk_update(void *opaque, ClockEvent event)
    453{
    454    CMSDKAPBDualTimer *s = CMSDK_APB_DUALTIMER(opaque);
    455    int i;
    456
    457    for (i = 0; i < ARRAY_SIZE(s->timermod); i++) {
    458        CMSDKAPBDualTimerModule *m = &s->timermod[i];
    459        ptimer_transaction_begin(m->timer);
    460        ptimer_set_period_from_clock(m->timer, m->parent->timclk,
    461                                     cmsdk_dualtimermod_divisor(m));
    462        ptimer_transaction_commit(m->timer);
    463    }
    464}
    465
    466static void cmsdk_apb_dualtimer_init(Object *obj)
    467{
    468    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
    469    CMSDKAPBDualTimer *s = CMSDK_APB_DUALTIMER(obj);
    470    int i;
    471
    472    memory_region_init_io(&s->iomem, obj, &cmsdk_apb_dualtimer_ops,
    473                          s, "cmsdk-apb-dualtimer", 0x1000);
    474    sysbus_init_mmio(sbd, &s->iomem);
    475    sysbus_init_irq(sbd, &s->timerintc);
    476
    477    for (i = 0; i < ARRAY_SIZE(s->timermod); i++) {
    478        sysbus_init_irq(sbd, &s->timermod[i].timerint);
    479    }
    480    s->timclk = qdev_init_clock_in(DEVICE(s), "TIMCLK",
    481                                   cmsdk_apb_dualtimer_clk_update, s,
    482                                   ClockUpdate);
    483}
    484
    485static void cmsdk_apb_dualtimer_realize(DeviceState *dev, Error **errp)
    486{
    487    CMSDKAPBDualTimer *s = CMSDK_APB_DUALTIMER(dev);
    488    int i;
    489
    490    if (!clock_has_source(s->timclk)) {
    491        error_setg(errp, "CMSDK APB dualtimer: TIMCLK clock must be connected");
    492        return;
    493    }
    494
    495    for (i = 0; i < ARRAY_SIZE(s->timermod); i++) {
    496        CMSDKAPBDualTimerModule *m = &s->timermod[i];
    497
    498        m->parent = s;
    499        m->timer = ptimer_init(cmsdk_dualtimermod_tick, m,
    500                               PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD |
    501                               PTIMER_POLICY_TRIGGER_ONLY_ON_DECREMENT |
    502                               PTIMER_POLICY_NO_IMMEDIATE_RELOAD |
    503                               PTIMER_POLICY_NO_COUNTER_ROUND_DOWN);
    504    }
    505}
    506
    507static const VMStateDescription cmsdk_dualtimermod_vmstate = {
    508    .name = "cmsdk-apb-dualtimer-module",
    509    .version_id = 1,
    510    .minimum_version_id = 1,
    511    .fields = (VMStateField[]) {
    512        VMSTATE_PTIMER(timer, CMSDKAPBDualTimerModule),
    513        VMSTATE_UINT32(load, CMSDKAPBDualTimerModule),
    514        VMSTATE_UINT32(value, CMSDKAPBDualTimerModule),
    515        VMSTATE_UINT32(control, CMSDKAPBDualTimerModule),
    516        VMSTATE_UINT32(intstatus, CMSDKAPBDualTimerModule),
    517        VMSTATE_END_OF_LIST()
    518    }
    519};
    520
    521static const VMStateDescription cmsdk_apb_dualtimer_vmstate = {
    522    .name = "cmsdk-apb-dualtimer",
    523    .version_id = 2,
    524    .minimum_version_id = 2,
    525    .fields = (VMStateField[]) {
    526        VMSTATE_CLOCK(timclk, CMSDKAPBDualTimer),
    527        VMSTATE_STRUCT_ARRAY(timermod, CMSDKAPBDualTimer,
    528                             CMSDK_APB_DUALTIMER_NUM_MODULES,
    529                             1, cmsdk_dualtimermod_vmstate,
    530                             CMSDKAPBDualTimerModule),
    531        VMSTATE_UINT32(timeritcr, CMSDKAPBDualTimer),
    532        VMSTATE_UINT32(timeritop, CMSDKAPBDualTimer),
    533        VMSTATE_END_OF_LIST()
    534    }
    535};
    536
    537static void cmsdk_apb_dualtimer_class_init(ObjectClass *klass, void *data)
    538{
    539    DeviceClass *dc = DEVICE_CLASS(klass);
    540
    541    dc->realize = cmsdk_apb_dualtimer_realize;
    542    dc->vmsd = &cmsdk_apb_dualtimer_vmstate;
    543    dc->reset = cmsdk_apb_dualtimer_reset;
    544}
    545
    546static const TypeInfo cmsdk_apb_dualtimer_info = {
    547    .name = TYPE_CMSDK_APB_DUALTIMER,
    548    .parent = TYPE_SYS_BUS_DEVICE,
    549    .instance_size = sizeof(CMSDKAPBDualTimer),
    550    .instance_init = cmsdk_apb_dualtimer_init,
    551    .class_init = cmsdk_apb_dualtimer_class_init,
    552};
    553
    554static void cmsdk_apb_dualtimer_register_types(void)
    555{
    556    type_register_static(&cmsdk_apb_dualtimer_info);
    557}
    558
    559type_init(cmsdk_apb_dualtimer_register_types);