diff --git a/hw/pci.c b/hw/pci.c index 0b5e7bf34f..f8cbf1a324 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -42,6 +42,7 @@ struct PCIBus { PCIBus *next; /* The bus IRQ state is the logical OR of the connected devices. Keep a count of the number of devices with raised IRQs. */ + int nirq; int irq_count[]; }; @@ -52,16 +53,51 @@ target_phys_addr_t pci_mem_base; static int pci_irq_index; static PCIBus *first_bus; +static void pcibus_save(QEMUFile *f, void *opaque) +{ + PCIBus *bus = (PCIBus *)opaque; + int i; + + qemu_put_be32(f, bus->nirq); + for (i = 0; i < bus->nirq; i++) + qemu_put_be32(f, bus->irq_count[i]); +} + +static int pcibus_load(QEMUFile *f, void *opaque, int version_id) +{ + PCIBus *bus = (PCIBus *)opaque; + int i, nirq; + + if (version_id != 1) + return -EINVAL; + + nirq = qemu_get_be32(f); + if (bus->nirq != nirq) { + fprintf(stderr, "pcibus_load: nirq mismatch: src=%d dst=%d\n", + nirq, bus->nirq); + return -EINVAL; + } + + for (i = 0; i < nirq; i++) + bus->irq_count[i] = qemu_get_be32(f); + + return 0; +} + PCIBus *pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, qemu_irq *pic, int devfn_min, int nirq) { PCIBus *bus; + static int nbus = 0; + bus = qemu_mallocz(sizeof(PCIBus) + (nirq * sizeof(int))); bus->set_irq = set_irq; bus->map_irq = map_irq; bus->irq_opaque = pic; bus->devfn_min = devfn_min; + bus->nirq = nirq; first_bus = bus; + register_savevm("PCIBUS", nbus++, 1, pcibus_save, pcibus_load, bus); return bus; } @@ -83,18 +119,29 @@ int pci_bus_num(PCIBus *s) void pci_device_save(PCIDevice *s, QEMUFile *f) { - qemu_put_be32(f, 1); /* PCI device version */ + int i; + + qemu_put_be32(f, 2); /* PCI device version */ qemu_put_buffer(f, s->config, 256); + for (i = 0; i < 4; i++) + qemu_put_be32(f, s->irq_state[i]); } int pci_device_load(PCIDevice *s, QEMUFile *f) { uint32_t version_id; + int i; + version_id = qemu_get_be32(f); - if (version_id != 1) + if (version_id > 2) return -EINVAL; qemu_get_buffer(f, s->config, 256); pci_update_mappings(s); + + if (version_id >= 2) + for (i = 0; i < 4; i ++) + s->irq_state[i] = qemu_get_be32(f); + return 0; } diff --git a/hw/piix_pci.c b/hw/piix_pci.c index 066817be64..d5c7e1e5c5 100644 --- a/hw/piix_pci.c +++ b/hw/piix_pci.c @@ -57,6 +57,7 @@ static int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num) static uint32_t isa_page_descs[384 / 4]; static uint8_t smm_enabled; +static int pci_irq_levels[4]; static void update_pam(PCIDevice *d, uint32_t start, uint32_t end, int r) { @@ -139,22 +140,32 @@ static void i440fx_write_config(PCIDevice *d, static void i440fx_save(QEMUFile* f, void *opaque) { PCIDevice *d = opaque; + int i; + pci_device_save(d, f); qemu_put_8s(f, &smm_enabled); + + for (i = 0; i < 4; i++) + qemu_put_be32(f, pci_irq_levels[i]); } static int i440fx_load(QEMUFile* f, void *opaque, int version_id) { PCIDevice *d = opaque; - int ret; + int ret, i; - if (version_id != 1) + if (version_id > 2) return -EINVAL; ret = pci_device_load(d, f); if (ret < 0) return ret; i440fx_update_memory_mappings(d); qemu_get_8s(f, &smm_enabled); + + if (version_id >= 2) + for (i = 0; i < 4; i++) + pci_irq_levels[i] = qemu_get_be32(f); + return 0; } @@ -192,7 +203,7 @@ PCIBus *i440fx_init(PCIDevice **pi440fx_state, qemu_irq *pic) d->config[0x72] = 0x02; /* SMRAM */ - register_savevm("I440FX", 0, 1, i440fx_save, i440fx_load, d); + register_savevm("I440FX", 0, 2, i440fx_save, i440fx_load, d); *pi440fx_state = d; return b; } @@ -205,8 +216,6 @@ PCIDevice *piix4_dev; /* just used for simpler irq handling. */ #define PCI_IRQ_WORDS ((PCI_DEVICES_MAX + 31) / 32) -static int pci_irq_levels[4]; - static void piix3_set_irq(qemu_irq *pic, int irq_num, int level) { int i, pic_irq, pic_level;