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

i8257.c (17567B)


      1/*
      2 * QEMU DMA emulation
      3 *
      4 * Copyright (c) 2003-2004 Vassili Karpov (malc)
      5 *
      6 * Permission is hereby granted, free of charge, to any person obtaining a copy
      7 * of this software and associated documentation files (the "Software"), to deal
      8 * in the Software without restriction, including without limitation the rights
      9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     10 * copies of the Software, and to permit persons to whom the Software is
     11 * furnished to do so, subject to the following conditions:
     12 *
     13 * The above copyright notice and this permission notice shall be included in
     14 * all copies or substantial portions of the Software.
     15 *
     16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     22 * THE SOFTWARE.
     23 */
     24
     25#include "qemu/osdep.h"
     26#include "hw/isa/isa.h"
     27#include "hw/qdev-properties.h"
     28#include "migration/vmstate.h"
     29#include "hw/dma/i8257.h"
     30#include "qapi/error.h"
     31#include "qemu/main-loop.h"
     32#include "qemu/module.h"
     33#include "qemu/log.h"
     34#include "trace.h"
     35
     36
     37/* #define DEBUG_DMA */
     38
     39#define dolog(...) fprintf (stderr, "dma: " __VA_ARGS__)
     40#ifdef DEBUG_DMA
     41#define linfo(...) fprintf (stderr, "dma: " __VA_ARGS__)
     42#define ldebug(...) fprintf (stderr, "dma: " __VA_ARGS__)
     43#else
     44#define linfo(...)
     45#define ldebug(...)
     46#endif
     47
     48#define ADDR 0
     49#define COUNT 1
     50
     51enum {
     52    CMD_MEMORY_TO_MEMORY = 0x01,
     53    CMD_FIXED_ADDRESS    = 0x02,
     54    CMD_BLOCK_CONTROLLER = 0x04,
     55    CMD_COMPRESSED_TIME  = 0x08,
     56    CMD_CYCLIC_PRIORITY  = 0x10,
     57    CMD_EXTENDED_WRITE   = 0x20,
     58    CMD_LOW_DREQ         = 0x40,
     59    CMD_LOW_DACK         = 0x80,
     60    CMD_NOT_SUPPORTED    = CMD_MEMORY_TO_MEMORY | CMD_FIXED_ADDRESS
     61    | CMD_COMPRESSED_TIME | CMD_CYCLIC_PRIORITY | CMD_EXTENDED_WRITE
     62    | CMD_LOW_DREQ | CMD_LOW_DACK
     63
     64};
     65
     66static void i8257_dma_run(void *opaque);
     67
     68static const int channels[8] = {-1, 2, 3, 1, -1, -1, -1, 0};
     69
     70static void i8257_write_page(void *opaque, uint32_t nport, uint32_t data)
     71{
     72    I8257State *d = opaque;
     73    int ichan;
     74
     75    ichan = channels[nport & 7];
     76    if (-1 == ichan) {
     77        dolog ("invalid channel %#x %#x\n", nport, data);
     78        return;
     79    }
     80    d->regs[ichan].page = data;
     81}
     82
     83static void i8257_write_pageh(void *opaque, uint32_t nport, uint32_t data)
     84{
     85    I8257State *d = opaque;
     86    int ichan;
     87
     88    ichan = channels[nport & 7];
     89    if (-1 == ichan) {
     90        dolog ("invalid channel %#x %#x\n", nport, data);
     91        return;
     92    }
     93    d->regs[ichan].pageh = data;
     94}
     95
     96static uint32_t i8257_read_page(void *opaque, uint32_t nport)
     97{
     98    I8257State *d = opaque;
     99    int ichan;
    100
    101    ichan = channels[nport & 7];
    102    if (-1 == ichan) {
    103        dolog ("invalid channel read %#x\n", nport);
    104        return 0;
    105    }
    106    return d->regs[ichan].page;
    107}
    108
    109static uint32_t i8257_read_pageh(void *opaque, uint32_t nport)
    110{
    111    I8257State *d = opaque;
    112    int ichan;
    113
    114    ichan = channels[nport & 7];
    115    if (-1 == ichan) {
    116        dolog ("invalid channel read %#x\n", nport);
    117        return 0;
    118    }
    119    return d->regs[ichan].pageh;
    120}
    121
    122static inline void i8257_init_chan(I8257State *d, int ichan)
    123{
    124    I8257Regs *r;
    125
    126    r = d->regs + ichan;
    127    r->now[ADDR] = r->base[ADDR] << d->dshift;
    128    r->now[COUNT] = 0;
    129}
    130
    131static inline int i8257_getff(I8257State *d)
    132{
    133    int ff;
    134
    135    ff = d->flip_flop;
    136    d->flip_flop = !ff;
    137    return ff;
    138}
    139
    140static uint64_t i8257_read_chan(void *opaque, hwaddr nport, unsigned size)
    141{
    142    I8257State *d = opaque;
    143    int ichan, nreg, iport, ff, val, dir;
    144    I8257Regs *r;
    145
    146    iport = (nport >> d->dshift) & 0x0f;
    147    ichan = iport >> 1;
    148    nreg = iport & 1;
    149    r = d->regs + ichan;
    150
    151    dir = ((r->mode >> 5) & 1) ? -1 : 1;
    152    ff = i8257_getff(d);
    153    if (nreg)
    154        val = (r->base[COUNT] << d->dshift) - r->now[COUNT];
    155    else
    156        val = r->now[ADDR] + r->now[COUNT] * dir;
    157
    158    ldebug ("read_chan %#x -> %d\n", iport, val);
    159    return (val >> (d->dshift + (ff << 3))) & 0xff;
    160}
    161
    162static void i8257_write_chan(void *opaque, hwaddr nport, uint64_t data,
    163                             unsigned int size)
    164{
    165    I8257State *d = opaque;
    166    int iport, ichan, nreg;
    167    I8257Regs *r;
    168
    169    iport = (nport >> d->dshift) & 0x0f;
    170    ichan = iport >> 1;
    171    nreg = iport & 1;
    172    r = d->regs + ichan;
    173    if (i8257_getff(d)) {
    174        r->base[nreg] = (r->base[nreg] & 0xff) | ((data << 8) & 0xff00);
    175        i8257_init_chan(d, ichan);
    176    } else {
    177        r->base[nreg] = (r->base[nreg] & 0xff00) | (data & 0xff);
    178    }
    179}
    180
    181static void i8257_write_cont(void *opaque, hwaddr nport, uint64_t data,
    182                             unsigned int size)
    183{
    184    I8257State *d = opaque;
    185    int iport, ichan = 0;
    186
    187    iport = (nport >> d->dshift) & 0x0f;
    188    switch (iport) {
    189    case 0x00:                  /* command */
    190        if ((data != 0) && (data & CMD_NOT_SUPPORTED)) {
    191            qemu_log_mask(LOG_UNIMP, "%s: cmd 0x%02"PRIx64" not supported\n",
    192                          __func__, data);
    193            return;
    194        }
    195        d->command = data;
    196        break;
    197
    198    case 0x01:
    199        ichan = data & 3;
    200        if (data & 4) {
    201            d->status |= 1 << (ichan + 4);
    202        }
    203        else {
    204            d->status &= ~(1 << (ichan + 4));
    205        }
    206        d->status &= ~(1 << ichan);
    207        i8257_dma_run(d);
    208        break;
    209
    210    case 0x02:                  /* single mask */
    211        if (data & 4)
    212            d->mask |= 1 << (data & 3);
    213        else
    214            d->mask &= ~(1 << (data & 3));
    215        i8257_dma_run(d);
    216        break;
    217
    218    case 0x03:                  /* mode */
    219        {
    220            ichan = data & 3;
    221#ifdef DEBUG_DMA
    222            {
    223                int op, ai, dir, opmode;
    224                op = (data >> 2) & 3;
    225                ai = (data >> 4) & 1;
    226                dir = (data >> 5) & 1;
    227                opmode = (data >> 6) & 3;
    228
    229                linfo ("ichan %d, op %d, ai %d, dir %d, opmode %d\n",
    230                       ichan, op, ai, dir, opmode);
    231            }
    232#endif
    233            d->regs[ichan].mode = data;
    234            break;
    235        }
    236
    237    case 0x04:                  /* clear flip flop */
    238        d->flip_flop = 0;
    239        break;
    240
    241    case 0x05:                  /* reset */
    242        d->flip_flop = 0;
    243        d->mask = ~0;
    244        d->status = 0;
    245        d->command = 0;
    246        break;
    247
    248    case 0x06:                  /* clear mask for all channels */
    249        d->mask = 0;
    250        i8257_dma_run(d);
    251        break;
    252
    253    case 0x07:                  /* write mask for all channels */
    254        d->mask = data;
    255        i8257_dma_run(d);
    256        break;
    257
    258    default:
    259        dolog ("unknown iport %#x\n", iport);
    260        break;
    261    }
    262
    263#ifdef DEBUG_DMA
    264    if (0xc != iport) {
    265        linfo ("write_cont: nport %#06x, ichan % 2d, val %#06x\n",
    266               nport, ichan, data);
    267    }
    268#endif
    269}
    270
    271static uint64_t i8257_read_cont(void *opaque, hwaddr nport, unsigned size)
    272{
    273    I8257State *d = opaque;
    274    int iport, val;
    275
    276    iport = (nport >> d->dshift) & 0x0f;
    277    switch (iport) {
    278    case 0x00:                  /* status */
    279        val = d->status;
    280        d->status &= 0xf0;
    281        break;
    282    case 0x01:                  /* mask */
    283        val = d->mask;
    284        break;
    285    default:
    286        val = 0;
    287        break;
    288    }
    289
    290    ldebug ("read_cont: nport %#06x, iport %#04x val %#x\n", nport, iport, val);
    291    return val;
    292}
    293
    294static bool i8257_dma_has_autoinitialization(IsaDma *obj, int nchan)
    295{
    296    I8257State *d = I8257(obj);
    297    return (d->regs[nchan & 3].mode >> 4) & 1;
    298}
    299
    300static void i8257_dma_hold_DREQ(IsaDma *obj, int nchan)
    301{
    302    I8257State *d = I8257(obj);
    303    int ichan;
    304
    305    ichan = nchan & 3;
    306    d->status |= 1 << (ichan + 4);
    307    i8257_dma_run(d);
    308}
    309
    310static void i8257_dma_release_DREQ(IsaDma *obj, int nchan)
    311{
    312    I8257State *d = I8257(obj);
    313    int ichan;
    314
    315    ichan = nchan & 3;
    316    d->status &= ~(1 << (ichan + 4));
    317    i8257_dma_run(d);
    318}
    319
    320static void i8257_channel_run(I8257State *d, int ichan)
    321{
    322    int ncont = d->dshift;
    323    int n;
    324    I8257Regs *r = &d->regs[ichan];
    325#ifdef DEBUG_DMA
    326    int dir, opmode;
    327
    328    dir = (r->mode >> 5) & 1;
    329    opmode = (r->mode >> 6) & 3;
    330
    331    if (dir) {
    332        dolog ("DMA in address decrement mode\n");
    333    }
    334    if (opmode != 1) {
    335        dolog ("DMA not in single mode select %#x\n", opmode);
    336    }
    337#endif
    338
    339    n = r->transfer_handler (r->opaque, ichan + (ncont << 2),
    340                             r->now[COUNT], (r->base[COUNT] + 1) << ncont);
    341    r->now[COUNT] = n;
    342    ldebug ("dma_pos %d size %d\n", n, (r->base[COUNT] + 1) << ncont);
    343    if (n == (r->base[COUNT] + 1) << ncont) {
    344        ldebug("transfer done\n");
    345        d->status |= (1 << ichan);
    346    }
    347}
    348
    349static void i8257_dma_run(void *opaque)
    350{
    351    I8257State *d = opaque;
    352    int ichan;
    353    int rearm = 0;
    354
    355    if (d->running) {
    356        rearm = 1;
    357        goto out;
    358    } else {
    359        d->running = 1;
    360    }
    361
    362    for (ichan = 0; ichan < 4; ichan++) {
    363        int mask;
    364
    365        mask = 1 << ichan;
    366
    367        if ((0 == (d->mask & mask)) && (0 != (d->status & (mask << 4)))) {
    368            i8257_channel_run(d, ichan);
    369            rearm = 1;
    370        }
    371    }
    372
    373    d->running = 0;
    374out:
    375    if (rearm) {
    376        qemu_bh_schedule_idle(d->dma_bh);
    377        d->dma_bh_scheduled = true;
    378    }
    379}
    380
    381static void i8257_dma_register_channel(IsaDma *obj, int nchan,
    382                                       IsaDmaTransferHandler transfer_handler,
    383                                       void *opaque)
    384{
    385    I8257State *d = I8257(obj);
    386    I8257Regs *r;
    387    int ichan;
    388
    389    ichan = nchan & 3;
    390
    391    r = d->regs + ichan;
    392    r->transfer_handler = transfer_handler;
    393    r->opaque = opaque;
    394}
    395
    396static bool i8257_is_verify_transfer(I8257Regs *r)
    397{
    398    return (r->mode & 0x0c) == 0;
    399}
    400
    401static int i8257_dma_read_memory(IsaDma *obj, int nchan, void *buf, int pos,
    402                                 int len)
    403{
    404    I8257State *d = I8257(obj);
    405    I8257Regs *r = &d->regs[nchan & 3];
    406    hwaddr addr = ((r->pageh & 0x7f) << 24) | (r->page << 16) | r->now[ADDR];
    407
    408    if (i8257_is_verify_transfer(r)) {
    409        return len;
    410    }
    411
    412    if (r->mode & 0x20) {
    413        int i;
    414        uint8_t *p = buf;
    415
    416        cpu_physical_memory_read (addr - pos - len, buf, len);
    417        /* What about 16bit transfers? */
    418        for (i = 0; i < len >> 1; i++) {
    419            uint8_t b = p[len - i - 1];
    420            p[i] = b;
    421        }
    422    }
    423    else
    424        cpu_physical_memory_read (addr + pos, buf, len);
    425
    426    return len;
    427}
    428
    429static int i8257_dma_write_memory(IsaDma *obj, int nchan, void *buf, int pos,
    430                                 int len)
    431{
    432    I8257State *s = I8257(obj);
    433    I8257Regs *r = &s->regs[nchan & 3];
    434    hwaddr addr = ((r->pageh & 0x7f) << 24) | (r->page << 16) | r->now[ADDR];
    435
    436    if (i8257_is_verify_transfer(r)) {
    437        return len;
    438    }
    439
    440    if (r->mode & 0x20) {
    441        int i;
    442        uint8_t *p = buf;
    443
    444        cpu_physical_memory_write (addr - pos - len, buf, len);
    445        /* What about 16bit transfers? */
    446        for (i = 0; i < len; i++) {
    447            uint8_t b = p[len - i - 1];
    448            p[i] = b;
    449        }
    450    }
    451    else
    452        cpu_physical_memory_write (addr + pos, buf, len);
    453
    454    return len;
    455}
    456
    457/* request the emulator to transfer a new DMA memory block ASAP (even
    458 * if the idle bottom half would not have exited the iothread yet).
    459 */
    460static void i8257_dma_schedule(IsaDma *obj)
    461{
    462    I8257State *d = I8257(obj);
    463    if (d->dma_bh_scheduled) {
    464        qemu_notify_event();
    465    }
    466}
    467
    468static void i8257_reset(DeviceState *dev)
    469{
    470    I8257State *d = I8257(dev);
    471    i8257_write_cont(d, (0x05 << d->dshift), 0, 1);
    472}
    473
    474static int i8257_phony_handler(void *opaque, int nchan, int dma_pos,
    475                               int dma_len)
    476{
    477    trace_i8257_unregistered_dma(nchan, dma_pos, dma_len);
    478    return dma_pos;
    479}
    480
    481
    482static const MemoryRegionOps channel_io_ops = {
    483    .read = i8257_read_chan,
    484    .write = i8257_write_chan,
    485    .endianness = DEVICE_NATIVE_ENDIAN,
    486    .impl = {
    487        .min_access_size = 1,
    488        .max_access_size = 1,
    489    },
    490};
    491
    492/* IOport from page_base */
    493static const MemoryRegionPortio page_portio_list[] = {
    494    { 0x01, 3, 1, .write = i8257_write_page, .read = i8257_read_page, },
    495    { 0x07, 1, 1, .write = i8257_write_page, .read = i8257_read_page, },
    496    PORTIO_END_OF_LIST(),
    497};
    498
    499/* IOport from pageh_base */
    500static const MemoryRegionPortio pageh_portio_list[] = {
    501    { 0x01, 3, 1, .write = i8257_write_pageh, .read = i8257_read_pageh, },
    502    { 0x07, 3, 1, .write = i8257_write_pageh, .read = i8257_read_pageh, },
    503    PORTIO_END_OF_LIST(),
    504};
    505
    506static const MemoryRegionOps cont_io_ops = {
    507    .read = i8257_read_cont,
    508    .write = i8257_write_cont,
    509    .endianness = DEVICE_NATIVE_ENDIAN,
    510    .impl = {
    511        .min_access_size = 1,
    512        .max_access_size = 1,
    513    },
    514};
    515
    516static const VMStateDescription vmstate_i8257_regs = {
    517    .name = "dma_regs",
    518    .version_id = 1,
    519    .minimum_version_id = 1,
    520    .fields = (VMStateField[]) {
    521        VMSTATE_INT32_ARRAY(now, I8257Regs, 2),
    522        VMSTATE_UINT16_ARRAY(base, I8257Regs, 2),
    523        VMSTATE_UINT8(mode, I8257Regs),
    524        VMSTATE_UINT8(page, I8257Regs),
    525        VMSTATE_UINT8(pageh, I8257Regs),
    526        VMSTATE_UINT8(dack, I8257Regs),
    527        VMSTATE_UINT8(eop, I8257Regs),
    528        VMSTATE_END_OF_LIST()
    529    }
    530};
    531
    532static int i8257_post_load(void *opaque, int version_id)
    533{
    534    I8257State *d = opaque;
    535    i8257_dma_run(d);
    536
    537    return 0;
    538}
    539
    540static const VMStateDescription vmstate_i8257 = {
    541    .name = "dma",
    542    .version_id = 1,
    543    .minimum_version_id = 1,
    544    .post_load = i8257_post_load,
    545    .fields = (VMStateField[]) {
    546        VMSTATE_UINT8(command, I8257State),
    547        VMSTATE_UINT8(mask, I8257State),
    548        VMSTATE_UINT8(flip_flop, I8257State),
    549        VMSTATE_INT32(dshift, I8257State),
    550        VMSTATE_STRUCT_ARRAY(regs, I8257State, 4, 1, vmstate_i8257_regs,
    551                             I8257Regs),
    552        VMSTATE_END_OF_LIST()
    553    }
    554};
    555
    556static void i8257_realize(DeviceState *dev, Error **errp)
    557{
    558    ISADevice *isa = ISA_DEVICE(dev);
    559    I8257State *d = I8257(dev);
    560    int i;
    561
    562    memory_region_init_io(&d->channel_io, OBJECT(dev), &channel_io_ops, d,
    563                          "dma-chan", 8 << d->dshift);
    564    memory_region_add_subregion(isa_address_space_io(isa),
    565                                d->base, &d->channel_io);
    566
    567    isa_register_portio_list(isa, &d->portio_page,
    568                             d->page_base, page_portio_list, d,
    569                             "dma-page");
    570    if (d->pageh_base >= 0) {
    571        isa_register_portio_list(isa, &d->portio_pageh,
    572                                 d->pageh_base, pageh_portio_list, d,
    573                                 "dma-pageh");
    574    }
    575
    576    memory_region_init_io(&d->cont_io, OBJECT(isa), &cont_io_ops, d,
    577                          "dma-cont", 8 << d->dshift);
    578    memory_region_add_subregion(isa_address_space_io(isa),
    579                                d->base + (8 << d->dshift), &d->cont_io);
    580
    581    for (i = 0; i < ARRAY_SIZE(d->regs); ++i) {
    582        d->regs[i].transfer_handler = i8257_phony_handler;
    583    }
    584
    585    d->dma_bh = qemu_bh_new(i8257_dma_run, d);
    586}
    587
    588static Property i8257_properties[] = {
    589    DEFINE_PROP_INT32("base", I8257State, base, 0x00),
    590    DEFINE_PROP_INT32("page-base", I8257State, page_base, 0x80),
    591    DEFINE_PROP_INT32("pageh-base", I8257State, pageh_base, 0x480),
    592    DEFINE_PROP_INT32("dshift", I8257State, dshift, 0),
    593    DEFINE_PROP_END_OF_LIST()
    594};
    595
    596static void i8257_class_init(ObjectClass *klass, void *data)
    597{
    598    DeviceClass *dc = DEVICE_CLASS(klass);
    599    IsaDmaClass *idc = ISADMA_CLASS(klass);
    600
    601    dc->realize = i8257_realize;
    602    dc->reset = i8257_reset;
    603    dc->vmsd = &vmstate_i8257;
    604    device_class_set_props(dc, i8257_properties);
    605
    606    idc->has_autoinitialization = i8257_dma_has_autoinitialization;
    607    idc->read_memory = i8257_dma_read_memory;
    608    idc->write_memory = i8257_dma_write_memory;
    609    idc->hold_DREQ = i8257_dma_hold_DREQ;
    610    idc->release_DREQ = i8257_dma_release_DREQ;
    611    idc->schedule = i8257_dma_schedule;
    612    idc->register_channel = i8257_dma_register_channel;
    613    /* Reason: needs to be wired up by isa_bus_dma() to work */
    614    dc->user_creatable = false;
    615}
    616
    617static const TypeInfo i8257_info = {
    618    .name = TYPE_I8257,
    619    .parent = TYPE_ISA_DEVICE,
    620    .instance_size = sizeof(I8257State),
    621    .class_init = i8257_class_init,
    622    .interfaces = (InterfaceInfo[]) {
    623        { TYPE_ISADMA },
    624        { }
    625    }
    626};
    627
    628static void i8257_register_types(void)
    629{
    630    type_register_static(&i8257_info);
    631}
    632
    633type_init(i8257_register_types)
    634
    635void i8257_dma_init(ISABus *bus, bool high_page_enable)
    636{
    637    ISADevice *isa1, *isa2;
    638    DeviceState *d;
    639
    640    isa1 = isa_new(TYPE_I8257);
    641    d = DEVICE(isa1);
    642    qdev_prop_set_int32(d, "base", 0x00);
    643    qdev_prop_set_int32(d, "page-base", 0x80);
    644    qdev_prop_set_int32(d, "pageh-base", high_page_enable ? 0x480 : -1);
    645    qdev_prop_set_int32(d, "dshift", 0);
    646    isa_realize_and_unref(isa1, bus, &error_fatal);
    647
    648    isa2 = isa_new(TYPE_I8257);
    649    d = DEVICE(isa2);
    650    qdev_prop_set_int32(d, "base", 0xc0);
    651    qdev_prop_set_int32(d, "page-base", 0x88);
    652    qdev_prop_set_int32(d, "pageh-base", high_page_enable ? 0x488 : -1);
    653    qdev_prop_set_int32(d, "dshift", 1);
    654    isa_realize_and_unref(isa2, bus, &error_fatal);
    655
    656    isa_bus_dma(bus, ISADMA(isa1), ISADMA(isa2));
    657}