Commit 52fc1d83bc50b0b6fc6861cfecc5763edbad7e60
1 parent
b26177d7
Save/load PCI-device, PCI-bus and PIIX3 irq-related state (patches by Uri Lublin.
Note that other PCI bridges are not fixed here. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3793 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
2 changed files
with
63 additions
and
7 deletions
hw/pci.c
| ... | ... | @@ -42,6 +42,7 @@ struct PCIBus { |
| 42 | 42 | PCIBus *next; |
| 43 | 43 | /* The bus IRQ state is the logical OR of the connected devices. |
| 44 | 44 | Keep a count of the number of devices with raised IRQs. */ |
| 45 | + int nirq; | |
| 45 | 46 | int irq_count[]; |
| 46 | 47 | }; |
| 47 | 48 | |
| ... | ... | @@ -52,16 +53,51 @@ target_phys_addr_t pci_mem_base; |
| 52 | 53 | static int pci_irq_index; |
| 53 | 54 | static PCIBus *first_bus; |
| 54 | 55 | |
| 56 | +static void pcibus_save(QEMUFile *f, void *opaque) | |
| 57 | +{ | |
| 58 | + PCIBus *bus = (PCIBus *)opaque; | |
| 59 | + int i; | |
| 60 | + | |
| 61 | + qemu_put_be32(f, bus->nirq); | |
| 62 | + for (i = 0; i < bus->nirq; i++) | |
| 63 | + qemu_put_be32(f, bus->irq_count[i]); | |
| 64 | +} | |
| 65 | + | |
| 66 | +static int pcibus_load(QEMUFile *f, void *opaque, int version_id) | |
| 67 | +{ | |
| 68 | + PCIBus *bus = (PCIBus *)opaque; | |
| 69 | + int i, nirq; | |
| 70 | + | |
| 71 | + if (version_id != 1) | |
| 72 | + return -EINVAL; | |
| 73 | + | |
| 74 | + nirq = qemu_get_be32(f); | |
| 75 | + if (bus->nirq != nirq) { | |
| 76 | + fprintf(stderr, "pcibus_load: nirq mismatch: src=%d dst=%d\n", | |
| 77 | + nirq, bus->nirq); | |
| 78 | + return -EINVAL; | |
| 79 | + } | |
| 80 | + | |
| 81 | + for (i = 0; i < nirq; i++) | |
| 82 | + bus->irq_count[i] = qemu_get_be32(f); | |
| 83 | + | |
| 84 | + return 0; | |
| 85 | +} | |
| 86 | + | |
| 55 | 87 | PCIBus *pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, |
| 56 | 88 | qemu_irq *pic, int devfn_min, int nirq) |
| 57 | 89 | { |
| 58 | 90 | PCIBus *bus; |
| 91 | + static int nbus = 0; | |
| 92 | + | |
| 59 | 93 | bus = qemu_mallocz(sizeof(PCIBus) + (nirq * sizeof(int))); |
| 60 | 94 | bus->set_irq = set_irq; |
| 61 | 95 | bus->map_irq = map_irq; |
| 62 | 96 | bus->irq_opaque = pic; |
| 63 | 97 | bus->devfn_min = devfn_min; |
| 98 | + bus->nirq = nirq; | |
| 64 | 99 | first_bus = bus; |
| 100 | + register_savevm("PCIBUS", nbus++, 1, pcibus_save, pcibus_load, bus); | |
| 65 | 101 | return bus; |
| 66 | 102 | } |
| 67 | 103 | |
| ... | ... | @@ -83,18 +119,29 @@ int pci_bus_num(PCIBus *s) |
| 83 | 119 | |
| 84 | 120 | void pci_device_save(PCIDevice *s, QEMUFile *f) |
| 85 | 121 | { |
| 86 | - qemu_put_be32(f, 1); /* PCI device version */ | |
| 122 | + int i; | |
| 123 | + | |
| 124 | + qemu_put_be32(f, 2); /* PCI device version */ | |
| 87 | 125 | qemu_put_buffer(f, s->config, 256); |
| 126 | + for (i = 0; i < 4; i++) | |
| 127 | + qemu_put_be32(f, s->irq_state[i]); | |
| 88 | 128 | } |
| 89 | 129 | |
| 90 | 130 | int pci_device_load(PCIDevice *s, QEMUFile *f) |
| 91 | 131 | { |
| 92 | 132 | uint32_t version_id; |
| 133 | + int i; | |
| 134 | + | |
| 93 | 135 | version_id = qemu_get_be32(f); |
| 94 | - if (version_id != 1) | |
| 136 | + if (version_id > 2) | |
| 95 | 137 | return -EINVAL; |
| 96 | 138 | qemu_get_buffer(f, s->config, 256); |
| 97 | 139 | pci_update_mappings(s); |
| 140 | + | |
| 141 | + if (version_id >= 2) | |
| 142 | + for (i = 0; i < 4; i ++) | |
| 143 | + s->irq_state[i] = qemu_get_be32(f); | |
| 144 | + | |
| 98 | 145 | return 0; |
| 99 | 146 | } |
| 100 | 147 | ... | ... |
hw/piix_pci.c
| ... | ... | @@ -57,6 +57,7 @@ static int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num) |
| 57 | 57 | |
| 58 | 58 | static uint32_t isa_page_descs[384 / 4]; |
| 59 | 59 | static uint8_t smm_enabled; |
| 60 | +static int pci_irq_levels[4]; | |
| 60 | 61 | |
| 61 | 62 | static void update_pam(PCIDevice *d, uint32_t start, uint32_t end, int r) |
| 62 | 63 | { |
| ... | ... | @@ -139,22 +140,32 @@ static void i440fx_write_config(PCIDevice *d, |
| 139 | 140 | static void i440fx_save(QEMUFile* f, void *opaque) |
| 140 | 141 | { |
| 141 | 142 | PCIDevice *d = opaque; |
| 143 | + int i; | |
| 144 | + | |
| 142 | 145 | pci_device_save(d, f); |
| 143 | 146 | qemu_put_8s(f, &smm_enabled); |
| 147 | + | |
| 148 | + for (i = 0; i < 4; i++) | |
| 149 | + qemu_put_be32(f, pci_irq_levels[i]); | |
| 144 | 150 | } |
| 145 | 151 | |
| 146 | 152 | static int i440fx_load(QEMUFile* f, void *opaque, int version_id) |
| 147 | 153 | { |
| 148 | 154 | PCIDevice *d = opaque; |
| 149 | - int ret; | |
| 155 | + int ret, i; | |
| 150 | 156 | |
| 151 | - if (version_id != 1) | |
| 157 | + if (version_id > 2) | |
| 152 | 158 | return -EINVAL; |
| 153 | 159 | ret = pci_device_load(d, f); |
| 154 | 160 | if (ret < 0) |
| 155 | 161 | return ret; |
| 156 | 162 | i440fx_update_memory_mappings(d); |
| 157 | 163 | qemu_get_8s(f, &smm_enabled); |
| 164 | + | |
| 165 | + if (version_id >= 2) | |
| 166 | + for (i = 0; i < 4; i++) | |
| 167 | + pci_irq_levels[i] = qemu_get_be32(f); | |
| 168 | + | |
| 158 | 169 | return 0; |
| 159 | 170 | } |
| 160 | 171 | |
| ... | ... | @@ -192,7 +203,7 @@ PCIBus *i440fx_init(PCIDevice **pi440fx_state, qemu_irq *pic) |
| 192 | 203 | |
| 193 | 204 | d->config[0x72] = 0x02; /* SMRAM */ |
| 194 | 205 | |
| 195 | - register_savevm("I440FX", 0, 1, i440fx_save, i440fx_load, d); | |
| 206 | + register_savevm("I440FX", 0, 2, i440fx_save, i440fx_load, d); | |
| 196 | 207 | *pi440fx_state = d; |
| 197 | 208 | return b; |
| 198 | 209 | } |
| ... | ... | @@ -205,8 +216,6 @@ PCIDevice *piix4_dev; |
| 205 | 216 | /* just used for simpler irq handling. */ |
| 206 | 217 | #define PCI_IRQ_WORDS ((PCI_DEVICES_MAX + 31) / 32) |
| 207 | 218 | |
| 208 | -static int pci_irq_levels[4]; | |
| 209 | - | |
| 210 | 219 | static void piix3_set_irq(qemu_irq *pic, int irq_num, int level) |
| 211 | 220 | { |
| 212 | 221 | int i, pic_irq, pic_level; | ... | ... |