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

nubus-bus.c (5495B)


      1/*
      2 * QEMU Macintosh Nubus
      3 *
      4 * Copyright (c) 2013-2018 Laurent Vivier <laurent@vivier.eu>
      5 *
      6 * This work is licensed under the terms of the GNU GPL, version 2 or later.
      7 * See the COPYING file in the top-level directory.
      8 *
      9 */
     10
     11/*
     12 * References:
     13 *   Nubus Specification (TI)
     14 *     http://www.bitsavers.org/pdf/ti/nubus/2242825-0001_NuBus_Spec1983.pdf
     15 *
     16 *   Designing Cards and Drivers for the Macintosh Family (Apple)
     17 */
     18
     19#include "qemu/osdep.h"
     20#include "hw/nubus/nubus.h"
     21#include "qapi/error.h"
     22#include "trace.h"
     23
     24
     25static NubusBus *nubus_find(void)
     26{
     27    /* Returns NULL unless there is exactly one nubus device */
     28    return NUBUS_BUS(object_resolve_path_type("", TYPE_NUBUS_BUS, NULL));
     29}
     30
     31static MemTxResult nubus_slot_write(void *opaque, hwaddr addr, uint64_t val,
     32                                    unsigned size, MemTxAttrs attrs)
     33{
     34    trace_nubus_slot_write(addr, val, size);
     35    return MEMTX_DECODE_ERROR;
     36}
     37
     38static MemTxResult nubus_slot_read(void *opaque, hwaddr addr, uint64_t *data,
     39                                   unsigned size, MemTxAttrs attrs)
     40{
     41    trace_nubus_slot_read(addr, size);
     42    return MEMTX_DECODE_ERROR;
     43}
     44
     45static const MemoryRegionOps nubus_slot_ops = {
     46    .read_with_attrs  = nubus_slot_read,
     47    .write_with_attrs = nubus_slot_write,
     48    .endianness = DEVICE_BIG_ENDIAN,
     49    .valid = {
     50        .min_access_size = 1,
     51        .max_access_size = 4,
     52    },
     53};
     54
     55static MemTxResult nubus_super_slot_write(void *opaque, hwaddr addr,
     56                                          uint64_t val, unsigned size,
     57                                          MemTxAttrs attrs)
     58{
     59    trace_nubus_super_slot_write(addr, val, size);
     60    return MEMTX_DECODE_ERROR;
     61}
     62
     63static MemTxResult nubus_super_slot_read(void *opaque, hwaddr addr,
     64                                         uint64_t *data, unsigned size,
     65                                         MemTxAttrs attrs)
     66{
     67    trace_nubus_super_slot_read(addr, size);
     68    return MEMTX_DECODE_ERROR;
     69}
     70
     71static const MemoryRegionOps nubus_super_slot_ops = {
     72    .read_with_attrs = nubus_super_slot_read,
     73    .write_with_attrs = nubus_super_slot_write,
     74    .endianness = DEVICE_BIG_ENDIAN,
     75    .valid = {
     76        .min_access_size = 1,
     77        .max_access_size = 4,
     78    },
     79};
     80
     81static void nubus_unrealize(BusState *bus)
     82{
     83    NubusBus *nubus = NUBUS_BUS(bus);
     84
     85    address_space_destroy(&nubus->nubus_as);
     86}
     87
     88static void nubus_realize(BusState *bus, Error **errp)
     89{
     90    NubusBus *nubus = NUBUS_BUS(bus);
     91
     92    if (!nubus_find()) {
     93        error_setg(errp, "at most one %s device is permitted", TYPE_NUBUS_BUS);
     94        return;
     95    }
     96
     97    address_space_init(&nubus->nubus_as, &nubus->nubus_mr, "nubus");
     98}
     99
    100static void nubus_init(Object *obj)
    101{
    102    NubusBus *nubus = NUBUS_BUS(obj);
    103
    104    memory_region_init(&nubus->nubus_mr, obj, "nubus", 0x100000000);
    105
    106    memory_region_init_io(&nubus->super_slot_io, obj, &nubus_super_slot_ops,
    107                          nubus, "nubus-super-slots",
    108                          (NUBUS_SUPER_SLOT_NB + 1) * NUBUS_SUPER_SLOT_SIZE);
    109    memory_region_add_subregion(&nubus->nubus_mr, 0x0, &nubus->super_slot_io);
    110
    111    memory_region_init_io(&nubus->slot_io, obj, &nubus_slot_ops,
    112                          nubus, "nubus-slots",
    113                          NUBUS_SLOT_NB * NUBUS_SLOT_SIZE);
    114    memory_region_add_subregion(&nubus->nubus_mr,
    115                                (NUBUS_SUPER_SLOT_NB + 1) *
    116                                NUBUS_SUPER_SLOT_SIZE, &nubus->slot_io);
    117
    118    nubus->slot_available_mask = MAKE_64BIT_MASK(NUBUS_FIRST_SLOT,
    119                                                 NUBUS_SLOT_NB);
    120}
    121
    122static char *nubus_get_dev_path(DeviceState *dev)
    123{
    124    NubusDevice *nd = NUBUS_DEVICE(dev);
    125    BusState *bus = qdev_get_parent_bus(dev);
    126    char *p = qdev_get_dev_path(bus->parent);
    127
    128    if (p) {
    129        char *ret = g_strdup_printf("%s/%s/%02x", p, bus->name, nd->slot);
    130        g_free(p);
    131        return ret;
    132    } else {
    133        return g_strdup_printf("%s/%02x", bus->name, nd->slot);
    134    }
    135}
    136
    137static bool nubus_check_address(BusState *bus, DeviceState *dev, Error **errp)
    138{
    139    NubusDevice *nd = NUBUS_DEVICE(dev);
    140    NubusBus *nubus = NUBUS_BUS(bus);
    141
    142    if (nd->slot == -1) {
    143        /* No slot specified, find first available free slot */
    144        int s = ctz32(nubus->slot_available_mask);
    145        if (s != 32) {
    146            nd->slot = s;
    147        } else {
    148            error_setg(errp, "Cannot register nubus card, no free slot "
    149                             "available");
    150            return false;
    151        }
    152    } else {
    153        /* Slot specified, make sure the slot is available */
    154        if (!(nubus->slot_available_mask & BIT(nd->slot))) {
    155            error_setg(errp, "Cannot register nubus card, slot %d is "
    156                             "unavailable or already occupied", nd->slot);
    157            return false;
    158        }
    159    }
    160
    161    nubus->slot_available_mask &= ~BIT(nd->slot);
    162    return true;
    163}
    164
    165static void nubus_class_init(ObjectClass *oc, void *data)
    166{
    167    BusClass *bc = BUS_CLASS(oc);
    168
    169    bc->realize = nubus_realize;
    170    bc->unrealize = nubus_unrealize;
    171    bc->check_address = nubus_check_address;
    172    bc->get_dev_path = nubus_get_dev_path;
    173}
    174
    175static const TypeInfo nubus_bus_info = {
    176    .name = TYPE_NUBUS_BUS,
    177    .parent = TYPE_BUS,
    178    .instance_size = sizeof(NubusBus),
    179    .instance_init = nubus_init,
    180    .class_init = nubus_class_init,
    181};
    182
    183static void nubus_register_types(void)
    184{
    185    type_register_static(&nubus_bus_info);
    186}
    187
    188type_init(nubus_register_types)