|
|
1.1 root 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:
1.1.1.2 ! root 43: static void piix3_set_irq(void *pic, int irq_num, int level);
1.1 root 44:
1.1.1.2 ! root 45: /* return the global irq number corresponding to a given device irq
! 46: pin. We could also use the bus number to have a more precise
! 47: mapping. */
! 48: static int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num)
! 49: {
! 50: int slot_addend;
! 51: slot_addend = (pci_dev->devfn >> 3) - 1;
! 52: return (irq_num + slot_addend) & 3;
! 53: }
! 54:
! 55: static uint32_t isa_page_descs[384 / 4];
! 56: static uint8_t smm_enabled;
! 57:
! 58: static void update_pam(PCIDevice *d, uint32_t start, uint32_t end, int r)
! 59: {
! 60: uint32_t addr;
! 61:
! 62: // printf("ISA mapping %08x-0x%08x: %d\n", start, end, r);
! 63: switch(r) {
! 64: case 3:
! 65: /* RAM */
! 66: cpu_register_physical_memory(start, end - start,
! 67: start);
! 68: break;
! 69: case 1:
! 70: /* ROM (XXX: not quite correct) */
! 71: cpu_register_physical_memory(start, end - start,
! 72: start | IO_MEM_ROM);
! 73: break;
! 74: case 2:
! 75: case 0:
! 76: /* XXX: should distinguish read/write cases */
! 77: for(addr = start; addr < end; addr += 4096) {
! 78: cpu_register_physical_memory(addr, 4096,
! 79: isa_page_descs[(addr - 0xa0000) >> 12]);
! 80: }
! 81: break;
! 82: }
! 83: }
! 84:
! 85: static void i440fx_update_memory_mappings(PCIDevice *d)
! 86: {
! 87: int i, r;
! 88: uint32_t smram, addr;
! 89:
! 90: update_pam(d, 0xf0000, 0x100000, (d->config[0x59] >> 4) & 3);
! 91: for(i = 0; i < 12; i++) {
! 92: r = (d->config[(i >> 1) + 0x5a] >> ((i & 1) * 4)) & 3;
! 93: update_pam(d, 0xc0000 + 0x4000 * i, 0xc0000 + 0x4000 * (i + 1), r);
! 94: }
! 95: smram = d->config[0x72];
! 96: if ((smm_enabled && (smram & 0x08)) || (smram & 0x40)) {
! 97: cpu_register_physical_memory(0xa0000, 0x20000, 0xa0000);
! 98: } else {
! 99: for(addr = 0xa0000; addr < 0xc0000; addr += 4096) {
! 100: cpu_register_physical_memory(addr, 4096,
! 101: isa_page_descs[(addr - 0xa0000) >> 12]);
! 102: }
! 103: }
! 104: }
! 105:
! 106: void i440fx_set_smm(PCIDevice *d, int val)
! 107: {
! 108: val = (val != 0);
! 109: if (smm_enabled != val) {
! 110: smm_enabled = val;
! 111: i440fx_update_memory_mappings(d);
! 112: }
! 113: }
! 114:
! 115:
! 116: /* XXX: suppress when better memory API. We make the assumption that
! 117: no device (in particular the VGA) changes the memory mappings in
! 118: the 0xa0000-0x100000 range */
! 119: void i440fx_init_memory_mappings(PCIDevice *d)
! 120: {
! 121: int i;
! 122: for(i = 0; i < 96; i++) {
! 123: isa_page_descs[i] = cpu_get_physical_page_desc(0xa0000 + i * 0x1000);
! 124: }
! 125: }
! 126:
! 127: static void i440fx_write_config(PCIDevice *d,
! 128: uint32_t address, uint32_t val, int len)
! 129: {
! 130: /* XXX: implement SMRAM.D_LOCK */
! 131: pci_default_write_config(d, address, val, len);
! 132: if ((address >= 0x59 && address <= 0x5f) || address == 0x72)
! 133: i440fx_update_memory_mappings(d);
! 134: }
! 135:
! 136: static void i440fx_save(QEMUFile* f, void *opaque)
! 137: {
! 138: PCIDevice *d = opaque;
! 139: pci_device_save(d, f);
! 140: qemu_put_8s(f, &smm_enabled);
! 141: }
! 142:
! 143: static int i440fx_load(QEMUFile* f, void *opaque, int version_id)
! 144: {
! 145: PCIDevice *d = opaque;
! 146: int ret;
! 147:
! 148: if (version_id != 1)
! 149: return -EINVAL;
! 150: ret = pci_device_load(d, f);
! 151: if (ret < 0)
! 152: return ret;
! 153: i440fx_update_memory_mappings(d);
! 154: qemu_get_8s(f, &smm_enabled);
! 155: return 0;
! 156: }
! 157:
! 158: PCIBus *i440fx_init(PCIDevice **pi440fx_state)
1.1 root 159: {
160: PCIBus *b;
161: PCIDevice *d;
162: I440FXState *s;
163:
164: s = qemu_mallocz(sizeof(I440FXState));
1.1.1.2 ! root 165: b = pci_register_bus(piix3_set_irq, pci_slot_get_pirq, NULL, 0, 4);
1.1 root 166: s->bus = b;
167:
168: register_ioport_write(0xcf8, 4, 4, i440fx_addr_writel, s);
169: register_ioport_read(0xcf8, 4, 4, i440fx_addr_readl, s);
170:
171: register_ioport_write(0xcfc, 4, 1, pci_host_data_writeb, s);
172: register_ioport_write(0xcfc, 4, 2, pci_host_data_writew, s);
173: register_ioport_write(0xcfc, 4, 4, pci_host_data_writel, s);
174: register_ioport_read(0xcfc, 4, 1, pci_host_data_readb, s);
175: register_ioport_read(0xcfc, 4, 2, pci_host_data_readw, s);
176: register_ioport_read(0xcfc, 4, 4, pci_host_data_readl, s);
177:
178: d = pci_register_device(b, "i440FX", sizeof(PCIDevice), 0,
1.1.1.2 ! root 179: NULL, i440fx_write_config);
1.1 root 180:
181: d->config[0x00] = 0x86; // vendor_id
182: d->config[0x01] = 0x80;
183: d->config[0x02] = 0x37; // device_id
184: d->config[0x03] = 0x12;
185: d->config[0x08] = 0x02; // revision
186: d->config[0x0a] = 0x00; // class_sub = host2pci
187: d->config[0x0b] = 0x06; // class_base = PCI_bridge
188: d->config[0x0e] = 0x00; // header_type
1.1.1.2 ! root 189:
! 190: d->config[0x72] = 0x02; /* SMRAM */
! 191:
! 192: register_savevm("I440FX", 0, 1, i440fx_save, i440fx_load, d);
! 193: *pi440fx_state = d;
1.1 root 194: return b;
195: }
196:
197: /* PIIX3 PCI to ISA bridge */
198:
1.1.1.2 ! root 199: PCIDevice *piix3_dev;
! 200: PCIDevice *piix4_dev;
1.1 root 201:
202: /* just used for simpler irq handling. */
203: #define PCI_IRQ_WORDS ((PCI_DEVICES_MAX + 31) / 32)
204:
1.1.1.2 ! root 205: static int pci_irq_levels[4];
1.1 root 206:
1.1.1.2 ! root 207: static void piix3_set_irq(void *pic, int irq_num, int level)
1.1 root 208: {
1.1.1.2 ! root 209: int i, pic_irq, pic_level;
1.1 root 210:
1.1.1.2 ! root 211: pci_irq_levels[irq_num] = level;
1.1 root 212:
213: /* now we change the pic irq level according to the piix irq mappings */
214: /* XXX: optimize */
215: pic_irq = piix3_dev->config[0x60 + irq_num];
216: if (pic_irq < 16) {
1.1.1.2 ! root 217: /* The pic level is the logical OR of all the PCI irqs mapped
1.1 root 218: to it */
219: pic_level = 0;
1.1.1.2 ! root 220: for (i = 0; i < 4; i++) {
! 221: if (pic_irq == piix3_dev->config[0x60 + i])
! 222: pic_level |= pci_irq_levels[i];
! 223: }
1.1 root 224: pic_set_irq(pic_irq, pic_level);
225: }
226: }
227:
228: static void piix3_reset(PCIDevice *d)
229: {
230: uint8_t *pci_conf = d->config;
231:
232: pci_conf[0x04] = 0x07; // master, memory and I/O
233: pci_conf[0x05] = 0x00;
234: pci_conf[0x06] = 0x00;
235: pci_conf[0x07] = 0x02; // PCI_status_devsel_medium
236: pci_conf[0x4c] = 0x4d;
237: pci_conf[0x4e] = 0x03;
238: pci_conf[0x4f] = 0x00;
239: pci_conf[0x60] = 0x80;
240: pci_conf[0x69] = 0x02;
241: pci_conf[0x70] = 0x80;
242: pci_conf[0x76] = 0x0c;
243: pci_conf[0x77] = 0x0c;
244: pci_conf[0x78] = 0x02;
245: pci_conf[0x79] = 0x00;
246: pci_conf[0x80] = 0x00;
247: pci_conf[0x82] = 0x00;
248: pci_conf[0xa0] = 0x08;
1.1.1.2 ! root 249: pci_conf[0xa2] = 0x00;
! 250: pci_conf[0xa3] = 0x00;
! 251: pci_conf[0xa4] = 0x00;
! 252: pci_conf[0xa5] = 0x00;
! 253: pci_conf[0xa6] = 0x00;
! 254: pci_conf[0xa7] = 0x00;
! 255: pci_conf[0xa8] = 0x0f;
! 256: pci_conf[0xaa] = 0x00;
! 257: pci_conf[0xab] = 0x00;
! 258: pci_conf[0xac] = 0x00;
! 259: pci_conf[0xae] = 0x00;
! 260: }
! 261:
! 262: static void piix4_reset(PCIDevice *d)
! 263: {
! 264: uint8_t *pci_conf = d->config;
! 265:
! 266: pci_conf[0x04] = 0x07; // master, memory and I/O
! 267: pci_conf[0x05] = 0x00;
! 268: pci_conf[0x06] = 0x00;
! 269: pci_conf[0x07] = 0x02; // PCI_status_devsel_medium
! 270: pci_conf[0x4c] = 0x4d;
! 271: pci_conf[0x4e] = 0x03;
! 272: pci_conf[0x4f] = 0x00;
! 273: pci_conf[0x60] = 0x0a; // PCI A -> IRQ 10
! 274: pci_conf[0x61] = 0x0a; // PCI B -> IRQ 10
! 275: pci_conf[0x62] = 0x0b; // PCI C -> IRQ 11
! 276: pci_conf[0x63] = 0x0b; // PCI D -> IRQ 11
! 277: pci_conf[0x69] = 0x02;
! 278: pci_conf[0x70] = 0x80;
! 279: pci_conf[0x76] = 0x0c;
! 280: pci_conf[0x77] = 0x0c;
! 281: pci_conf[0x78] = 0x02;
! 282: pci_conf[0x79] = 0x00;
! 283: pci_conf[0x80] = 0x00;
! 284: pci_conf[0x82] = 0x00;
1.1 root 285: pci_conf[0xa0] = 0x08;
286: pci_conf[0xa2] = 0x00;
287: pci_conf[0xa3] = 0x00;
288: pci_conf[0xa4] = 0x00;
289: pci_conf[0xa5] = 0x00;
290: pci_conf[0xa6] = 0x00;
291: pci_conf[0xa7] = 0x00;
292: pci_conf[0xa8] = 0x0f;
293: pci_conf[0xaa] = 0x00;
294: pci_conf[0xab] = 0x00;
295: pci_conf[0xac] = 0x00;
296: pci_conf[0xae] = 0x00;
297: }
298:
1.1.1.2 ! root 299: static void piix_save(QEMUFile* f, void *opaque)
! 300: {
! 301: PCIDevice *d = opaque;
! 302: pci_device_save(d, f);
! 303: }
! 304:
! 305: static int piix_load(QEMUFile* f, void *opaque, int version_id)
! 306: {
! 307: PCIDevice *d = opaque;
! 308: if (version_id != 2)
! 309: return -EINVAL;
! 310: return pci_device_load(d, f);
! 311: }
! 312:
! 313: int piix_init(PCIBus *bus, int devfn)
1.1 root 314: {
315: PCIDevice *d;
316: uint8_t *pci_conf;
317:
1.1.1.2 ! root 318: d = pci_register_device(bus, "PIIX", sizeof(PCIDevice),
! 319: devfn, NULL, NULL);
! 320: register_savevm("PIIX", 0, 2, piix_save, piix_load, d);
1.1 root 321:
322: piix3_dev = d;
323: pci_conf = d->config;
324:
325: pci_conf[0x00] = 0x86; // Intel
326: pci_conf[0x01] = 0x80;
1.1.1.2 ! root 327: pci_conf[0x02] = 0x2E; // 82371FB PIIX PCI-to-ISA bridge
! 328: pci_conf[0x03] = 0x12;
! 329: pci_conf[0x08] = 0x02; // Step A1
1.1 root 330: pci_conf[0x0a] = 0x01; // class_sub = PCI_ISA
331: pci_conf[0x0b] = 0x06; // class_base = PCI_bridge
332: pci_conf[0x0e] = 0x80; // header_type = PCI_multifunction, generic
333:
334: piix3_reset(d);
335: return d->devfn;
336: }
337:
1.1.1.2 ! root 338: int piix3_init(PCIBus *bus, int devfn)
1.1 root 339: {
1.1.1.2 ! root 340: PCIDevice *d;
! 341: uint8_t *pci_conf;
1.1 root 342:
1.1.1.2 ! root 343: d = pci_register_device(bus, "PIIX3", sizeof(PCIDevice),
! 344: devfn, NULL, NULL);
! 345: register_savevm("PIIX3", 0, 2, piix_save, piix_load, d);
1.1 root 346:
1.1.1.2 ! root 347: piix3_dev = d;
! 348: pci_conf = d->config;
1.1 root 349:
1.1.1.2 ! root 350: pci_conf[0x00] = 0x86; // Intel
! 351: pci_conf[0x01] = 0x80;
! 352: pci_conf[0x02] = 0x00; // 82371SB PIIX3 PCI-to-ISA bridge (Step A1)
! 353: pci_conf[0x03] = 0x70;
! 354: pci_conf[0x0a] = 0x01; // class_sub = PCI_ISA
! 355: pci_conf[0x0b] = 0x06; // class_base = PCI_bridge
! 356: pci_conf[0x0e] = 0x80; // header_type = PCI_multifunction, generic
1.1 root 357:
1.1.1.2 ! root 358: piix3_reset(d);
! 359: return d->devfn;
1.1 root 360: }
361:
1.1.1.2 ! root 362: int piix4_init(PCIBus *bus, int devfn)
1.1 root 363: {
1.1.1.2 ! root 364: PCIDevice *d;
! 365: uint8_t *pci_conf;
1.1 root 366:
1.1.1.2 ! root 367: d = pci_register_device(bus, "PIIX4", sizeof(PCIDevice),
! 368: devfn, NULL, NULL);
! 369: register_savevm("PIIX4", 0, 2, piix_save, piix_load, d);
1.1 root 370:
1.1.1.2 ! root 371: piix4_dev = d;
! 372: pci_conf = d->config;
1.1 root 373:
1.1.1.2 ! root 374: pci_conf[0x00] = 0x86; // Intel
! 375: pci_conf[0x01] = 0x80;
! 376: pci_conf[0x02] = 0x10; // 82371AB/EB/MB PIIX4 PCI-to-ISA bridge
! 377: pci_conf[0x03] = 0x71;
! 378: pci_conf[0x0a] = 0x01; // class_sub = PCI_ISA
! 379: pci_conf[0x0b] = 0x06; // class_base = PCI_bridge
! 380: pci_conf[0x0e] = 0x80; // header_type = PCI_multifunction, generic
1.1 root 381:
1.1.1.2 ! root 382: piix4_reset(d);
! 383: return d->devfn;
1.1 root 384: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.