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_adc.c (14406B)


      1/*
      2 * Aspeed ADC
      3 *
      4 * Copyright 2017-2021 IBM Corp.
      5 *
      6 * Andrew Jeffery <andrew@aj.id.au>
      7 *
      8 * SPDX-License-Identifier: GPL-2.0-or-later
      9 */
     10
     11#include "qemu/osdep.h"
     12#include "qapi/error.h"
     13#include "qemu/log.h"
     14#include "hw/irq.h"
     15#include "hw/qdev-properties.h"
     16#include "migration/vmstate.h"
     17#include "hw/adc/aspeed_adc.h"
     18#include "trace.h"
     19
     20#define ASPEED_ADC_MEMORY_REGION_SIZE           0x1000
     21#define ASPEED_ADC_ENGINE_MEMORY_REGION_SIZE    0x100
     22#define  ASPEED_ADC_ENGINE_CH_EN_MASK           0xffff0000
     23#define   ASPEED_ADC_ENGINE_CH_EN(x)            ((BIT(x)) << 16)
     24#define  ASPEED_ADC_ENGINE_INIT                 BIT(8)
     25#define  ASPEED_ADC_ENGINE_AUTO_COMP            BIT(5)
     26#define  ASPEED_ADC_ENGINE_COMP                 BIT(4)
     27#define  ASPEED_ADC_ENGINE_MODE_MASK            0x0000000e
     28#define   ASPEED_ADC_ENGINE_MODE_OFF            (0b000 << 1)
     29#define   ASPEED_ADC_ENGINE_MODE_STANDBY        (0b001 << 1)
     30#define   ASPEED_ADC_ENGINE_MODE_NORMAL         (0b111 << 1)
     31#define  ASPEED_ADC_ENGINE_EN                   BIT(0)
     32#define ASPEED_ADC_HYST_EN                      BIT(31)
     33
     34#define ASPEED_ADC_L_MASK       ((1 << 10) - 1)
     35#define ASPEED_ADC_L(x)         ((x) & ASPEED_ADC_L_MASK)
     36#define ASPEED_ADC_H(x)         (((x) >> 16) & ASPEED_ADC_L_MASK)
     37#define ASPEED_ADC_LH_MASK      (ASPEED_ADC_L_MASK << 16 | ASPEED_ADC_L_MASK)
     38#define LOWER_CHANNEL_MASK      ((1 << 10) - 1)
     39#define LOWER_CHANNEL_DATA(x)   ((x) & LOWER_CHANNEL_MASK)
     40#define UPPER_CHANNEL_DATA(x)   (((x) >> 16) & LOWER_CHANNEL_MASK)
     41
     42#define TO_REG(addr) (addr >> 2)
     43
     44#define ENGINE_CONTROL              TO_REG(0x00)
     45#define INTERRUPT_CONTROL           TO_REG(0x04)
     46#define VGA_DETECT_CONTROL          TO_REG(0x08)
     47#define CLOCK_CONTROL               TO_REG(0x0C)
     48#define DATA_CHANNEL_1_AND_0        TO_REG(0x10)
     49#define DATA_CHANNEL_7_AND_6        TO_REG(0x1C)
     50#define DATA_CHANNEL_9_AND_8        TO_REG(0x20)
     51#define DATA_CHANNEL_15_AND_14      TO_REG(0x2C)
     52#define BOUNDS_CHANNEL_0            TO_REG(0x30)
     53#define BOUNDS_CHANNEL_7            TO_REG(0x4C)
     54#define BOUNDS_CHANNEL_8            TO_REG(0x50)
     55#define BOUNDS_CHANNEL_15           TO_REG(0x6C)
     56#define HYSTERESIS_CHANNEL_0        TO_REG(0x70)
     57#define HYSTERESIS_CHANNEL_7        TO_REG(0x8C)
     58#define HYSTERESIS_CHANNEL_8        TO_REG(0x90)
     59#define HYSTERESIS_CHANNEL_15       TO_REG(0xAC)
     60#define INTERRUPT_SOURCE            TO_REG(0xC0)
     61#define COMPENSATING_AND_TRIMMING   TO_REG(0xC4)
     62
     63static inline uint32_t update_channels(uint32_t current)
     64{
     65    return ((((current >> 16) & ASPEED_ADC_L_MASK) + 7) << 16) |
     66        ((current + 5) & ASPEED_ADC_L_MASK);
     67}
     68
     69static bool breaks_threshold(AspeedADCEngineState *s, int reg)
     70{
     71    assert(reg >= DATA_CHANNEL_1_AND_0 &&
     72           reg < DATA_CHANNEL_1_AND_0 + s->nr_channels / 2);
     73
     74    int a_bounds_reg = BOUNDS_CHANNEL_0 + (reg - DATA_CHANNEL_1_AND_0) * 2;
     75    int b_bounds_reg = a_bounds_reg + 1;
     76    uint32_t a_and_b = s->regs[reg];
     77    uint32_t a_bounds = s->regs[a_bounds_reg];
     78    uint32_t b_bounds = s->regs[b_bounds_reg];
     79    uint32_t a = ASPEED_ADC_L(a_and_b);
     80    uint32_t b = ASPEED_ADC_H(a_and_b);
     81    uint32_t a_lower = ASPEED_ADC_L(a_bounds);
     82    uint32_t a_upper = ASPEED_ADC_H(a_bounds);
     83    uint32_t b_lower = ASPEED_ADC_L(b_bounds);
     84    uint32_t b_upper = ASPEED_ADC_H(b_bounds);
     85
     86    return (a < a_lower || a > a_upper) ||
     87           (b < b_lower || b > b_upper);
     88}
     89
     90static uint32_t read_channel_sample(AspeedADCEngineState *s, int reg)
     91{
     92    assert(reg >= DATA_CHANNEL_1_AND_0 &&
     93           reg < DATA_CHANNEL_1_AND_0 + s->nr_channels / 2);
     94
     95    /* Poor man's sampling */
     96    uint32_t value = s->regs[reg];
     97    s->regs[reg] = update_channels(s->regs[reg]);
     98
     99    if (breaks_threshold(s, reg)) {
    100        s->regs[INTERRUPT_CONTROL] |= BIT(reg - DATA_CHANNEL_1_AND_0);
    101        qemu_irq_raise(s->irq);
    102    }
    103
    104    return value;
    105}
    106
    107static uint64_t aspeed_adc_engine_read(void *opaque, hwaddr addr,
    108                                       unsigned int size)
    109{
    110    AspeedADCEngineState *s = ASPEED_ADC_ENGINE(opaque);
    111    int reg = TO_REG(addr);
    112    uint32_t value = 0;
    113
    114    switch (reg) {
    115    case BOUNDS_CHANNEL_8 ... BOUNDS_CHANNEL_15:
    116        if (s->nr_channels <= 8) {
    117            qemu_log_mask(LOG_GUEST_ERROR, "%s: engine[%u]: "
    118                          "bounds register %u invalid, only 0...7 valid\n",
    119                          __func__, s->engine_id, reg - BOUNDS_CHANNEL_0);
    120            break;
    121        }
    122        /* fallthrough */
    123    case HYSTERESIS_CHANNEL_8 ... HYSTERESIS_CHANNEL_15:
    124        if (s->nr_channels <= 8) {
    125            qemu_log_mask(LOG_GUEST_ERROR, "%s: engine[%u]: "
    126                          "hysteresis register %u invalid, only 0...7 valid\n",
    127                          __func__, s->engine_id, reg - HYSTERESIS_CHANNEL_0);
    128            break;
    129        }
    130        /* fallthrough */
    131    case BOUNDS_CHANNEL_0 ... BOUNDS_CHANNEL_7:
    132    case HYSTERESIS_CHANNEL_0 ... HYSTERESIS_CHANNEL_7:
    133    case ENGINE_CONTROL:
    134    case INTERRUPT_CONTROL:
    135    case VGA_DETECT_CONTROL:
    136    case CLOCK_CONTROL:
    137    case INTERRUPT_SOURCE:
    138    case COMPENSATING_AND_TRIMMING:
    139        value = s->regs[reg];
    140        break;
    141    case DATA_CHANNEL_9_AND_8 ... DATA_CHANNEL_15_AND_14:
    142        if (s->nr_channels <= 8) {
    143            qemu_log_mask(LOG_GUEST_ERROR, "%s: engine[%u]: "
    144                          "data register %u invalid, only 0...3 valid\n",
    145                          __func__, s->engine_id, reg - DATA_CHANNEL_1_AND_0);
    146            break;
    147        }
    148        /* fallthrough */
    149    case DATA_CHANNEL_1_AND_0 ... DATA_CHANNEL_7_AND_6:
    150        value = read_channel_sample(s, reg);
    151        /* Allow 16-bit reads of the data registers */
    152        if (addr & 0x2) {
    153            assert(size == 2);
    154            value >>= 16;
    155        }
    156        break;
    157    default:
    158        qemu_log_mask(LOG_UNIMP, "%s: engine[%u]: 0x%" HWADDR_PRIx "\n",
    159                      __func__, s->engine_id, addr);
    160        break;
    161    }
    162
    163    trace_aspeed_adc_engine_read(s->engine_id, addr, value);
    164    return value;
    165}
    166
    167static void aspeed_adc_engine_write(void *opaque, hwaddr addr, uint64_t value,
    168                                    unsigned int size)
    169{
    170    AspeedADCEngineState *s = ASPEED_ADC_ENGINE(opaque);
    171    int reg = TO_REG(addr);
    172    uint32_t init = 0;
    173
    174    trace_aspeed_adc_engine_write(s->engine_id, addr, value);
    175
    176    switch (reg) {
    177    case ENGINE_CONTROL:
    178        init = !!(value & ASPEED_ADC_ENGINE_EN);
    179        init *= ASPEED_ADC_ENGINE_INIT;
    180
    181        value &= ~ASPEED_ADC_ENGINE_INIT;
    182        value |= init;
    183
    184        value &= ~ASPEED_ADC_ENGINE_AUTO_COMP;
    185        break;
    186    case INTERRUPT_CONTROL:
    187    case VGA_DETECT_CONTROL:
    188    case CLOCK_CONTROL:
    189        break;
    190    case DATA_CHANNEL_9_AND_8 ... DATA_CHANNEL_15_AND_14:
    191        if (s->nr_channels <= 8) {
    192            qemu_log_mask(LOG_GUEST_ERROR, "%s: engine[%u]: "
    193                          "data register %u invalid, only 0...3 valid\n",
    194                          __func__, s->engine_id, reg - DATA_CHANNEL_1_AND_0);
    195            return;
    196        }
    197        /* fallthrough */
    198    case BOUNDS_CHANNEL_8 ... BOUNDS_CHANNEL_15:
    199        if (s->nr_channels <= 8) {
    200            qemu_log_mask(LOG_GUEST_ERROR, "%s: engine[%u]: "
    201                          "bounds register %u invalid, only 0...7 valid\n",
    202                          __func__, s->engine_id, reg - BOUNDS_CHANNEL_0);
    203            return;
    204        }
    205        /* fallthrough */
    206    case DATA_CHANNEL_1_AND_0 ... DATA_CHANNEL_7_AND_6:
    207    case BOUNDS_CHANNEL_0 ... BOUNDS_CHANNEL_7:
    208        value &= ASPEED_ADC_LH_MASK;
    209        break;
    210    case HYSTERESIS_CHANNEL_8 ... HYSTERESIS_CHANNEL_15:
    211        if (s->nr_channels <= 8) {
    212            qemu_log_mask(LOG_GUEST_ERROR, "%s: engine[%u]: "
    213                          "hysteresis register %u invalid, only 0...7 valid\n",
    214                          __func__, s->engine_id, reg - HYSTERESIS_CHANNEL_0);
    215            return;
    216        }
    217        /* fallthrough */
    218    case HYSTERESIS_CHANNEL_0 ... HYSTERESIS_CHANNEL_7:
    219        value &= (ASPEED_ADC_HYST_EN | ASPEED_ADC_LH_MASK);
    220        break;
    221    case INTERRUPT_SOURCE:
    222        value &= 0xffff;
    223        break;
    224    case COMPENSATING_AND_TRIMMING:
    225        value &= 0xf;
    226        break;
    227    default:
    228        qemu_log_mask(LOG_UNIMP, "%s: engine[%u]: "
    229                      "0x%" HWADDR_PRIx " 0x%" PRIx64 "\n",
    230                      __func__, s->engine_id, addr, value);
    231        break;
    232    }
    233
    234    s->regs[reg] = value;
    235}
    236
    237static const MemoryRegionOps aspeed_adc_engine_ops = {
    238    .read = aspeed_adc_engine_read,
    239    .write = aspeed_adc_engine_write,
    240    .endianness = DEVICE_LITTLE_ENDIAN,
    241    .valid = {
    242        .min_access_size = 2,
    243        .max_access_size = 4,
    244        .unaligned = false,
    245    },
    246};
    247
    248static const uint32_t aspeed_adc_resets[ASPEED_ADC_NR_REGS] = {
    249    [ENGINE_CONTROL]     = 0x00000000,
    250    [INTERRUPT_CONTROL]  = 0x00000000,
    251    [VGA_DETECT_CONTROL] = 0x0000000f,
    252    [CLOCK_CONTROL]      = 0x0000000f,
    253};
    254
    255static void aspeed_adc_engine_reset(DeviceState *dev)
    256{
    257    AspeedADCEngineState *s = ASPEED_ADC_ENGINE(dev);
    258
    259    memcpy(s->regs, aspeed_adc_resets, sizeof(aspeed_adc_resets));
    260}
    261
    262static void aspeed_adc_engine_realize(DeviceState *dev, Error **errp)
    263{
    264    AspeedADCEngineState *s = ASPEED_ADC_ENGINE(dev);
    265    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
    266    g_autofree char *name = g_strdup_printf(TYPE_ASPEED_ADC_ENGINE ".%d",
    267                                            s->engine_id);
    268
    269    assert(s->engine_id < 2);
    270
    271    sysbus_init_irq(sbd, &s->irq);
    272
    273    memory_region_init_io(&s->mmio, OBJECT(s), &aspeed_adc_engine_ops, s, name,
    274                          ASPEED_ADC_ENGINE_MEMORY_REGION_SIZE);
    275
    276    sysbus_init_mmio(sbd, &s->mmio);
    277}
    278
    279static const VMStateDescription vmstate_aspeed_adc_engine = {
    280    .name = TYPE_ASPEED_ADC,
    281    .version_id = 1,
    282    .minimum_version_id = 1,
    283    .fields = (VMStateField[]) {
    284        VMSTATE_UINT32_ARRAY(regs, AspeedADCEngineState, ASPEED_ADC_NR_REGS),
    285        VMSTATE_END_OF_LIST(),
    286    }
    287};
    288
    289static Property aspeed_adc_engine_properties[] = {
    290    DEFINE_PROP_UINT32("engine-id", AspeedADCEngineState, engine_id, 0),
    291    DEFINE_PROP_UINT32("nr-channels", AspeedADCEngineState, nr_channels, 0),
    292    DEFINE_PROP_END_OF_LIST(),
    293};
    294
    295static void aspeed_adc_engine_class_init(ObjectClass *klass, void *data)
    296{
    297    DeviceClass *dc = DEVICE_CLASS(klass);
    298
    299    dc->realize = aspeed_adc_engine_realize;
    300    dc->reset = aspeed_adc_engine_reset;
    301    device_class_set_props(dc, aspeed_adc_engine_properties);
    302    dc->desc = "Aspeed Analog-to-Digital Engine";
    303    dc->vmsd = &vmstate_aspeed_adc_engine;
    304}
    305
    306static const TypeInfo aspeed_adc_engine_info = {
    307    .name = TYPE_ASPEED_ADC_ENGINE,
    308    .parent = TYPE_SYS_BUS_DEVICE,
    309    .instance_size = sizeof(AspeedADCEngineState),
    310    .class_init = aspeed_adc_engine_class_init,
    311};
    312
    313static void aspeed_adc_instance_init(Object *obj)
    314{
    315    AspeedADCState *s = ASPEED_ADC(obj);
    316    AspeedADCClass *aac = ASPEED_ADC_GET_CLASS(obj);
    317    uint32_t nr_channels = ASPEED_ADC_NR_CHANNELS / aac->nr_engines;
    318
    319    for (int i = 0; i < aac->nr_engines; i++) {
    320        AspeedADCEngineState *engine = &s->engines[i];
    321        object_initialize_child(obj, "engine[*]", engine,
    322                                TYPE_ASPEED_ADC_ENGINE);
    323        qdev_prop_set_uint32(DEVICE(engine), "engine-id", i);
    324        qdev_prop_set_uint32(DEVICE(engine), "nr-channels", nr_channels);
    325    }
    326}
    327
    328static void aspeed_adc_set_irq(void *opaque, int n, int level)
    329{
    330    AspeedADCState *s = opaque;
    331    AspeedADCClass *aac = ASPEED_ADC_GET_CLASS(s);
    332    uint32_t pending = 0;
    333
    334    /* TODO: update Global IRQ status register on AST2600 (Need specs) */
    335    for (int i = 0; i < aac->nr_engines; i++) {
    336        uint32_t irq_status = s->engines[i].regs[INTERRUPT_CONTROL] & 0xFF;
    337        pending |= irq_status << (i * 8);
    338    }
    339
    340    qemu_set_irq(s->irq, !!pending);
    341}
    342
    343static void aspeed_adc_realize(DeviceState *dev, Error **errp)
    344{
    345    AspeedADCState *s = ASPEED_ADC(dev);
    346    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
    347    AspeedADCClass *aac = ASPEED_ADC_GET_CLASS(dev);
    348
    349    qdev_init_gpio_in_named_with_opaque(DEVICE(sbd), aspeed_adc_set_irq,
    350                                        s, NULL, aac->nr_engines);
    351
    352    sysbus_init_irq(sbd, &s->irq);
    353
    354    memory_region_init(&s->mmio, OBJECT(s), TYPE_ASPEED_ADC,
    355                       ASPEED_ADC_MEMORY_REGION_SIZE);
    356
    357    sysbus_init_mmio(sbd, &s->mmio);
    358
    359    for (int i = 0; i < aac->nr_engines; i++) {
    360        Object *eng = OBJECT(&s->engines[i]);
    361
    362        if (!sysbus_realize(SYS_BUS_DEVICE(eng), errp)) {
    363            return;
    364        }
    365        sysbus_connect_irq(SYS_BUS_DEVICE(eng), 0,
    366                           qdev_get_gpio_in(DEVICE(sbd), i));
    367        memory_region_add_subregion(&s->mmio,
    368                                    i * ASPEED_ADC_ENGINE_MEMORY_REGION_SIZE,
    369                                    &s->engines[i].mmio);
    370    }
    371}
    372
    373static void aspeed_adc_class_init(ObjectClass *klass, void *data)
    374{
    375    DeviceClass *dc = DEVICE_CLASS(klass);
    376    AspeedADCClass *aac = ASPEED_ADC_CLASS(klass);
    377
    378    dc->realize = aspeed_adc_realize;
    379    dc->desc = "Aspeed Analog-to-Digital Converter";
    380    aac->nr_engines = 1;
    381}
    382
    383static void aspeed_2600_adc_class_init(ObjectClass *klass, void *data)
    384{
    385    DeviceClass *dc = DEVICE_CLASS(klass);
    386    AspeedADCClass *aac = ASPEED_ADC_CLASS(klass);
    387
    388    dc->desc = "ASPEED 2600 ADC Controller";
    389    aac->nr_engines = 2;
    390}
    391
    392static const TypeInfo aspeed_adc_info = {
    393    .name = TYPE_ASPEED_ADC,
    394    .parent = TYPE_SYS_BUS_DEVICE,
    395    .instance_init = aspeed_adc_instance_init,
    396    .instance_size = sizeof(AspeedADCState),
    397    .class_init = aspeed_adc_class_init,
    398    .class_size = sizeof(AspeedADCClass),
    399    .abstract   = true,
    400};
    401
    402static const TypeInfo aspeed_2400_adc_info = {
    403    .name = TYPE_ASPEED_2400_ADC,
    404    .parent = TYPE_ASPEED_ADC,
    405};
    406
    407static const TypeInfo aspeed_2500_adc_info = {
    408    .name = TYPE_ASPEED_2500_ADC,
    409    .parent = TYPE_ASPEED_ADC,
    410};
    411
    412static const TypeInfo aspeed_2600_adc_info = {
    413    .name = TYPE_ASPEED_2600_ADC,
    414    .parent = TYPE_ASPEED_ADC,
    415    .class_init = aspeed_2600_adc_class_init,
    416};
    417
    418static void aspeed_adc_register_types(void)
    419{
    420    type_register_static(&aspeed_adc_engine_info);
    421    type_register_static(&aspeed_adc_info);
    422    type_register_static(&aspeed_2400_adc_info);
    423    type_register_static(&aspeed_2500_adc_info);
    424    type_register_static(&aspeed_2600_adc_info);
    425}
    426
    427type_init(aspeed_adc_register_types);