diff options
| -rw-r--r-- | Makefile | 8 | ||||
| -rw-r--r-- | README.md | 2 | ||||
| -rw-r--r-- | kernel/e1000.c | 5 | ||||
| -rw-r--r-- | kernel/kernel.c | 3 | ||||
| -rw-r--r-- | kernel/pci.c | 175 |
5 files changed, 192 insertions, 1 deletions
@@ -38,6 +38,12 @@ vmem.o: kernel/vmem.c mem.o: kernel/mem.c gcc -ffreestanding -m32 -o $@ -c $< -fno-asynchronous-unwind-tables -O0 +e1000.o: kernel/e1000.c + gcc -ffreestanding -m32 -o $@ -c $< -fno-asynchronous-unwind-tables -O0 + +pci.o: kernel/pci.c + gcc -ffreestanding -m32 -o $@ -c $< -fno-asynchronous-unwind-tables -O0 + console.o: kernel/console.c kernel/console.h gcc -ffreestanding -m32 -o $@ -c $< -fno-asynchronous-unwind-tables -O0 @@ -53,7 +59,7 @@ timer.o: kernel/timer.c shell.o: kernel/shell.c gcc -ffreestanding -m32 -o $@ -c $< -fno-asynchronous-unwind-tables -O0 -kernel.bin: kernel_entry.o kernel.o console.o interrupts.o keyboard.o timer.o shell.o mem.o vmem.o +kernel.bin: kernel_entry.o kernel.o console.o interrupts.o keyboard.o timer.o shell.o mem.o vmem.o pci.o e1000.o ld -o $@ -Ttext 0x1000 --oformat binary -melf_i386 $^ -O0 @@ -110,6 +110,7 @@ TODOS * GNU HURD * MINIX * FreeBSD etc. + * xv6 (!) look at following linux drivers: * e1000 @@ -144,3 +145,4 @@ REFERENCES * http://www.jamesmolloy.co.uk/tutorial_html/9.-Multitasking.html * http://pdos.csail.mit.edu/6.828/2011/labs/lab6/ * http://wiki.osdev.org/Virtual_8086_Mode +* http://pdos.csail.mit.edu/6.828/2011/xv6.html diff --git a/kernel/e1000.c b/kernel/e1000.c new file mode 100644 index 0000000..800b771 --- /dev/null +++ b/kernel/e1000.c @@ -0,0 +1,5 @@ + +void init_e1000() +{ + scr_put_string_nl("initializing E1000 Intel PCI Ethernet Controller (TODO)"); +} diff --git a/kernel/kernel.c b/kernel/kernel.c index 7dd89f7..91634ec 100644 --- a/kernel/kernel.c +++ b/kernel/kernel.c @@ -71,6 +71,9 @@ void kernel_main() scr_put_string_nl("Interrupts are up and running"); scr_put_string_nl(""); + // pci + pci_init(); + //init shell shell_init(); diff --git a/kernel/pci.c b/kernel/pci.c new file mode 100644 index 0000000..6cf71f8 --- /dev/null +++ b/kernel/pci.c @@ -0,0 +1,175 @@ +#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); + + } + + } + +} |
