From: Joshua Wise Date: Fri, 26 Sep 2008 03:16:58 +0000 (-0400) Subject: Add PCI bus probe and enumeration routines. X-Git-Url: http://git.joshuawise.com/netwatch.git/commitdiff_plain/83a025567a37236fd819b30d12e32828d8fd2dc4?ds=inline;hp=--cc Add PCI bus probe and enumeration routines. --- 83a025567a37236fd819b30d12e32828d8fd2dc4 diff --git a/grubload/Makefile b/grubload/Makefile index 0ff596a..3c7e395 100644 --- a/grubload/Makefile +++ b/grubload/Makefile @@ -1,4 +1,4 @@ -OBJS=multiboot_c.o multiboot_asm.o realmode.o loader.o ../pci/pci-raw.o ../lib/minilib.o ../lib/console.o ../ich2/smram-ich2.o ../ich2/smi.o output.o ../lib/sprintf.o ../lib/doprnt.o +OBJS=multiboot_c.o multiboot_asm.o realmode.o loader.o ../pci/pci-raw.o ../lib/minilib.o ../lib/console.o ../ich2/smram-ich2.o ../ich2/smi.o output.o ../lib/sprintf.o ../lib/doprnt.o ../pci/pci.o CC=gcc CFLAGS=-nostdlib -I../include -I../include/raw -I. -D__RAW__ -fno-builtin -nostdinc -Wall -Werror -pedantic -std=gnu99 diff --git a/grubload/multiboot_c.c b/grubload/multiboot_c.c index 17c1542..372363c 100644 --- a/grubload/multiboot_c.c +++ b/grubload/multiboot_c.c @@ -54,7 +54,6 @@ void c_start(unsigned int magic, struct mb_info *mbinfo) outputf("Current USB state is: %04x %04x", pci_read16(0, 31, 2, 0xC0), pci_read16(0, 31, 4, 0xC0)); outputf("Current SMI state is: %08x", inl(0x830)); - smi_disable(); /* Try really hard to shut up USB_LEGKEY. */ @@ -62,6 +61,8 @@ void c_start(unsigned int magic, struct mb_info *mbinfo) pci_write16(0, 31, 2, 0xC0, 0); pci_write16(0, 31, 4, 0xC0, pci_read16(0, 31, 4, 0xC0)); pci_write16(0, 31, 4, 0xC0, 0); + + pci_bus_enum(); /* Open the SMRAM aperture and load our ELF. */ old_smramc = smram_save_state(); diff --git a/include/pci.h b/include/pci.h index 60b665f..313b3e0 100644 --- a/include/pci.h +++ b/include/pci.h @@ -16,4 +16,29 @@ uint32_t pci_read32(int bus, int slot, int fn, int addr); uint16_t pci_read16(int bus, int slot, int fn, int addr); uint8_t pci_read8(int bus, int slot, int fn, int addr); +/* Hardware-agnostic functions implemented by pci.c */ +typedef enum { + PCI_BAR_NONE = 0, + PCI_BAR_MEMORY32, + PCI_BAR_MEMORY64, + PCI_BAR_IO +} pci_bar_type_t; + +typedef struct pci_bar { + pci_bar_type_t type; + unsigned char prefetchable; + unsigned long addr; +} pci_bar_t; + +typedef struct pci_dev { + unsigned short vid, did; + int bus, dev, fn; + pci_bar_t bars[6]; +} pci_dev_t; + +typedef int (*pci_probe_fn_t)(pci_dev_t *); + +void pci_bus_enum(); +int pci_probe(pci_probe_fn_t probe); + #endif diff --git a/pci/pci.c b/pci/pci.c new file mode 100644 index 0000000..e5ab816 --- /dev/null +++ b/pci/pci.c @@ -0,0 +1,100 @@ +#include +#include + +int pci_probe(pci_probe_fn_t probe) +{ + int devsfound = 0; + pci_dev_t pdev; + unsigned int bus; + unsigned int dev; + unsigned int fn; + + for (bus = 0; bus < 0x100; bus++) + for (dev = 0; dev < 0x20; dev++) + if (pci_read32(bus, dev, 0, 0) != 0xFFFFFFFF) + for (fn = 0; fn < 8; fn++) + { + int bar; + + if (pci_read32(bus, dev, fn, 0) == 0xFFFFFFFF) + continue; + + if ((fn != 0) && !(pci_read8(bus, dev, 0, 0x0E) & 0x80)) + continue; + + pdev.bus = bus; + pdev.dev = dev; + pdev.fn = fn; + pdev.vid = pci_read16(bus, dev, fn, 0); + pdev.did = pci_read16(bus, dev, fn, 2); + + for (bar = 0; bar < 6; bar++) + { + unsigned long bardat = pci_read32(bus, dev, fn, 0x10 + bar*4); + if (bardat == 0) + { + pdev.bars[bar].type = PCI_BAR_NONE; + continue; + } + if (bardat & 1) + { + pdev.bars[bar].type = PCI_BAR_IO; + pdev.bars[bar].addr = bardat & ~0x3; + } else { + pdev.bars[bar].prefetchable = (bardat >> 3) & 1; + switch ((bardat >> 1) & 0x3) + { + case 0: + pdev.bars[bar].type = PCI_BAR_MEMORY32; + pdev.bars[bar].addr = bardat & ~0xF; + break; + case 2: + pdev.bars[bar].type = PCI_BAR_MEMORY64; + bar++; + pdev.bars[bar].type = PCI_BAR_NONE; + break; + default: + pdev.bars[bar].type = PCI_BAR_NONE; + continue; + } + } + } + + devsfound += probe(&pdev); + } + + return devsfound; +} + +static int _enumfn(pci_dev_t *pdev) +{ + int bar; + + outputf("Found device: %02x:%02x.%1x: %04X:%04X", + pdev->bus, pdev->dev, pdev->fn, + pdev->vid, pdev->did); + for (bar = 0; bar < 6; bar++) + { + switch (pdev->bars[bar].type) + { + case PCI_BAR_IO: + outputf(" BAR %d: I/O, Addr %04x", bar, pdev->bars[bar].addr); + break; + case PCI_BAR_MEMORY32: + outputf(" BAR %d: Mem32, Addr %04x", bar, pdev->bars[bar].addr); + break; + case PCI_BAR_MEMORY64: + outputf(" BAR %d: Mem64, Addr %04x", bar, pdev->bars[bar].addr); + break; + default: + break; + } + } + return 0; +} + +void pci_bus_enum() +{ + pci_probe(_enumfn); +} +