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