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

macio.c (14169B)


      1/*
      2 * QEMU IDE Emulation: MacIO support.
      3 *
      4 * Copyright (c) 2003 Fabrice Bellard
      5 * Copyright (c) 2006 Openedhand Ltd.
      6 *
      7 * Permission is hereby granted, free of charge, to any person obtaining a copy
      8 * of this software and associated documentation files (the "Software"), to deal
      9 * in the Software without restriction, including without limitation the rights
     10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     11 * copies of the Software, and to permit persons to whom the Software is
     12 * furnished to do so, subject to the following conditions:
     13 *
     14 * The above copyright notice and this permission notice shall be included in
     15 * all copies or substantial portions of the Software.
     16 *
     17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     23 * THE SOFTWARE.
     24 */
     25
     26#include "qemu/osdep.h"
     27#include "hw/ppc/mac.h"
     28#include "hw/ppc/mac_dbdma.h"
     29#include "hw/qdev-properties.h"
     30#include "migration/vmstate.h"
     31#include "qemu/module.h"
     32#include "hw/misc/macio/macio.h"
     33#include "sysemu/block-backend.h"
     34#include "sysemu/dma.h"
     35
     36#include "hw/ide/internal.h"
     37
     38/* debug MACIO */
     39// #define DEBUG_MACIO
     40
     41#ifdef DEBUG_MACIO
     42static const int debug_macio = 1;
     43#else
     44static const int debug_macio = 0;
     45#endif
     46
     47#define MACIO_DPRINTF(fmt, ...) do { \
     48        if (debug_macio) { \
     49            printf(fmt , ## __VA_ARGS__); \
     50        } \
     51    } while (0)
     52
     53
     54/***********************************************************/
     55/* MacIO based PowerPC IDE */
     56
     57#define MACIO_PAGE_SIZE 4096
     58
     59static void pmac_ide_atapi_transfer_cb(void *opaque, int ret)
     60{
     61    DBDMA_io *io = opaque;
     62    MACIOIDEState *m = io->opaque;
     63    IDEState *s = idebus_active_if(&m->bus);
     64    int64_t offset;
     65
     66    MACIO_DPRINTF("pmac_ide_atapi_transfer_cb\n");
     67
     68    if (ret < 0) {
     69        MACIO_DPRINTF("DMA error: %d\n", ret);
     70        qemu_sglist_destroy(&s->sg);
     71        ide_atapi_io_error(s, ret);
     72        goto done;
     73    }
     74
     75    if (!m->dma_active) {
     76        MACIO_DPRINTF("waiting for data (%#x - %#x - %x)\n",
     77                      s->nsector, io->len, s->status);
     78        /* data not ready yet, wait for the channel to get restarted */
     79        io->processing = false;
     80        return;
     81    }
     82
     83    if (s->io_buffer_size <= 0) {
     84        MACIO_DPRINTF("End of IDE transfer\n");
     85        qemu_sglist_destroy(&s->sg);
     86        ide_atapi_cmd_ok(s);
     87        m->dma_active = false;
     88        goto done;
     89    }
     90
     91    if (io->len == 0) {
     92        MACIO_DPRINTF("End of DMA transfer\n");
     93        goto done;
     94    }
     95
     96    if (s->lba == -1) {
     97        /* Non-block ATAPI transfer - just copy to RAM */
     98        s->io_buffer_size = MIN(s->io_buffer_size, io->len);
     99        dma_memory_write(&address_space_memory, io->addr, s->io_buffer,
    100                         s->io_buffer_size);
    101        io->len = 0;
    102        ide_atapi_cmd_ok(s);
    103        m->dma_active = false;
    104        goto done;
    105    }
    106
    107    /* Calculate current offset */
    108    offset = ((int64_t)s->lba << 11) + s->io_buffer_index;
    109
    110    qemu_sglist_init(&s->sg, DEVICE(m), io->len / MACIO_PAGE_SIZE + 1,
    111                     &address_space_memory);
    112    qemu_sglist_add(&s->sg, io->addr, io->len);
    113    s->io_buffer_size -= io->len;
    114    s->io_buffer_index += io->len;
    115    io->len = 0;
    116
    117    s->bus->dma->aiocb = dma_blk_read(s->blk, &s->sg, offset, 0x1,
    118                                      pmac_ide_atapi_transfer_cb, io);
    119    return;
    120
    121done:
    122    dma_memory_unmap(&address_space_memory, io->dma_mem, io->dma_len,
    123                     io->dir, io->dma_len);
    124
    125    if (ret < 0) {
    126        block_acct_failed(blk_get_stats(s->blk), &s->acct);
    127    } else {
    128        block_acct_done(blk_get_stats(s->blk), &s->acct);
    129    }
    130
    131    ide_set_inactive(s, false);
    132    io->dma_end(opaque);
    133}
    134
    135static void pmac_ide_transfer_cb(void *opaque, int ret)
    136{
    137    DBDMA_io *io = opaque;
    138    MACIOIDEState *m = io->opaque;
    139    IDEState *s = idebus_active_if(&m->bus);
    140    int64_t offset;
    141
    142    MACIO_DPRINTF("pmac_ide_transfer_cb\n");
    143
    144    if (ret < 0) {
    145        MACIO_DPRINTF("DMA error: %d\n", ret);
    146        qemu_sglist_destroy(&s->sg);
    147        ide_dma_error(s);
    148        goto done;
    149    }
    150
    151    if (!m->dma_active) {
    152        MACIO_DPRINTF("waiting for data (%#x - %#x - %x)\n",
    153                      s->nsector, io->len, s->status);
    154        /* data not ready yet, wait for the channel to get restarted */
    155        io->processing = false;
    156        return;
    157    }
    158
    159    if (s->io_buffer_size <= 0) {
    160        MACIO_DPRINTF("End of IDE transfer\n");
    161        qemu_sglist_destroy(&s->sg);
    162        s->status = READY_STAT | SEEK_STAT;
    163        ide_set_irq(s->bus);
    164        m->dma_active = false;
    165        goto done;
    166    }
    167
    168    if (io->len == 0) {
    169        MACIO_DPRINTF("End of DMA transfer\n");
    170        goto done;
    171    }
    172
    173    /* Calculate number of sectors */
    174    offset = (ide_get_sector(s) << 9) + s->io_buffer_index;
    175
    176    qemu_sglist_init(&s->sg, DEVICE(m), io->len / MACIO_PAGE_SIZE + 1,
    177                     &address_space_memory);
    178    qemu_sglist_add(&s->sg, io->addr, io->len);
    179    s->io_buffer_size -= io->len;
    180    s->io_buffer_index += io->len;
    181    io->len = 0;
    182
    183    switch (s->dma_cmd) {
    184    case IDE_DMA_READ:
    185        s->bus->dma->aiocb = dma_blk_read(s->blk, &s->sg, offset, 0x1,
    186                                          pmac_ide_atapi_transfer_cb, io);
    187        break;
    188    case IDE_DMA_WRITE:
    189        s->bus->dma->aiocb = dma_blk_write(s->blk, &s->sg, offset, 0x1,
    190                                           pmac_ide_transfer_cb, io);
    191        break;
    192    case IDE_DMA_TRIM:
    193        s->bus->dma->aiocb = dma_blk_io(blk_get_aio_context(s->blk), &s->sg,
    194                                        offset, 0x1, ide_issue_trim, s,
    195                                        pmac_ide_transfer_cb, io,
    196                                        DMA_DIRECTION_TO_DEVICE);
    197        break;
    198    default:
    199        abort();
    200    }
    201
    202    return;
    203
    204done:
    205    dma_memory_unmap(&address_space_memory, io->dma_mem, io->dma_len,
    206                     io->dir, io->dma_len);
    207
    208    if (s->dma_cmd == IDE_DMA_READ || s->dma_cmd == IDE_DMA_WRITE) {
    209        if (ret < 0) {
    210            block_acct_failed(blk_get_stats(s->blk), &s->acct);
    211        } else {
    212            block_acct_done(blk_get_stats(s->blk), &s->acct);
    213        }
    214    }
    215
    216    ide_set_inactive(s, false);
    217    io->dma_end(opaque);
    218}
    219
    220static void pmac_ide_transfer(DBDMA_io *io)
    221{
    222    MACIOIDEState *m = io->opaque;
    223    IDEState *s = idebus_active_if(&m->bus);
    224
    225    MACIO_DPRINTF("\n");
    226
    227    if (s->drive_kind == IDE_CD) {
    228        block_acct_start(blk_get_stats(s->blk), &s->acct, io->len,
    229                         BLOCK_ACCT_READ);
    230
    231        pmac_ide_atapi_transfer_cb(io, 0);
    232        return;
    233    }
    234
    235    switch (s->dma_cmd) {
    236    case IDE_DMA_READ:
    237        block_acct_start(blk_get_stats(s->blk), &s->acct, io->len,
    238                         BLOCK_ACCT_READ);
    239        break;
    240    case IDE_DMA_WRITE:
    241        block_acct_start(blk_get_stats(s->blk), &s->acct, io->len,
    242                         BLOCK_ACCT_WRITE);
    243        break;
    244    default:
    245        break;
    246    }
    247
    248    pmac_ide_transfer_cb(io, 0);
    249}
    250
    251static void pmac_ide_flush(DBDMA_io *io)
    252{
    253    MACIOIDEState *m = io->opaque;
    254    IDEState *s = idebus_active_if(&m->bus);
    255
    256    if (s->bus->dma->aiocb) {
    257        blk_drain(s->blk);
    258    }
    259}
    260
    261/* PowerMac IDE memory IO */
    262static uint64_t pmac_ide_read(void *opaque, hwaddr addr, unsigned size)
    263{
    264    MACIOIDEState *d = opaque;
    265    uint64_t retval = 0xffffffff;
    266    int reg = addr >> 4;
    267
    268    switch (reg) {
    269    case 0x0:
    270        if (size == 2) {
    271            retval = ide_data_readw(&d->bus, 0);
    272        } else if (size == 4) {
    273            retval = ide_data_readl(&d->bus, 0);
    274        }
    275        break;
    276    case 0x1 ... 0x7:
    277        if (size == 1) {
    278            retval = ide_ioport_read(&d->bus, reg);
    279        }
    280        break;
    281    case 0x8:
    282    case 0x16:
    283        if (size == 1) {
    284            retval = ide_status_read(&d->bus, 0);
    285        }
    286        break;
    287    case 0x20:
    288        if (size == 4) {
    289            retval = d->timing_reg;
    290        }
    291        break;
    292    case 0x30:
    293        /* This is an interrupt state register that only exists
    294         * in the KeyLargo and later variants. Bit 0x8000_0000
    295         * latches the DMA interrupt and has to be written to
    296         * clear. Bit 0x4000_0000 is an image of the disk
    297         * interrupt. MacOS X relies on this and will hang if
    298         * we don't provide at least the disk interrupt
    299         */
    300        if (size == 4) {
    301            retval = d->irq_reg;
    302        }
    303        break;
    304    }
    305
    306    return retval;
    307}
    308
    309
    310static void pmac_ide_write(void *opaque, hwaddr addr, uint64_t val,
    311                           unsigned size)
    312{
    313    MACIOIDEState *d = opaque;
    314    int reg = addr >> 4;
    315
    316    switch (reg) {
    317    case 0x0:
    318        if (size == 2) {
    319            ide_data_writew(&d->bus, 0, val);
    320        } else if (size == 4) {
    321            ide_data_writel(&d->bus, 0, val);
    322        }
    323        break;
    324    case 0x1 ... 0x7:
    325        if (size == 1) {
    326            ide_ioport_write(&d->bus, reg, val);
    327        }
    328        break;
    329    case 0x8:
    330    case 0x16:
    331        if (size == 1) {
    332            ide_ctrl_write(&d->bus, 0, val);
    333        }
    334        break;
    335    case 0x20:
    336        if (size == 4) {
    337            d->timing_reg = val;
    338        }
    339        break;
    340    case 0x30:
    341        if (size == 4) {
    342            if (val & 0x80000000u) {
    343                d->irq_reg &= 0x7fffffff;
    344            }
    345        }
    346        break;
    347    }
    348}
    349
    350static const MemoryRegionOps pmac_ide_ops = {
    351    .read = pmac_ide_read,
    352    .write = pmac_ide_write,
    353    .valid.min_access_size = 1,
    354    .valid.max_access_size = 4,
    355    .endianness = DEVICE_LITTLE_ENDIAN,
    356};
    357
    358static const VMStateDescription vmstate_pmac = {
    359    .name = "ide",
    360    .version_id = 5,
    361    .minimum_version_id = 0,
    362    .fields = (VMStateField[]) {
    363        VMSTATE_IDE_BUS(bus, MACIOIDEState),
    364        VMSTATE_IDE_DRIVES(bus.ifs, MACIOIDEState),
    365        VMSTATE_BOOL(dma_active, MACIOIDEState),
    366        VMSTATE_UINT32(timing_reg, MACIOIDEState),
    367        VMSTATE_UINT32(irq_reg, MACIOIDEState),
    368        VMSTATE_END_OF_LIST()
    369    }
    370};
    371
    372static void macio_ide_reset(DeviceState *dev)
    373{
    374    MACIOIDEState *d = MACIO_IDE(dev);
    375
    376    ide_bus_reset(&d->bus);
    377}
    378
    379static int ide_nop_int(const IDEDMA *dma, bool is_write)
    380{
    381    return 0;
    382}
    383
    384static int32_t ide_nop_int32(const IDEDMA *dma, int32_t l)
    385{
    386    return 0;
    387}
    388
    389static void ide_dbdma_start(const IDEDMA *dma, IDEState *s,
    390                            BlockCompletionFunc *cb)
    391{
    392    MACIOIDEState *m = container_of(dma, MACIOIDEState, dma);
    393
    394    s->io_buffer_index = 0;
    395    if (s->drive_kind == IDE_CD) {
    396        s->io_buffer_size = s->packet_transfer_size;
    397    } else {
    398        s->io_buffer_size = s->nsector * BDRV_SECTOR_SIZE;
    399    }
    400
    401    MACIO_DPRINTF("\n\n------------ IDE transfer\n");
    402    MACIO_DPRINTF("buffer_size: %x   buffer_index: %x\n",
    403                  s->io_buffer_size, s->io_buffer_index);
    404    MACIO_DPRINTF("lba: %x    size: %x\n", s->lba, s->io_buffer_size);
    405    MACIO_DPRINTF("-------------------------\n");
    406
    407    m->dma_active = true;
    408    DBDMA_kick(m->dbdma);
    409}
    410
    411static const IDEDMAOps dbdma_ops = {
    412    .start_dma      = ide_dbdma_start,
    413    .prepare_buf    = ide_nop_int32,
    414    .rw_buf         = ide_nop_int,
    415};
    416
    417static void macio_ide_realizefn(DeviceState *dev, Error **errp)
    418{
    419    MACIOIDEState *s = MACIO_IDE(dev);
    420
    421    ide_init2(&s->bus, s->ide_irq);
    422
    423    /* Register DMA callbacks */
    424    s->dma.ops = &dbdma_ops;
    425    s->bus.dma = &s->dma;
    426}
    427
    428static void pmac_ide_irq(void *opaque, int n, int level)
    429{
    430    MACIOIDEState *s = opaque;
    431    uint32_t mask = 0x80000000u >> n;
    432
    433    /* We need to reflect the IRQ state in the irq register */
    434    if (level) {
    435        s->irq_reg |= mask;
    436    } else {
    437        s->irq_reg &= ~mask;
    438    }
    439
    440    if (n) {
    441        qemu_set_irq(s->real_ide_irq, level);
    442    } else {
    443        qemu_set_irq(s->real_dma_irq, level);
    444    }
    445}
    446
    447static void macio_ide_initfn(Object *obj)
    448{
    449    SysBusDevice *d = SYS_BUS_DEVICE(obj);
    450    MACIOIDEState *s = MACIO_IDE(obj);
    451
    452    ide_bus_init(&s->bus, sizeof(s->bus), DEVICE(obj), 0, 2);
    453    memory_region_init_io(&s->mem, obj, &pmac_ide_ops, s, "pmac-ide", 0x1000);
    454    sysbus_init_mmio(d, &s->mem);
    455    sysbus_init_irq(d, &s->real_ide_irq);
    456    sysbus_init_irq(d, &s->real_dma_irq);
    457    s->dma_irq = qemu_allocate_irq(pmac_ide_irq, s, 0);
    458    s->ide_irq = qemu_allocate_irq(pmac_ide_irq, s, 1);
    459
    460    object_property_add_link(obj, "dbdma", TYPE_MAC_DBDMA,
    461                             (Object **) &s->dbdma,
    462                             qdev_prop_allow_set_link_before_realize, 0);
    463}
    464
    465static Property macio_ide_properties[] = {
    466    DEFINE_PROP_UINT32("channel", MACIOIDEState, channel, 0),
    467    DEFINE_PROP_UINT32("addr", MACIOIDEState, addr, -1),
    468    DEFINE_PROP_END_OF_LIST(),
    469};
    470
    471static void macio_ide_class_init(ObjectClass *oc, void *data)
    472{
    473    DeviceClass *dc = DEVICE_CLASS(oc);
    474
    475    dc->realize = macio_ide_realizefn;
    476    dc->reset = macio_ide_reset;
    477    device_class_set_props(dc, macio_ide_properties);
    478    dc->vmsd = &vmstate_pmac;
    479    set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
    480}
    481
    482static const TypeInfo macio_ide_type_info = {
    483    .name = TYPE_MACIO_IDE,
    484    .parent = TYPE_SYS_BUS_DEVICE,
    485    .instance_size = sizeof(MACIOIDEState),
    486    .instance_init = macio_ide_initfn,
    487    .class_init = macio_ide_class_init,
    488};
    489
    490static void macio_ide_register_types(void)
    491{
    492    type_register_static(&macio_ide_type_info);
    493}
    494
    495/* hd_table must contain 2 block drivers */
    496void macio_ide_init_drives(MACIOIDEState *s, DriveInfo **hd_table)
    497{
    498    int i;
    499
    500    for (i = 0; i < 2; i++) {
    501        if (hd_table[i]) {
    502            ide_create_drive(&s->bus, i, hd_table[i]);
    503        }
    504    }
    505}
    506
    507void macio_ide_register_dma(MACIOIDEState *s)
    508{
    509    DBDMA_register_channel(s->dbdma, s->channel, s->dma_irq,
    510                           pmac_ide_transfer, pmac_ide_flush, s);
    511}
    512
    513type_init(macio_ide_register_types)