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:
Peter Maydell 2021-09-29 21:20:49 +01:00
commit ba0fa56bc0
11 changed files with 281 additions and 232 deletions

View File

@ -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)

View File

@ -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 */

View File

@ -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,
};

View File

@ -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,
};

View File

@ -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 = {

View File

@ -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
View 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
View File

@ -0,0 +1 @@
#include "trace/trace-hw_nubus.h"

View File

@ -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

View File

@ -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

View File

@ -2142,6 +2142,7 @@ if have_system
'hw/misc/macio',
'hw/net',
'hw/net/can',
'hw/nubus',
'hw/nvme',
'hw/nvram',
'hw/pci',