|
|
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: ! 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: ! 184: int piix3_init(PCIBus *bus) ! 185: { ! 186: PCIDevice *d; ! 187: uint8_t *pci_conf; ! 188: ! 189: d = pci_register_device(bus, "PIIX3", sizeof(PCIDevice), ! 190: -1, NULL, NULL); ! 191: register_savevm("PIIX3", 0, 1, generic_pci_save, generic_pci_load, d); ! 192: ! 193: piix3_dev = d; ! 194: pci_conf = d->config; ! 195: ! 196: pci_conf[0x00] = 0x86; // Intel ! 197: pci_conf[0x01] = 0x80; ! 198: pci_conf[0x02] = 0x00; // 82371SB PIIX3 PCI-to-ISA bridge (Step A1) ! 199: pci_conf[0x03] = 0x70; ! 200: pci_conf[0x0a] = 0x01; // class_sub = PCI_ISA ! 201: pci_conf[0x0b] = 0x06; // class_base = PCI_bridge ! 202: pci_conf[0x0e] = 0x80; // header_type = PCI_multifunction, generic ! 203: ! 204: piix3_reset(d); ! 205: return d->devfn; ! 206: } ! 207: ! 208: /***********************************************************/ ! 209: /* XXX: the following should be moved to the PC BIOS */ ! 210: ! 211: static __attribute__((unused)) uint32_t isa_inb(uint32_t addr) ! 212: { ! 213: return cpu_inb(NULL, addr); ! 214: } ! 215: ! 216: static void isa_outb(uint32_t val, uint32_t addr) ! 217: { ! 218: cpu_outb(NULL, addr, val); ! 219: } ! 220: ! 221: static __attribute__((unused)) uint32_t isa_inw(uint32_t addr) ! 222: { ! 223: return cpu_inw(NULL, addr); ! 224: } ! 225: ! 226: static __attribute__((unused)) void isa_outw(uint32_t val, uint32_t addr) ! 227: { ! 228: cpu_outw(NULL, addr, val); ! 229: } ! 230: ! 231: static __attribute__((unused)) uint32_t isa_inl(uint32_t addr) ! 232: { ! 233: return cpu_inl(NULL, addr); ! 234: } ! 235: ! 236: static __attribute__((unused)) void isa_outl(uint32_t val, uint32_t addr) ! 237: { ! 238: cpu_outl(NULL, addr, val); ! 239: } ! 240: ! 241: static uint32_t pci_bios_io_addr; ! 242: static uint32_t pci_bios_mem_addr; ! 243: /* host irqs corresponding to PCI irqs A-D */ ! 244: static uint8_t pci_irqs[4] = { 11, 9, 11, 9 }; ! 245: ! 246: static void pci_config_writel(PCIDevice *d, uint32_t addr, uint32_t val) ! 247: { ! 248: PCIBus *s = d->bus; ! 249: addr |= (pci_bus_num(s) << 16) | (d->devfn << 8); ! 250: pci_data_write(s, addr, val, 4); ! 251: } ! 252: ! 253: static void pci_config_writew(PCIDevice *d, uint32_t addr, uint32_t val) ! 254: { ! 255: PCIBus *s = d->bus; ! 256: addr |= (pci_bus_num(s) << 16) | (d->devfn << 8); ! 257: pci_data_write(s, addr, val, 2); ! 258: } ! 259: ! 260: static void pci_config_writeb(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, 1); ! 265: } ! 266: ! 267: static __attribute__((unused)) uint32_t pci_config_readl(PCIDevice *d, uint32_t addr) ! 268: { ! 269: PCIBus *s = d->bus; ! 270: addr |= (pci_bus_num(s) << 16) | (d->devfn << 8); ! 271: return pci_data_read(s, addr, 4); ! 272: } ! 273: ! 274: static uint32_t pci_config_readw(PCIDevice *d, uint32_t addr) ! 275: { ! 276: PCIBus *s = d->bus; ! 277: addr |= (pci_bus_num(s) << 16) | (d->devfn << 8); ! 278: return pci_data_read(s, addr, 2); ! 279: } ! 280: ! 281: static uint32_t pci_config_readb(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, 1); ! 286: } ! 287: ! 288: static void pci_set_io_region_addr(PCIDevice *d, int region_num, uint32_t addr) ! 289: { ! 290: PCIIORegion *r; ! 291: uint16_t cmd; ! 292: uint32_t ofs; ! 293: ! 294: if ( region_num == PCI_ROM_SLOT ) { ! 295: ofs = 0x30; ! 296: }else{ ! 297: ofs = 0x10 + region_num * 4; ! 298: } ! 299: ! 300: pci_config_writel(d, ofs, addr); ! 301: r = &d->io_regions[region_num]; ! 302: ! 303: /* enable memory mappings */ ! 304: cmd = pci_config_readw(d, PCI_COMMAND); ! 305: if ( region_num == PCI_ROM_SLOT ) ! 306: cmd |= 2; ! 307: else if (r->type & PCI_ADDRESS_SPACE_IO) ! 308: cmd |= 1; ! 309: else ! 310: cmd |= 2; ! 311: pci_config_writew(d, PCI_COMMAND, cmd); ! 312: } ! 313: ! 314: static void pci_bios_init_device(PCIDevice *d) ! 315: { ! 316: int class; ! 317: PCIIORegion *r; ! 318: uint32_t *paddr; ! 319: int i, pin, pic_irq, vendor_id, device_id; ! 320: ! 321: class = pci_config_readw(d, PCI_CLASS_DEVICE); ! 322: vendor_id = pci_config_readw(d, PCI_VENDOR_ID); ! 323: device_id = pci_config_readw(d, PCI_DEVICE_ID); ! 324: switch(class) { ! 325: case 0x0101: ! 326: if (vendor_id == 0x8086 && device_id == 0x7010) { ! 327: /* PIIX3 IDE */ ! 328: pci_config_writew(d, 0x40, 0x8000); // enable IDE0 ! 329: pci_config_writew(d, 0x42, 0x8000); // enable IDE1 ! 330: goto default_map; ! 331: } else { ! 332: /* IDE: we map it as in ISA mode */ ! 333: pci_set_io_region_addr(d, 0, 0x1f0); ! 334: pci_set_io_region_addr(d, 1, 0x3f4); ! 335: pci_set_io_region_addr(d, 2, 0x170); ! 336: pci_set_io_region_addr(d, 3, 0x374); ! 337: } ! 338: break; ! 339: case 0x0300: ! 340: if (vendor_id != 0x1234) ! 341: goto default_map; ! 342: /* VGA: map frame buffer to default Bochs VBE address */ ! 343: pci_set_io_region_addr(d, 0, 0xE0000000); ! 344: break; ! 345: case 0x0800: ! 346: /* PIC */ ! 347: vendor_id = pci_config_readw(d, PCI_VENDOR_ID); ! 348: device_id = pci_config_readw(d, PCI_DEVICE_ID); ! 349: if (vendor_id == 0x1014) { ! 350: /* IBM */ ! 351: if (device_id == 0x0046 || device_id == 0xFFFF) { ! 352: /* MPIC & MPIC2 */ ! 353: pci_set_io_region_addr(d, 0, 0x80800000 + 0x00040000); ! 354: } ! 355: } ! 356: break; ! 357: case 0xff00: ! 358: if (vendor_id == 0x0106b && ! 359: (device_id == 0x0017 || device_id == 0x0022)) { ! 360: /* macio bridge */ ! 361: pci_set_io_region_addr(d, 0, 0x80800000); ! 362: } ! 363: break; ! 364: default: ! 365: default_map: ! 366: /* default memory mappings */ ! 367: for(i = 0; i < PCI_NUM_REGIONS; i++) { ! 368: r = &d->io_regions[i]; ! 369: if (r->size) { ! 370: if (r->type & PCI_ADDRESS_SPACE_IO) ! 371: paddr = &pci_bios_io_addr; ! 372: else ! 373: paddr = &pci_bios_mem_addr; ! 374: *paddr = (*paddr + r->size - 1) & ~(r->size - 1); ! 375: pci_set_io_region_addr(d, i, *paddr); ! 376: *paddr += r->size; ! 377: } ! 378: } ! 379: break; ! 380: } ! 381: ! 382: /* map the interrupt */ ! 383: pin = pci_config_readb(d, PCI_INTERRUPT_PIN); ! 384: if (pin != 0) { ! 385: pin = pci_slot_get_pirq(d, pin - 1); ! 386: pic_irq = pci_irqs[pin]; ! 387: pci_config_writeb(d, PCI_INTERRUPT_LINE, pic_irq); ! 388: } ! 389: } ! 390: ! 391: /* ! 392: * This function initializes the PCI devices as a normal PCI BIOS ! 393: * would do. It is provided just in case the BIOS has no support for ! 394: * PCI. ! 395: */ ! 396: void pci_bios_init(void) ! 397: { ! 398: int i, irq; ! 399: uint8_t elcr[2]; ! 400: ! 401: pci_bios_io_addr = 0xc000; ! 402: pci_bios_mem_addr = 0xf0000000; ! 403: ! 404: /* activate IRQ mappings */ ! 405: elcr[0] = 0x00; ! 406: elcr[1] = 0x00; ! 407: for(i = 0; i < 4; i++) { ! 408: irq = pci_irqs[i]; ! 409: /* set to trigger level */ ! 410: elcr[irq >> 3] |= (1 << (irq & 7)); ! 411: /* activate irq remapping in PIIX */ ! 412: pci_config_writeb(piix3_dev, 0x60 + i, irq); ! 413: } ! 414: isa_outb(elcr[0], 0x4d0); ! 415: isa_outb(elcr[1], 0x4d1); ! 416: ! 417: pci_for_each_device(pci_bios_init_device); ! 418: } ! 419:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.