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

swim.c (13324B)


      1/*
      2 * QEMU Macintosh floppy disk controller emulator (SWIM)
      3 *
      4 * Copyright (c) 2014-2018 Laurent Vivier <laurent@vivier.eu>
      5 *
      6 * This work is licensed under the terms of the GNU GPL, version 2.  See
      7 * the COPYING file in the top-level directory.
      8 *
      9 * Only the basic support: it allows to switch from IWM (Integrated WOZ
     10 * Machine) mode to the SWIM mode and makes the linux driver happy.
     11 */
     12
     13#include "qemu/osdep.h"
     14#include "qemu/main-loop.h"
     15#include "qapi/error.h"
     16#include "sysemu/block-backend.h"
     17#include "hw/sysbus.h"
     18#include "migration/vmstate.h"
     19#include "hw/block/block.h"
     20#include "hw/block/swim.h"
     21#include "hw/qdev-properties.h"
     22
     23/* IWM registers */
     24
     25#define IWM_PH0L                0
     26#define IWM_PH0H                1
     27#define IWM_PH1L                2
     28#define IWM_PH1H                3
     29#define IWM_PH2L                4
     30#define IWM_PH2H                5
     31#define IWM_PH3L                6
     32#define IWM_PH3H                7
     33#define IWM_MTROFF              8
     34#define IWM_MTRON               9
     35#define IWM_INTDRIVE            10
     36#define IWM_EXTDRIVE            11
     37#define IWM_Q6L                 12
     38#define IWM_Q6H                 13
     39#define IWM_Q7L                 14
     40#define IWM_Q7H                 15
     41
     42/* SWIM registers */
     43
     44#define SWIM_WRITE_DATA         0
     45#define SWIM_WRITE_MARK         1
     46#define SWIM_WRITE_CRC          2
     47#define SWIM_WRITE_PARAMETER    3
     48#define SWIM_WRITE_PHASE        4
     49#define SWIM_WRITE_SETUP        5
     50#define SWIM_WRITE_MODE0        6
     51#define SWIM_WRITE_MODE1        7
     52
     53#define SWIM_READ_DATA          8
     54#define SWIM_READ_MARK          9
     55#define SWIM_READ_ERROR         10
     56#define SWIM_READ_PARAMETER     11
     57#define SWIM_READ_PHASE         12
     58#define SWIM_READ_SETUP         13
     59#define SWIM_READ_STATUS        14
     60#define SWIM_READ_HANDSHAKE     15
     61
     62#define REG_SHIFT               9
     63
     64#define SWIM_MODE_IWM  0
     65#define SWIM_MODE_SWIM 1
     66
     67/* bits in phase register */
     68
     69#define SWIM_SEEK_NEGATIVE   0x074
     70#define SWIM_STEP            0x071
     71#define SWIM_MOTOR_ON        0x072
     72#define SWIM_MOTOR_OFF       0x076
     73#define SWIM_INDEX           0x073
     74#define SWIM_EJECT           0x077
     75#define SWIM_SETMFM          0x171
     76#define SWIM_SETGCR          0x175
     77#define SWIM_RELAX           0x033
     78#define SWIM_LSTRB           0x008
     79#define SWIM_CA_MASK         0x077
     80
     81/* Select values for swim_select and swim_readbit */
     82
     83#define SWIM_READ_DATA_0     0x074
     84#define SWIM_TWOMEG_DRIVE    0x075
     85#define SWIM_SINGLE_SIDED    0x076
     86#define SWIM_DRIVE_PRESENT   0x077
     87#define SWIM_DISK_IN         0x170
     88#define SWIM_WRITE_PROT      0x171
     89#define SWIM_TRACK_ZERO      0x172
     90#define SWIM_TACHO           0x173
     91#define SWIM_READ_DATA_1     0x174
     92#define SWIM_MFM_MODE        0x175
     93#define SWIM_SEEK_COMPLETE   0x176
     94#define SWIM_ONEMEG_MEDIA    0x177
     95
     96/* Bits in handshake register */
     97
     98#define SWIM_MARK_BYTE       0x01
     99#define SWIM_CRC_ZERO        0x02
    100#define SWIM_RDDATA          0x04
    101#define SWIM_SENSE           0x08
    102#define SWIM_MOTEN           0x10
    103#define SWIM_ERROR           0x20
    104#define SWIM_DAT2BYTE        0x40
    105#define SWIM_DAT1BYTE        0x80
    106
    107/* bits in setup register */
    108
    109#define SWIM_S_INV_WDATA     0x01
    110#define SWIM_S_3_5_SELECT    0x02
    111#define SWIM_S_GCR           0x04
    112#define SWIM_S_FCLK_DIV2     0x08
    113#define SWIM_S_ERROR_CORR    0x10
    114#define SWIM_S_IBM_DRIVE     0x20
    115#define SWIM_S_GCR_WRITE     0x40
    116#define SWIM_S_TIMEOUT       0x80
    117
    118/* bits in mode register */
    119
    120#define SWIM_CLFIFO          0x01
    121#define SWIM_ENBL1           0x02
    122#define SWIM_ENBL2           0x04
    123#define SWIM_ACTION          0x08
    124#define SWIM_WRITE_MODE      0x10
    125#define SWIM_HEDSEL          0x20
    126#define SWIM_MOTON           0x80
    127
    128static void fd_recalibrate(FDrive *drive)
    129{
    130}
    131
    132static void swim_change_cb(void *opaque, bool load, Error **errp)
    133{
    134    FDrive *drive = opaque;
    135
    136    if (!load) {
    137        blk_set_perm(drive->blk, 0, BLK_PERM_ALL, &error_abort);
    138    } else {
    139        if (!blkconf_apply_backend_options(drive->conf,
    140                                           !blk_supports_write_perm(drive->blk),
    141                                           false, errp)) {
    142            return;
    143        }
    144    }
    145}
    146
    147static const BlockDevOps swim_block_ops = {
    148    .change_media_cb = swim_change_cb,
    149};
    150
    151static Property swim_drive_properties[] = {
    152    DEFINE_PROP_INT32("unit", SWIMDrive, unit, -1),
    153    DEFINE_BLOCK_PROPERTIES(SWIMDrive, conf),
    154    DEFINE_PROP_END_OF_LIST(),
    155};
    156
    157static void swim_drive_realize(DeviceState *qdev, Error **errp)
    158{
    159    SWIMDrive *dev = SWIM_DRIVE(qdev);
    160    SWIMBus *bus = SWIM_BUS(qdev->parent_bus);
    161    FDrive *drive;
    162    int ret;
    163
    164    if (dev->unit == -1) {
    165        for (dev->unit = 0; dev->unit < SWIM_MAX_FD; dev->unit++) {
    166            drive = &bus->ctrl->drives[dev->unit];
    167            if (!drive->blk) {
    168                break;
    169            }
    170        }
    171    }
    172
    173    if (dev->unit >= SWIM_MAX_FD) {
    174        error_setg(errp, "Can't create floppy unit %d, bus supports "
    175                   "only %d units", dev->unit, SWIM_MAX_FD);
    176        return;
    177    }
    178
    179    drive = &bus->ctrl->drives[dev->unit];
    180    if (drive->blk) {
    181        error_setg(errp, "Floppy unit %d is in use", dev->unit);
    182        return;
    183    }
    184
    185    if (!dev->conf.blk) {
    186        /* Anonymous BlockBackend for an empty drive */
    187        dev->conf.blk = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL);
    188        ret = blk_attach_dev(dev->conf.blk, qdev);
    189        assert(ret == 0);
    190    }
    191
    192    if (!blkconf_blocksizes(&dev->conf, errp)) {
    193        return;
    194    }
    195
    196    if (dev->conf.logical_block_size != 512 ||
    197        dev->conf.physical_block_size != 512)
    198    {
    199        error_setg(errp, "Physical and logical block size must "
    200                   "be 512 for floppy");
    201        return;
    202    }
    203
    204    /*
    205     * rerror/werror aren't supported by fdc and therefore not even registered
    206     * with qdev. So set the defaults manually before they are used in
    207     * blkconf_apply_backend_options().
    208     */
    209    dev->conf.rerror = BLOCKDEV_ON_ERROR_AUTO;
    210    dev->conf.werror = BLOCKDEV_ON_ERROR_AUTO;
    211
    212    if (!blkconf_apply_backend_options(&dev->conf,
    213                                       !blk_supports_write_perm(dev->conf.blk),
    214                                       false, errp)) {
    215        return;
    216    }
    217
    218    /*
    219     * 'enospc' is the default for -drive, 'report' is what blk_new() gives us
    220     * for empty drives.
    221     */
    222    if (blk_get_on_error(dev->conf.blk, 0) != BLOCKDEV_ON_ERROR_ENOSPC &&
    223        blk_get_on_error(dev->conf.blk, 0) != BLOCKDEV_ON_ERROR_REPORT) {
    224        error_setg(errp, "fdc doesn't support drive option werror");
    225        return;
    226    }
    227    if (blk_get_on_error(dev->conf.blk, 1) != BLOCKDEV_ON_ERROR_REPORT) {
    228        error_setg(errp, "fdc doesn't support drive option rerror");
    229        return;
    230    }
    231
    232    drive->conf = &dev->conf;
    233    drive->blk = dev->conf.blk;
    234    drive->swimctrl = bus->ctrl;
    235
    236    blk_set_dev_ops(drive->blk, &swim_block_ops, drive);
    237}
    238
    239static void swim_drive_class_init(ObjectClass *klass, void *data)
    240{
    241    DeviceClass *k = DEVICE_CLASS(klass);
    242    k->realize = swim_drive_realize;
    243    set_bit(DEVICE_CATEGORY_STORAGE, k->categories);
    244    k->bus_type = TYPE_SWIM_BUS;
    245    device_class_set_props(k, swim_drive_properties);
    246    k->desc = "virtual SWIM drive";
    247}
    248
    249static const TypeInfo swim_drive_info = {
    250    .name = TYPE_SWIM_DRIVE,
    251    .parent = TYPE_DEVICE,
    252    .instance_size = sizeof(SWIMDrive),
    253    .class_init = swim_drive_class_init,
    254};
    255
    256static const TypeInfo swim_bus_info = {
    257    .name = TYPE_SWIM_BUS,
    258    .parent = TYPE_BUS,
    259    .instance_size = sizeof(SWIMBus),
    260};
    261
    262static void iwmctrl_write(void *opaque, hwaddr reg, uint64_t value,
    263                          unsigned size)
    264{
    265    SWIMCtrl *swimctrl = opaque;
    266
    267    reg >>= REG_SHIFT;
    268
    269    swimctrl->regs[reg >> 1] = reg & 1;
    270
    271    if (swimctrl->regs[IWM_Q6] &&
    272        swimctrl->regs[IWM_Q7]) {
    273        if (swimctrl->regs[IWM_MTR]) {
    274            /* data register */
    275            swimctrl->iwm_data = value;
    276        } else {
    277            /* mode register */
    278            swimctrl->iwm_mode = value;
    279            /* detect sequence to switch from IWM mode to SWIM mode */
    280            switch (swimctrl->iwm_switch) {
    281            case 0:
    282                if (value == 0x57) {
    283                    swimctrl->iwm_switch++;
    284                }
    285                break;
    286            case 1:
    287                if (value == 0x17) {
    288                    swimctrl->iwm_switch++;
    289                }
    290                break;
    291            case 2:
    292                if (value == 0x57) {
    293                    swimctrl->iwm_switch++;
    294                }
    295                break;
    296            case 3:
    297                if (value == 0x57) {
    298                    swimctrl->mode = SWIM_MODE_SWIM;
    299                    swimctrl->iwm_switch = 0;
    300                }
    301                break;
    302            }
    303        }
    304    }
    305}
    306
    307static uint64_t iwmctrl_read(void *opaque, hwaddr reg, unsigned size)
    308{
    309    SWIMCtrl *swimctrl = opaque;
    310
    311    reg >>= REG_SHIFT;
    312
    313    swimctrl->regs[reg >> 1] = reg & 1;
    314
    315    return 0;
    316}
    317
    318static void swimctrl_write(void *opaque, hwaddr reg, uint64_t value,
    319                           unsigned size)
    320{
    321    SWIMCtrl *swimctrl = opaque;
    322
    323    if (swimctrl->mode == SWIM_MODE_IWM) {
    324        iwmctrl_write(opaque, reg, value, size);
    325        return;
    326    }
    327
    328    reg >>= REG_SHIFT;
    329
    330    switch (reg) {
    331    case SWIM_WRITE_PHASE:
    332        swimctrl->swim_phase = value;
    333        break;
    334    case SWIM_WRITE_MODE0:
    335        swimctrl->swim_mode &= ~value;
    336        break;
    337    case SWIM_WRITE_MODE1:
    338        swimctrl->swim_mode |= value;
    339        break;
    340    case SWIM_WRITE_DATA:
    341    case SWIM_WRITE_MARK:
    342    case SWIM_WRITE_CRC:
    343    case SWIM_WRITE_PARAMETER:
    344    case SWIM_WRITE_SETUP:
    345        break;
    346    }
    347}
    348
    349static uint64_t swimctrl_read(void *opaque, hwaddr reg, unsigned size)
    350{
    351    SWIMCtrl *swimctrl = opaque;
    352    uint32_t value = 0;
    353
    354    if (swimctrl->mode == SWIM_MODE_IWM) {
    355        return iwmctrl_read(opaque, reg, size);
    356    }
    357
    358    reg >>= REG_SHIFT;
    359
    360    switch (reg) {
    361    case SWIM_READ_PHASE:
    362        value = swimctrl->swim_phase;
    363        break;
    364    case SWIM_READ_HANDSHAKE:
    365        if (swimctrl->swim_phase == SWIM_DRIVE_PRESENT) {
    366            /* always answer "no drive present" */
    367            value = SWIM_SENSE;
    368        }
    369        break;
    370    case SWIM_READ_DATA:
    371    case SWIM_READ_MARK:
    372    case SWIM_READ_ERROR:
    373    case SWIM_READ_PARAMETER:
    374    case SWIM_READ_SETUP:
    375    case SWIM_READ_STATUS:
    376        break;
    377    }
    378
    379    return value;
    380}
    381
    382static const MemoryRegionOps swimctrl_mem_ops = {
    383    .write = swimctrl_write,
    384    .read = swimctrl_read,
    385    .endianness = DEVICE_NATIVE_ENDIAN,
    386};
    387
    388static void sysbus_swim_reset(DeviceState *d)
    389{
    390    Swim *sys = SWIM(d);
    391    SWIMCtrl *ctrl = &sys->ctrl;
    392    int i;
    393
    394    ctrl->mode = 0;
    395    ctrl->iwm_switch = 0;
    396    for (i = 0; i < 8; i++) {
    397        ctrl->regs[i] = 0;
    398    }
    399    ctrl->iwm_data = 0;
    400    ctrl->iwm_mode = 0;
    401    ctrl->swim_phase = 0;
    402    ctrl->swim_mode = 0;
    403    for (i = 0; i < SWIM_MAX_FD; i++) {
    404        fd_recalibrate(&ctrl->drives[i]);
    405    }
    406}
    407
    408static void sysbus_swim_init(Object *obj)
    409{
    410    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
    411    Swim *sbs = SWIM(obj);
    412    SWIMCtrl *swimctrl = &sbs->ctrl;
    413
    414    memory_region_init_io(&swimctrl->iomem, obj, &swimctrl_mem_ops, swimctrl,
    415                          "swim", 0x2000);
    416    sysbus_init_mmio(sbd, &swimctrl->iomem);
    417}
    418
    419static void sysbus_swim_realize(DeviceState *dev, Error **errp)
    420{
    421    Swim *sys = SWIM(dev);
    422    SWIMCtrl *swimctrl = &sys->ctrl;
    423
    424    qbus_init(&swimctrl->bus, sizeof(SWIMBus), TYPE_SWIM_BUS, dev, NULL);
    425    swimctrl->bus.ctrl = swimctrl;
    426}
    427
    428static const VMStateDescription vmstate_fdrive = {
    429    .name = "fdrive",
    430    .version_id = 1,
    431    .minimum_version_id = 1,
    432    .fields = (VMStateField[]) {
    433        VMSTATE_END_OF_LIST()
    434    },
    435};
    436
    437static const VMStateDescription vmstate_swim = {
    438    .name = "swim",
    439    .version_id = 1,
    440    .minimum_version_id = 1,
    441    .fields = (VMStateField[]) {
    442        VMSTATE_INT32(mode, SWIMCtrl),
    443        /* IWM mode */
    444        VMSTATE_INT32(iwm_switch, SWIMCtrl),
    445        VMSTATE_UINT16_ARRAY(regs, SWIMCtrl, 8),
    446        VMSTATE_UINT8(iwm_data, SWIMCtrl),
    447        VMSTATE_UINT8(iwm_mode, SWIMCtrl),
    448        /* SWIM mode */
    449        VMSTATE_UINT8(swim_phase, SWIMCtrl),
    450        VMSTATE_UINT8(swim_mode, SWIMCtrl),
    451        /* Drives */
    452        VMSTATE_STRUCT_ARRAY(drives, SWIMCtrl, SWIM_MAX_FD, 1,
    453                             vmstate_fdrive, FDrive),
    454        VMSTATE_END_OF_LIST()
    455    },
    456};
    457
    458static const VMStateDescription vmstate_sysbus_swim = {
    459    .name = "SWIM",
    460    .version_id = 1,
    461    .fields = (VMStateField[]) {
    462        VMSTATE_STRUCT(ctrl, Swim, 0, vmstate_swim, SWIMCtrl),
    463        VMSTATE_END_OF_LIST()
    464    }
    465};
    466
    467static void sysbus_swim_class_init(ObjectClass *oc, void *data)
    468{
    469    DeviceClass *dc = DEVICE_CLASS(oc);
    470
    471    dc->realize = sysbus_swim_realize;
    472    dc->reset = sysbus_swim_reset;
    473    dc->vmsd = &vmstate_sysbus_swim;
    474}
    475
    476static const TypeInfo sysbus_swim_info = {
    477    .name          = TYPE_SWIM,
    478    .parent        = TYPE_SYS_BUS_DEVICE,
    479    .instance_size = sizeof(Swim),
    480    .instance_init = sysbus_swim_init,
    481    .class_init    = sysbus_swim_class_init,
    482};
    483
    484static void swim_register_types(void)
    485{
    486    type_register_static(&sysbus_swim_info);
    487    type_register_static(&swim_bus_info);
    488    type_register_static(&swim_drive_info);
    489}
    490
    491type_init(swim_register_types)