1fa2ba3b8SLaurent Vivier /* 2fa2ba3b8SLaurent Vivier * QEMU Macintosh Nubus 3fa2ba3b8SLaurent Vivier * 4fa2ba3b8SLaurent Vivier * Copyright (c) 2013-2018 Laurent Vivier <laurent@vivier.eu> 5fa2ba3b8SLaurent Vivier * 6fa2ba3b8SLaurent Vivier * This work is licensed under the terms of the GNU GPL, version 2 or later. 7fa2ba3b8SLaurent Vivier * See the COPYING file in the top-level directory. 8fa2ba3b8SLaurent Vivier * 9fa2ba3b8SLaurent Vivier */ 10fa2ba3b8SLaurent Vivier 11fa2ba3b8SLaurent Vivier #include "qemu/osdep.h" 12*3616f424SMark Cave-Ayland #include "qemu/datadir.h" 13*3616f424SMark Cave-Ayland #include "hw/loader.h" 14fa2ba3b8SLaurent Vivier #include "hw/nubus/nubus.h" 15fa2ba3b8SLaurent Vivier #include "qapi/error.h" 16*3616f424SMark Cave-Ayland #include "qemu/error-report.h" 17fa2ba3b8SLaurent Vivier 18fa2ba3b8SLaurent Vivier 19fa2ba3b8SLaurent Vivier static void nubus_device_realize(DeviceState *dev, Error **errp) 20fa2ba3b8SLaurent Vivier { 218e5c952bSPhilippe Mathieu-Daudé NubusBus *nubus = NUBUS_BUS(qdev_get_parent_bus(dev)); 22fa2ba3b8SLaurent Vivier NubusDevice *nd = NUBUS_DEVICE(dev); 23*3616f424SMark Cave-Ayland char *name, *path; 24fa2ba3b8SLaurent Vivier hwaddr slot_offset; 25*3616f424SMark Cave-Ayland int64_t size; 26*3616f424SMark Cave-Ayland int ret; 27fa2ba3b8SLaurent Vivier 28fa2ba3b8SLaurent Vivier /* Super */ 2990be1deaSMark Cave-Ayland slot_offset = nd->slot * NUBUS_SUPER_SLOT_SIZE; 30fa2ba3b8SLaurent Vivier 3190be1deaSMark Cave-Ayland name = g_strdup_printf("nubus-super-slot-%x", nd->slot); 3290be1deaSMark Cave-Ayland memory_region_init(&nd->super_slot_mem, OBJECT(dev), name, 33fa2ba3b8SLaurent Vivier NUBUS_SUPER_SLOT_SIZE); 34fa2ba3b8SLaurent Vivier memory_region_add_subregion(&nubus->super_slot_io, slot_offset, 3590be1deaSMark Cave-Ayland &nd->super_slot_mem); 3690be1deaSMark Cave-Ayland g_free(name); 3790be1deaSMark Cave-Ayland 38fa2ba3b8SLaurent Vivier /* Normal */ 39e2c49c05SMark Cave-Ayland slot_offset = nd->slot * NUBUS_SLOT_SIZE; 40fa2ba3b8SLaurent Vivier 4190be1deaSMark Cave-Ayland name = g_strdup_printf("nubus-slot-%x", nd->slot); 42fa2ba3b8SLaurent Vivier memory_region_init(&nd->slot_mem, OBJECT(dev), name, NUBUS_SLOT_SIZE); 43fa2ba3b8SLaurent Vivier memory_region_add_subregion(&nubus->slot_io, slot_offset, 44fa2ba3b8SLaurent Vivier &nd->slot_mem); 45fa2ba3b8SLaurent Vivier g_free(name); 46*3616f424SMark Cave-Ayland 47*3616f424SMark Cave-Ayland /* Declaration ROM */ 48*3616f424SMark Cave-Ayland if (nd->romfile != NULL) { 49*3616f424SMark Cave-Ayland path = qemu_find_file(QEMU_FILE_TYPE_BIOS, nd->romfile); 50*3616f424SMark Cave-Ayland if (path == NULL) { 51*3616f424SMark Cave-Ayland path = g_strdup(nd->romfile); 52*3616f424SMark Cave-Ayland } 53*3616f424SMark Cave-Ayland 54*3616f424SMark Cave-Ayland size = get_image_size(path); 55*3616f424SMark Cave-Ayland if (size < 0) { 56*3616f424SMark Cave-Ayland error_setg(errp, "failed to find romfile \"%s\"", nd->romfile); 57*3616f424SMark Cave-Ayland g_free(path); 58*3616f424SMark Cave-Ayland return; 59*3616f424SMark Cave-Ayland } else if (size == 0) { 60*3616f424SMark Cave-Ayland error_setg(errp, "romfile \"%s\" is empty", nd->romfile); 61*3616f424SMark Cave-Ayland g_free(path); 62*3616f424SMark Cave-Ayland return; 63*3616f424SMark Cave-Ayland } else if (size > NUBUS_DECL_ROM_MAX_SIZE) { 64*3616f424SMark Cave-Ayland error_setg(errp, "romfile \"%s\" too large (maximum size 128K)", 65*3616f424SMark Cave-Ayland nd->romfile); 66*3616f424SMark Cave-Ayland g_free(path); 67*3616f424SMark Cave-Ayland return; 68*3616f424SMark Cave-Ayland } 69*3616f424SMark Cave-Ayland 70*3616f424SMark Cave-Ayland name = g_strdup_printf("nubus-slot-%x-declaration-rom", nd->slot); 71*3616f424SMark Cave-Ayland memory_region_init_rom(&nd->decl_rom, OBJECT(dev), name, size, 72*3616f424SMark Cave-Ayland &error_abort); 73*3616f424SMark Cave-Ayland ret = load_image_mr(path, &nd->decl_rom); 74*3616f424SMark Cave-Ayland g_free(path); 75*3616f424SMark Cave-Ayland if (ret < 0) { 76*3616f424SMark Cave-Ayland error_setg(errp, "could not load romfile \"%s\"", nd->romfile); 77*3616f424SMark Cave-Ayland return; 78*3616f424SMark Cave-Ayland } 79*3616f424SMark Cave-Ayland memory_region_add_subregion(&nd->slot_mem, NUBUS_SLOT_SIZE - size, 80*3616f424SMark Cave-Ayland &nd->decl_rom); 81*3616f424SMark Cave-Ayland } 82fa2ba3b8SLaurent Vivier } 83fa2ba3b8SLaurent Vivier 8403deab99SMark Cave-Ayland static Property nubus_device_properties[] = { 8503deab99SMark Cave-Ayland DEFINE_PROP_INT32("slot", NubusDevice, slot, -1), 86*3616f424SMark Cave-Ayland DEFINE_PROP_STRING("romfile", NubusDevice, romfile), 8703deab99SMark Cave-Ayland DEFINE_PROP_END_OF_LIST() 8803deab99SMark Cave-Ayland }; 8903deab99SMark Cave-Ayland 90fa2ba3b8SLaurent Vivier static void nubus_device_class_init(ObjectClass *oc, void *data) 91fa2ba3b8SLaurent Vivier { 92fa2ba3b8SLaurent Vivier DeviceClass *dc = DEVICE_CLASS(oc); 93fa2ba3b8SLaurent Vivier 94fa2ba3b8SLaurent Vivier dc->realize = nubus_device_realize; 95fa2ba3b8SLaurent Vivier dc->bus_type = TYPE_NUBUS_BUS; 9603deab99SMark Cave-Ayland device_class_set_props(dc, nubus_device_properties); 97fa2ba3b8SLaurent Vivier } 98fa2ba3b8SLaurent Vivier 99fa2ba3b8SLaurent Vivier static const TypeInfo nubus_device_type_info = { 100fa2ba3b8SLaurent Vivier .name = TYPE_NUBUS_DEVICE, 101fa2ba3b8SLaurent Vivier .parent = TYPE_DEVICE, 102fa2ba3b8SLaurent Vivier .abstract = true, 103fa2ba3b8SLaurent Vivier .instance_size = sizeof(NubusDevice), 104fa2ba3b8SLaurent Vivier .class_init = nubus_device_class_init, 105fa2ba3b8SLaurent Vivier }; 106fa2ba3b8SLaurent Vivier 107fa2ba3b8SLaurent Vivier static void nubus_register_types(void) 108fa2ba3b8SLaurent Vivier { 109fa2ba3b8SLaurent Vivier type_register_static(&nubus_device_type_info); 110fa2ba3b8SLaurent Vivier } 111fa2ba3b8SLaurent Vivier 112fa2ba3b8SLaurent Vivier type_init(nubus_register_types) 113