#include "kernel.h" #define PCI_CONFIG_DATA 0xCFC #define PCI_CONFIG_ADDRESS 0xCF8 void OutPort(unsigned short int IO_port,char Value) { asm("outb %%al,%%dx;" : //no output data :"d"(IO_port),"a"(Value) //input data (EDX<-IO_port; AL<-Value) ); } char InPort(unsigned short int IO_port) { asm("inb %%dx,%%al;" : //output data is in al register :"d"(IO_port) //input data (EDX<-IO_port AL<-Value) ); } x86_outl(int port, uint32_t data) { __asm __volatile("outl %0,%w1" : : "a" (data), "d" (port)); } x86_inl(int port) { uint32_t data; __asm __volatile("inl %w1,%0" : "=a" (data) : "d" (port)); return data; } void pciConfigSet (uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset, uint32_t data) { uint32_t address; uint32_t lbus = (uint32_t)bus; uint32_t lslot = (uint32_t)slot; uint32_t lfunc = (uint32_t)func; uint16_t tmp = 0; /* create configuration address as per Figure 1 */ address = (uint32_t)((lbus << 16) | (lslot << 11) | (lfunc << 8) | (offset & 0xfc) | ((uint32_t)0x80000000)); /* write out the address */ x86_outl (0xCF8, address); x86_outl (0xCFC,data); } uint16_t pciConfigReadWord (uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset) { uint32_t address; uint32_t lbus = (uint32_t)bus; uint32_t lslot = (uint32_t)slot; uint32_t lfunc = (uint32_t)func; uint16_t tmp = 0; /* create configuration address as per Figure 1 */ address = (uint32_t)((lbus << 16) | (lslot << 11) | (lfunc << 8) | (offset & 0xfc) | ((uint32_t)0x80000000)); /* write out the address */ x86_outl (0xCF8, address); /* read in the data */ /* (offset & 2) * 8) = 0 will choose the first word of the 32 bits register */ tmp = (uint16_t)((x86_inl (0xCFC) >> ((offset & 2) * 8)) & 0xffff); return (tmp); } void test_bar(uint8_t bus, uint8_t slot, uint8_t offset) { uint16_t bar_low=pciConfigReadWord(bus,slot,0,offset); uint16_t bar_high=pciConfigReadWord(bus,slot,0,offset+2); // check size pciConfigSet(bus,slot,0,offset,0xffffffff); uint16_t size_low=pciConfigReadWord(bus,slot,0,offset); uint16_t size_high=pciConfigReadWord(bus,slot,0,offset+2); uint32_t size=(size_high<<16)+size_low; size=~size; size++; // // restore original values pciConfigSet(bus,slot,0,offset,(bar_high<<16)+bar_low); scr_put_string("BAR: "); if(bar_low& 1)scr_put_string("i/o "); else scr_put_string("mem "); scr_put_hex(bar_high); scr_put_hex(bar_low); scr_put_string(" size: "); scr_put_hex(size_high); scr_put_hex(size_low); scr_put_string(" => "); scr_put_hex32(size); scr_put_string_nl(";"); } uint16_t pciCheck(uint8_t bus, uint8_t slot) { uint16_t vendor, device; /* try and read the first configuration register. Since there are no */ /* vendors that == 0xFFFF, it must be a non-existent device. */ if ((vendor = pciConfigReadWord(bus,slot,0,0)) != 0xFFFF) { device = pciConfigReadWord(bus,slot,0,2); scr_put_hex(vendor); scr_put_hex(device); scr_put_string_nl(";"); // check for: E1000 (82540EM). PCI Ethernet Controller if(vendor==0x8086&&device==0x100e) { // uint16_t irq=pciConfigReadWord(bus,slot,0,0x3C); // uint16_t irq2=pciConfigReadWord(bus,slot,0,0x3E); test_bar(bus,slot,0x10); test_bar(bus,slot,0x14); test_bar(bus,slot,0x18); // scr_put_hex(irq); // scr_put_hex(irq2); // scr_put_string_nl(";"); init_e1000(); } } return (vendor); } void pci_init() { scr_put_string_nl("scanning pci bus"); // todo: recurse on pci to pci bridges! // todo: support multiple pci host controllers! // (check more funcitons of device 0:0) uint16_t bus; uint8_t device; for(bus = 0; bus < 256; bus++) { for(device = 0; device < 32; device++) { pciCheck(bus, device); } } }