📄 pci.c
字号:
{ PCIBus *s = opaque; pci_data_write(s, addr & 7, val, 2);}static void pci_apb_writel (void *opaque, target_phys_addr_t addr, uint32_t val){ PCIBus *s = opaque; pci_data_write(s, addr & 7, val, 4);}static uint32_t pci_apb_readb (void *opaque, target_phys_addr_t addr){ PCIBus *s = opaque; uint32_t val; val = pci_data_read(s, addr & 7, 1); return val;}static uint32_t pci_apb_readw (void *opaque, target_phys_addr_t addr){ PCIBus *s = opaque; uint32_t val; val = pci_data_read(s, addr & 7, 2); return val;}static uint32_t pci_apb_readl (void *opaque, target_phys_addr_t addr){ PCIBus *s = opaque; uint32_t val; val = pci_data_read(s, addr, 4); return val;}static CPUWriteMemoryFunc *pci_apb_write[] = { &pci_apb_writeb, &pci_apb_writew, &pci_apb_writel,};static CPUReadMemoryFunc *pci_apb_read[] = { &pci_apb_readb, &pci_apb_readw, &pci_apb_readl,};static void pci_apb_iowriteb (void *opaque, target_phys_addr_t addr, uint32_t val){ cpu_outb(NULL, addr & 0xffff, val);}static void pci_apb_iowritew (void *opaque, target_phys_addr_t addr, uint32_t val){ cpu_outw(NULL, addr & 0xffff, val);}static void pci_apb_iowritel (void *opaque, target_phys_addr_t addr, uint32_t val){ cpu_outl(NULL, addr & 0xffff, val);}static uint32_t pci_apb_ioreadb (void *opaque, target_phys_addr_t addr){ uint32_t val; val = cpu_inb(NULL, addr & 0xffff); return val;}static uint32_t pci_apb_ioreadw (void *opaque, target_phys_addr_t addr){ uint32_t val; val = cpu_inw(NULL, addr & 0xffff); return val;}static uint32_t pci_apb_ioreadl (void *opaque, target_phys_addr_t addr){ uint32_t val; val = cpu_inl(NULL, addr & 0xffff); return val;}static CPUWriteMemoryFunc *pci_apb_iowrite[] = { &pci_apb_iowriteb, &pci_apb_iowritew, &pci_apb_iowritel,};static CPUReadMemoryFunc *pci_apb_ioread[] = { &pci_apb_ioreadb, &pci_apb_ioreadw, &pci_apb_ioreadl,};PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base){ PCIBus *s; PCIDevice *d; int pci_mem_config, pci_mem_data, apb_config, pci_ioport; /* Ultrasparc APB main bus */ s = pci_register_bus(); s->set_irq = pci_set_irq_simple; pci_mem_config = cpu_register_io_memory(0, pci_apb_config_read, pci_apb_config_write, s); apb_config = cpu_register_io_memory(0, apb_config_read, apb_config_write, s); pci_mem_data = cpu_register_io_memory(0, pci_apb_read, pci_apb_write, s); pci_ioport = cpu_register_io_memory(0, pci_apb_ioread, pci_apb_iowrite, s); cpu_register_physical_memory(special_base + 0x2000ULL, 0x40, apb_config); cpu_register_physical_memory(special_base + 0x1000000ULL, 0x10, pci_mem_config); cpu_register_physical_memory(special_base + 0x2000000ULL, 0x10000, pci_ioport); cpu_register_physical_memory(mem_base, 0x10000000, pci_mem_data); // XXX size should be 4G-prom d = pci_register_device(s, "Advanced PCI Bus", sizeof(PCIDevice), -1, NULL, NULL); d->config[0x00] = 0x8e; // vendor_id : Sun d->config[0x01] = 0x10; d->config[0x02] = 0x00; // device_id d->config[0x03] = 0xa0; d->config[0x04] = 0x06; // command = bus master, pci mem d->config[0x05] = 0x00; d->config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error d->config[0x07] = 0x03; // status = medium devsel d->config[0x08] = 0x00; // revision d->config[0x09] = 0x00; // programming i/f d->config[0x0A] = 0x00; // class_sub = pci host d->config[0x0B] = 0x06; // class_base = PCI_bridge d->config[0x0D] = 0x10; // latency_timer d->config[0x0E] = 0x00; // header_type return s;}/***********************************************************//* generic PCI irq support *//* 0 <= irq_num <= 3. level must be 0 or 1 */void pci_set_irq(PCIDevice *pci_dev, int irq_num, int level){ PCIBus *bus = pci_dev->bus; bus->set_irq(pci_dev, irq_num, level);}/***********************************************************//* monitor info on PCI */static void pci_info_device(PCIDevice *d){ int i, class; PCIIORegion *r; term_printf(" Bus %2d, device %3d, function %d:\n", d->bus->bus_num, d->devfn >> 3, d->devfn & 7); class = le16_to_cpu(*((uint16_t *)(d->config + PCI_CLASS_DEVICE))); term_printf(" "); switch(class) { case 0x0101: term_printf("IDE controller"); break; case 0x0200: term_printf("Ethernet controller"); break; case 0x0300: term_printf("VGA controller"); break; default: term_printf("Class %04x", class); break; } term_printf(": PCI device %04x:%04x\n", le16_to_cpu(*((uint16_t *)(d->config + PCI_VENDOR_ID))), le16_to_cpu(*((uint16_t *)(d->config + PCI_DEVICE_ID)))); if (d->config[PCI_INTERRUPT_PIN] != 0) { term_printf(" IRQ %d.\n", d->config[PCI_INTERRUPT_LINE]); } for(i = 0;i < PCI_NUM_REGIONS; i++) { r = &d->io_regions[i]; if (r->size != 0) { term_printf(" BAR%d: ", i); if (r->type & PCI_ADDRESS_SPACE_IO) { term_printf("I/O at 0x%04x [0x%04x].\n", r->addr, r->addr + r->size - 1); } else { term_printf("32 bit memory at 0x%08x [0x%08x].\n", r->addr, r->addr + r->size - 1); } } }}void pci_info(void){ PCIBus *bus = first_bus; PCIDevice *d; int devfn; if (bus) { for(devfn = 0; devfn < 256; devfn++) { d = bus->devices[devfn]; if (d) pci_info_device(d); } }}/***********************************************************//* XXX: the following should be moved to the PC BIOS */static __attribute__((unused)) uint32_t isa_inb(uint32_t addr){ return cpu_inb(NULL, addr);}static void isa_outb(uint32_t val, uint32_t addr){ cpu_outb(NULL, addr, val);}static __attribute__((unused)) uint32_t isa_inw(uint32_t addr){ return cpu_inw(NULL, addr);}static __attribute__((unused)) void isa_outw(uint32_t val, uint32_t addr){ cpu_outw(NULL, addr, val);}static __attribute__((unused)) uint32_t isa_inl(uint32_t addr){ return cpu_inl(NULL, addr);}static __attribute__((unused)) void isa_outl(uint32_t val, uint32_t addr){ cpu_outl(NULL, addr, val);}static void pci_config_writel(PCIDevice *d, uint32_t addr, uint32_t val){ PCIBus *s = d->bus; s->config_reg = 0x80000000 | (s->bus_num << 16) | (d->devfn << 8) | addr; pci_data_write(s, 0, val, 4);}static void pci_config_writew(PCIDevice *d, uint32_t addr, uint32_t val){ PCIBus *s = d->bus; s->config_reg = 0x80000000 | (s->bus_num << 16) | (d->devfn << 8) | (addr & ~3); pci_data_write(s, addr & 3, val, 2);}static void pci_config_writeb(PCIDevice *d, uint32_t addr, uint32_t val){ PCIBus *s = d->bus; s->config_reg = 0x80000000 | (s->bus_num << 16) | (d->devfn << 8) | (addr & ~3); pci_data_write(s, addr & 3, val, 1);}static __attribute__((unused)) uint32_t pci_config_readl(PCIDevice *d, uint32_t addr){ PCIBus *s = d->bus; s->config_reg = 0x80000000 | (s->bus_num << 16) | (d->devfn << 8) | addr; return pci_data_read(s, 0, 4);}static uint32_t pci_config_readw(PCIDevice *d, uint32_t addr){ PCIBus *s = d->bus; s->config_reg = 0x80000000 | (s->bus_num << 16) | (d->devfn << 8) | (addr & ~3); return pci_data_read(s, addr & 3, 2);}static uint32_t pci_config_readb(PCIDevice *d, uint32_t addr){ PCIBus *s = d->bus; s->config_reg = 0x80000000 | (s->bus_num << 16) | (d->devfn << 8) | (addr & ~3); return pci_data_read(s, addr & 3, 1);}static uint32_t pci_bios_io_addr;static uint32_t pci_bios_mem_addr;/* host irqs corresponding to PCI irqs A-D */static uint8_t pci_irqs[4] = { 11, 9, 11, 9 };static void pci_set_io_region_addr(PCIDevice *d, int region_num, uint32_t addr){ PCIIORegion *r; uint16_t cmd; uint32_t ofs; if ( region_num == PCI_ROM_SLOT ) { ofs = 0x30; }else{ ofs = 0x10 + region_num * 4; } pci_config_writel(d, ofs, addr); r = &d->io_regions[region_num]; /* enable memory mappings */ cmd = pci_config_readw(d, PCI_COMMAND); if ( region_num == PCI_ROM_SLOT ) cmd |= 2; else if (r->type & PCI_ADDRESS_SPACE_IO) cmd |= 1; else cmd |= 2; pci_config_writew(d, PCI_COMMAND, cmd);}static void pci_bios_init_device(PCIDevice *d){ int class; PCIIORegion *r; uint32_t *paddr; int i, pin, pic_irq, vendor_id, device_id; class = pci_config_readw(d, PCI_CLASS_DEVICE); vendor_id = pci_config_readw(d, PCI_VENDOR_ID); device_id = pci_config_readw(d, PCI_DEVICE_ID); switch(class) { case 0x0101: if (vendor_id == 0x8086 && device_id == 0x7010) { /* PIIX3 IDE */ pci_config_writew(d, 0x40, 0x8000); // enable IDE0 pci_config_writew(d, 0x42, 0x8000); // enable IDE1 goto default_map; } else { /* IDE: we map it as in ISA mode */ pci_set_io_region_addr(d, 0, 0x1f0); pci_set_io_region_addr(d, 1, 0x3f4); pci_set_io_region_addr(d, 2, 0x170); pci_set_io_region_addr(d, 3, 0x374); } break; case 0x0300: if (vendor_id != 0x1234) goto default_map; /* VGA: map frame buffer to default Bochs VBE address */ pci_set_io_region_addr(d, 0, 0xE0000000); break; case 0x0800: /* PIC */ vendor_id = pci_config_readw(d, PCI_VENDOR_ID); device_id = pci_config_readw(d, PCI_DEVICE_ID); if (vendor_id == 0x1014) { /* IBM */ if (device_id == 0x0046 || device_id == 0xFFFF) { /* MPIC & MPIC2 */ pci_set_io_region_addr(d, 0, 0x80800000 + 0x00040000); } } break; case 0xff00: if (vendor_id == 0x0106b && (device_id == 0x0017 || device_id == 0x0022)) { /* macio bridge */ pci_set_io_region_addr(d, 0, 0x80800000); } break; default: default_map: /* default memory mappings */ for(i = 0; i < PCI_NUM_REGIONS; i++) { r = &d->io_regions[i]; if (r->size) { if (r->type & PCI_ADDRESS_SPACE_IO) paddr = &pci_bios_io_addr; else paddr = &pci_bios_mem_addr; *paddr = (*paddr + r->size - 1) & ~(r->size - 1); pci_set_io_region_addr(d, i, *paddr); *paddr += r->size; } } break; } /* map the interrupt */ pin = pci_config_readb(d, PCI_INTERRUPT_PIN); if (pin != 0) { pin = pci_slot_get_pirq(d, pin - 1); pic_irq = pci_irqs[pin]; pci_config_writeb(d, PCI_INTERRUPT_LINE, pic_irq); }}/* * This function initializes the PCI devices as a normal PCI BIOS * would do. It is provided just in case the BIOS has no support for * PCI. */void pci_bios_init(void){ PCIBus *bus; PCIDevice *d; int devfn, i, irq; uint8_t elcr[2]; pci_bios_io_addr = 0xc000; pci_bios_mem_addr = 0xf0000000; /* activate IRQ mappings */ elcr[0] = 0x00; elcr[1] = 0x00; for(i = 0; i < 4; i++) { irq = pci_irqs[i]; /* set to trigger level */ elcr[irq >> 3] |= (1 << (irq & 7)); /* activate irq remapping in PIIX */ pci_config_writeb((PCIDevice *)piix3_state, 0x60 + i, irq); } isa_outb(elcr[0], 0x4d0); isa_outb(elcr[1], 0x4d1); bus = first_bus; if (bus) { for(devfn = 0; devfn < 256; devfn++) { d = bus->devices[devfn]; if (d) pci_bios_init_device(d); } }}/* Initialize a PCI NIC. */void pci_nic_init(PCIBus *bus, NICInfo *nd){ if (strcmp(nd->model, "ne2k_pci") == 0) { pci_ne2000_init(bus, nd); } else if (strcmp(nd->model, "rtl8139") == 0) { pci_rtl8139_init(bus, nd); } else { fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd->model); exit (1); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -