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

aspeed_timer.c (21393B)


      1/*
      2 * ASPEED AST2400 Timer
      3 *
      4 * Andrew Jeffery <andrew@aj.id.au>
      5 *
      6 * Copyright (C) 2016 IBM Corp.
      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 "qapi/error.h"
     14#include "hw/irq.h"
     15#include "hw/sysbus.h"
     16#include "hw/timer/aspeed_timer.h"
     17#include "migration/vmstate.h"
     18#include "qemu/bitops.h"
     19#include "qemu/timer.h"
     20#include "qemu/log.h"
     21#include "qemu/module.h"
     22#include "hw/qdev-properties.h"
     23#include "trace.h"
     24
     25#define TIMER_NR_REGS 4
     26
     27#define TIMER_CTRL_BITS 4
     28#define TIMER_CTRL_MASK ((1 << TIMER_CTRL_BITS) - 1)
     29
     30#define TIMER_CLOCK_USE_EXT true
     31#define TIMER_CLOCK_EXT_HZ 1000000
     32#define TIMER_CLOCK_USE_APB false
     33
     34#define TIMER_REG_STATUS 0
     35#define TIMER_REG_RELOAD 1
     36#define TIMER_REG_MATCH_FIRST 2
     37#define TIMER_REG_MATCH_SECOND 3
     38
     39#define TIMER_FIRST_CAP_PULSE 4
     40
     41enum timer_ctrl_op {
     42    op_enable = 0,
     43    op_external_clock,
     44    op_overflow_interrupt,
     45    op_pulse_enable
     46};
     47
     48/*
     49 * Minimum value of the reload register to filter out short period
     50 * timers which have a noticeable impact in emulation. 5us should be
     51 * enough, use 20us for "safety".
     52 */
     53#define TIMER_MIN_NS (20 * SCALE_US)
     54
     55/**
     56 * Avoid mutual references between AspeedTimerCtrlState and AspeedTimer
     57 * structs, as it's a waste of memory. The ptimer BH callback needs to know
     58 * whether a specific AspeedTimer is enabled, but this information is held in
     59 * AspeedTimerCtrlState. So, provide a helper to hoist ourselves from an
     60 * arbitrary AspeedTimer to AspeedTimerCtrlState.
     61 */
     62static inline AspeedTimerCtrlState *timer_to_ctrl(AspeedTimer *t)
     63{
     64    const AspeedTimer (*timers)[] = (void *)t - (t->id * sizeof(*t));
     65    return container_of(timers, AspeedTimerCtrlState, timers);
     66}
     67
     68static inline bool timer_ctrl_status(AspeedTimer *t, enum timer_ctrl_op op)
     69{
     70    return !!(timer_to_ctrl(t)->ctrl & BIT(t->id * TIMER_CTRL_BITS + op));
     71}
     72
     73static inline bool timer_enabled(AspeedTimer *t)
     74{
     75    return timer_ctrl_status(t, op_enable);
     76}
     77
     78static inline bool timer_overflow_interrupt(AspeedTimer *t)
     79{
     80    return timer_ctrl_status(t, op_overflow_interrupt);
     81}
     82
     83static inline bool timer_can_pulse(AspeedTimer *t)
     84{
     85    return t->id >= TIMER_FIRST_CAP_PULSE;
     86}
     87
     88static inline bool timer_external_clock(AspeedTimer *t)
     89{
     90    return timer_ctrl_status(t, op_external_clock);
     91}
     92
     93static inline uint32_t calculate_rate(struct AspeedTimer *t)
     94{
     95    AspeedTimerCtrlState *s = timer_to_ctrl(t);
     96
     97    return timer_external_clock(t) ? TIMER_CLOCK_EXT_HZ :
     98        aspeed_scu_get_apb_freq(s->scu);
     99}
    100
    101static inline uint32_t calculate_ticks(struct AspeedTimer *t, uint64_t now_ns)
    102{
    103    uint64_t delta_ns = now_ns - MIN(now_ns, t->start);
    104    uint32_t rate = calculate_rate(t);
    105    uint64_t ticks = muldiv64(delta_ns, rate, NANOSECONDS_PER_SECOND);
    106
    107    return t->reload - MIN(t->reload, ticks);
    108}
    109
    110static uint32_t calculate_min_ticks(AspeedTimer *t, uint32_t value)
    111{
    112    uint32_t rate = calculate_rate(t);
    113    uint32_t min_ticks = muldiv64(TIMER_MIN_NS, rate, NANOSECONDS_PER_SECOND);
    114
    115    return  value < min_ticks ? min_ticks : value;
    116}
    117
    118static inline uint64_t calculate_time(struct AspeedTimer *t, uint32_t ticks)
    119{
    120    uint64_t delta_ns;
    121    uint64_t delta_ticks;
    122
    123    delta_ticks = t->reload - MIN(t->reload, ticks);
    124    delta_ns = muldiv64(delta_ticks, NANOSECONDS_PER_SECOND, calculate_rate(t));
    125
    126    return t->start + delta_ns;
    127}
    128
    129static inline uint32_t calculate_match(struct AspeedTimer *t, int i)
    130{
    131    return t->match[i] < t->reload ? t->match[i] : 0;
    132}
    133
    134static uint64_t calculate_next(struct AspeedTimer *t)
    135{
    136    uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
    137    uint64_t next;
    138
    139    /*
    140     * We don't know the relationship between the values in the match
    141     * registers, so sort using MAX/MIN/zero. We sort in that order as
    142     * the timer counts down to zero.
    143     */
    144
    145    next = calculate_time(t, MAX(calculate_match(t, 0), calculate_match(t, 1)));
    146    if (now < next) {
    147        return next;
    148    }
    149
    150    next = calculate_time(t, MIN(calculate_match(t, 0), calculate_match(t, 1)));
    151    if (now < next) {
    152        return next;
    153    }
    154
    155    next = calculate_time(t, 0);
    156    if (now < next) {
    157        return next;
    158    }
    159
    160    /* We've missed all deadlines, fire interrupt and try again */
    161    timer_del(&t->timer);
    162
    163    if (timer_overflow_interrupt(t)) {
    164        AspeedTimerCtrlState *s = timer_to_ctrl(t);
    165        t->level = !t->level;
    166        s->irq_sts |= BIT(t->id);
    167        qemu_set_irq(t->irq, t->level);
    168    }
    169
    170    next = MAX(MAX(calculate_match(t, 0), calculate_match(t, 1)), 0);
    171    t->start = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
    172
    173    return calculate_time(t, next);
    174}
    175
    176static void aspeed_timer_mod(AspeedTimer *t)
    177{
    178    uint64_t next = calculate_next(t);
    179    if (next) {
    180        timer_mod(&t->timer, next);
    181    }
    182}
    183
    184static void aspeed_timer_expire(void *opaque)
    185{
    186    AspeedTimer *t = opaque;
    187    bool interrupt = false;
    188    uint32_t ticks;
    189
    190    if (!timer_enabled(t)) {
    191        return;
    192    }
    193
    194    ticks = calculate_ticks(t, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
    195
    196    if (!ticks) {
    197        interrupt = timer_overflow_interrupt(t) || !t->match[0] || !t->match[1];
    198    } else if (ticks <= MIN(t->match[0], t->match[1])) {
    199        interrupt = true;
    200    } else if (ticks <= MAX(t->match[0], t->match[1])) {
    201        interrupt = true;
    202    }
    203
    204    if (interrupt) {
    205        AspeedTimerCtrlState *s = timer_to_ctrl(t);
    206        t->level = !t->level;
    207        s->irq_sts |= BIT(t->id);
    208        qemu_set_irq(t->irq, t->level);
    209    }
    210
    211    aspeed_timer_mod(t);
    212}
    213
    214static uint64_t aspeed_timer_get_value(AspeedTimer *t, int reg)
    215{
    216    uint64_t value;
    217
    218    switch (reg) {
    219    case TIMER_REG_STATUS:
    220        if (timer_enabled(t)) {
    221            value = calculate_ticks(t, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
    222        } else {
    223            value = t->reload;
    224        }
    225        break;
    226    case TIMER_REG_RELOAD:
    227        value = t->reload;
    228        break;
    229    case TIMER_REG_MATCH_FIRST:
    230    case TIMER_REG_MATCH_SECOND:
    231        value = t->match[reg - 2];
    232        break;
    233    default:
    234        qemu_log_mask(LOG_UNIMP, "%s: Programming error: unexpected reg: %d\n",
    235                      __func__, reg);
    236        value = 0;
    237        break;
    238    }
    239    return value;
    240}
    241
    242static uint64_t aspeed_timer_read(void *opaque, hwaddr offset, unsigned size)
    243{
    244    AspeedTimerCtrlState *s = opaque;
    245    const int reg = (offset & 0xf) / 4;
    246    uint64_t value;
    247
    248    switch (offset) {
    249    case 0x30: /* Control Register */
    250        value = s->ctrl;
    251        break;
    252    case 0x00 ... 0x2c: /* Timers 1 - 4 */
    253        value = aspeed_timer_get_value(&s->timers[(offset >> 4)], reg);
    254        break;
    255    case 0x40 ... 0x8c: /* Timers 5 - 8 */
    256        value = aspeed_timer_get_value(&s->timers[(offset >> 4) - 1], reg);
    257        break;
    258    default:
    259        value = ASPEED_TIMER_GET_CLASS(s)->read(s, offset);
    260        break;
    261    }
    262    trace_aspeed_timer_read(offset, size, value);
    263    return value;
    264}
    265
    266static void aspeed_timer_set_value(AspeedTimerCtrlState *s, int timer, int reg,
    267                                   uint32_t value)
    268{
    269    AspeedTimer *t;
    270    uint32_t old_reload;
    271
    272    trace_aspeed_timer_set_value(timer, reg, value);
    273    t = &s->timers[timer];
    274    switch (reg) {
    275    case TIMER_REG_RELOAD:
    276        old_reload = t->reload;
    277        t->reload = calculate_min_ticks(t, value);
    278
    279        /* If the reload value was not previously set, or zero, and
    280         * the current value is valid, try to start the timer if it is
    281         * enabled.
    282         */
    283        if (old_reload || !t->reload) {
    284            break;
    285        }
    286        /* fall through to re-enable */
    287    case TIMER_REG_STATUS:
    288        if (timer_enabled(t)) {
    289            uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
    290            int64_t delta = (int64_t) value - (int64_t) calculate_ticks(t, now);
    291            uint32_t rate = calculate_rate(t);
    292
    293            if (delta >= 0) {
    294                t->start += muldiv64(delta, NANOSECONDS_PER_SECOND, rate);
    295            } else {
    296                t->start -= muldiv64(-delta, NANOSECONDS_PER_SECOND, rate);
    297            }
    298            aspeed_timer_mod(t);
    299        }
    300        break;
    301    case TIMER_REG_MATCH_FIRST:
    302    case TIMER_REG_MATCH_SECOND:
    303        t->match[reg - 2] = value;
    304        if (timer_enabled(t)) {
    305            aspeed_timer_mod(t);
    306        }
    307        break;
    308    default:
    309        qemu_log_mask(LOG_UNIMP, "%s: Programming error: unexpected reg: %d\n",
    310                      __func__, reg);
    311        break;
    312    }
    313}
    314
    315/* Control register operations are broken out into helpers that can be
    316 * explicitly called on aspeed_timer_reset(), but also from
    317 * aspeed_timer_ctrl_op().
    318 */
    319
    320static void aspeed_timer_ctrl_enable(AspeedTimer *t, bool enable)
    321{
    322    trace_aspeed_timer_ctrl_enable(t->id, enable);
    323    if (enable) {
    324        t->start = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
    325        aspeed_timer_mod(t);
    326    } else {
    327        timer_del(&t->timer);
    328    }
    329}
    330
    331static void aspeed_timer_ctrl_external_clock(AspeedTimer *t, bool enable)
    332{
    333    trace_aspeed_timer_ctrl_external_clock(t->id, enable);
    334}
    335
    336static void aspeed_timer_ctrl_overflow_interrupt(AspeedTimer *t, bool enable)
    337{
    338    trace_aspeed_timer_ctrl_overflow_interrupt(t->id, enable);
    339}
    340
    341static void aspeed_timer_ctrl_pulse_enable(AspeedTimer *t, bool enable)
    342{
    343    if (timer_can_pulse(t)) {
    344        trace_aspeed_timer_ctrl_pulse_enable(t->id, enable);
    345    } else {
    346        qemu_log_mask(LOG_GUEST_ERROR,
    347                "%s: Timer does not support pulse mode\n", __func__);
    348    }
    349}
    350
    351/**
    352 * Given the actions are fixed in number and completely described in helper
    353 * functions, dispatch with a lookup table rather than manage control flow with
    354 * a switch statement.
    355 */
    356static void (*const ctrl_ops[])(AspeedTimer *, bool) = {
    357    [op_enable] = aspeed_timer_ctrl_enable,
    358    [op_external_clock] = aspeed_timer_ctrl_external_clock,
    359    [op_overflow_interrupt] = aspeed_timer_ctrl_overflow_interrupt,
    360    [op_pulse_enable] = aspeed_timer_ctrl_pulse_enable,
    361};
    362
    363/**
    364 * Conditionally affect changes chosen by a timer's control bit.
    365 *
    366 * The aspeed_timer_ctrl_op() interface is convenient for the
    367 * aspeed_timer_set_ctrl() function as the "no change" early exit can be
    368 * calculated for all operations, which cleans up the caller code. However the
    369 * interface isn't convenient for the reset function where we want to enter a
    370 * specific state without artificially constructing old and new values that
    371 * will fall through the change guard (and motivates extracting the actions
    372 * out to helper functions).
    373 *
    374 * @t: The timer to manipulate
    375 * @op: The type of operation to be performed
    376 * @old: The old state of the timer's control bits
    377 * @new: The incoming state for the timer's control bits
    378 */
    379static void aspeed_timer_ctrl_op(AspeedTimer *t, enum timer_ctrl_op op,
    380                                 uint8_t old, uint8_t new)
    381{
    382    const uint8_t mask = BIT(op);
    383    const bool enable = !!(new & mask);
    384    const bool changed = ((old ^ new) & mask);
    385    if (!changed) {
    386        return;
    387    }
    388    ctrl_ops[op](t, enable);
    389}
    390
    391static void aspeed_timer_set_ctrl(AspeedTimerCtrlState *s, uint32_t reg)
    392{
    393    int i;
    394    int shift;
    395    uint8_t t_old, t_new;
    396    AspeedTimer *t;
    397    const uint8_t enable_mask = BIT(op_enable);
    398
    399    /* Handle a dependency between the 'enable' and remaining three
    400     * configuration bits - i.e. if more than one bit in the control set has
    401     * changed, including the 'enable' bit, then we want either disable the
    402     * timer and perform configuration, or perform configuration and then
    403     * enable the timer
    404     */
    405    for (i = 0; i < ASPEED_TIMER_NR_TIMERS; i++) {
    406        t = &s->timers[i];
    407        shift = (i * TIMER_CTRL_BITS);
    408        t_old = (s->ctrl >> shift) & TIMER_CTRL_MASK;
    409        t_new = (reg >> shift) & TIMER_CTRL_MASK;
    410
    411        /* If we are disabling, do so first */
    412        if ((t_old & enable_mask) && !(t_new & enable_mask)) {
    413            aspeed_timer_ctrl_enable(t, false);
    414        }
    415        aspeed_timer_ctrl_op(t, op_external_clock, t_old, t_new);
    416        aspeed_timer_ctrl_op(t, op_overflow_interrupt, t_old, t_new);
    417        aspeed_timer_ctrl_op(t, op_pulse_enable, t_old, t_new);
    418        /* If we are enabling, do so last */
    419        if (!(t_old & enable_mask) && (t_new & enable_mask)) {
    420            aspeed_timer_ctrl_enable(t, true);
    421        }
    422    }
    423    s->ctrl = reg;
    424}
    425
    426static void aspeed_timer_set_ctrl2(AspeedTimerCtrlState *s, uint32_t value)
    427{
    428    trace_aspeed_timer_set_ctrl2(value);
    429}
    430
    431static void aspeed_timer_write(void *opaque, hwaddr offset, uint64_t value,
    432                               unsigned size)
    433{
    434    const uint32_t tv = (uint32_t)(value & 0xFFFFFFFF);
    435    const int reg = (offset & 0xf) / 4;
    436    AspeedTimerCtrlState *s = opaque;
    437
    438    switch (offset) {
    439    /* Control Registers */
    440    case 0x30:
    441        aspeed_timer_set_ctrl(s, tv);
    442        break;
    443    /* Timer Registers */
    444    case 0x00 ... 0x2c:
    445        aspeed_timer_set_value(s, (offset >> TIMER_NR_REGS), reg, tv);
    446        break;
    447    case 0x40 ... 0x8c:
    448        aspeed_timer_set_value(s, (offset >> TIMER_NR_REGS) - 1, reg, tv);
    449        break;
    450    default:
    451        ASPEED_TIMER_GET_CLASS(s)->write(s, offset, value);
    452        break;
    453    }
    454}
    455
    456static const MemoryRegionOps aspeed_timer_ops = {
    457    .read = aspeed_timer_read,
    458    .write = aspeed_timer_write,
    459    .endianness = DEVICE_LITTLE_ENDIAN,
    460    .valid.min_access_size = 4,
    461    .valid.max_access_size = 4,
    462    .valid.unaligned = false,
    463};
    464
    465static uint64_t aspeed_2400_timer_read(AspeedTimerCtrlState *s, hwaddr offset)
    466{
    467    uint64_t value;
    468
    469    switch (offset) {
    470    case 0x34:
    471        value = s->ctrl2;
    472        break;
    473    case 0x38:
    474    case 0x3C:
    475    default:
    476        qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
    477                __func__, offset);
    478        value = 0;
    479        break;
    480    }
    481    return value;
    482}
    483
    484static void aspeed_2400_timer_write(AspeedTimerCtrlState *s, hwaddr offset,
    485                                    uint64_t value)
    486{
    487    const uint32_t tv = (uint32_t)(value & 0xFFFFFFFF);
    488
    489    switch (offset) {
    490    case 0x34:
    491        aspeed_timer_set_ctrl2(s, tv);
    492        break;
    493    case 0x38:
    494    case 0x3C:
    495    default:
    496        qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
    497                __func__, offset);
    498        break;
    499    }
    500}
    501
    502static uint64_t aspeed_2500_timer_read(AspeedTimerCtrlState *s, hwaddr offset)
    503{
    504    uint64_t value;
    505
    506    switch (offset) {
    507    case 0x34:
    508        value = s->ctrl2;
    509        break;
    510    case 0x38:
    511        value = s->ctrl3 & BIT(0);
    512        break;
    513    case 0x3C:
    514    default:
    515        qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
    516                __func__, offset);
    517        value = 0;
    518        break;
    519    }
    520    return value;
    521}
    522
    523static void aspeed_2500_timer_write(AspeedTimerCtrlState *s, hwaddr offset,
    524                                    uint64_t value)
    525{
    526    const uint32_t tv = (uint32_t)(value & 0xFFFFFFFF);
    527    uint8_t command;
    528
    529    switch (offset) {
    530    case 0x34:
    531        aspeed_timer_set_ctrl2(s, tv);
    532        break;
    533    case 0x38:
    534        command = (value >> 1) & 0xFF;
    535        if (command == 0xAE) {
    536            s->ctrl3 = 0x1;
    537        } else if (command == 0xEA) {
    538            s->ctrl3 = 0x0;
    539        }
    540        break;
    541    case 0x3C:
    542        if (s->ctrl3 & BIT(0)) {
    543            aspeed_timer_set_ctrl(s, s->ctrl & ~tv);
    544        }
    545        break;
    546
    547    default:
    548        qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
    549                __func__, offset);
    550        break;
    551    }
    552}
    553
    554static uint64_t aspeed_2600_timer_read(AspeedTimerCtrlState *s, hwaddr offset)
    555{
    556    uint64_t value;
    557
    558    switch (offset) {
    559    case 0x34:
    560        value = s->irq_sts;
    561        break;
    562    case 0x38:
    563    case 0x3C:
    564    default:
    565        qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
    566                __func__, offset);
    567        value = 0;
    568        break;
    569    }
    570    return value;
    571}
    572
    573static void aspeed_2600_timer_write(AspeedTimerCtrlState *s, hwaddr offset,
    574                                    uint64_t value)
    575{
    576    const uint32_t tv = (uint32_t)(value & 0xFFFFFFFF);
    577
    578    switch (offset) {
    579    case 0x34:
    580        s->irq_sts &= tv;
    581        break;
    582    case 0x3C:
    583        aspeed_timer_set_ctrl(s, s->ctrl & ~tv);
    584        break;
    585
    586    case 0x38:
    587    default:
    588        qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
    589                __func__, offset);
    590        break;
    591    }
    592}
    593
    594static void aspeed_init_one_timer(AspeedTimerCtrlState *s, uint8_t id)
    595{
    596    AspeedTimer *t = &s->timers[id];
    597
    598    t->id = id;
    599    timer_init_ns(&t->timer, QEMU_CLOCK_VIRTUAL, aspeed_timer_expire, t);
    600}
    601
    602static void aspeed_timer_realize(DeviceState *dev, Error **errp)
    603{
    604    int i;
    605    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
    606    AspeedTimerCtrlState *s = ASPEED_TIMER(dev);
    607
    608    assert(s->scu);
    609
    610    for (i = 0; i < ASPEED_TIMER_NR_TIMERS; i++) {
    611        aspeed_init_one_timer(s, i);
    612        sysbus_init_irq(sbd, &s->timers[i].irq);
    613    }
    614    memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_timer_ops, s,
    615                          TYPE_ASPEED_TIMER, 0x1000);
    616    sysbus_init_mmio(sbd, &s->iomem);
    617}
    618
    619static void aspeed_timer_reset(DeviceState *dev)
    620{
    621    int i;
    622    AspeedTimerCtrlState *s = ASPEED_TIMER(dev);
    623
    624    for (i = 0; i < ASPEED_TIMER_NR_TIMERS; i++) {
    625        AspeedTimer *t = &s->timers[i];
    626        /* Explicitly call helpers to avoid any conditional behaviour through
    627         * aspeed_timer_set_ctrl().
    628         */
    629        aspeed_timer_ctrl_enable(t, false);
    630        aspeed_timer_ctrl_external_clock(t, TIMER_CLOCK_USE_APB);
    631        aspeed_timer_ctrl_overflow_interrupt(t, false);
    632        aspeed_timer_ctrl_pulse_enable(t, false);
    633        t->level = 0;
    634        t->reload = 0;
    635        t->match[0] = 0;
    636        t->match[1] = 0;
    637    }
    638    s->ctrl = 0;
    639    s->ctrl2 = 0;
    640    s->ctrl3 = 0;
    641    s->irq_sts = 0;
    642}
    643
    644static const VMStateDescription vmstate_aspeed_timer = {
    645    .name = "aspeed.timer",
    646    .version_id = 2,
    647    .minimum_version_id = 2,
    648    .fields = (VMStateField[]) {
    649        VMSTATE_UINT8(id, AspeedTimer),
    650        VMSTATE_INT32(level, AspeedTimer),
    651        VMSTATE_TIMER(timer, AspeedTimer),
    652        VMSTATE_UINT32(reload, AspeedTimer),
    653        VMSTATE_UINT32_ARRAY(match, AspeedTimer, 2),
    654        VMSTATE_END_OF_LIST()
    655    }
    656};
    657
    658static const VMStateDescription vmstate_aspeed_timer_state = {
    659    .name = "aspeed.timerctrl",
    660    .version_id = 2,
    661    .minimum_version_id = 2,
    662    .fields = (VMStateField[]) {
    663        VMSTATE_UINT32(ctrl, AspeedTimerCtrlState),
    664        VMSTATE_UINT32(ctrl2, AspeedTimerCtrlState),
    665        VMSTATE_UINT32(ctrl3, AspeedTimerCtrlState),
    666        VMSTATE_UINT32(irq_sts, AspeedTimerCtrlState),
    667        VMSTATE_STRUCT_ARRAY(timers, AspeedTimerCtrlState,
    668                             ASPEED_TIMER_NR_TIMERS, 1, vmstate_aspeed_timer,
    669                             AspeedTimer),
    670        VMSTATE_END_OF_LIST()
    671    }
    672};
    673
    674static Property aspeed_timer_properties[] = {
    675    DEFINE_PROP_LINK("scu", AspeedTimerCtrlState, scu, TYPE_ASPEED_SCU,
    676                     AspeedSCUState *),
    677    DEFINE_PROP_END_OF_LIST(),
    678};
    679
    680static void timer_class_init(ObjectClass *klass, void *data)
    681{
    682    DeviceClass *dc = DEVICE_CLASS(klass);
    683
    684    dc->realize = aspeed_timer_realize;
    685    dc->reset = aspeed_timer_reset;
    686    dc->desc = "ASPEED Timer";
    687    dc->vmsd = &vmstate_aspeed_timer_state;
    688    device_class_set_props(dc, aspeed_timer_properties);
    689}
    690
    691static const TypeInfo aspeed_timer_info = {
    692    .name = TYPE_ASPEED_TIMER,
    693    .parent = TYPE_SYS_BUS_DEVICE,
    694    .instance_size = sizeof(AspeedTimerCtrlState),
    695    .class_init = timer_class_init,
    696    .class_size = sizeof(AspeedTimerClass),
    697    .abstract   = true,
    698};
    699
    700static void aspeed_2400_timer_class_init(ObjectClass *klass, void *data)
    701{
    702    DeviceClass *dc = DEVICE_CLASS(klass);
    703    AspeedTimerClass *awc = ASPEED_TIMER_CLASS(klass);
    704
    705    dc->desc = "ASPEED 2400 Timer";
    706    awc->read = aspeed_2400_timer_read;
    707    awc->write = aspeed_2400_timer_write;
    708}
    709
    710static const TypeInfo aspeed_2400_timer_info = {
    711    .name = TYPE_ASPEED_2400_TIMER,
    712    .parent = TYPE_ASPEED_TIMER,
    713    .class_init = aspeed_2400_timer_class_init,
    714};
    715
    716static void aspeed_2500_timer_class_init(ObjectClass *klass, void *data)
    717{
    718    DeviceClass *dc = DEVICE_CLASS(klass);
    719    AspeedTimerClass *awc = ASPEED_TIMER_CLASS(klass);
    720
    721    dc->desc = "ASPEED 2500 Timer";
    722    awc->read = aspeed_2500_timer_read;
    723    awc->write = aspeed_2500_timer_write;
    724}
    725
    726static const TypeInfo aspeed_2500_timer_info = {
    727    .name = TYPE_ASPEED_2500_TIMER,
    728    .parent = TYPE_ASPEED_TIMER,
    729    .class_init = aspeed_2500_timer_class_init,
    730};
    731
    732static void aspeed_2600_timer_class_init(ObjectClass *klass, void *data)
    733{
    734    DeviceClass *dc = DEVICE_CLASS(klass);
    735    AspeedTimerClass *awc = ASPEED_TIMER_CLASS(klass);
    736
    737    dc->desc = "ASPEED 2600 Timer";
    738    awc->read = aspeed_2600_timer_read;
    739    awc->write = aspeed_2600_timer_write;
    740}
    741
    742static const TypeInfo aspeed_2600_timer_info = {
    743    .name = TYPE_ASPEED_2600_TIMER,
    744    .parent = TYPE_ASPEED_TIMER,
    745    .class_init = aspeed_2600_timer_class_init,
    746};
    747
    748static void aspeed_timer_register_types(void)
    749{
    750    type_register_static(&aspeed_timer_info);
    751    type_register_static(&aspeed_2400_timer_info);
    752    type_register_static(&aspeed_2500_timer_info);
    753    type_register_static(&aspeed_2600_timer_info);
    754}
    755
    756type_init(aspeed_timer_register_types)