static void pci_setup_device(int bdf, uint32_t *p_io_base, uint32_t *p_mem_base) { int vendor_id, device_id, class_id, region; vendor_id = pci_config_readw(bdf, PCI_VENDOR_ID); device_id = pci_config_readw(bdf, PCI_DEVICE_ID); class_id = pci_config_readw(bdf, PCI_CLASS_DEVICE); printf("PCI: %02x:%02x:%x class %04x id %04x:%04x\r\n", PCI_BUS(bdf), PCI_SLOT(bdf), PCI_FUNC(bdf), class_id, vendor_id, device_id); for (region = 0; region < PCI_REGION_ROM; region++) { int ofs = PCI_BASE_ADDRESS_0 + region * 4; uint32_t old, mask, val, size, align; uint32_t *p_base; old = pci_config_readl(bdf, ofs); if (old & PCI_BASE_ADDRESS_SPACE_IO) { mask = PCI_BASE_ADDRESS_IO_MASK; p_base = p_io_base; } else { mask = PCI_BASE_ADDRESS_MEM_MASK; p_base = p_mem_base; } pci_config_writel(bdf, ofs, -1); val = pci_config_readl(bdf, ofs); pci_config_writel(bdf, ofs, old); align = size = ~(val & mask) + 1; if (val != 0) { uint32_t addr = *p_base; addr = (addr + align - 1) & ~(align - 1); *p_base = addr + size; pci_config_writel(bdf, ofs, addr); printf("PCI: region %d: %08x\r\n", region, addr); if ((val & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == PCI_BASE_ADDRESS_MEM_TYPE_64) { pci_config_writel(bdf, ofs + 4, 0); region++; } } } pci_config_maskw(bdf, PCI_COMMAND, 0, PCI_COMMAND_IO | PCI_COMMAND_MEMORY); /* Map the interrupt. */ }
// This code is hardcoded for PIIX4 Power Management device. static void piix4_apmc_smm_init(struct pci_device *pci, void *arg) { struct pci_device *i440_pci = pci_find_device(PCI_VENDOR_ID_INTEL , PCI_DEVICE_ID_INTEL_82441); if (!i440_pci) return; /* check if SMM init is already done */ u32 value = pci_config_readl(pci->bdf, PIIX_DEVACTB); if (value & PIIX_APMC_EN) return; /* enable the SMM memory window */ pci_config_writeb(i440_pci->bdf, I440FX_SMRAM, 0x02 | 0x48); smm_save_and_copy(); /* enable SMI generation when writing to the APMC register */ pci_config_writel(pci->bdf, PIIX_DEVACTB, value | PIIX_APMC_EN); smm_relocate_and_restore(); /* close the SMM memory window and enable normal SMM */ pci_config_writeb(i440_pci->bdf, I440FX_SMRAM, 0x02 | 0x08); }
u16 vp_init_simple(u16 bdf) { u16 ioaddr = pci_config_readl(bdf, PCI_BASE_ADDRESS_0) & PCI_BASE_ADDRESS_IO_MASK; vp_reset(ioaddr); vp_set_status(ioaddr, VIRTIO_CONFIG_S_ACKNOWLEDGE | VIRTIO_CONFIG_S_DRIVER ); return ioaddr; }
void ohci_init(void *data) { if (! CONFIG_USB_OHCI) return; struct usb_s *cntl = data; // XXX - don't call pci_config_XXX from a thread cntl->type = USB_TYPE_OHCI; u32 baseaddr = pci_config_readl(cntl->bdf, PCI_BASE_ADDRESS_0); cntl->ohci.regs = (void*)(baseaddr & PCI_BASE_ADDRESS_MEM_MASK); dprintf(3, "OHCI init on dev %02x:%02x.%x (regs=%p)\n" , pci_bdf_to_bus(cntl->bdf), pci_bdf_to_dev(cntl->bdf) , pci_bdf_to_fn(cntl->bdf), cntl->ohci.regs); // Enable bus mastering and memory access. pci_config_maskw(cntl->bdf, PCI_COMMAND , 0, PCI_COMMAND_MASTER|PCI_COMMAND_MEMORY); // XXX - check for and disable SMM control? // Disable interrupts writel(&cntl->ohci.regs->intrdisable, ~0); writel(&cntl->ohci.regs->intrstatus, ~0); // Allocate memory struct ohci_hcca *hcca = memalign_high(256, sizeof(*hcca)); struct ohci_ed *control_ed = malloc_high(sizeof(*control_ed)); if (!hcca || !control_ed) { dprintf(1, "No ram for ohci init\n"); return; } memset(hcca, 0, sizeof(*hcca)); memset(control_ed, 0, sizeof(*control_ed)); control_ed->hwINFO = ED_SKIP; cntl->ohci.control_ed = control_ed; int ret = start_ohci(cntl, hcca); if (ret) goto err; int count = check_ohci_ports(cntl); if (! count) goto err; return; err: stop_ohci(cntl); free(hcca); free(control_ed); }
int ehci_init(struct pci_device *pci, int busid, struct pci_device *comppci) { if (! CONFIG_USB_EHCI) return -1; u16 bdf = pci->bdf; u32 baseaddr = pci_config_readl(bdf, PCI_BASE_ADDRESS_0); struct ehci_caps *caps = (void*)(baseaddr & PCI_BASE_ADDRESS_MEM_MASK); u32 hcc_params = readl(&caps->hccparams); if (hcc_params & HCC_64BIT_ADDR) { dprintf(1, "No support for 64bit EHCI\n"); return -1; } struct usb_ehci_s *cntl = malloc_tmphigh(sizeof(*cntl)); if (!cntl) { warn_noalloc(); return -1; } memset(cntl, 0, sizeof(*cntl)); cntl->usb.busid = busid; cntl->usb.pci = pci; cntl->usb.type = USB_TYPE_EHCI; cntl->caps = caps; cntl->regs = (void*)caps + readb(&caps->caplength); dprintf(1, "EHCI init on dev %02x:%02x.%x (regs=%p)\n" , pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf) , pci_bdf_to_fn(bdf), cntl->regs); pci_config_maskw(bdf, PCI_COMMAND, 0, PCI_COMMAND_MASTER); // XXX - check for and disable SMM control? // Find companion controllers. int count = 0; for (;;) { if (!comppci || comppci == pci) break; if (pci_classprog(comppci) == PCI_CLASS_SERIAL_USB_UHCI) cntl->companion[count++] = comppci; else if (pci_classprog(comppci) == PCI_CLASS_SERIAL_USB_OHCI) cntl->companion[count++] = comppci; comppci = comppci->next; } run_thread(configure_ehci, cntl); return 0; }
static void pci_set_io_region_addr(u16 bdf, int region_num, u32 addr) { u32 ofs, old_addr; if (region_num == PCI_ROM_SLOT) { ofs = PCI_ROM_ADDRESS; } else { ofs = PCI_BASE_ADDRESS_0 + region_num * 4; } old_addr = pci_config_readl(bdf, ofs); pci_config_writel(bdf, ofs, addr); dprintf(1, "region %d: 0x%08x\n", region_num, addr); }
// find pci device static void handle_1ab102(struct bregs *regs) { u32 id = (regs->cx << 16) | regs->dx; int count = regs->si; int bdf, max; foreachpci(bdf, max) { u32 v = pci_config_readl(bdf, PCI_VENDOR_ID); if (v != id) continue; if (count--) continue; regs->bx = bdf; set_code_success(regs); return; }
// find pci device static void handle_1ab102(struct bregs *regs) { u32 id = (regs->cx << 16) | regs->dx; int count = regs->si; int bus = -1; while (bus < GET_GLOBAL(MaxPCIBus)) { bus++; int bdf; foreachbdf(bdf, bus) { u32 v = pci_config_readl(bdf, PCI_VENDOR_ID); if (v != id) continue; if (count--) continue; regs->bx = bdf; set_code_success(regs); return; } }
static void init_pvscsi(struct pci_device *pci) { struct pvscsi_ring_dsc_s *ring_dsc = NULL; int i; u16 bdf = pci->bdf; void *iobase = (void*)(pci_config_readl(pci->bdf, PCI_BASE_ADDRESS_0) & PCI_BASE_ADDRESS_MEM_MASK); pci_config_maskw(bdf, PCI_COMMAND, 0, PCI_COMMAND_MASTER); dprintf(1, "found pvscsi at %02x:%02x.%x, io @ %p\n", pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf), pci_bdf_to_fn(bdf), iobase); pvscsi_write_cmd_desc(iobase, PVSCSI_CMD_ADAPTER_RESET, NULL, 0); pvscsi_init_rings(iobase, &ring_dsc); for (i = 0; i < 7; i++) pvscsi_scan_target(pci, iobase, ring_dsc, i); return; }
int bochsvga_setup(void) { int ret = stdvga_setup(); if (ret) return ret; /* Sanity checks */ dispi_write(VBE_DISPI_INDEX_ID, VBE_DISPI_ID0); if (dispi_read(VBE_DISPI_INDEX_ID) != VBE_DISPI_ID0) { dprintf(1, "No VBE DISPI interface detected, falling back to stdvga\n"); return 0; } dispi_write(VBE_DISPI_INDEX_ID, VBE_DISPI_ID5); SET_VGA(dispi_found, 1); if (GET_GLOBAL(HaveRunInit)) return 0; u32 lfb_addr = VBE_DISPI_LFB_PHYSICAL_ADDRESS; int bdf = GET_GLOBAL(VgaBDF); if (CONFIG_VGA_PCI && bdf >= 0) { u16 vendor = pci_config_readw(bdf, PCI_VENDOR_ID); int barid; switch (vendor) { case 0x15ad: /* qemu vmware vga */ barid = 1; break; case 0x1af4: /* virtio-vga */ barid = 2; break; default: /* stdvga, qxl */ barid = 0; break; } u32 bar = pci_config_readl(bdf, PCI_BASE_ADDRESS_0 + barid * 4); lfb_addr = bar & PCI_BASE_ADDRESS_MEM_MASK; dprintf(1, "VBE DISPI: bdf %02x:%02x.%x, bar %d\n", pci_bdf_to_bus(bdf) , pci_bdf_to_dev(bdf), pci_bdf_to_fn(bdf), barid); } SET_VGA(VBE_framebuffer, lfb_addr); u32 totalmem = dispi_read(VBE_DISPI_INDEX_VIDEO_MEMORY_64K) * 64 * 1024; SET_VGA(VBE_total_memory, totalmem); SET_VGA(VBE_win_granularity, 64); SET_VGA(VBE_capabilities, VBE_CAPABILITY_8BIT_DAC); dprintf(1, "VBE DISPI: lfb_addr=%x, size %d MB\n", lfb_addr, totalmem >> 20); // Validate modes u16 en = dispi_read(VBE_DISPI_INDEX_ENABLE); dispi_write(VBE_DISPI_INDEX_ENABLE, en | VBE_DISPI_GETCAPS); u16 max_xres = dispi_read(VBE_DISPI_INDEX_XRES); u16 max_bpp = dispi_read(VBE_DISPI_INDEX_BPP); dispi_write(VBE_DISPI_INDEX_ENABLE, en); struct bochsvga_mode *m = bochsvga_modes; for (; m < &bochsvga_modes[ARRAY_SIZE(bochsvga_modes)]; m++) { u16 width = GET_GLOBAL(m->info.width); u16 height = GET_GLOBAL(m->info.height); u8 depth = GET_GLOBAL(m->info.depth); u32 mem = (height * DIV_ROUND_UP(width * vga_bpp(&m->info), 8) * stdvga_vram_ratio(&m->info)); if (width > max_xres || depth > max_bpp || mem > totalmem) { dprintf(1, "Removing mode %x\n", GET_GLOBAL(m->mode)); SET_VGA(m->mode, 0xffff); } } return 0; }
void smm_init() { if (CONFIG_COREBOOT) // SMM only supported on emulators. return; if (!CONFIG_USE_SMM) return; dprintf(3, "init smm\n"); // This code is hardcoded for PIIX4 Power Management device. int bdf = pci_find_device(PCI_VENDOR_ID_INTEL , PCI_DEVICE_ID_INTEL_82371AB_3); if (bdf < 0) // Device not found return; int i440_bdf = pci_find_device(PCI_VENDOR_ID_INTEL , PCI_DEVICE_ID_INTEL_82441); if (i440_bdf < 0) return; /* check if SMM init is already done */ u32 value = pci_config_readl(bdf, 0x58); if (value & (1 << 25)) return; /* enable the SMM memory window */ pci_config_writeb(i440_bdf, 0x72, 0x02 | 0x48); /* save original memory content */ memcpy((void *)BUILD_SMM_ADDR, (void *)BUILD_SMM_INIT_ADDR, BUILD_SMM_SIZE); /* copy the SMM relocation code */ memcpy((void *)BUILD_SMM_INIT_ADDR, &smm_relocation_start, &smm_relocation_end - &smm_relocation_start); /* enable SMI generation when writing to the APMC register */ pci_config_writel(bdf, 0x58, value | (1 << 25)); /* init APM status port */ outb(0x01, PORT_SMI_STATUS); /* raise an SMI interrupt */ outb(0x00, PORT_SMI_CMD); /* wait until SMM code executed */ while (inb(PORT_SMI_STATUS) != 0x00) ; /* restore original memory content */ memcpy((void *)BUILD_SMM_INIT_ADDR, (void *)BUILD_SMM_ADDR, BUILD_SMM_SIZE); /* copy the SMM code */ memcpy((void *)BUILD_SMM_ADDR, &smm_code_start , &smm_code_end - &smm_code_start); wbinvd(); /* close the SMM memory window and enable normal SMM */ pci_config_writeb(i440_bdf, 0x72, 0x02 | 0x08); }