Q800 Pull request 20210929
NuBus cleanup and improvement -----BEGIN PGP SIGNATURE----- iQJGBAABCAAwFiEEzS913cjjpNwuT1Fz8ww4vT8vvjwFAmFUMZcSHGxhdXJlbnRA dml2aWVyLmV1AAoJEPMMOL0/L748CSgQAJ+ZeCbtf0YZWgaMqQvzwbfNmAEANQI/ xJnMwucuXHuOBbugJxdzAAqgp1lm4VQ26z4qfotjnOGQYkxtdkgfAud/yyNVtl8d 85tD2iTMGXEEZ6iInTedAbzDlro9qCuMGCYgXRz/qyesWur902kxQNAjT1hy3WDT ZU5ur6c2eS0R22Yh22onGZRwaPu2QMs0mbnkIPODoNRoJF2/WVYOj8Lw8gLuybqD 9Z+6yAoBbPSKkr1bL0vrkT13SypImiRDwfK8r4Q2tWPWfl01q/0WJfqW7FlRUB9g jgY8Hx0mRSRU3OvKMxBYd7emN28go4PMNvkjDYoF5U5ceTg/v1u/GuMAgPmHmeqe f04hZDVChawAfSS84AedrgXQ3Xs+IDedB9Hrbj+PR7qqTRAlw6QUZhQt0ILbNrkg jVWJ8XYRjitseUsTi5gn8PEuHrYNoEmME8cb845r2hkvzkhuKiezZ5IQ/NbfMOMA QWS//16MSMacFxodIXcONhJ5tWhnA08xGPfFzfpL6cM6ymIWPza7qW8/JcMR5jAu UwPkF1WE25ZmrypYqNSGSoCD2d7jf8/SjcxjRtKx7S9Sz/scDJtFW/UUXliU4u4u KFV+3TPld41/LAwkhBAYp5Lo2o1tfq5XpTx6n9GBwG2OYKPmSUNkPy4fXyW6Gbrw wuBujm8fZGFa =wQ8t -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/vivier/tags/q800-for-6.2-pull-request' into staging Q800 Pull request 20210929 NuBus cleanup and improvement # gpg: Signature made Wed 29 Sep 2021 10:27:51 BST # gpg: using RSA key CD2F75DDC8E3A4DC2E4F5173F30C38BD3F2FBE3C # gpg: issuer "laurent@vivier.eu" # gpg: Good signature from "Laurent Vivier <lvivier@redhat.com>" [full] # gpg: aka "Laurent Vivier <laurent@vivier.eu>" [full] # gpg: aka "Laurent Vivier (Red Hat) <lvivier@redhat.com>" [full] # Primary key fingerprint: CD2F 75DD C8E3 A4DC 2E4F 5173 F30C 38BD 3F2F BE3C * remotes/vivier/tags/q800-for-6.2-pull-request: q800: configure nubus available slots for Quadra 800 q800: wire up nubus IRQs nubus: add support for slot IRQs nubus-bridge: make slot_available_mask a qdev property nubus-bridge: embed the NubusBus object directly within nubus-bridge nubus: move NubusBus from mac-nubus-bridge to nubus-bridge mac-nubus-bridge: rename MacNubusState to MacNubusBridge nubus-bridge: introduce separate NubusBridge structure nubus: move nubus to its own 32-bit address space nubus-device: add romfile property for loading declaration ROMs nubus-device: remove nubus_register_rom() and nubus_register_format_block() macfb: don't register declaration ROM nubus: generate bus error when attempting to access empty slots nubus: add trace-events for empty slot accesses nubus: implement BusClass get_dev_path() nubus: move slot bitmap checks from NubusDevice realize() to BusClass check_address() nubus: use bitmap to manage available slots nubus-device: expose separate super slot memory region nubus-device: rename slot_nb variable to slot nubus: add comment indicating reference documents Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
ba0fa56bc0
@ -383,10 +383,6 @@ static void macfb_sysbus_realize(DeviceState *dev, Error **errp)
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(s), &ms->mem_vram);
|
||||
}
|
||||
|
||||
const uint8_t macfb_rom[] = {
|
||||
255, 0, 0, 0,
|
||||
};
|
||||
|
||||
static void macfb_nubus_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
NubusDevice *nd = NUBUS_DEVICE(dev);
|
||||
@ -399,8 +395,6 @@ static void macfb_nubus_realize(DeviceState *dev, Error **errp)
|
||||
macfb_common_realize(dev, ms, errp);
|
||||
memory_region_add_subregion(&nd->slot_mem, DAFB_BASE, &ms->mem_ctrl);
|
||||
memory_region_add_subregion(&nd->slot_mem, VIDEO_BASE, &ms->mem_vram);
|
||||
|
||||
nubus_register_rom(nd, macfb_rom, sizeof(macfb_rom), 1, 9, 0xf);
|
||||
}
|
||||
|
||||
static void macfb_sysbus_reset(DeviceState *d)
|
||||
|
@ -67,9 +67,6 @@
|
||||
#define ASC_BASE (IO_BASE + 0x14000)
|
||||
#define SWIM_BASE (IO_BASE + 0x1E000)
|
||||
|
||||
#define NUBUS_SUPER_SLOT_BASE 0x60000000
|
||||
#define NUBUS_SLOT_BASE 0xf0000000
|
||||
|
||||
#define SONIC_PROM_SIZE 0x1000
|
||||
|
||||
/*
|
||||
@ -81,6 +78,13 @@
|
||||
|
||||
#define MAC_CLOCK 3686418
|
||||
|
||||
/*
|
||||
* Slot 0x9 is reserved for use by the in-built framebuffer whilst only
|
||||
* slots 0xc, 0xd and 0xe physically exist on the Quadra 800
|
||||
*/
|
||||
#define Q800_NUBUS_SLOTS_AVAILABLE (BIT(0x9) | BIT(0xc) | BIT(0xd) | \
|
||||
BIT(0xe))
|
||||
|
||||
/*
|
||||
* The GLUE (General Logic Unit) is an Apple custom integrated circuit chip
|
||||
* that performs a variety of functions (RAM management, clock generation, ...).
|
||||
@ -395,11 +399,21 @@ static void q800_init(MachineState *machine)
|
||||
/* NuBus */
|
||||
|
||||
dev = qdev_new(TYPE_MAC_NUBUS_BRIDGE);
|
||||
qdev_prop_set_uint32(dev, "slot-available-mask",
|
||||
Q800_NUBUS_SLOTS_AVAILABLE);
|
||||
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, NUBUS_SUPER_SLOT_BASE);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, NUBUS_SLOT_BASE);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0,
|
||||
MAC_NUBUS_FIRST_SLOT * NUBUS_SUPER_SLOT_SIZE);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, NUBUS_SLOT_BASE +
|
||||
MAC_NUBUS_FIRST_SLOT * NUBUS_SLOT_SIZE);
|
||||
|
||||
nubus = MAC_NUBUS_BRIDGE(dev)->bus;
|
||||
for (i = 0; i < VIA2_NUBUS_IRQ_NB; i++) {
|
||||
qdev_connect_gpio_out(dev, 9 + i,
|
||||
qdev_get_gpio_in_named(via2_dev, "nubus-irq",
|
||||
VIA2_NUBUS_IRQ_9 + i));
|
||||
}
|
||||
|
||||
nubus = &NUBUS_BRIDGE(dev)->bus;
|
||||
|
||||
/* framebuffer in nubus slot #9 */
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2018 Laurent Vivier <laurent@vivier.eu>
|
||||
* QEMU Macintosh Nubus
|
||||
*
|
||||
* Copyright (c) 2013-2018 Laurent Vivier <laurent@vivier.eu>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
@ -13,13 +15,29 @@
|
||||
|
||||
static void mac_nubus_bridge_init(Object *obj)
|
||||
{
|
||||
MacNubusState *s = MAC_NUBUS_BRIDGE(obj);
|
||||
MacNubusBridge *s = MAC_NUBUS_BRIDGE(obj);
|
||||
NubusBridge *nb = NUBUS_BRIDGE(obj);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
NubusBus *bus = &nb->bus;
|
||||
|
||||
s->bus = NUBUS_BUS(qbus_create(TYPE_NUBUS_BUS, DEVICE(s), NULL));
|
||||
/* Macintosh only has slots 0x9 to 0xe available */
|
||||
bus->slot_available_mask = MAKE_64BIT_MASK(MAC_NUBUS_FIRST_SLOT,
|
||||
MAC_NUBUS_SLOT_NB);
|
||||
|
||||
sysbus_init_mmio(sbd, &s->bus->super_slot_io);
|
||||
sysbus_init_mmio(sbd, &s->bus->slot_io);
|
||||
/* Aliases for slots 0x9 to 0xe */
|
||||
memory_region_init_alias(&s->super_slot_alias, obj, "super-slot-alias",
|
||||
&bus->nubus_mr,
|
||||
MAC_NUBUS_FIRST_SLOT * NUBUS_SUPER_SLOT_SIZE,
|
||||
MAC_NUBUS_SLOT_NB * NUBUS_SUPER_SLOT_SIZE);
|
||||
|
||||
memory_region_init_alias(&s->slot_alias, obj, "slot-alias",
|
||||
&bus->nubus_mr,
|
||||
NUBUS_SLOT_BASE +
|
||||
MAC_NUBUS_FIRST_SLOT * NUBUS_SLOT_SIZE,
|
||||
MAC_NUBUS_SLOT_NB * NUBUS_SLOT_SIZE);
|
||||
|
||||
sysbus_init_mmio(sbd, &s->super_slot_alias);
|
||||
sysbus_init_mmio(sbd, &s->slot_alias);
|
||||
}
|
||||
|
||||
static void mac_nubus_bridge_class_init(ObjectClass *klass, void *data)
|
||||
@ -33,7 +51,7 @@ static const TypeInfo mac_nubus_bridge_info = {
|
||||
.name = TYPE_MAC_NUBUS_BRIDGE,
|
||||
.parent = TYPE_NUBUS_BRIDGE,
|
||||
.instance_init = mac_nubus_bridge_init,
|
||||
.instance_size = sizeof(MacNubusState),
|
||||
.instance_size = sizeof(MacNubusBridge),
|
||||
.class_init = mac_nubus_bridge_class_init,
|
||||
};
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* QEMU Macintosh Nubus
|
||||
* QEMU Nubus
|
||||
*
|
||||
* Copyright (c) 2013-2018 Laurent Vivier <laurent@vivier.eu>
|
||||
*
|
||||
@ -12,17 +12,36 @@
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/nubus/nubus.h"
|
||||
|
||||
|
||||
static void nubus_bridge_init(Object *obj)
|
||||
{
|
||||
NubusBridge *s = NUBUS_BRIDGE(obj);
|
||||
NubusBus *bus = &s->bus;
|
||||
|
||||
qbus_create_inplace(bus, sizeof(s->bus), TYPE_NUBUS_BUS, DEVICE(s), NULL);
|
||||
|
||||
qdev_init_gpio_out(DEVICE(s), bus->irqs, NUBUS_IRQS);
|
||||
}
|
||||
|
||||
static Property nubus_bridge_properties[] = {
|
||||
DEFINE_PROP_UINT16("slot-available-mask", NubusBridge,
|
||||
bus.slot_available_mask, 0xffff),
|
||||
DEFINE_PROP_END_OF_LIST()
|
||||
};
|
||||
|
||||
static void nubus_bridge_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->fw_name = "nubus";
|
||||
device_class_set_props(dc, nubus_bridge_properties);
|
||||
}
|
||||
|
||||
static const TypeInfo nubus_bridge_info = {
|
||||
.name = TYPE_NUBUS_BRIDGE,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(SysBusDevice),
|
||||
.instance_init = nubus_bridge_init,
|
||||
.instance_size = sizeof(NubusBridge),
|
||||
.class_init = nubus_bridge_class_init,
|
||||
};
|
||||
|
||||
|
@ -8,9 +8,18 @@
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* References:
|
||||
* Nubus Specification (TI)
|
||||
* http://www.bitsavers.org/pdf/ti/nubus/2242825-0001_NuBus_Spec1983.pdf
|
||||
*
|
||||
* Designing Cards and Drivers for the Macintosh Family (Apple)
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/nubus/nubus.h"
|
||||
#include "qapi/error.h"
|
||||
#include "trace.h"
|
||||
|
||||
|
||||
static NubusBus *nubus_find(void)
|
||||
@ -19,72 +28,138 @@ static NubusBus *nubus_find(void)
|
||||
return NUBUS_BUS(object_resolve_path_type("", TYPE_NUBUS_BUS, NULL));
|
||||
}
|
||||
|
||||
static void nubus_slot_write(void *opaque, hwaddr addr, uint64_t val,
|
||||
unsigned int size)
|
||||
static MemTxResult nubus_slot_write(void *opaque, hwaddr addr, uint64_t val,
|
||||
unsigned size, MemTxAttrs attrs)
|
||||
{
|
||||
/* read only */
|
||||
trace_nubus_slot_write(addr, val, size);
|
||||
return MEMTX_DECODE_ERROR;
|
||||
}
|
||||
|
||||
|
||||
static uint64_t nubus_slot_read(void *opaque, hwaddr addr,
|
||||
unsigned int size)
|
||||
static MemTxResult nubus_slot_read(void *opaque, hwaddr addr, uint64_t *data,
|
||||
unsigned size, MemTxAttrs attrs)
|
||||
{
|
||||
return 0;
|
||||
trace_nubus_slot_read(addr, size);
|
||||
return MEMTX_DECODE_ERROR;
|
||||
}
|
||||
|
||||
static const MemoryRegionOps nubus_slot_ops = {
|
||||
.read = nubus_slot_read,
|
||||
.write = nubus_slot_write,
|
||||
.read_with_attrs = nubus_slot_read,
|
||||
.write_with_attrs = nubus_slot_write,
|
||||
.endianness = DEVICE_BIG_ENDIAN,
|
||||
.valid = {
|
||||
.min_access_size = 1,
|
||||
.max_access_size = 1,
|
||||
.max_access_size = 4,
|
||||
},
|
||||
};
|
||||
|
||||
static void nubus_super_slot_write(void *opaque, hwaddr addr, uint64_t val,
|
||||
unsigned int size)
|
||||
static MemTxResult nubus_super_slot_write(void *opaque, hwaddr addr,
|
||||
uint64_t val, unsigned size,
|
||||
MemTxAttrs attrs)
|
||||
{
|
||||
/* read only */
|
||||
trace_nubus_super_slot_write(addr, val, size);
|
||||
return MEMTX_DECODE_ERROR;
|
||||
}
|
||||
|
||||
static uint64_t nubus_super_slot_read(void *opaque, hwaddr addr,
|
||||
unsigned int size)
|
||||
static MemTxResult nubus_super_slot_read(void *opaque, hwaddr addr,
|
||||
uint64_t *data, unsigned size,
|
||||
MemTxAttrs attrs)
|
||||
{
|
||||
return 0;
|
||||
trace_nubus_super_slot_read(addr, size);
|
||||
return MEMTX_DECODE_ERROR;
|
||||
}
|
||||
|
||||
static const MemoryRegionOps nubus_super_slot_ops = {
|
||||
.read = nubus_super_slot_read,
|
||||
.write = nubus_super_slot_write,
|
||||
.read_with_attrs = nubus_super_slot_read,
|
||||
.write_with_attrs = nubus_super_slot_write,
|
||||
.endianness = DEVICE_BIG_ENDIAN,
|
||||
.valid = {
|
||||
.min_access_size = 1,
|
||||
.max_access_size = 1,
|
||||
.max_access_size = 4,
|
||||
},
|
||||
};
|
||||
|
||||
static void nubus_unrealize(BusState *bus)
|
||||
{
|
||||
NubusBus *nubus = NUBUS_BUS(bus);
|
||||
|
||||
address_space_destroy(&nubus->nubus_as);
|
||||
}
|
||||
|
||||
static void nubus_realize(BusState *bus, Error **errp)
|
||||
{
|
||||
NubusBus *nubus = NUBUS_BUS(bus);
|
||||
|
||||
if (!nubus_find()) {
|
||||
error_setg(errp, "at most one %s device is permitted", TYPE_NUBUS_BUS);
|
||||
return;
|
||||
}
|
||||
|
||||
address_space_init(&nubus->nubus_as, &nubus->nubus_mr, "nubus");
|
||||
}
|
||||
|
||||
static void nubus_init(Object *obj)
|
||||
{
|
||||
NubusBus *nubus = NUBUS_BUS(obj);
|
||||
|
||||
memory_region_init(&nubus->nubus_mr, obj, "nubus", 0x100000000);
|
||||
|
||||
memory_region_init_io(&nubus->super_slot_io, obj, &nubus_super_slot_ops,
|
||||
nubus, "nubus-super-slots",
|
||||
NUBUS_SUPER_SLOT_NB * NUBUS_SUPER_SLOT_SIZE);
|
||||
(NUBUS_SUPER_SLOT_NB + 1) * NUBUS_SUPER_SLOT_SIZE);
|
||||
memory_region_add_subregion(&nubus->nubus_mr, 0x0, &nubus->super_slot_io);
|
||||
|
||||
memory_region_init_io(&nubus->slot_io, obj, &nubus_slot_ops,
|
||||
nubus, "nubus-slots",
|
||||
NUBUS_SLOT_NB * NUBUS_SLOT_SIZE);
|
||||
memory_region_add_subregion(&nubus->nubus_mr,
|
||||
(NUBUS_SUPER_SLOT_NB + 1) *
|
||||
NUBUS_SUPER_SLOT_SIZE, &nubus->slot_io);
|
||||
|
||||
nubus->current_slot = NUBUS_FIRST_SLOT;
|
||||
nubus->slot_available_mask = MAKE_64BIT_MASK(NUBUS_FIRST_SLOT,
|
||||
NUBUS_SLOT_NB);
|
||||
}
|
||||
|
||||
static char *nubus_get_dev_path(DeviceState *dev)
|
||||
{
|
||||
NubusDevice *nd = NUBUS_DEVICE(dev);
|
||||
BusState *bus = qdev_get_parent_bus(dev);
|
||||
char *p = qdev_get_dev_path(bus->parent);
|
||||
|
||||
if (p) {
|
||||
char *ret = g_strdup_printf("%s/%s/%02x", p, bus->name, nd->slot);
|
||||
g_free(p);
|
||||
return ret;
|
||||
} else {
|
||||
return g_strdup_printf("%s/%02x", bus->name, nd->slot);
|
||||
}
|
||||
}
|
||||
|
||||
static bool nubus_check_address(BusState *bus, DeviceState *dev, Error **errp)
|
||||
{
|
||||
NubusDevice *nd = NUBUS_DEVICE(dev);
|
||||
NubusBus *nubus = NUBUS_BUS(bus);
|
||||
|
||||
if (nd->slot == -1) {
|
||||
/* No slot specified, find first available free slot */
|
||||
int s = ctz32(nubus->slot_available_mask);
|
||||
if (s != 32) {
|
||||
nd->slot = s;
|
||||
} else {
|
||||
error_setg(errp, "Cannot register nubus card, no free slot "
|
||||
"available");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
/* Slot specified, make sure the slot is available */
|
||||
if (!(nubus->slot_available_mask & BIT(nd->slot))) {
|
||||
error_setg(errp, "Cannot register nubus card, slot %d is "
|
||||
"unavailable or already occupied", nd->slot);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
nubus->slot_available_mask &= ~BIT(nd->slot);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void nubus_class_init(ObjectClass *oc, void *data)
|
||||
@ -92,6 +167,9 @@ static void nubus_class_init(ObjectClass *oc, void *data)
|
||||
BusClass *bc = BUS_CLASS(oc);
|
||||
|
||||
bc->realize = nubus_realize;
|
||||
bc->unrealize = nubus_unrealize;
|
||||
bc->check_address = nubus_check_address;
|
||||
bc->get_dev_path = nubus_get_dev_path;
|
||||
}
|
||||
|
||||
static const TypeInfo nubus_bus_info = {
|
||||
|
@ -9,194 +9,99 @@
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/datadir.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/loader.h"
|
||||
#include "hw/nubus/nubus.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/error-report.h"
|
||||
|
||||
|
||||
/* The Format Block Structure */
|
||||
|
||||
#define FBLOCK_DIRECTORY_OFFSET 0
|
||||
#define FBLOCK_LENGTH 4
|
||||
#define FBLOCK_CRC 8
|
||||
#define FBLOCK_REVISION_LEVEL 12
|
||||
#define FBLOCK_FORMAT 13
|
||||
#define FBLOCK_TEST_PATTERN 14
|
||||
#define FBLOCK_RESERVED 18
|
||||
#define FBLOCK_BYTE_LANES 19
|
||||
|
||||
#define FBLOCK_SIZE 20
|
||||
#define FBLOCK_PATTERN_VAL 0x5a932bc7
|
||||
|
||||
static uint64_t nubus_fblock_read(void *opaque, hwaddr addr, unsigned int size)
|
||||
void nubus_set_irq(NubusDevice *nd, int level)
|
||||
{
|
||||
NubusDevice *dev = opaque;
|
||||
uint64_t val;
|
||||
NubusBus *nubus = NUBUS_BUS(qdev_get_parent_bus(DEVICE(nd)));
|
||||
|
||||
#define BYTE(v, b) (((v) >> (24 - 8 * (b))) & 0xff)
|
||||
switch (addr) {
|
||||
case FBLOCK_BYTE_LANES:
|
||||
val = dev->byte_lanes;
|
||||
val |= (val ^ 0xf) << 4;
|
||||
break;
|
||||
case FBLOCK_RESERVED:
|
||||
val = 0x00;
|
||||
break;
|
||||
case FBLOCK_TEST_PATTERN...FBLOCK_TEST_PATTERN + 3:
|
||||
val = BYTE(FBLOCK_PATTERN_VAL, addr - FBLOCK_TEST_PATTERN);
|
||||
break;
|
||||
case FBLOCK_FORMAT:
|
||||
val = dev->rom_format;
|
||||
break;
|
||||
case FBLOCK_REVISION_LEVEL:
|
||||
val = dev->rom_rev;
|
||||
break;
|
||||
case FBLOCK_CRC...FBLOCK_CRC + 3:
|
||||
val = BYTE(dev->rom_crc, addr - FBLOCK_CRC);
|
||||
break;
|
||||
case FBLOCK_LENGTH...FBLOCK_LENGTH + 3:
|
||||
val = BYTE(dev->rom_length, addr - FBLOCK_LENGTH);
|
||||
break;
|
||||
case FBLOCK_DIRECTORY_OFFSET...FBLOCK_DIRECTORY_OFFSET + 3:
|
||||
val = BYTE(dev->directory_offset, addr - FBLOCK_DIRECTORY_OFFSET);
|
||||
break;
|
||||
default:
|
||||
val = 0;
|
||||
break;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
static void nubus_fblock_write(void *opaque, hwaddr addr, uint64_t val,
|
||||
unsigned int size)
|
||||
{
|
||||
/* read only */
|
||||
}
|
||||
|
||||
static const MemoryRegionOps nubus_format_block_ops = {
|
||||
.read = nubus_fblock_read,
|
||||
.write = nubus_fblock_write,
|
||||
.endianness = DEVICE_BIG_ENDIAN,
|
||||
.valid = {
|
||||
.min_access_size = 1,
|
||||
.max_access_size = 1,
|
||||
}
|
||||
};
|
||||
|
||||
static void nubus_register_format_block(NubusDevice *dev)
|
||||
{
|
||||
char *fblock_name;
|
||||
|
||||
fblock_name = g_strdup_printf("nubus-slot-%d-format-block",
|
||||
dev->slot_nb);
|
||||
|
||||
hwaddr fblock_offset = memory_region_size(&dev->slot_mem) - FBLOCK_SIZE;
|
||||
memory_region_init_io(&dev->fblock_io, NULL, &nubus_format_block_ops,
|
||||
dev, fblock_name, FBLOCK_SIZE);
|
||||
memory_region_add_subregion(&dev->slot_mem, fblock_offset,
|
||||
&dev->fblock_io);
|
||||
|
||||
g_free(fblock_name);
|
||||
}
|
||||
|
||||
static void mac_nubus_rom_write(void *opaque, hwaddr addr, uint64_t val,
|
||||
unsigned int size)
|
||||
{
|
||||
/* read only */
|
||||
}
|
||||
|
||||
static uint64_t mac_nubus_rom_read(void *opaque, hwaddr addr,
|
||||
unsigned int size)
|
||||
{
|
||||
NubusDevice *dev = opaque;
|
||||
|
||||
return dev->rom[addr];
|
||||
}
|
||||
|
||||
static const MemoryRegionOps mac_nubus_rom_ops = {
|
||||
.read = mac_nubus_rom_read,
|
||||
.write = mac_nubus_rom_write,
|
||||
.endianness = DEVICE_BIG_ENDIAN,
|
||||
.valid = {
|
||||
.min_access_size = 1,
|
||||
.max_access_size = 1,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
void nubus_register_rom(NubusDevice *dev, const uint8_t *rom, uint32_t size,
|
||||
int revision, int format, uint8_t byte_lanes)
|
||||
{
|
||||
hwaddr rom_offset;
|
||||
char *rom_name;
|
||||
|
||||
/* FIXME : really compute CRC */
|
||||
dev->rom_length = 0;
|
||||
dev->rom_crc = 0;
|
||||
|
||||
dev->rom_rev = revision;
|
||||
dev->rom_format = format;
|
||||
|
||||
dev->byte_lanes = byte_lanes;
|
||||
dev->directory_offset = -size;
|
||||
|
||||
/* ROM */
|
||||
|
||||
dev->rom = rom;
|
||||
rom_name = g_strdup_printf("nubus-slot-%d-rom", dev->slot_nb);
|
||||
memory_region_init_io(&dev->rom_io, NULL, &mac_nubus_rom_ops,
|
||||
dev, rom_name, size);
|
||||
memory_region_set_readonly(&dev->rom_io, true);
|
||||
|
||||
rom_offset = memory_region_size(&dev->slot_mem) - FBLOCK_SIZE +
|
||||
dev->directory_offset;
|
||||
memory_region_add_subregion(&dev->slot_mem, rom_offset, &dev->rom_io);
|
||||
|
||||
g_free(rom_name);
|
||||
qemu_set_irq(nubus->irqs[nd->slot], level);
|
||||
}
|
||||
|
||||
static void nubus_device_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
NubusBus *nubus = NUBUS_BUS(qdev_get_parent_bus(dev));
|
||||
NubusDevice *nd = NUBUS_DEVICE(dev);
|
||||
char *name;
|
||||
char *name, *path;
|
||||
hwaddr slot_offset;
|
||||
int64_t size;
|
||||
int ret;
|
||||
|
||||
if (nubus->current_slot < NUBUS_FIRST_SLOT ||
|
||||
nubus->current_slot > NUBUS_LAST_SLOT) {
|
||||
error_setg(errp, "Cannot register nubus card, not enough slots");
|
||||
return;
|
||||
}
|
||||
|
||||
nd->slot_nb = nubus->current_slot++;
|
||||
name = g_strdup_printf("nubus-slot-%d", nd->slot_nb);
|
||||
|
||||
if (nd->slot_nb < NUBUS_FIRST_SLOT) {
|
||||
/* Super */
|
||||
slot_offset = (nd->slot_nb - 6) * NUBUS_SUPER_SLOT_SIZE;
|
||||
|
||||
memory_region_init(&nd->slot_mem, OBJECT(dev), name,
|
||||
NUBUS_SUPER_SLOT_SIZE);
|
||||
memory_region_add_subregion(&nubus->super_slot_io, slot_offset,
|
||||
&nd->slot_mem);
|
||||
} else {
|
||||
/* Normal */
|
||||
slot_offset = nd->slot_nb * NUBUS_SLOT_SIZE;
|
||||
|
||||
memory_region_init(&nd->slot_mem, OBJECT(dev), name, NUBUS_SLOT_SIZE);
|
||||
memory_region_add_subregion(&nubus->slot_io, slot_offset,
|
||||
&nd->slot_mem);
|
||||
}
|
||||
/* Super */
|
||||
slot_offset = nd->slot * NUBUS_SUPER_SLOT_SIZE;
|
||||
|
||||
name = g_strdup_printf("nubus-super-slot-%x", nd->slot);
|
||||
memory_region_init(&nd->super_slot_mem, OBJECT(dev), name,
|
||||
NUBUS_SUPER_SLOT_SIZE);
|
||||
memory_region_add_subregion(&nubus->super_slot_io, slot_offset,
|
||||
&nd->super_slot_mem);
|
||||
g_free(name);
|
||||
nubus_register_format_block(nd);
|
||||
|
||||
/* Normal */
|
||||
slot_offset = nd->slot * NUBUS_SLOT_SIZE;
|
||||
|
||||
name = g_strdup_printf("nubus-slot-%x", nd->slot);
|
||||
memory_region_init(&nd->slot_mem, OBJECT(dev), name, NUBUS_SLOT_SIZE);
|
||||
memory_region_add_subregion(&nubus->slot_io, slot_offset,
|
||||
&nd->slot_mem);
|
||||
g_free(name);
|
||||
|
||||
/* Declaration ROM */
|
||||
if (nd->romfile != NULL) {
|
||||
path = qemu_find_file(QEMU_FILE_TYPE_BIOS, nd->romfile);
|
||||
if (path == NULL) {
|
||||
path = g_strdup(nd->romfile);
|
||||
}
|
||||
|
||||
size = get_image_size(path);
|
||||
if (size < 0) {
|
||||
error_setg(errp, "failed to find romfile \"%s\"", nd->romfile);
|
||||
g_free(path);
|
||||
return;
|
||||
} else if (size == 0) {
|
||||
error_setg(errp, "romfile \"%s\" is empty", nd->romfile);
|
||||
g_free(path);
|
||||
return;
|
||||
} else if (size > NUBUS_DECL_ROM_MAX_SIZE) {
|
||||
error_setg(errp, "romfile \"%s\" too large (maximum size 128K)",
|
||||
nd->romfile);
|
||||
g_free(path);
|
||||
return;
|
||||
}
|
||||
|
||||
name = g_strdup_printf("nubus-slot-%x-declaration-rom", nd->slot);
|
||||
memory_region_init_rom(&nd->decl_rom, OBJECT(dev), name, size,
|
||||
&error_abort);
|
||||
ret = load_image_mr(path, &nd->decl_rom);
|
||||
g_free(path);
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "could not load romfile \"%s\"", nd->romfile);
|
||||
return;
|
||||
}
|
||||
memory_region_add_subregion(&nd->slot_mem, NUBUS_SLOT_SIZE - size,
|
||||
&nd->decl_rom);
|
||||
}
|
||||
}
|
||||
|
||||
static Property nubus_device_properties[] = {
|
||||
DEFINE_PROP_INT32("slot", NubusDevice, slot, -1),
|
||||
DEFINE_PROP_STRING("romfile", NubusDevice, romfile),
|
||||
DEFINE_PROP_END_OF_LIST()
|
||||
};
|
||||
|
||||
static void nubus_device_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
|
||||
dc->realize = nubus_device_realize;
|
||||
dc->bus_type = TYPE_NUBUS_BUS;
|
||||
device_class_set_props(dc, nubus_device_properties);
|
||||
}
|
||||
|
||||
static const TypeInfo nubus_device_type_info = {
|
||||
|
7
hw/nubus/trace-events
Normal file
7
hw/nubus/trace-events
Normal file
@ -0,0 +1,7 @@
|
||||
# See docs/devel/tracing.txt for syntax documentation.
|
||||
|
||||
# nubus-bus.c
|
||||
nubus_slot_read(uint64_t addr, int size) "reading unassigned addr 0x%"PRIx64 " size %d"
|
||||
nubus_slot_write(uint64_t addr, uint64_t val, int size) "writing unassigned addr 0x%"PRIx64 " value 0x%"PRIx64 " size %d"
|
||||
nubus_super_slot_read(uint64_t addr, int size) "reading unassigned addr 0x%"PRIx64 " size %d"
|
||||
nubus_super_slot_write(uint64_t addr, uint64_t val, int size) "writing unassigned addr 0x%"PRIx64 " value 0x%"PRIx64 " size %d"
|
1
hw/nubus/trace.h
Normal file
1
hw/nubus/trace.h
Normal file
@ -0,0 +1 @@
|
||||
#include "trace/trace-hw_nubus.h"
|
@ -12,13 +12,18 @@
|
||||
#include "hw/nubus/nubus.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
#define MAC_NUBUS_FIRST_SLOT 0x9
|
||||
#define MAC_NUBUS_LAST_SLOT 0xe
|
||||
#define MAC_NUBUS_SLOT_NB (MAC_NUBUS_LAST_SLOT - MAC_NUBUS_FIRST_SLOT + 1)
|
||||
|
||||
#define TYPE_MAC_NUBUS_BRIDGE "mac-nubus-bridge"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(MacNubusState, MAC_NUBUS_BRIDGE)
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(MacNubusBridge, MAC_NUBUS_BRIDGE)
|
||||
|
||||
struct MacNubusState {
|
||||
SysBusDevice sysbus_dev;
|
||||
struct MacNubusBridge {
|
||||
NubusBridge parent_obj;
|
||||
|
||||
NubusBus *bus;
|
||||
MemoryRegion super_slot_alias;
|
||||
MemoryRegion slot_alias;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -10,17 +10,23 @@
|
||||
#define HW_NUBUS_NUBUS_H
|
||||
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "qom/object.h"
|
||||
#include "qemu/units.h"
|
||||
|
||||
#define NUBUS_SUPER_SLOT_SIZE 0x10000000U
|
||||
#define NUBUS_SUPER_SLOT_NB 0x9
|
||||
#define NUBUS_SUPER_SLOT_NB 0xe
|
||||
|
||||
#define NUBUS_SLOT_BASE (NUBUS_SUPER_SLOT_SIZE * \
|
||||
(NUBUS_SUPER_SLOT_NB + 1))
|
||||
|
||||
#define NUBUS_SLOT_SIZE 0x01000000
|
||||
#define NUBUS_SLOT_NB 0xF
|
||||
#define NUBUS_FIRST_SLOT 0x0
|
||||
#define NUBUS_LAST_SLOT 0xf
|
||||
#define NUBUS_SLOT_NB (NUBUS_LAST_SLOT - NUBUS_FIRST_SLOT + 1)
|
||||
|
||||
#define NUBUS_FIRST_SLOT 0x9
|
||||
#define NUBUS_LAST_SLOT 0xF
|
||||
#define NUBUS_IRQS 16
|
||||
|
||||
#define TYPE_NUBUS_DEVICE "nubus-device"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(NubusDevice, NUBUS_DEVICE)
|
||||
@ -29,40 +35,41 @@ OBJECT_DECLARE_SIMPLE_TYPE(NubusDevice, NUBUS_DEVICE)
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(NubusBus, NUBUS_BUS)
|
||||
|
||||
#define TYPE_NUBUS_BRIDGE "nubus-bridge"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(NubusBridge, NUBUS_BRIDGE);
|
||||
|
||||
struct NubusBus {
|
||||
BusState qbus;
|
||||
|
||||
AddressSpace nubus_as;
|
||||
MemoryRegion nubus_mr;
|
||||
|
||||
MemoryRegion super_slot_io;
|
||||
MemoryRegion slot_io;
|
||||
|
||||
int current_slot;
|
||||
uint16_t slot_available_mask;
|
||||
|
||||
qemu_irq irqs[NUBUS_IRQS];
|
||||
};
|
||||
|
||||
#define NUBUS_DECL_ROM_MAX_SIZE (128 * KiB)
|
||||
|
||||
struct NubusDevice {
|
||||
DeviceState qdev;
|
||||
|
||||
int slot_nb;
|
||||
int32_t slot;
|
||||
MemoryRegion super_slot_mem;
|
||||
MemoryRegion slot_mem;
|
||||
|
||||
/* Format Block */
|
||||
|
||||
MemoryRegion fblock_io;
|
||||
|
||||
uint32_t rom_length;
|
||||
uint32_t rom_crc;
|
||||
uint8_t rom_rev;
|
||||
uint8_t rom_format;
|
||||
uint8_t byte_lanes;
|
||||
int32_t directory_offset;
|
||||
|
||||
/* ROM */
|
||||
|
||||
MemoryRegion rom_io;
|
||||
const uint8_t *rom;
|
||||
char *romfile;
|
||||
MemoryRegion decl_rom;
|
||||
};
|
||||
|
||||
void nubus_register_rom(NubusDevice *dev, const uint8_t *rom, uint32_t size,
|
||||
int revision, int format, uint8_t byte_lanes);
|
||||
void nubus_set_irq(NubusDevice *nd, int level);
|
||||
|
||||
struct NubusBridge {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
NubusBus bus;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -2142,6 +2142,7 @@ if have_system
|
||||
'hw/misc/macio',
|
||||
'hw/net',
|
||||
'hw/net/can',
|
||||
'hw/nubus',
|
||||
'hw/nvme',
|
||||
'hw/nvram',
|
||||
'hw/pci',
|
||||
|
Loading…
Reference in New Issue
Block a user