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

bcm2835_systmr.c (5315B)


      1/*
      2 * BCM2835 SYS timer emulation
      3 *
      4 * Copyright (C) 2019 Philippe Mathieu-Daudé <f4bug@amsat.org>
      5 *
      6 * SPDX-License-Identifier: GPL-2.0-or-later
      7 *
      8 * Datasheet: BCM2835 ARM Peripherals (C6357-M-1398)
      9 * https://www.raspberrypi.org/app/uploads/2012/02/BCM2835-ARM-Peripherals.pdf
     10 *
     11 * Only the free running 64-bit counter is implemented.
     12 * The 4 COMPARE registers and the interruption are not implemented.
     13 */
     14
     15#include "qemu/osdep.h"
     16#include "qemu/log.h"
     17#include "qemu/timer.h"
     18#include "hw/timer/bcm2835_systmr.h"
     19#include "hw/registerfields.h"
     20#include "migration/vmstate.h"
     21#include "trace.h"
     22
     23REG32(CTRL_STATUS,  0x00)
     24REG32(COUNTER_LOW,  0x04)
     25REG32(COUNTER_HIGH, 0x08)
     26REG32(COMPARE0,     0x0c)
     27REG32(COMPARE1,     0x10)
     28REG32(COMPARE2,     0x14)
     29REG32(COMPARE3,     0x18)
     30
     31static void bcm2835_systmr_timer_expire(void *opaque)
     32{
     33    BCM2835SystemTimerCompare *tmr = opaque;
     34
     35    trace_bcm2835_systmr_timer_expired(tmr->id);
     36    tmr->state->reg.ctrl_status |= 1 << tmr->id;
     37    qemu_set_irq(tmr->irq, 1);
     38}
     39
     40static uint64_t bcm2835_systmr_read(void *opaque, hwaddr offset,
     41                                    unsigned size)
     42{
     43    BCM2835SystemTimerState *s = BCM2835_SYSTIMER(opaque);
     44    uint64_t r = 0;
     45
     46    switch (offset) {
     47    case A_CTRL_STATUS:
     48        r = s->reg.ctrl_status;
     49        break;
     50    case A_COMPARE0 ... A_COMPARE3:
     51        r = s->reg.compare[(offset - A_COMPARE0) >> 2];
     52        break;
     53    case A_COUNTER_LOW:
     54    case A_COUNTER_HIGH:
     55        /* Free running counter at 1MHz */
     56        r = qemu_clock_get_us(QEMU_CLOCK_VIRTUAL);
     57        r >>= 8 * (offset - A_COUNTER_LOW);
     58        r &= UINT32_MAX;
     59        break;
     60    default:
     61        qemu_log_mask(LOG_GUEST_ERROR, "%s: bad offset 0x%" HWADDR_PRIx "\n",
     62                      __func__, offset);
     63        break;
     64    }
     65    trace_bcm2835_systmr_read(offset, r);
     66
     67    return r;
     68}
     69
     70static void bcm2835_systmr_write(void *opaque, hwaddr offset,
     71                                 uint64_t value64, unsigned size)
     72{
     73    BCM2835SystemTimerState *s = BCM2835_SYSTIMER(opaque);
     74    int index;
     75    uint32_t value = value64;
     76    uint32_t triggers_delay_us;
     77    uint64_t now;
     78
     79    trace_bcm2835_systmr_write(offset, value);
     80    switch (offset) {
     81    case A_CTRL_STATUS:
     82        s->reg.ctrl_status &= ~value; /* Ack */
     83        for (index = 0; index < ARRAY_SIZE(s->tmr); index++) {
     84            if (extract32(value, index, 1)) {
     85                trace_bcm2835_systmr_irq_ack(index);
     86                qemu_set_irq(s->tmr[index].irq, 0);
     87            }
     88        }
     89        break;
     90    case A_COMPARE0 ... A_COMPARE3:
     91        index = (offset - A_COMPARE0) >> 2;
     92        s->reg.compare[index] = value;
     93        now = qemu_clock_get_us(QEMU_CLOCK_VIRTUAL);
     94        /* Compare lower 32-bits of the free-running counter. */
     95        triggers_delay_us = value - now;
     96        trace_bcm2835_systmr_run(index, triggers_delay_us);
     97        timer_mod(&s->tmr[index].timer, now + triggers_delay_us);
     98        break;
     99    case A_COUNTER_LOW:
    100    case A_COUNTER_HIGH:
    101        qemu_log_mask(LOG_GUEST_ERROR, "%s: read-only ofs 0x%" HWADDR_PRIx "\n",
    102                      __func__, offset);
    103        break;
    104    default:
    105        qemu_log_mask(LOG_GUEST_ERROR, "%s: bad offset 0x%" HWADDR_PRIx "\n",
    106                      __func__, offset);
    107        break;
    108    }
    109}
    110
    111static const MemoryRegionOps bcm2835_systmr_ops = {
    112    .read = bcm2835_systmr_read,
    113    .write = bcm2835_systmr_write,
    114    .endianness = DEVICE_LITTLE_ENDIAN,
    115    .impl = {
    116        .min_access_size = 4,
    117        .max_access_size = 4,
    118    },
    119};
    120
    121static void bcm2835_systmr_reset(DeviceState *dev)
    122{
    123    BCM2835SystemTimerState *s = BCM2835_SYSTIMER(dev);
    124
    125    memset(&s->reg, 0, sizeof(s->reg));
    126}
    127
    128static void bcm2835_systmr_realize(DeviceState *dev, Error **errp)
    129{
    130    BCM2835SystemTimerState *s = BCM2835_SYSTIMER(dev);
    131
    132    memory_region_init_io(&s->iomem, OBJECT(dev), &bcm2835_systmr_ops,
    133                          s, "bcm2835-sys-timer", 0x20);
    134    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
    135
    136    for (size_t i = 0; i < ARRAY_SIZE(s->tmr); i++) {
    137        s->tmr[i].id = i;
    138        s->tmr[i].state = s;
    139        sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->tmr[i].irq);
    140        timer_init_us(&s->tmr[i].timer, QEMU_CLOCK_VIRTUAL,
    141                      bcm2835_systmr_timer_expire, &s->tmr[i]);
    142    }
    143}
    144
    145static const VMStateDescription bcm2835_systmr_vmstate = {
    146    .name = "bcm2835_sys_timer",
    147    .version_id = 1,
    148    .minimum_version_id = 1,
    149    .fields = (VMStateField[]) {
    150        VMSTATE_UINT32(reg.ctrl_status, BCM2835SystemTimerState),
    151        VMSTATE_UINT32_ARRAY(reg.compare, BCM2835SystemTimerState,
    152                             BCM2835_SYSTIMER_COUNT),
    153        VMSTATE_END_OF_LIST()
    154    }
    155};
    156
    157static void bcm2835_systmr_class_init(ObjectClass *klass, void *data)
    158{
    159    DeviceClass *dc = DEVICE_CLASS(klass);
    160
    161    dc->realize = bcm2835_systmr_realize;
    162    dc->reset = bcm2835_systmr_reset;
    163    dc->vmsd = &bcm2835_systmr_vmstate;
    164}
    165
    166static const TypeInfo bcm2835_systmr_info = {
    167    .name = TYPE_BCM2835_SYSTIMER,
    168    .parent = TYPE_SYS_BUS_DEVICE,
    169    .instance_size = sizeof(BCM2835SystemTimerState),
    170    .class_init = bcm2835_systmr_class_init,
    171};
    172
    173static void bcm2835_systmr_register_types(void)
    174{
    175    type_register_static(&bcm2835_systmr_info);
    176}
    177
    178type_init(bcm2835_systmr_register_types);