]>
Commit | Line | Data |
---|---|---|
502a5395 PB |
1 | /* |
2 | * QEMU i440FX/PIIX3 PCI Bridge Emulation | |
3 | * | |
4 | * Copyright (c) 2006 Fabrice Bellard | |
5 | * | |
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
7 | * of this software and associated documentation files (the "Software"), to deal | |
8 | * in the Software without restriction, including without limitation the rights | |
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
10 | * copies of the Software, and to permit persons to whom the Software is | |
11 | * furnished to do so, subject to the following conditions: | |
12 | * | |
13 | * The above copyright notice and this permission notice shall be included in | |
14 | * all copies or substantial portions of the Software. | |
15 | * | |
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
22 | * THE SOFTWARE. | |
23 | */ | |
24 | ||
25 | #include "vl.h" | |
26 | typedef uint32_t pci_addr_t; | |
27 | #include "pci_host.h" | |
28 | ||
29 | typedef PCIHostState I440FXState; | |
30 | ||
31 | static void i440fx_addr_writel(void* opaque, uint32_t addr, uint32_t val) | |
32 | { | |
33 | I440FXState *s = opaque; | |
34 | s->config_reg = val; | |
35 | } | |
36 | ||
37 | static uint32_t i440fx_addr_readl(void* opaque, uint32_t addr) | |
38 | { | |
39 | I440FXState *s = opaque; | |
40 | return s->config_reg; | |
41 | } | |
42 | ||
43 | static void piix3_set_irq(PCIDevice *pci_dev, void *pic, int irq_num, int level); | |
44 | ||
45 | PCIBus *i440fx_init(void) | |
46 | { | |
47 | PCIBus *b; | |
48 | PCIDevice *d; | |
49 | I440FXState *s; | |
50 | ||
51 | s = qemu_mallocz(sizeof(I440FXState)); | |
52 | b = pci_register_bus(piix3_set_irq, NULL, 0); | |
53 | s->bus = b; | |
54 | ||
55 | register_ioport_write(0xcf8, 4, 4, i440fx_addr_writel, s); | |
56 | register_ioport_read(0xcf8, 4, 4, i440fx_addr_readl, s); | |
57 | ||
58 | register_ioport_write(0xcfc, 4, 1, pci_host_data_writeb, s); | |
59 | register_ioport_write(0xcfc, 4, 2, pci_host_data_writew, s); | |
60 | register_ioport_write(0xcfc, 4, 4, pci_host_data_writel, s); | |
61 | register_ioport_read(0xcfc, 4, 1, pci_host_data_readb, s); | |
62 | register_ioport_read(0xcfc, 4, 2, pci_host_data_readw, s); | |
63 | register_ioport_read(0xcfc, 4, 4, pci_host_data_readl, s); | |
64 | ||
65 | d = pci_register_device(b, "i440FX", sizeof(PCIDevice), 0, | |
66 | NULL, NULL); | |
67 | ||
68 | d->config[0x00] = 0x86; // vendor_id | |
69 | d->config[0x01] = 0x80; | |
70 | d->config[0x02] = 0x37; // device_id | |
71 | d->config[0x03] = 0x12; | |
72 | d->config[0x08] = 0x02; // revision | |
73 | d->config[0x0a] = 0x00; // class_sub = host2pci | |
74 | d->config[0x0b] = 0x06; // class_base = PCI_bridge | |
75 | d->config[0x0e] = 0x00; // header_type | |
76 | return b; | |
77 | } | |
78 | ||
79 | /* PIIX3 PCI to ISA bridge */ | |
80 | ||
81 | static PCIDevice *piix3_dev; | |
82 | ||
83 | /* just used for simpler irq handling. */ | |
84 | #define PCI_IRQ_WORDS ((PCI_DEVICES_MAX + 31) / 32) | |
85 | ||
86 | static uint32_t pci_irq_levels[4][PCI_IRQ_WORDS]; | |
87 | ||
88 | /* return the global irq number corresponding to a given device irq | |
89 | pin. We could also use the bus number to have a more precise | |
90 | mapping. */ | |
91 | static inline int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num) | |
92 | { | |
93 | int slot_addend; | |
94 | slot_addend = (pci_dev->devfn >> 3) - 1; | |
95 | return (irq_num + slot_addend) & 3; | |
96 | } | |
97 | ||
98 | static inline int get_pci_irq_level(int irq_num) | |
99 | { | |
100 | int pic_level; | |
101 | #if (PCI_IRQ_WORDS == 2) | |
102 | pic_level = ((pci_irq_levels[irq_num][0] | | |
103 | pci_irq_levels[irq_num][1]) != 0); | |
104 | #else | |
105 | { | |
106 | int i; | |
107 | pic_level = 0; | |
108 | for(i = 0; i < PCI_IRQ_WORDS; i++) { | |
109 | if (pci_irq_levels[irq_num][i]) { | |
110 | pic_level = 1; | |
111 | break; | |
112 | } | |
113 | } | |
114 | } | |
115 | #endif | |
116 | return pic_level; | |
117 | } | |
118 | ||
119 | static void piix3_set_irq(PCIDevice *pci_dev, void *pic, int irq_num, int level) | |
120 | { | |
121 | int irq_index, shift, pic_irq, pic_level; | |
122 | uint32_t *p; | |
123 | ||
124 | irq_num = pci_slot_get_pirq(pci_dev, irq_num); | |
125 | irq_index = pci_dev->irq_index; | |
126 | p = &pci_irq_levels[irq_num][irq_index >> 5]; | |
127 | shift = (irq_index & 0x1f); | |
128 | *p = (*p & ~(1 << shift)) | (level << shift); | |
129 | ||
130 | /* now we change the pic irq level according to the piix irq mappings */ | |
131 | /* XXX: optimize */ | |
132 | pic_irq = piix3_dev->config[0x60 + irq_num]; | |
133 | if (pic_irq < 16) { | |
134 | /* the pic level is the logical OR of all the PCI irqs mapped | |
135 | to it */ | |
136 | pic_level = 0; | |
137 | if (pic_irq == piix3_dev->config[0x60]) | |
138 | pic_level |= get_pci_irq_level(0); | |
139 | if (pic_irq == piix3_dev->config[0x61]) | |
140 | pic_level |= get_pci_irq_level(1); | |
141 | if (pic_irq == piix3_dev->config[0x62]) | |
142 | pic_level |= get_pci_irq_level(2); | |
143 | if (pic_irq == piix3_dev->config[0x63]) | |
144 | pic_level |= get_pci_irq_level(3); | |
145 | pic_set_irq(pic_irq, pic_level); | |
146 | } | |
147 | } | |
148 | ||
149 | static void piix3_reset(PCIDevice *d) | |
150 | { | |
151 | uint8_t *pci_conf = d->config; | |
152 | ||
153 | pci_conf[0x04] = 0x07; // master, memory and I/O | |
154 | pci_conf[0x05] = 0x00; | |
155 | pci_conf[0x06] = 0x00; | |
156 | pci_conf[0x07] = 0x02; // PCI_status_devsel_medium | |
157 | pci_conf[0x4c] = 0x4d; | |
158 | pci_conf[0x4e] = 0x03; | |
159 | pci_conf[0x4f] = 0x00; | |
160 | pci_conf[0x60] = 0x80; | |
161 | pci_conf[0x69] = 0x02; | |
162 | pci_conf[0x70] = 0x80; | |
163 | pci_conf[0x76] = 0x0c; | |
164 | pci_conf[0x77] = 0x0c; | |
165 | pci_conf[0x78] = 0x02; | |
166 | pci_conf[0x79] = 0x00; | |
167 | pci_conf[0x80] = 0x00; | |
168 | pci_conf[0x82] = 0x00; | |
169 | pci_conf[0xa0] = 0x08; | |
170 | pci_conf[0xa0] = 0x08; | |
171 | pci_conf[0xa2] = 0x00; | |
172 | pci_conf[0xa3] = 0x00; | |
173 | pci_conf[0xa4] = 0x00; | |
174 | pci_conf[0xa5] = 0x00; | |
175 | pci_conf[0xa6] = 0x00; | |
176 | pci_conf[0xa7] = 0x00; | |
177 | pci_conf[0xa8] = 0x0f; | |
178 | pci_conf[0xaa] = 0x00; | |
179 | pci_conf[0xab] = 0x00; | |
180 | pci_conf[0xac] = 0x00; | |
181 | pci_conf[0xae] = 0x00; | |
182 | } | |
183 | ||
1941d19c FB |
184 | static void piix_save(QEMUFile* f, void *opaque) |
185 | { | |
186 | PCIDevice *d = opaque; | |
187 | pci_device_save(d, f); | |
188 | } | |
189 | ||
190 | static int piix_load(QEMUFile* f, void *opaque, int version_id) | |
191 | { | |
192 | PCIDevice *d = opaque; | |
193 | if (version_id != 2) | |
194 | return -EINVAL; | |
195 | return pci_device_load(d, f); | |
196 | } | |
197 | ||
502a5395 PB |
198 | int piix3_init(PCIBus *bus) |
199 | { | |
200 | PCIDevice *d; | |
201 | uint8_t *pci_conf; | |
202 | ||
203 | d = pci_register_device(bus, "PIIX3", sizeof(PCIDevice), | |
204 | -1, NULL, NULL); | |
1941d19c | 205 | register_savevm("PIIX3", 0, 2, piix_save, piix_load, d); |
502a5395 PB |
206 | |
207 | piix3_dev = d; | |
208 | pci_conf = d->config; | |
209 | ||
210 | pci_conf[0x00] = 0x86; // Intel | |
211 | pci_conf[0x01] = 0x80; | |
212 | pci_conf[0x02] = 0x00; // 82371SB PIIX3 PCI-to-ISA bridge (Step A1) | |
213 | pci_conf[0x03] = 0x70; | |
214 | pci_conf[0x0a] = 0x01; // class_sub = PCI_ISA | |
215 | pci_conf[0x0b] = 0x06; // class_base = PCI_bridge | |
216 | pci_conf[0x0e] = 0x80; // header_type = PCI_multifunction, generic | |
217 | ||
218 | piix3_reset(d); | |
219 | return d->devfn; | |
220 | } | |
221 | ||
222 | /***********************************************************/ | |
223 | /* XXX: the following should be moved to the PC BIOS */ | |
224 | ||
225 | static __attribute__((unused)) uint32_t isa_inb(uint32_t addr) | |
226 | { | |
227 | return cpu_inb(NULL, addr); | |
228 | } | |
229 | ||
230 | static void isa_outb(uint32_t val, uint32_t addr) | |
231 | { | |
232 | cpu_outb(NULL, addr, val); | |
233 | } | |
234 | ||
235 | static __attribute__((unused)) uint32_t isa_inw(uint32_t addr) | |
236 | { | |
237 | return cpu_inw(NULL, addr); | |
238 | } | |
239 | ||
240 | static __attribute__((unused)) void isa_outw(uint32_t val, uint32_t addr) | |
241 | { | |
242 | cpu_outw(NULL, addr, val); | |
243 | } | |
244 | ||
245 | static __attribute__((unused)) uint32_t isa_inl(uint32_t addr) | |
246 | { | |
247 | return cpu_inl(NULL, addr); | |
248 | } | |
249 | ||
250 | static __attribute__((unused)) void isa_outl(uint32_t val, uint32_t addr) | |
251 | { | |
252 | cpu_outl(NULL, addr, val); | |
253 | } | |
254 | ||
255 | static uint32_t pci_bios_io_addr; | |
256 | static uint32_t pci_bios_mem_addr; | |
257 | /* host irqs corresponding to PCI irqs A-D */ | |
258 | static uint8_t pci_irqs[4] = { 11, 9, 11, 9 }; | |
259 | ||
260 | static void pci_config_writel(PCIDevice *d, uint32_t addr, uint32_t val) | |
261 | { | |
262 | PCIBus *s = d->bus; | |
263 | addr |= (pci_bus_num(s) << 16) | (d->devfn << 8); | |
264 | pci_data_write(s, addr, val, 4); | |
265 | } | |
266 | ||
267 | static void pci_config_writew(PCIDevice *d, uint32_t addr, uint32_t val) | |
268 | { | |
269 | PCIBus *s = d->bus; | |
270 | addr |= (pci_bus_num(s) << 16) | (d->devfn << 8); | |
271 | pci_data_write(s, addr, val, 2); | |
272 | } | |
273 | ||
274 | static void pci_config_writeb(PCIDevice *d, uint32_t addr, uint32_t val) | |
275 | { | |
276 | PCIBus *s = d->bus; | |
277 | addr |= (pci_bus_num(s) << 16) | (d->devfn << 8); | |
278 | pci_data_write(s, addr, val, 1); | |
279 | } | |
280 | ||
281 | static __attribute__((unused)) uint32_t pci_config_readl(PCIDevice *d, uint32_t addr) | |
282 | { | |
283 | PCIBus *s = d->bus; | |
284 | addr |= (pci_bus_num(s) << 16) | (d->devfn << 8); | |
285 | return pci_data_read(s, addr, 4); | |
286 | } | |
287 | ||
288 | static uint32_t pci_config_readw(PCIDevice *d, uint32_t addr) | |
289 | { | |
290 | PCIBus *s = d->bus; | |
291 | addr |= (pci_bus_num(s) << 16) | (d->devfn << 8); | |
292 | return pci_data_read(s, addr, 2); | |
293 | } | |
294 | ||
295 | static uint32_t pci_config_readb(PCIDevice *d, uint32_t addr) | |
296 | { | |
297 | PCIBus *s = d->bus; | |
298 | addr |= (pci_bus_num(s) << 16) | (d->devfn << 8); | |
299 | return pci_data_read(s, addr, 1); | |
300 | } | |
301 | ||
302 | static void pci_set_io_region_addr(PCIDevice *d, int region_num, uint32_t addr) | |
303 | { | |
304 | PCIIORegion *r; | |
305 | uint16_t cmd; | |
306 | uint32_t ofs; | |
307 | ||
308 | if ( region_num == PCI_ROM_SLOT ) { | |
309 | ofs = 0x30; | |
310 | }else{ | |
311 | ofs = 0x10 + region_num * 4; | |
312 | } | |
313 | ||
314 | pci_config_writel(d, ofs, addr); | |
315 | r = &d->io_regions[region_num]; | |
316 | ||
317 | /* enable memory mappings */ | |
318 | cmd = pci_config_readw(d, PCI_COMMAND); | |
319 | if ( region_num == PCI_ROM_SLOT ) | |
320 | cmd |= 2; | |
321 | else if (r->type & PCI_ADDRESS_SPACE_IO) | |
322 | cmd |= 1; | |
323 | else | |
324 | cmd |= 2; | |
325 | pci_config_writew(d, PCI_COMMAND, cmd); | |
326 | } | |
327 | ||
328 | static void pci_bios_init_device(PCIDevice *d) | |
329 | { | |
330 | int class; | |
331 | PCIIORegion *r; | |
332 | uint32_t *paddr; | |
333 | int i, pin, pic_irq, vendor_id, device_id; | |
334 | ||
335 | class = pci_config_readw(d, PCI_CLASS_DEVICE); | |
336 | vendor_id = pci_config_readw(d, PCI_VENDOR_ID); | |
337 | device_id = pci_config_readw(d, PCI_DEVICE_ID); | |
338 | switch(class) { | |
339 | case 0x0101: | |
340 | if (vendor_id == 0x8086 && device_id == 0x7010) { | |
341 | /* PIIX3 IDE */ | |
342 | pci_config_writew(d, 0x40, 0x8000); // enable IDE0 | |
343 | pci_config_writew(d, 0x42, 0x8000); // enable IDE1 | |
344 | goto default_map; | |
345 | } else { | |
346 | /* IDE: we map it as in ISA mode */ | |
347 | pci_set_io_region_addr(d, 0, 0x1f0); | |
348 | pci_set_io_region_addr(d, 1, 0x3f4); | |
349 | pci_set_io_region_addr(d, 2, 0x170); | |
350 | pci_set_io_region_addr(d, 3, 0x374); | |
351 | } | |
352 | break; | |
353 | case 0x0300: | |
354 | if (vendor_id != 0x1234) | |
355 | goto default_map; | |
356 | /* VGA: map frame buffer to default Bochs VBE address */ | |
357 | pci_set_io_region_addr(d, 0, 0xE0000000); | |
358 | break; | |
359 | case 0x0800: | |
360 | /* PIC */ | |
361 | vendor_id = pci_config_readw(d, PCI_VENDOR_ID); | |
362 | device_id = pci_config_readw(d, PCI_DEVICE_ID); | |
363 | if (vendor_id == 0x1014) { | |
364 | /* IBM */ | |
365 | if (device_id == 0x0046 || device_id == 0xFFFF) { | |
366 | /* MPIC & MPIC2 */ | |
367 | pci_set_io_region_addr(d, 0, 0x80800000 + 0x00040000); | |
368 | } | |
369 | } | |
370 | break; | |
371 | case 0xff00: | |
372 | if (vendor_id == 0x0106b && | |
373 | (device_id == 0x0017 || device_id == 0x0022)) { | |
374 | /* macio bridge */ | |
375 | pci_set_io_region_addr(d, 0, 0x80800000); | |
376 | } | |
377 | break; | |
378 | default: | |
379 | default_map: | |
380 | /* default memory mappings */ | |
381 | for(i = 0; i < PCI_NUM_REGIONS; i++) { | |
382 | r = &d->io_regions[i]; | |
383 | if (r->size) { | |
384 | if (r->type & PCI_ADDRESS_SPACE_IO) | |
385 | paddr = &pci_bios_io_addr; | |
386 | else | |
387 | paddr = &pci_bios_mem_addr; | |
388 | *paddr = (*paddr + r->size - 1) & ~(r->size - 1); | |
389 | pci_set_io_region_addr(d, i, *paddr); | |
390 | *paddr += r->size; | |
391 | } | |
392 | } | |
393 | break; | |
394 | } | |
395 | ||
396 | /* map the interrupt */ | |
397 | pin = pci_config_readb(d, PCI_INTERRUPT_PIN); | |
398 | if (pin != 0) { | |
399 | pin = pci_slot_get_pirq(d, pin - 1); | |
400 | pic_irq = pci_irqs[pin]; | |
401 | pci_config_writeb(d, PCI_INTERRUPT_LINE, pic_irq); | |
402 | } | |
403 | } | |
404 | ||
405 | /* | |
406 | * This function initializes the PCI devices as a normal PCI BIOS | |
407 | * would do. It is provided just in case the BIOS has no support for | |
408 | * PCI. | |
409 | */ | |
410 | void pci_bios_init(void) | |
411 | { | |
412 | int i, irq; | |
413 | uint8_t elcr[2]; | |
414 | ||
415 | pci_bios_io_addr = 0xc000; | |
416 | pci_bios_mem_addr = 0xf0000000; | |
417 | ||
418 | /* activate IRQ mappings */ | |
419 | elcr[0] = 0x00; | |
420 | elcr[1] = 0x00; | |
421 | for(i = 0; i < 4; i++) { | |
422 | irq = pci_irqs[i]; | |
423 | /* set to trigger level */ | |
424 | elcr[irq >> 3] |= (1 << (irq & 7)); | |
425 | /* activate irq remapping in PIIX */ | |
426 | pci_config_writeb(piix3_dev, 0x60 + i, irq); | |
427 | } | |
428 | isa_outb(elcr[0], 0x4d0); | |
429 | isa_outb(elcr[1], 0x4d1); | |
430 | ||
431 | pci_for_each_device(pci_bios_init_device); | |
432 | } | |
433 |