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; | ... | ... |