diff --git a/qemu/hw/pci_ids.h b/qemu/hw/pci_ids.h index 63379c2..ca32656 100644 --- a/qemu/hw/pci_ids.h +++ b/qemu/hw/pci_ids.h @@ -57,6 +57,10 @@ #define PCI_VENDOR_ID_AMD 0x1022 #define PCI_DEVICE_ID_AMD_LANCE 0x2000 +#define PCI_VENDOR_ID_NEC 0x1033 +#define PCI_DEVICE_ID_NEC_CBUS_BRIDGE 0x0001 +#define PCI_DEVICE_ID_NEC_PC98_GRAPHICS 0x0009 + #define PCI_VENDOR_ID_MOTOROLA 0x1057 #define PCI_DEVICE_ID_MOTOROLA_MPC106 0x0002 #define PCI_DEVICE_ID_MOTOROLA_RAVEN 0x4801 diff --git a/qemu/hw/piix_pci.c b/qemu/hw/piix_pci.c index ed036fe..8b7ff9d 100644 --- a/qemu/hw/piix_pci.c +++ b/qemu/hw/piix_pci.c @@ -44,6 +44,9 @@ struct PCII440FXState { target_phys_addr_t isa_page_descs[384 / 4]; uint8_t smm_enabled; PIIX3State *piix3; + /* NEC PC-9821 */ + uint8_t drb; + uint8_t errsts_no_error; }; static void i440fx_addr_writel(void* opaque, uint32_t addr, uint32_t val) @@ -139,6 +142,20 @@ void i440fx_init_memory_mappings(PCII440FXState *d) } } +void i440fx_update_isa_page_descs(PCII440FXState *d, + target_phys_addr_t start_addr, + ram_addr_t size) +{ + target_phys_addr_t addr; + + for (addr = start_addr; addr < start_addr + size; addr += 0x1000) { + if (addr >= 0xa0000 && addr < 0x100000) { + int i = (addr - 0xa0000) >> 12; + d->isa_page_descs[i] = cpu_get_physical_page_desc(addr); + } + } +} + static void i440fx_write_config(PCIDevice *dev, uint32_t address, uint32_t val, int len) { @@ -146,8 +163,17 @@ static void i440fx_write_config(PCIDevice *dev, /* XXX: implement SMRAM.D_LOCK */ pci_default_write_config(dev, address, val, len); - if ((address >= 0x59 && address <= 0x5f) || address == 0x72) + if ((address >= 0x59 && address <= 0x5f) || address == 0x72) { i440fx_update_memory_mappings(d); + } else if (address >= 0x60 && address <= 0x67) { + if (d->drb) { + d->dev.config[address] = d->drb; /* DRB */ + } + } else if (address == 0x91) { + if (d->errsts_no_error) { + d->dev.config[address] = 0x00; /* ERRSTS */ + } + } } static int i440fx_load_old(QEMUFile* f, void *opaque, int version_id) @@ -222,7 +248,9 @@ static int i440fx_initfn(PCIDevice *dev) return 0; } -PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix3_devfn, qemu_irq *pic) +static PCIBus *i440fx_init_common(PCII440FXState **pi440fx_state, + int *piix3_devfn, qemu_irq *pic, + const char *piix3_name, int devfn) { DeviceState *dev; PCIBus *b; @@ -240,7 +268,7 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix3_devfn, qemu_irq * *pi440fx_state = DO_UPCAST(PCII440FXState, dev, d); piix3 = DO_UPCAST(PIIX3State, dev, - pci_create_simple(b, -1, "PIIX3")); + pci_create_simple(b, devfn, piix3_name)); piix3->pic = pic; pci_bus_irqs(b, piix3_set_irq, pci_slot_get_pirq, piix3, 4); (*pi440fx_state)->piix3 = piix3; @@ -250,6 +278,11 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix3_devfn, qemu_irq * return b; } +PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix3_devfn, qemu_irq *pic) +{ + return i440fx_init_common(pi440fx_state, piix3_devfn, pic, "PIIX3", -1); +} + /* PIIX3 PCI to ISA bridge */ static void piix3_set_irq(void *opaque, int irq_num, int level) @@ -346,6 +379,87 @@ static int piix3_initfn(PCIDevice *dev) return 0; } +/* NEC PC-9821 */ + +PCIBus *pc98_i440fx_init(PCII440FXState **pi440fx_state, + int *piix3_devfn, qemu_irq *pic, ram_addr_t ram_size) +{ + PCIBus *pci_bus; + PCII440FXState *d; + int i; + + /* XXX: implement PC-98 graphics bus bridge */ + pci_bus = i440fx_init_common(pi440fx_state, piix3_devfn, pic, + "STAR_ALPHA", 0x30); + d = *pi440fx_state; + d->drb = (uint8_t)(ram_size / 0x800000); + for (i = 0; i < 8; i++) { + d->dev.config[0x60 + i] = d->drb; + } + d->errsts_no_error = 1; + + return pci_bus; +} + +static void pc98_piix3_reset(void *opaque) +{ + static const struct { + int port; + uint32_t data; + } params[] = { + /* initialized in PC-9821Rv20 ITF */ + { 0x04, 0x3a000107 }, + { 0x40, 0x00ef0010 }, + { 0x44, 0xfffbfffa }, + { 0x48, 0xfffefffe }, + { 0x4c, 0x0000ffff }, + { 0x50, 0x0f020100 }, + { 0x54, 0x078a0504 }, + { 0x58, 0x0b8a0908 }, + { 0x5c, 0x8f0e0d8c }, + { 0x60, 0x80808080 }, + { 0x64, 0x18073f50 }, + { 0x68, 0xac000000 }, + { 0x6c, 0x00000000 }, + { 0x70, 0x0000c00c }, + { 0x78, 0x000fd9b2 }, + /* end of params */ + { -1, 0xffffffff }, + }; + PIIX3State *d = opaque; + uint8_t *pci_conf = d->dev.config; + int i; + + for (i = 0; params[i].port != -1; i++) { + pci_conf[params[i].port + 0] = (params[i].data >> 0) & 0xff; + pci_conf[params[i].port + 1] = (params[i].data >> 8) & 0xff; + pci_conf[params[i].port + 2] = (params[i].data >> 16) & 0xff; + pci_conf[params[i].port + 3] = (params[i].data >> 24) & 0xff; + } + + memset(d->pci_irq_levels, 0, sizeof(d->pci_irq_levels)); +} + +static int pc98_piix3_initfn(PCIDevice *dev) +{ + PIIX3State *d = DO_UPCAST(PIIX3State, dev, dev); + uint8_t *pci_conf; + + isa_bus_new(&d->dev.qdev); + vmstate_register(0, &vmstate_piix3, d); + + pci_conf = d->dev.config; + pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_NEC); + pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_NEC_CBUS_BRIDGE); // STAR ALPHA + pci_config_set_class(pci_conf, PCI_CLASS_BRIDGE_OTHER); + pci_conf[PCI_HEADER_TYPE] = + PCI_HEADER_TYPE_NORMAL | PCI_HEADER_TYPE_MULTI_FUNCTION; // header_type = PCI_multifunction, generic + + pc98_piix3_reset(d); + qemu_register_reset(pc98_piix3_reset, d); + return 0; +} + static PCIDeviceInfo i440fx_info[] = { { .qdev.name = "i440FX", @@ -361,6 +475,12 @@ static PCIDeviceInfo i440fx_info[] = { .qdev.no_user = 1, .init = piix3_initfn, },{ + .qdev.name = "STAR_ALPHA", + .qdev.desc = "ISA bridge", + .qdev.size = sizeof(PIIX3State), + .qdev.no_user = 1, + .init = pc98_piix3_initfn, + },{ /* end of list */ } };