xbox: Support MCPX ROM overlay disable

This commit is contained in:
Mike 2020-11-12 00:11:30 -06:00 committed by mborgerson
parent ada547c981
commit 5a353bf500
3 changed files with 67 additions and 44 deletions

View File

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

View File

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

View File

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