diff --git a/hw/xbox/xbox.c b/hw/xbox/xbox.c index 103604a120..d97175c9b5 100644 --- a/hw/xbox/xbox.c +++ b/hw/xbox/xbox.c @@ -62,6 +62,8 @@ /* FIXME: Clean this up and propagate errors to UI */ static void xbox_flash_init(MemoryRegion *rom_memory) { + const uint32_t rom_start = 0xFF000000; + /* Locate BIOS ROM image */ if (bios_name == NULL) { bios_name = "bios.bin"; @@ -69,7 +71,7 @@ static void xbox_flash_init(MemoryRegion *rom_memory) int failed_to_load_bios = 1; char *filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); - int bios_size = 256*1024; + uint32_t bios_size = 256*1024; if (filename != NULL) { int bios_file_size = get_image_size(filename); @@ -93,7 +95,6 @@ static void xbox_flash_init(MemoryRegion *rom_memory) } close(fd); } - } if (failed_to_load_bios) { @@ -104,6 +105,24 @@ static void xbox_flash_init(MemoryRegion *rom_memory) g_free(filename); } + /* Create BIOS region */ + MemoryRegion *bios; + bios = g_malloc(sizeof(*bios)); + assert(bios != NULL); + memory_region_init_rom(bios, NULL, "xbox.bios", bios_size, &error_fatal); + rom_add_blob_fixed("xbox.bios", bios_data, bios_size, rom_start); + + /* Mirror ROM from 0xff000000 - 0xffffffff */ + uint32_t map_loc; + for (map_loc = rom_start; + map_loc >= rom_start; + map_loc += bios_size) { + MemoryRegion *map_bios = g_malloc(sizeof(*map_bios)); + memory_region_init_alias(map_bios, NULL, "pci-bios", bios, 0, bios_size); + memory_region_add_subregion(rom_memory, map_loc, map_bios); + memory_region_set_readonly(map_bios, true); + } + /* XBOX_FIXME: What follows is a big hack to overlay the MCPX ROM on the * top 512 bytes of the ROM region. This differs from original XQEMU * sources which copied it in at lpc init; new QEMU seems to be different @@ -137,49 +156,25 @@ static void xbox_flash_init(MemoryRegion *rom_memory) /* Read in MCPX ROM over last 512 bytes of BIOS data */ int fd = open(filename, O_RDONLY | O_BINARY); assert(fd >= 0); - int rc = read(fd, &bios_data[bios_size - bootrom_size], bootrom_size); + int rc = read(fd, bios_data + bios_size - bootrom_size, bootrom_size); assert(rc == bootrom_size); close(fd); g_free(filename); + + /* This last overlay instance is special with bios and MCPX combined. + * The overlay must be page-aligned or it will take a huge performance hit. + * Retail 1.1+ kernels rely on cached writes here so it's not marked readonly. + * Once the MCPX is disabled things should resort back to the readonly alias. + */ + + MemoryRegion *mcpx = g_malloc(sizeof(MemoryRegion)); + memory_region_init_ram(mcpx, NULL, "xbox.mcpx", bios_size, &error_fatal); + rom_add_blob_fixed("xbox.mcpx", bios_data, bios_size, -bios_size); + memory_region_add_subregion_overlap(rom_memory, -bios_size, mcpx, 1); } - /* XBOX_FIXME: The "memory_region_set_readonly" calls below have been - * temporarily commented out due to MCPX 1.1-based kernels hanging - * in the first bootloader stage when doing RSA signature verification. - * - * This is caused by code incorrectly using the flash memory range to - * store the following computation; luckily real hardware's writeback - * cache policy (verified against MTRR config) appears to allow this - * to succeed, but qemu's emulation of such isn't capable of this yet - * so the value is never updated in ROM unless readonly is unspecified. - * - * sub ds:0FFFFD52Ch, eax - * mov eax, ds:0FFFFD52Ch - */ - - /* Create BIOS region */ - MemoryRegion *bios; - bios = g_malloc(sizeof(*bios)); - assert(bios != NULL); - memory_region_init_ram(bios, NULL, "xbox.bios", bios_size, &error_fatal); - //memory_region_set_readonly(bios, true); - rom_add_blob_fixed("xbox.bios", bios_data, bios_size, - (uint32_t)(-2 * bios_size)); - - /* Assuming bios_data will be needed for duration of execution - * so no free(bios) here. - */ - - /* Mirror ROM from 0xff000000 - 0xffffffff */ - uint32_t map_loc; - for (map_loc = (uint32_t)(-bios_size); - map_loc >= 0xff000000; - map_loc -= bios_size) { - MemoryRegion *map_bios = g_malloc(sizeof(*map_bios)); - memory_region_init_alias(map_bios, NULL, "pci-bios", bios, 0, bios_size); - memory_region_add_subregion(rom_memory, map_loc, map_bios); - //memory_region_set_readonly(map_bios, true); - } + // no longer needed, rom_add_blob_fixed results in a copy, not a reference + g_free(bios_data); } static void xbox_memory_init(PCMachineState *pcms, @@ -270,7 +265,7 @@ void xbox_init_common(MachineState *machine, xbox_pci_init(x86ms->gsi, get_system_memory(), get_system_io(), - pci_memory, ram_memory, + pci_memory, ram_memory, rom_memory, &pci_bus, &isa_bus, &smbus, diff --git a/hw/xbox/xbox_pci.c b/hw/xbox/xbox_pci.c index 995efd9808..ceb8e72f40 100644 --- a/hw/xbox/xbox_pci.c +++ b/hw/xbox/xbox_pci.c @@ -146,6 +146,7 @@ void xbox_pci_init(qemu_irq *pic, MemoryRegion *address_space_io, MemoryRegion *pci_memory, MemoryRegion *ram_memory, + MemoryRegion *rom_memory, PCIBus **out_host_bus, ISABus **out_isa_bus, I2CBus **out_smbus, @@ -188,6 +189,7 @@ void xbox_pci_init(qemu_irq *pic, true, "xbox-lpc"); XBOX_LPCState *lpc_state = XBOX_LPC_DEVICE(lpc); lpc_state->pic = pic; + lpc_state->rom_memory = rom_memory; pci_bus_irqs(host_bus, xbox_lpc_set_irq, xbox_lpc_map_irq, lpc_state, XBOX_NUM_INT_IRQS + XBOX_NUM_PIRQS); @@ -309,10 +311,34 @@ static void xbox_lpc_realize(PCIDevice *dev, Error **errp) d->isa_bus = isa_bus; } +static void xbox_lpc_enable_mcpx_rom(PCIDevice *dev, bool enable) { + XBOX_LPCState *s = XBOX_LPC_DEVICE(dev); + MemoryRegion *subregion; + QTAILQ_FOREACH(subregion, &s->rom_memory->subregions, subregions_link) { + if (subregion->name != NULL && strcmp(subregion->name, "xbox.mcpx") == 0) { + memory_region_set_enabled(subregion, enable); + break; + } + } +} + static void xbox_lpc_reset(DeviceState *dev) { - // PCIDevice *d = PCI_DEVICE(dev); - // XBOX_LPCState *s = XBOX_LPC_DEVICE(d); + XBOXPCI_DPRINTF("ACTIVATING BOOT ROM\n"); + xbox_lpc_enable_mcpx_rom(PCI_DEVICE(dev), true); +} + +static void xbox_lpc_config_write(PCIDevice *dev, + uint32_t addr, uint32_t val, int len) +{ + pci_default_write_config(dev, addr, val, len); + + if ((addr == 0x80) && (val & 2)) { + XBOXPCI_DPRINTF("DEACTIVATING BOOT ROM\n"); + xbox_lpc_enable_mcpx_rom(dev, false); + } + + XBOXPCI_DPRINTF("%s: %x %x %d\n", __func__, addr, val, len); } #if 0 @@ -389,7 +415,7 @@ static void xbox_lpc_class_init(ObjectClass *klass, void *data) dc->hotpluggable = false; k->realize = xbox_lpc_realize; - //k->config_write = xbox_lpc_config_write; + k->config_write = xbox_lpc_config_write; k->vendor_id = PCI_VENDOR_ID_NVIDIA; k->device_id = PCI_DEVICE_ID_NVIDIA_NFORCE_LPC; /* FIXME - correct revision for this is 0xB2 (178) for retail 1.0 Xbox, causes known USB bug */ diff --git a/hw/xbox/xbox_pci.h b/hw/xbox/xbox_pci.h index 1d20f2d5a5..c8febfde0a 100644 --- a/hw/xbox/xbox_pci.h +++ b/hw/xbox/xbox_pci.h @@ -53,6 +53,7 @@ typedef struct XBOX_LPCState { XBOX_PMRegs pm; qemu_irq *pic; + MemoryRegion *rom_memory; int bootrom_size; uint8_t bootrom_data[512]; } XBOX_LPCState; @@ -73,6 +74,7 @@ void xbox_pci_init(qemu_irq *pic, MemoryRegion *address_space_io, MemoryRegion *pci_memory, MemoryRegion *ram_memory, + MemoryRegion *rom_memory, PCIBus **out_host_bus, ISABus **out_isa_bus, I2CBus **out_smbus,