qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

hw/m68k: add Nubus support

This patch adds basic support for the NuBus bus. This is used by 680x0
Macintosh.

Co-developed-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Signed-off-by: Laurent Vivier <laurent@vivier.eu>
Reviewed-by: Thomas Huth <huth@tuxfamily.org>
Message-Id: <20191026164546.30020-8-laurent@vivier.eu>

+509
+2
MAINTAINERS
··· 921 921 M: Laurent Vivier <laurent@vivier.eu> 922 922 S: Maintained 923 923 F: hw/misc/mac_via.c 924 + F: hw/nubus/* 924 925 F: include/hw/misc/mac_via.h 926 + F: include/hw/nubus/* 925 927 926 928 MicroBlaze Machines 927 929 -------------------
+1
hw/Kconfig
··· 21 21 source mem/Kconfig 22 22 source misc/Kconfig 23 23 source net/Kconfig 24 + source nubus/Kconfig 24 25 source nvram/Kconfig 25 26 source pci-bridge/Kconfig 26 27 source pci-host/Kconfig
+1
hw/Makefile.objs
··· 37 37 devices-dirs-y += watchdog/ 38 38 devices-dirs-y += xen/ 39 39 devices-dirs-$(CONFIG_MEM_DEVICE) += mem/ 40 + devices-dirs-$(CONFIG_NUBUS) += nubus/ 40 41 devices-dirs-y += semihosting/ 41 42 devices-dirs-y += smbios/ 42 43 endif
+1
hw/m68k/Kconfig
··· 16 16 config Q800 17 17 bool 18 18 select MAC_VIA 19 + select NUBUS
+2
hw/nubus/Kconfig
··· 1 + config NUBUS 2 + bool
+4
hw/nubus/Makefile.objs
··· 1 + common-obj-y += nubus-device.o 2 + common-obj-y += nubus-bus.o 3 + common-obj-y += nubus-bridge.o 4 + common-obj-$(CONFIG_Q800) += mac-nubus-bridge.o
+45
hw/nubus/mac-nubus-bridge.c
··· 1 + /* 2 + * Copyright (c) 2013-2018 Laurent Vivier <laurent@vivier.eu> 3 + * 4 + * This work is licensed under the terms of the GNU GPL, version 2 or later. 5 + * See the COPYING file in the top-level directory. 6 + * 7 + */ 8 + 9 + #include "qemu/osdep.h" 10 + #include "hw/sysbus.h" 11 + #include "hw/nubus/mac-nubus-bridge.h" 12 + 13 + 14 + static void mac_nubus_bridge_init(Object *obj) 15 + { 16 + MacNubusState *s = MAC_NUBUS_BRIDGE(obj); 17 + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 18 + 19 + s->bus = NUBUS_BUS(qbus_create(TYPE_NUBUS_BUS, DEVICE(s), NULL)); 20 + 21 + sysbus_init_mmio(sbd, &s->bus->super_slot_io); 22 + sysbus_init_mmio(sbd, &s->bus->slot_io); 23 + } 24 + 25 + static void mac_nubus_bridge_class_init(ObjectClass *klass, void *data) 26 + { 27 + DeviceClass *dc = DEVICE_CLASS(klass); 28 + 29 + dc->desc = "Nubus bridge"; 30 + } 31 + 32 + static const TypeInfo mac_nubus_bridge_info = { 33 + .name = TYPE_MAC_NUBUS_BRIDGE, 34 + .parent = TYPE_NUBUS_BRIDGE, 35 + .instance_init = mac_nubus_bridge_init, 36 + .instance_size = sizeof(MacNubusState), 37 + .class_init = mac_nubus_bridge_class_init, 38 + }; 39 + 40 + static void mac_nubus_bridge_register_types(void) 41 + { 42 + type_register_static(&mac_nubus_bridge_info); 43 + } 44 + 45 + type_init(mac_nubus_bridge_register_types)
+34
hw/nubus/nubus-bridge.c
··· 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 + #include "qemu/osdep.h" 12 + #include "hw/sysbus.h" 13 + #include "hw/nubus/nubus.h" 14 + 15 + static void nubus_bridge_class_init(ObjectClass *klass, void *data) 16 + { 17 + DeviceClass *dc = DEVICE_CLASS(klass); 18 + 19 + dc->fw_name = "nubus"; 20 + } 21 + 22 + static const TypeInfo nubus_bridge_info = { 23 + .name = TYPE_NUBUS_BRIDGE, 24 + .parent = TYPE_SYS_BUS_DEVICE, 25 + .instance_size = sizeof(SysBusDevice), 26 + .class_init = nubus_bridge_class_init, 27 + }; 28 + 29 + static void nubus_register_types(void) 30 + { 31 + type_register_static(&nubus_bridge_info); 32 + } 33 + 34 + type_init(nubus_register_types)
+111
hw/nubus/nubus-bus.c
··· 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 + #include "qemu/osdep.h" 12 + #include "hw/nubus/nubus.h" 13 + #include "hw/sysbus.h" 14 + #include "qapi/error.h" 15 + 16 + 17 + static NubusBus *nubus_find(void) 18 + { 19 + /* Returns NULL unless there is exactly one nubus device */ 20 + return NUBUS_BUS(object_resolve_path_type("", TYPE_NUBUS_BUS, NULL)); 21 + } 22 + 23 + static void nubus_slot_write(void *opaque, hwaddr addr, uint64_t val, 24 + unsigned int size) 25 + { 26 + /* read only */ 27 + } 28 + 29 + 30 + static uint64_t nubus_slot_read(void *opaque, hwaddr addr, 31 + unsigned int size) 32 + { 33 + return 0; 34 + } 35 + 36 + static const MemoryRegionOps nubus_slot_ops = { 37 + .read = nubus_slot_read, 38 + .write = nubus_slot_write, 39 + .endianness = DEVICE_BIG_ENDIAN, 40 + .valid = { 41 + .min_access_size = 1, 42 + .max_access_size = 1, 43 + }, 44 + }; 45 + 46 + static void nubus_super_slot_write(void *opaque, hwaddr addr, uint64_t val, 47 + unsigned int size) 48 + { 49 + /* read only */ 50 + } 51 + 52 + static uint64_t nubus_super_slot_read(void *opaque, hwaddr addr, 53 + unsigned int size) 54 + { 55 + return 0; 56 + } 57 + 58 + static const MemoryRegionOps nubus_super_slot_ops = { 59 + .read = nubus_super_slot_read, 60 + .write = nubus_super_slot_write, 61 + .endianness = DEVICE_BIG_ENDIAN, 62 + .valid = { 63 + .min_access_size = 1, 64 + .max_access_size = 1, 65 + }, 66 + }; 67 + 68 + static void nubus_realize(BusState *bus, Error **errp) 69 + { 70 + if (!nubus_find()) { 71 + error_setg(errp, "at most one %s device is permitted", TYPE_NUBUS_BUS); 72 + return; 73 + } 74 + } 75 + 76 + static void nubus_init(Object *obj) 77 + { 78 + NubusBus *nubus = NUBUS_BUS(obj); 79 + 80 + memory_region_init_io(&nubus->super_slot_io, obj, &nubus_super_slot_ops, 81 + nubus, "nubus-super-slots", 82 + NUBUS_SUPER_SLOT_NB * NUBUS_SUPER_SLOT_SIZE); 83 + 84 + memory_region_init_io(&nubus->slot_io, obj, &nubus_slot_ops, 85 + nubus, "nubus-slots", 86 + NUBUS_SLOT_NB * NUBUS_SLOT_SIZE); 87 + 88 + nubus->current_slot = NUBUS_FIRST_SLOT; 89 + } 90 + 91 + static void nubus_class_init(ObjectClass *oc, void *data) 92 + { 93 + BusClass *bc = BUS_CLASS(oc); 94 + 95 + bc->realize = nubus_realize; 96 + } 97 + 98 + static const TypeInfo nubus_bus_info = { 99 + .name = TYPE_NUBUS_BUS, 100 + .parent = TYPE_BUS, 101 + .instance_size = sizeof(NubusBus), 102 + .instance_init = nubus_init, 103 + .class_init = nubus_class_init, 104 + }; 105 + 106 + static void nubus_register_types(void) 107 + { 108 + type_register_static(&nubus_bus_info); 109 + } 110 + 111 + type_init(nubus_register_types)
+215
hw/nubus/nubus-device.c
··· 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 + #include "qemu/osdep.h" 12 + #include "hw/nubus/nubus.h" 13 + #include "qapi/error.h" 14 + 15 + 16 + /* The Format Block Structure */ 17 + 18 + #define FBLOCK_DIRECTORY_OFFSET 0 19 + #define FBLOCK_LENGTH 4 20 + #define FBLOCK_CRC 8 21 + #define FBLOCK_REVISION_LEVEL 12 22 + #define FBLOCK_FORMAT 13 23 + #define FBLOCK_TEST_PATTERN 14 24 + #define FBLOCK_RESERVED 18 25 + #define FBLOCK_BYTE_LANES 19 26 + 27 + #define FBLOCK_SIZE 20 28 + #define FBLOCK_PATTERN_VAL 0x5a932bc7 29 + 30 + static uint64_t nubus_fblock_read(void *opaque, hwaddr addr, unsigned int size) 31 + { 32 + NubusDevice *dev = opaque; 33 + uint64_t val; 34 + 35 + #define BYTE(v, b) (((v) >> (24 - 8 * (b))) & 0xff) 36 + switch (addr) { 37 + case FBLOCK_BYTE_LANES: 38 + val = dev->byte_lanes; 39 + val |= (val ^ 0xf) << 4; 40 + break; 41 + case FBLOCK_RESERVED: 42 + val = 0x00; 43 + break; 44 + case FBLOCK_TEST_PATTERN...FBLOCK_TEST_PATTERN + 3: 45 + val = BYTE(FBLOCK_PATTERN_VAL, addr - FBLOCK_TEST_PATTERN); 46 + break; 47 + case FBLOCK_FORMAT: 48 + val = dev->rom_format; 49 + break; 50 + case FBLOCK_REVISION_LEVEL: 51 + val = dev->rom_rev; 52 + break; 53 + case FBLOCK_CRC...FBLOCK_CRC + 3: 54 + val = BYTE(dev->rom_crc, addr - FBLOCK_CRC); 55 + break; 56 + case FBLOCK_LENGTH...FBLOCK_LENGTH + 3: 57 + val = BYTE(dev->rom_length, addr - FBLOCK_LENGTH); 58 + break; 59 + case FBLOCK_DIRECTORY_OFFSET...FBLOCK_DIRECTORY_OFFSET + 3: 60 + val = BYTE(dev->directory_offset, addr - FBLOCK_DIRECTORY_OFFSET); 61 + break; 62 + default: 63 + val = 0; 64 + break; 65 + } 66 + return val; 67 + } 68 + 69 + static void nubus_fblock_write(void *opaque, hwaddr addr, uint64_t val, 70 + unsigned int size) 71 + { 72 + /* read only */ 73 + } 74 + 75 + static const MemoryRegionOps nubus_format_block_ops = { 76 + .read = nubus_fblock_read, 77 + .write = nubus_fblock_write, 78 + .endianness = DEVICE_BIG_ENDIAN, 79 + .valid = { 80 + .min_access_size = 1, 81 + .max_access_size = 1, 82 + } 83 + }; 84 + 85 + static void nubus_register_format_block(NubusDevice *dev) 86 + { 87 + char *fblock_name; 88 + 89 + fblock_name = g_strdup_printf("nubus-slot-%d-format-block", 90 + dev->slot_nb); 91 + 92 + hwaddr fblock_offset = memory_region_size(&dev->slot_mem) - FBLOCK_SIZE; 93 + memory_region_init_io(&dev->fblock_io, NULL, &nubus_format_block_ops, 94 + dev, fblock_name, FBLOCK_SIZE); 95 + memory_region_add_subregion(&dev->slot_mem, fblock_offset, 96 + &dev->fblock_io); 97 + 98 + g_free(fblock_name); 99 + } 100 + 101 + static void mac_nubus_rom_write(void *opaque, hwaddr addr, uint64_t val, 102 + unsigned int size) 103 + { 104 + /* read only */ 105 + } 106 + 107 + static uint64_t mac_nubus_rom_read(void *opaque, hwaddr addr, 108 + unsigned int size) 109 + { 110 + NubusDevice *dev = opaque; 111 + 112 + return dev->rom[addr]; 113 + } 114 + 115 + static const MemoryRegionOps mac_nubus_rom_ops = { 116 + .read = mac_nubus_rom_read, 117 + .write = mac_nubus_rom_write, 118 + .endianness = DEVICE_BIG_ENDIAN, 119 + .valid = { 120 + .min_access_size = 1, 121 + .max_access_size = 1, 122 + }, 123 + }; 124 + 125 + 126 + void nubus_register_rom(NubusDevice *dev, const uint8_t *rom, uint32_t size, 127 + int revision, int format, uint8_t byte_lanes) 128 + { 129 + hwaddr rom_offset; 130 + char *rom_name; 131 + 132 + /* FIXME : really compute CRC */ 133 + dev->rom_length = 0; 134 + dev->rom_crc = 0; 135 + 136 + dev->rom_rev = revision; 137 + dev->rom_format = format; 138 + 139 + dev->byte_lanes = byte_lanes; 140 + dev->directory_offset = -size; 141 + 142 + /* ROM */ 143 + 144 + dev->rom = rom; 145 + rom_name = g_strdup_printf("nubus-slot-%d-rom", dev->slot_nb); 146 + memory_region_init_io(&dev->rom_io, NULL, &mac_nubus_rom_ops, 147 + dev, rom_name, size); 148 + memory_region_set_readonly(&dev->rom_io, true); 149 + 150 + rom_offset = memory_region_size(&dev->slot_mem) - FBLOCK_SIZE + 151 + dev->directory_offset; 152 + memory_region_add_subregion(&dev->slot_mem, rom_offset, &dev->rom_io); 153 + 154 + g_free(rom_name); 155 + } 156 + 157 + static void nubus_device_realize(DeviceState *dev, Error **errp) 158 + { 159 + NubusBus *nubus = NUBUS_BUS(qdev_get_parent_bus(DEVICE(dev))); 160 + NubusDevice *nd = NUBUS_DEVICE(dev); 161 + char *name; 162 + hwaddr slot_offset; 163 + 164 + if (nubus->current_slot < NUBUS_FIRST_SLOT || 165 + nubus->current_slot > NUBUS_LAST_SLOT) { 166 + error_setg(errp, "Cannot register nubus card, not enough slots"); 167 + return; 168 + } 169 + 170 + nd->slot_nb = nubus->current_slot++; 171 + name = g_strdup_printf("nubus-slot-%d", nd->slot_nb); 172 + 173 + if (nd->slot_nb < NUBUS_FIRST_SLOT) { 174 + /* Super */ 175 + slot_offset = (nd->slot_nb - 6) * NUBUS_SUPER_SLOT_SIZE; 176 + 177 + memory_region_init(&nd->slot_mem, OBJECT(dev), name, 178 + NUBUS_SUPER_SLOT_SIZE); 179 + memory_region_add_subregion(&nubus->super_slot_io, slot_offset, 180 + &nd->slot_mem); 181 + } else { 182 + /* Normal */ 183 + slot_offset = nd->slot_nb * NUBUS_SLOT_SIZE; 184 + 185 + memory_region_init(&nd->slot_mem, OBJECT(dev), name, NUBUS_SLOT_SIZE); 186 + memory_region_add_subregion(&nubus->slot_io, slot_offset, 187 + &nd->slot_mem); 188 + } 189 + 190 + g_free(name); 191 + nubus_register_format_block(nd); 192 + } 193 + 194 + static void nubus_device_class_init(ObjectClass *oc, void *data) 195 + { 196 + DeviceClass *dc = DEVICE_CLASS(oc); 197 + 198 + dc->realize = nubus_device_realize; 199 + dc->bus_type = TYPE_NUBUS_BUS; 200 + } 201 + 202 + static const TypeInfo nubus_device_type_info = { 203 + .name = TYPE_NUBUS_DEVICE, 204 + .parent = TYPE_DEVICE, 205 + .abstract = true, 206 + .instance_size = sizeof(NubusDevice), 207 + .class_init = nubus_device_class_init, 208 + }; 209 + 210 + static void nubus_register_types(void) 211 + { 212 + type_register_static(&nubus_device_type_info); 213 + } 214 + 215 + type_init(nubus_register_types)
+24
include/hw/nubus/mac-nubus-bridge.h
··· 1 + /* 2 + * Copyright (c) 2013-2018 Laurent Vivier <laurent@vivier.eu> 3 + * 4 + * This work is licensed under the terms of the GNU GPL, version 2 or later. 5 + * See the COPYING file in the top-level directory. 6 + * 7 + */ 8 + 9 + #ifndef HW_NUBUS_MAC_H 10 + #define HW_NUBUS_MAC_H 11 + 12 + #include "hw/nubus/nubus.h" 13 + 14 + #define TYPE_MAC_NUBUS_BRIDGE "mac-nubus-bridge" 15 + #define MAC_NUBUS_BRIDGE(obj) OBJECT_CHECK(MacNubusState, (obj), \ 16 + TYPE_MAC_NUBUS_BRIDGE) 17 + 18 + typedef struct MacNubusState { 19 + SysBusDevice sysbus_dev; 20 + 21 + NubusBus *bus; 22 + } MacNubusState; 23 + 24 + #endif
+69
include/hw/nubus/nubus.h
··· 1 + /* 2 + * Copyright (c) 2013-2018 Laurent Vivier <laurent@vivier.eu> 3 + * 4 + * This work is licensed under the terms of the GNU GPL, version 2 or later. 5 + * See the COPYING file in the top-level directory. 6 + * 7 + */ 8 + 9 + #ifndef HW_NUBUS_NUBUS_H 10 + #define HW_NUBUS_NUBUS_H 11 + 12 + #include "hw/qdev-properties.h" 13 + #include "exec/address-spaces.h" 14 + 15 + #define NUBUS_SUPER_SLOT_SIZE 0x10000000U 16 + #define NUBUS_SUPER_SLOT_NB 0x9 17 + 18 + #define NUBUS_SLOT_SIZE 0x01000000 19 + #define NUBUS_SLOT_NB 0xF 20 + 21 + #define NUBUS_FIRST_SLOT 0x9 22 + #define NUBUS_LAST_SLOT 0xF 23 + 24 + #define TYPE_NUBUS_DEVICE "nubus-device" 25 + #define NUBUS_DEVICE(obj) \ 26 + OBJECT_CHECK(NubusDevice, (obj), TYPE_NUBUS_DEVICE) 27 + 28 + #define TYPE_NUBUS_BUS "nubus-bus" 29 + #define NUBUS_BUS(obj) OBJECT_CHECK(NubusBus, (obj), TYPE_NUBUS_BUS) 30 + 31 + #define TYPE_NUBUS_BRIDGE "nubus-bridge" 32 + #define NUBUS_BRIDGE(obj) OBJECT_CHECK(NubusBridge, (obj), TYPE_NUBUS_BRIDGE) 33 + 34 + typedef struct NubusBus { 35 + BusState qbus; 36 + 37 + MemoryRegion super_slot_io; 38 + MemoryRegion slot_io; 39 + 40 + int current_slot; 41 + } NubusBus; 42 + 43 + typedef struct NubusDevice { 44 + DeviceState qdev; 45 + 46 + int slot_nb; 47 + MemoryRegion slot_mem; 48 + 49 + /* Format Block */ 50 + 51 + MemoryRegion fblock_io; 52 + 53 + uint32_t rom_length; 54 + uint32_t rom_crc; 55 + uint8_t rom_rev; 56 + uint8_t rom_format; 57 + uint8_t byte_lanes; 58 + int32_t directory_offset; 59 + 60 + /* ROM */ 61 + 62 + MemoryRegion rom_io; 63 + const uint8_t *rom; 64 + } NubusDevice; 65 + 66 + void nubus_register_rom(NubusDevice *dev, const uint8_t *rom, uint32_t size, 67 + int revision, int format, uint8_t byte_lanes); 68 + 69 + #endif