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

smbus_slave.c (5891B)


      1/*
      2 * QEMU SMBus device emulation.
      3 *
      4 * This code is a helper for SMBus device emulation.  It implements an
      5 * I2C device inteface and runs the SMBus protocol from the device
      6 * point of view and maps those to simple calls to emulate.
      7 *
      8 * Copyright (c) 2007 CodeSourcery.
      9 * Written by Paul Brook
     10 *
     11 * This code is licensed under the LGPL.
     12 */
     13
     14/* TODO: Implement PEC.  */
     15
     16#include "qemu/osdep.h"
     17#include "hw/i2c/i2c.h"
     18#include "hw/i2c/smbus_slave.h"
     19#include "migration/vmstate.h"
     20#include "qemu/module.h"
     21
     22//#define DEBUG_SMBUS 1
     23
     24#ifdef DEBUG_SMBUS
     25#define DPRINTF(fmt, ...) \
     26do { printf("smbus(%02x): " fmt , dev->i2c.address, ## __VA_ARGS__); } while (0)
     27#define BADF(fmt, ...) \
     28do { fprintf(stderr, "smbus: error: " fmt , ## __VA_ARGS__); exit(1);} while (0)
     29#else
     30#define DPRINTF(fmt, ...) do {} while(0)
     31#define BADF(fmt, ...) \
     32do { fprintf(stderr, "smbus: error: " fmt , ## __VA_ARGS__);} while (0)
     33#endif
     34
     35enum {
     36    SMBUS_IDLE,
     37    SMBUS_WRITE_DATA,
     38    SMBUS_READ_DATA,
     39    SMBUS_DONE,
     40    SMBUS_CONFUSED = -1
     41};
     42
     43static void smbus_do_quick_cmd(SMBusDevice *dev, int recv)
     44{
     45    SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
     46
     47    DPRINTF("Quick Command %d\n", recv);
     48    if (sc->quick_cmd) {
     49        sc->quick_cmd(dev, recv);
     50    }
     51}
     52
     53static void smbus_do_write(SMBusDevice *dev)
     54{
     55    SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
     56
     57    DPRINTF("Command %d len %d\n", dev->data_buf[0], dev->data_len);
     58    if (sc->write_data) {
     59        sc->write_data(dev, dev->data_buf, dev->data_len);
     60    }
     61}
     62
     63static int smbus_i2c_event(I2CSlave *s, enum i2c_event event)
     64{
     65    SMBusDevice *dev = SMBUS_DEVICE(s);
     66
     67    switch (event) {
     68    case I2C_START_SEND:
     69        switch (dev->mode) {
     70        case SMBUS_IDLE:
     71            DPRINTF("Incoming data\n");
     72            dev->mode = SMBUS_WRITE_DATA;
     73            break;
     74
     75        default:
     76            BADF("Unexpected send start condition in state %d\n", dev->mode);
     77            dev->mode = SMBUS_CONFUSED;
     78            break;
     79        }
     80        break;
     81
     82    case I2C_START_RECV:
     83        switch (dev->mode) {
     84        case SMBUS_IDLE:
     85            DPRINTF("Read mode\n");
     86            dev->mode = SMBUS_READ_DATA;
     87            break;
     88
     89        case SMBUS_WRITE_DATA:
     90            if (dev->data_len == 0) {
     91                BADF("Read after write with no data\n");
     92                dev->mode = SMBUS_CONFUSED;
     93            } else {
     94                smbus_do_write(dev);
     95                DPRINTF("Read mode\n");
     96                dev->mode = SMBUS_READ_DATA;
     97            }
     98            break;
     99
    100        default:
    101            BADF("Unexpected recv start condition in state %d\n", dev->mode);
    102            dev->mode = SMBUS_CONFUSED;
    103            break;
    104        }
    105        break;
    106
    107    case I2C_FINISH:
    108        if (dev->data_len == 0) {
    109            if (dev->mode == SMBUS_WRITE_DATA || dev->mode == SMBUS_READ_DATA) {
    110                smbus_do_quick_cmd(dev, dev->mode == SMBUS_READ_DATA);
    111            }
    112        } else {
    113            switch (dev->mode) {
    114            case SMBUS_WRITE_DATA:
    115                smbus_do_write(dev);
    116                break;
    117
    118            case SMBUS_READ_DATA:
    119                BADF("Unexpected stop during receive\n");
    120                break;
    121
    122            default:
    123                /* Nothing to do.  */
    124                break;
    125            }
    126        }
    127        dev->mode = SMBUS_IDLE;
    128        dev->data_len = 0;
    129        break;
    130
    131    case I2C_NACK:
    132        switch (dev->mode) {
    133        case SMBUS_DONE:
    134            /* Nothing to do.  */
    135            break;
    136
    137        case SMBUS_READ_DATA:
    138            dev->mode = SMBUS_DONE;
    139            break;
    140
    141        default:
    142            BADF("Unexpected NACK in state %d\n", dev->mode);
    143            dev->mode = SMBUS_CONFUSED;
    144            break;
    145        }
    146    }
    147
    148    return 0;
    149}
    150
    151static uint8_t smbus_i2c_recv(I2CSlave *s)
    152{
    153    SMBusDevice *dev = SMBUS_DEVICE(s);
    154    SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
    155    uint8_t ret = 0xff;
    156
    157    switch (dev->mode) {
    158    case SMBUS_READ_DATA:
    159        if (sc->receive_byte) {
    160            ret = sc->receive_byte(dev);
    161        }
    162        DPRINTF("Read data %02x\n", ret);
    163        break;
    164
    165    default:
    166        BADF("Unexpected read in state %d\n", dev->mode);
    167        dev->mode = SMBUS_CONFUSED;
    168        break;
    169    }
    170
    171    return ret;
    172}
    173
    174static int smbus_i2c_send(I2CSlave *s, uint8_t data)
    175{
    176    SMBusDevice *dev = SMBUS_DEVICE(s);
    177
    178    switch (dev->mode) {
    179    case SMBUS_WRITE_DATA:
    180        DPRINTF("Write data %02x\n", data);
    181        if (dev->data_len >= sizeof(dev->data_buf)) {
    182            BADF("Too many bytes sent\n");
    183        } else {
    184            dev->data_buf[dev->data_len++] = data;
    185        }
    186        break;
    187
    188    default:
    189        BADF("Unexpected write in state %d\n", dev->mode);
    190        break;
    191    }
    192
    193    return 0;
    194}
    195
    196static void smbus_device_class_init(ObjectClass *klass, void *data)
    197{
    198    I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass);
    199
    200    sc->event = smbus_i2c_event;
    201    sc->recv = smbus_i2c_recv;
    202    sc->send = smbus_i2c_send;
    203}
    204
    205bool smbus_vmstate_needed(SMBusDevice *dev)
    206{
    207    return dev->mode != SMBUS_IDLE;
    208}
    209
    210const VMStateDescription vmstate_smbus_device = {
    211    .name = TYPE_SMBUS_DEVICE,
    212    .version_id = 1,
    213    .minimum_version_id = 1,
    214    .fields      = (VMStateField[]) {
    215        VMSTATE_I2C_SLAVE(i2c, SMBusDevice),
    216        VMSTATE_INT32(mode, SMBusDevice),
    217        VMSTATE_INT32(data_len, SMBusDevice),
    218        VMSTATE_UINT8_ARRAY(data_buf, SMBusDevice, SMBUS_DATA_MAX_LEN),
    219        VMSTATE_END_OF_LIST()
    220    }
    221};
    222
    223static const TypeInfo smbus_device_type_info = {
    224    .name = TYPE_SMBUS_DEVICE,
    225    .parent = TYPE_I2C_SLAVE,
    226    .instance_size = sizeof(SMBusDevice),
    227    .abstract = true,
    228    .class_size = sizeof(SMBusDeviceClass),
    229    .class_init = smbus_device_class_init,
    230};
    231
    232static void smbus_device_register_types(void)
    233{
    234    type_register_static(&smbus_device_type_info);
    235}
    236
    237type_init(smbus_device_register_types)