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

sii9022.c (4799B)


      1/*
      2 * Silicon Image SiI9022
      3 *
      4 * This is a pretty hollow emulation: all we do is acknowledge that we
      5 * exist (chip ID) and confirm that we get switched over into DDC mode
      6 * so the emulated host can proceed to read out EDID data. All subsequent
      7 * set-up of connectors etc will be acknowledged and ignored.
      8 *
      9 * Copyright (C) 2018 Linus Walleij
     10 *
     11 * This work is licensed under the terms of the GNU GPL, version 2 or later.
     12 * See the COPYING file in the top-level directory.
     13 * SPDX-License-Identifier: GPL-2.0-or-later
     14 */
     15
     16#include "qemu/osdep.h"
     17#include "qemu/module.h"
     18#include "hw/i2c/i2c.h"
     19#include "migration/vmstate.h"
     20#include "hw/display/i2c-ddc.h"
     21#include "trace.h"
     22#include "qom/object.h"
     23
     24#define SII9022_SYS_CTRL_DATA 0x1a
     25#define SII9022_SYS_CTRL_PWR_DWN 0x10
     26#define SII9022_SYS_CTRL_AV_MUTE 0x08
     27#define SII9022_SYS_CTRL_DDC_BUS_REQ 0x04
     28#define SII9022_SYS_CTRL_DDC_BUS_GRTD 0x02
     29#define SII9022_SYS_CTRL_OUTPUT_MODE 0x01
     30#define SII9022_SYS_CTRL_OUTPUT_HDMI 1
     31#define SII9022_SYS_CTRL_OUTPUT_DVI 0
     32#define SII9022_REG_CHIPID 0x1b
     33#define SII9022_INT_ENABLE 0x3c
     34#define SII9022_INT_STATUS 0x3d
     35#define SII9022_INT_STATUS_HOTPLUG 0x01;
     36#define SII9022_INT_STATUS_PLUGGED 0x04;
     37
     38#define TYPE_SII9022 "sii9022"
     39OBJECT_DECLARE_SIMPLE_TYPE(sii9022_state, SII9022)
     40
     41struct sii9022_state {
     42    I2CSlave parent_obj;
     43    uint8_t ptr;
     44    bool addr_byte;
     45    bool ddc_req;
     46    bool ddc_skip_finish;
     47    bool ddc;
     48};
     49
     50static const VMStateDescription vmstate_sii9022 = {
     51    .name = "sii9022",
     52    .version_id = 1,
     53    .minimum_version_id = 1,
     54    .fields = (VMStateField[]) {
     55        VMSTATE_I2C_SLAVE(parent_obj, sii9022_state),
     56        VMSTATE_UINT8(ptr, sii9022_state),
     57        VMSTATE_BOOL(addr_byte, sii9022_state),
     58        VMSTATE_BOOL(ddc_req, sii9022_state),
     59        VMSTATE_BOOL(ddc_skip_finish, sii9022_state),
     60        VMSTATE_BOOL(ddc, sii9022_state),
     61        VMSTATE_END_OF_LIST()
     62    }
     63};
     64
     65static int sii9022_event(I2CSlave *i2c, enum i2c_event event)
     66{
     67    sii9022_state *s = SII9022(i2c);
     68
     69    switch (event) {
     70    case I2C_START_SEND:
     71        s->addr_byte = true;
     72        break;
     73    case I2C_START_RECV:
     74        break;
     75    case I2C_FINISH:
     76        break;
     77    case I2C_NACK:
     78        break;
     79    }
     80
     81    return 0;
     82}
     83
     84static uint8_t sii9022_rx(I2CSlave *i2c)
     85{
     86    sii9022_state *s = SII9022(i2c);
     87    uint8_t res = 0x00;
     88
     89    switch (s->ptr) {
     90    case SII9022_SYS_CTRL_DATA:
     91        if (s->ddc_req) {
     92            /* Acknowledge DDC bus request */
     93            res = SII9022_SYS_CTRL_DDC_BUS_GRTD | SII9022_SYS_CTRL_DDC_BUS_REQ;
     94        }
     95        break;
     96    case SII9022_REG_CHIPID:
     97        res = 0xb0;
     98        break;
     99    case SII9022_INT_STATUS:
    100        /* Something is cold-plugged in, no interrupts */
    101        res = SII9022_INT_STATUS_PLUGGED;
    102        break;
    103    default:
    104        break;
    105    }
    106
    107    trace_sii9022_read_reg(s->ptr, res);
    108    s->ptr++;
    109
    110    return res;
    111}
    112
    113static int sii9022_tx(I2CSlave *i2c, uint8_t data)
    114{
    115    sii9022_state *s = SII9022(i2c);
    116
    117    if (s->addr_byte) {
    118        s->ptr = data;
    119        s->addr_byte = false;
    120        return 0;
    121    }
    122
    123    switch (s->ptr) {
    124    case SII9022_SYS_CTRL_DATA:
    125        if (data & SII9022_SYS_CTRL_DDC_BUS_REQ) {
    126            s->ddc_req = true;
    127            if (data & SII9022_SYS_CTRL_DDC_BUS_GRTD) {
    128                s->ddc = true;
    129                /* Skip this finish since we just switched to DDC */
    130                s->ddc_skip_finish = true;
    131                trace_sii9022_switch_mode("DDC");
    132            }
    133        } else {
    134            s->ddc_req = false;
    135            s->ddc = false;
    136            trace_sii9022_switch_mode("normal");
    137        }
    138        break;
    139    default:
    140        break;
    141    }
    142
    143    trace_sii9022_write_reg(s->ptr, data);
    144    s->ptr++;
    145
    146    return 0;
    147}
    148
    149static void sii9022_reset(DeviceState *dev)
    150{
    151    sii9022_state *s = SII9022(dev);
    152
    153    s->ptr = 0;
    154    s->addr_byte = false;
    155    s->ddc_req = false;
    156    s->ddc_skip_finish = false;
    157    s->ddc = false;
    158}
    159
    160static void sii9022_realize(DeviceState *dev, Error **errp)
    161{
    162    I2CBus *bus;
    163
    164    bus = I2C_BUS(qdev_get_parent_bus(dev));
    165    i2c_slave_create_simple(bus, TYPE_I2CDDC, 0x50);
    166}
    167
    168static void sii9022_class_init(ObjectClass *klass, void *data)
    169{
    170    DeviceClass *dc = DEVICE_CLASS(klass);
    171    I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
    172
    173    k->event = sii9022_event;
    174    k->recv = sii9022_rx;
    175    k->send = sii9022_tx;
    176    dc->reset = sii9022_reset;
    177    dc->realize = sii9022_realize;
    178    dc->vmsd = &vmstate_sii9022;
    179}
    180
    181static const TypeInfo sii9022_info = {
    182    .name          = TYPE_SII9022,
    183    .parent        = TYPE_I2C_SLAVE,
    184    .instance_size = sizeof(sii9022_state),
    185    .class_init    = sii9022_class_init,
    186};
    187
    188static void sii9022_register_types(void)
    189{
    190    type_register_static(&sii9022_info);
    191}
    192
    193type_init(sii9022_register_types)