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

auxbus.c (9212B)


      1/*
      2 * auxbus.c
      3 *
      4 *  Copyright 2015 : GreenSocs Ltd
      5 *      http://www.greensocs.com/ , email: info@greensocs.com
      6 *
      7 *  Developed by :
      8 *  Frederic Konrad   <fred.konrad@greensocs.com>
      9 *
     10 * This program is free software; you can redistribute it and/or modify
     11 * it under the terms of the GNU General Public License as published by
     12 * the Free Software Foundation, either version 2 of the License, or
     13 * (at your option)any later version.
     14 *
     15 * This program is distributed in the hope that it will be useful,
     16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     18 * GNU General Public License for more details.
     19 *
     20 * You should have received a copy of the GNU General Public License along
     21 * with this program; if not, see <http://www.gnu.org/licenses/>.
     22 *
     23 */
     24
     25/*
     26 * This is an implementation of the AUX bus for VESA Display Port v1.1a.
     27 */
     28
     29#include "qemu/osdep.h"
     30#include "qemu/units.h"
     31#include "qemu/log.h"
     32#include "qemu/module.h"
     33#include "hw/misc/auxbus.h"
     34#include "hw/i2c/i2c.h"
     35#include "monitor/monitor.h"
     36#include "qapi/error.h"
     37
     38#ifndef DEBUG_AUX
     39#define DEBUG_AUX 0
     40#endif
     41
     42#define DPRINTF(fmt, ...) do {                                                 \
     43    if (DEBUG_AUX) {                                                           \
     44        qemu_log("aux: " fmt , ## __VA_ARGS__);                                \
     45    }                                                                          \
     46} while (0)
     47
     48
     49static void aux_slave_dev_print(Monitor *mon, DeviceState *dev, int indent);
     50static inline I2CBus *aux_bridge_get_i2c_bus(AUXTOI2CState *bridge);
     51
     52/* aux-bus implementation (internal not public) */
     53static void aux_bus_class_init(ObjectClass *klass, void *data)
     54{
     55    BusClass *k = BUS_CLASS(klass);
     56
     57    /* AUXSlave has an MMIO so we need to change the way we print information
     58     * in monitor.
     59     */
     60    k->print_dev = aux_slave_dev_print;
     61}
     62
     63AUXBus *aux_bus_init(DeviceState *parent, const char *name)
     64{
     65    AUXBus *bus;
     66    Object *auxtoi2c;
     67
     68    bus = AUX_BUS(qbus_new(TYPE_AUX_BUS, parent, name));
     69    auxtoi2c = object_new_with_props(TYPE_AUXTOI2C, OBJECT(bus), "i2c",
     70                                     &error_abort, NULL);
     71
     72    bus->bridge = AUXTOI2C(auxtoi2c);
     73
     74    /* Memory related. */
     75    bus->aux_io = g_malloc(sizeof(*bus->aux_io));
     76    memory_region_init(bus->aux_io, OBJECT(bus), "aux-io", 1 * MiB);
     77    address_space_init(&bus->aux_addr_space, bus->aux_io, "aux-io");
     78    return bus;
     79}
     80
     81void aux_bus_realize(AUXBus *bus)
     82{
     83    qdev_realize(DEVICE(bus->bridge), BUS(bus), &error_fatal);
     84}
     85
     86void aux_map_slave(AUXSlave *aux_dev, hwaddr addr)
     87{
     88    DeviceState *dev = DEVICE(aux_dev);
     89    AUXBus *bus = AUX_BUS(qdev_get_parent_bus(dev));
     90    memory_region_add_subregion(bus->aux_io, addr, aux_dev->mmio);
     91}
     92
     93static bool aux_bus_is_bridge(AUXBus *bus, DeviceState *dev)
     94{
     95    return (dev == DEVICE(bus->bridge));
     96}
     97
     98I2CBus *aux_get_i2c_bus(AUXBus *bus)
     99{
    100    return aux_bridge_get_i2c_bus(bus->bridge);
    101}
    102
    103AUXReply aux_request(AUXBus *bus, AUXCommand cmd, uint32_t address,
    104                      uint8_t len, uint8_t *data)
    105{
    106    AUXReply ret = AUX_NACK;
    107    I2CBus *i2c_bus = aux_get_i2c_bus(bus);
    108    size_t i;
    109
    110    DPRINTF("request at address 0x%" PRIX32 ", command %u, len %u\n", address,
    111            cmd, len);
    112
    113    switch (cmd) {
    114    /*
    115     * Forward the request on the AUX bus..
    116     */
    117    case WRITE_AUX:
    118    case READ_AUX:
    119        for (i = 0; i < len; i++) {
    120            if (!address_space_rw(&bus->aux_addr_space, address++,
    121                                  MEMTXATTRS_UNSPECIFIED, data++, 1,
    122                                  cmd == WRITE_AUX)) {
    123                ret = AUX_I2C_ACK;
    124            } else {
    125                ret = AUX_NACK;
    126                break;
    127            }
    128        }
    129        break;
    130    /*
    131     * Classic I2C transactions..
    132     */
    133    case READ_I2C:
    134        if (i2c_bus_busy(i2c_bus)) {
    135            i2c_end_transfer(i2c_bus);
    136        }
    137
    138        if (i2c_start_recv(i2c_bus, address)) {
    139            ret = AUX_I2C_NACK;
    140            break;
    141        }
    142
    143        ret = AUX_I2C_ACK;
    144        for (i = 0; i < len; i++) {
    145            data[i] = i2c_recv(i2c_bus);
    146        }
    147        i2c_end_transfer(i2c_bus);
    148        break;
    149    case WRITE_I2C:
    150        if (i2c_bus_busy(i2c_bus)) {
    151            i2c_end_transfer(i2c_bus);
    152        }
    153
    154        if (i2c_start_send(i2c_bus, address)) {
    155            ret = AUX_I2C_NACK;
    156            break;
    157        }
    158
    159        ret = AUX_I2C_ACK;
    160        for (i = 0; i < len; i++) {
    161            if (i2c_send(i2c_bus, data[i]) < 0) {
    162                ret = AUX_I2C_NACK;
    163                break;
    164            }
    165        }
    166        i2c_end_transfer(i2c_bus);
    167        break;
    168    /*
    169     * I2C MOT transactions.
    170     *
    171     * Here we send a start when:
    172     *  - We didn't start transaction yet.
    173     *  - We had a READ and we do a WRITE.
    174     *  - We changed the address.
    175     */
    176    case WRITE_I2C_MOT:
    177        ret = AUX_I2C_NACK;
    178        if (!i2c_bus_busy(i2c_bus)) {
    179            /*
    180             * No transactions started..
    181             */
    182            if (i2c_start_send(i2c_bus, address)) {
    183                break;
    184            }
    185        } else if ((address != bus->last_i2c_address) ||
    186                   (bus->last_transaction != cmd)) {
    187            /*
    188             * Transaction started but we need to restart..
    189             */
    190            i2c_end_transfer(i2c_bus);
    191            if (i2c_start_send(i2c_bus, address)) {
    192                break;
    193            }
    194        }
    195
    196        bus->last_transaction = cmd;
    197        bus->last_i2c_address = address;
    198        ret = AUX_I2C_ACK;
    199        for (i = 0; i < len; i++) {
    200            if (i2c_send(i2c_bus, data[i]) < 0) {
    201                i2c_end_transfer(i2c_bus);
    202                ret = AUX_I2C_NACK;
    203                break;
    204            }
    205        }
    206        break;
    207    case READ_I2C_MOT:
    208        ret = AUX_I2C_NACK;
    209        if (!i2c_bus_busy(i2c_bus)) {
    210            /*
    211             * No transactions started..
    212             */
    213            if (i2c_start_recv(i2c_bus, address)) {
    214                break;
    215            }
    216        } else if ((address != bus->last_i2c_address) ||
    217                   (bus->last_transaction != cmd)) {
    218            /*
    219             * Transaction started but we need to restart..
    220             */
    221            i2c_end_transfer(i2c_bus);
    222            if (i2c_start_recv(i2c_bus, address)) {
    223                break;
    224            }
    225        }
    226
    227        bus->last_transaction = cmd;
    228        bus->last_i2c_address = address;
    229        for (i = 0; i < len; i++) {
    230            data[i] = i2c_recv(i2c_bus);
    231        }
    232        ret = AUX_I2C_ACK;
    233        break;
    234    default:
    235        qemu_log_mask(LOG_UNIMP, "AUX cmd=%u not implemented\n", cmd);
    236        return AUX_NACK;
    237    }
    238
    239    DPRINTF("reply: %u\n", ret);
    240    return ret;
    241}
    242
    243static const TypeInfo aux_bus_info = {
    244    .name = TYPE_AUX_BUS,
    245    .parent = TYPE_BUS,
    246    .instance_size = sizeof(AUXBus),
    247    .class_init = aux_bus_class_init
    248};
    249
    250/* aux-i2c implementation (internal not public) */
    251struct AUXTOI2CState {
    252    /*< private >*/
    253    DeviceState parent_obj;
    254
    255    /*< public >*/
    256    I2CBus *i2c_bus;
    257};
    258
    259static void aux_bridge_class_init(ObjectClass *oc, void *data)
    260{
    261    DeviceClass *dc = DEVICE_CLASS(oc);
    262
    263    /* This device is private and is created only once for each
    264     * aux-bus in aux_bus_init(..). So don't allow the user to add one.
    265     */
    266    dc->user_creatable = false;
    267}
    268
    269static void aux_bridge_init(Object *obj)
    270{
    271    AUXTOI2CState *s = AUXTOI2C(obj);
    272
    273    s->i2c_bus = i2c_init_bus(DEVICE(obj), "aux-i2c");
    274}
    275
    276static inline I2CBus *aux_bridge_get_i2c_bus(AUXTOI2CState *bridge)
    277{
    278    return bridge->i2c_bus;
    279}
    280
    281static const TypeInfo aux_to_i2c_type_info = {
    282    .name = TYPE_AUXTOI2C,
    283    .parent = TYPE_AUX_SLAVE,
    284    .class_init = aux_bridge_class_init,
    285    .instance_size = sizeof(AUXTOI2CState),
    286    .instance_init = aux_bridge_init
    287};
    288
    289/* aux-slave implementation */
    290static void aux_slave_dev_print(Monitor *mon, DeviceState *dev, int indent)
    291{
    292    AUXBus *bus = AUX_BUS(qdev_get_parent_bus(dev));
    293    AUXSlave *s;
    294
    295    /* Don't print anything if the device is I2C "bridge". */
    296    if (aux_bus_is_bridge(bus, dev)) {
    297        return;
    298    }
    299
    300    s = AUX_SLAVE(dev);
    301
    302    monitor_printf(mon, "%*smemory " TARGET_FMT_plx "/" TARGET_FMT_plx "\n",
    303                   indent, "",
    304                   object_property_get_uint(OBJECT(s->mmio), "addr", NULL),
    305                   memory_region_size(s->mmio));
    306}
    307
    308void aux_init_mmio(AUXSlave *aux_slave, MemoryRegion *mmio)
    309{
    310    assert(!aux_slave->mmio);
    311    aux_slave->mmio = mmio;
    312}
    313
    314static void aux_slave_class_init(ObjectClass *klass, void *data)
    315{
    316    DeviceClass *k = DEVICE_CLASS(klass);
    317
    318    set_bit(DEVICE_CATEGORY_MISC, k->categories);
    319    k->bus_type = TYPE_AUX_BUS;
    320}
    321
    322static const TypeInfo aux_slave_type_info = {
    323    .name = TYPE_AUX_SLAVE,
    324    .parent = TYPE_DEVICE,
    325    .instance_size = sizeof(AUXSlave),
    326    .abstract = true,
    327    .class_init = aux_slave_class_init,
    328};
    329
    330static void aux_register_types(void)
    331{
    332    type_register_static(&aux_bus_info);
    333    type_register_static(&aux_slave_type_info);
    334    type_register_static(&aux_to_i2c_type_info);
    335}
    336
    337type_init(aux_register_types)