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

ioport.c (9168B)


      1/*
      2 * QEMU System Emulator
      3 *
      4 * Copyright (c) 2003-2008 Fabrice Bellard
      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 * splitted out ioport related stuffs from vl.c.
     26 */
     27
     28#include "qemu/osdep.h"
     29#include "cpu.h"
     30#include "exec/ioport.h"
     31#include "exec/memory.h"
     32#include "exec/address-spaces.h"
     33#include "trace.h"
     34
     35typedef struct MemoryRegionPortioList {
     36    MemoryRegion mr;
     37    void *portio_opaque;
     38    MemoryRegionPortio ports[];
     39} MemoryRegionPortioList;
     40
     41static uint64_t unassigned_io_read(void *opaque, hwaddr addr, unsigned size)
     42{
     43    return -1ULL;
     44}
     45
     46static void unassigned_io_write(void *opaque, hwaddr addr, uint64_t val,
     47                                unsigned size)
     48{
     49}
     50
     51const MemoryRegionOps unassigned_io_ops = {
     52    .read = unassigned_io_read,
     53    .write = unassigned_io_write,
     54    .endianness = DEVICE_NATIVE_ENDIAN,
     55};
     56
     57void cpu_outb(uint32_t addr, uint8_t val)
     58{
     59    trace_cpu_out(addr, 'b', val);
     60    address_space_write(&address_space_io, addr, MEMTXATTRS_UNSPECIFIED,
     61                        &val, 1);
     62}
     63
     64void cpu_outw(uint32_t addr, uint16_t val)
     65{
     66    uint8_t buf[2];
     67
     68    trace_cpu_out(addr, 'w', val);
     69    stw_p(buf, val);
     70    address_space_write(&address_space_io, addr, MEMTXATTRS_UNSPECIFIED,
     71                        buf, 2);
     72}
     73
     74void cpu_outl(uint32_t addr, uint32_t val)
     75{
     76    uint8_t buf[4];
     77
     78    trace_cpu_out(addr, 'l', val);
     79    stl_p(buf, val);
     80    address_space_write(&address_space_io, addr, MEMTXATTRS_UNSPECIFIED,
     81                        buf, 4);
     82}
     83
     84uint8_t cpu_inb(uint32_t addr)
     85{
     86    uint8_t val;
     87
     88    address_space_read(&address_space_io, addr, MEMTXATTRS_UNSPECIFIED,
     89                       &val, 1);
     90    trace_cpu_in(addr, 'b', val);
     91    return val;
     92}
     93
     94uint16_t cpu_inw(uint32_t addr)
     95{
     96    uint8_t buf[2];
     97    uint16_t val;
     98
     99    address_space_read(&address_space_io, addr, MEMTXATTRS_UNSPECIFIED, buf, 2);
    100    val = lduw_p(buf);
    101    trace_cpu_in(addr, 'w', val);
    102    return val;
    103}
    104
    105uint32_t cpu_inl(uint32_t addr)
    106{
    107    uint8_t buf[4];
    108    uint32_t val;
    109
    110    address_space_read(&address_space_io, addr, MEMTXATTRS_UNSPECIFIED, buf, 4);
    111    val = ldl_p(buf);
    112    trace_cpu_in(addr, 'l', val);
    113    return val;
    114}
    115
    116void portio_list_init(PortioList *piolist,
    117                      Object *owner,
    118                      const MemoryRegionPortio *callbacks,
    119                      void *opaque, const char *name)
    120{
    121    unsigned n = 0;
    122
    123    while (callbacks[n].size) {
    124        ++n;
    125    }
    126
    127    piolist->ports = callbacks;
    128    piolist->nr = 0;
    129    piolist->regions = g_new0(MemoryRegion *, n);
    130    piolist->address_space = NULL;
    131    piolist->opaque = opaque;
    132    piolist->owner = owner;
    133    piolist->name = name;
    134    piolist->flush_coalesced_mmio = false;
    135}
    136
    137void portio_list_set_flush_coalesced(PortioList *piolist)
    138{
    139    piolist->flush_coalesced_mmio = true;
    140}
    141
    142void portio_list_destroy(PortioList *piolist)
    143{
    144    MemoryRegionPortioList *mrpio;
    145    unsigned i;
    146
    147    for (i = 0; i < piolist->nr; ++i) {
    148        mrpio = container_of(piolist->regions[i], MemoryRegionPortioList, mr);
    149        object_unparent(OBJECT(&mrpio->mr));
    150        g_free(mrpio);
    151    }
    152    g_free(piolist->regions);
    153}
    154
    155static const MemoryRegionPortio *find_portio(MemoryRegionPortioList *mrpio,
    156                                             uint64_t offset, unsigned size,
    157                                             bool write)
    158{
    159    const MemoryRegionPortio *mrp;
    160
    161    for (mrp = mrpio->ports; mrp->size; ++mrp) {
    162        if (offset >= mrp->offset && offset < mrp->offset + mrp->len &&
    163            size == mrp->size &&
    164            (write ? (bool)mrp->write : (bool)mrp->read)) {
    165            return mrp;
    166        }
    167    }
    168    return NULL;
    169}
    170
    171static uint64_t portio_read(void *opaque, hwaddr addr, unsigned size)
    172{
    173    MemoryRegionPortioList *mrpio = opaque;
    174    const MemoryRegionPortio *mrp = find_portio(mrpio, addr, size, false);
    175    uint64_t data;
    176
    177    data = ((uint64_t)1 << (size * 8)) - 1;
    178    if (mrp) {
    179        data = mrp->read(mrpio->portio_opaque, mrp->base + addr);
    180    } else if (size == 2) {
    181        mrp = find_portio(mrpio, addr, 1, false);
    182        if (mrp) {
    183            data = mrp->read(mrpio->portio_opaque, mrp->base + addr);
    184            if (addr + 1 < mrp->offset + mrp->len) {
    185                data |= mrp->read(mrpio->portio_opaque, mrp->base + addr + 1) << 8;
    186            } else {
    187                data |= 0xff00;
    188            }
    189        }
    190    }
    191    return data;
    192}
    193
    194static void portio_write(void *opaque, hwaddr addr, uint64_t data,
    195                         unsigned size)
    196{
    197    MemoryRegionPortioList *mrpio = opaque;
    198    const MemoryRegionPortio *mrp = find_portio(mrpio, addr, size, true);
    199
    200    if (mrp) {
    201        mrp->write(mrpio->portio_opaque, mrp->base + addr, data);
    202    } else if (size == 2) {
    203        mrp = find_portio(mrpio, addr, 1, true);
    204        if (mrp) {
    205            mrp->write(mrpio->portio_opaque, mrp->base + addr, data & 0xff);
    206            if (addr + 1 < mrp->offset + mrp->len) {
    207                mrp->write(mrpio->portio_opaque, mrp->base + addr + 1, data >> 8);
    208            }
    209        }
    210    }
    211}
    212
    213static const MemoryRegionOps portio_ops = {
    214    .read = portio_read,
    215    .write = portio_write,
    216    .endianness = DEVICE_LITTLE_ENDIAN,
    217    .valid.unaligned = true,
    218    .impl.unaligned = true,
    219};
    220
    221static void portio_list_add_1(PortioList *piolist,
    222                              const MemoryRegionPortio *pio_init,
    223                              unsigned count, unsigned start,
    224                              unsigned off_low, unsigned off_high)
    225{
    226    MemoryRegionPortioList *mrpio;
    227    unsigned i;
    228
    229    /* Copy the sub-list and null-terminate it.  */
    230    mrpio = g_malloc0(sizeof(MemoryRegionPortioList) +
    231                      sizeof(MemoryRegionPortio) * (count + 1));
    232    mrpio->portio_opaque = piolist->opaque;
    233    memcpy(mrpio->ports, pio_init, sizeof(MemoryRegionPortio) * count);
    234    memset(mrpio->ports + count, 0, sizeof(MemoryRegionPortio));
    235
    236    /* Adjust the offsets to all be zero-based for the region.  */
    237    for (i = 0; i < count; ++i) {
    238        mrpio->ports[i].offset -= off_low;
    239        mrpio->ports[i].base = start + off_low;
    240    }
    241
    242    memory_region_init_io(&mrpio->mr, piolist->owner, &portio_ops, mrpio,
    243                          piolist->name, off_high - off_low);
    244    if (piolist->flush_coalesced_mmio) {
    245        memory_region_set_flush_coalesced(&mrpio->mr);
    246    }
    247    memory_region_add_subregion(piolist->address_space,
    248                                start + off_low, &mrpio->mr);
    249    piolist->regions[piolist->nr] = &mrpio->mr;
    250    ++piolist->nr;
    251}
    252
    253void portio_list_add(PortioList *piolist,
    254                     MemoryRegion *address_space,
    255                     uint32_t start)
    256{
    257    const MemoryRegionPortio *pio, *pio_start = piolist->ports;
    258    unsigned int off_low, off_high, off_last, count;
    259
    260    piolist->address_space = address_space;
    261
    262    /* Handle the first entry specially.  */
    263    off_last = off_low = pio_start->offset;
    264    off_high = off_low + pio_start->len + pio_start->size - 1;
    265    count = 1;
    266
    267    for (pio = pio_start + 1; pio->size != 0; pio++, count++) {
    268        /* All entries must be sorted by offset.  */
    269        assert(pio->offset >= off_last);
    270        off_last = pio->offset;
    271
    272        /* If we see a hole, break the region.  */
    273        if (off_last > off_high) {
    274            portio_list_add_1(piolist, pio_start, count, start, off_low,
    275                              off_high);
    276            /* ... and start collecting anew.  */
    277            pio_start = pio;
    278            off_low = off_last;
    279            off_high = off_low + pio->len + pio_start->size - 1;
    280            count = 0;
    281        } else if (off_last + pio->len > off_high) {
    282            off_high = off_last + pio->len + pio_start->size - 1;
    283        }
    284    }
    285
    286    /* There will always be an open sub-list.  */
    287    portio_list_add_1(piolist, pio_start, count, start, off_low, off_high);
    288}
    289
    290void portio_list_del(PortioList *piolist)
    291{
    292    MemoryRegionPortioList *mrpio;
    293    unsigned i;
    294
    295    for (i = 0; i < piolist->nr; ++i) {
    296        mrpio = container_of(piolist->regions[i], MemoryRegionPortioList, mr);
    297        memory_region_del_subregion(piolist->address_space, &mrpio->mr);
    298    }
    299}