diff options
Diffstat (limited to 'driver')
| -rw-r--r-- | driver/e1000.c | 262 | ||||
| -rw-r--r-- | driver/keyboard.c | 46 | ||||
| -rw-r--r-- | driver/pci.c | 6 |
3 files changed, 219 insertions, 95 deletions
diff --git a/driver/e1000.c b/driver/e1000.c index 8233993..35e106e 100644 --- a/driver/e1000.c +++ b/driver/e1000.c @@ -1,10 +1,49 @@ //https://github.com/blanham/ChickenOS/blob/master/src/device/net/e1000.c //https://wiki.osdev.org/Intel_Ethernet_i217 +//https://github.com/torvalds/linux/blob/master/drivers/net/ethernet/intel/e1000/e1000_hw.c +//https://github.com/qemu/qemu/blob/master/hw/net/e1000.c +//registers etc. verified from pdf at https://pdos.csail.mit.edu/6.828/2006/readings/hardware/8254x_GBe_SDM.pdf + #include <stdint.h> #include "log.h" #include "e1000.h" #include "kmalloc.h" +#define REG_CTRL 0x0000 // device control R/W +#define REG_CTRL_LRST 1<<3 // Link Reset / transition to 0 to initiates auto-negotiation +#define REG_CTRL_SLU 1<<6 // Set Link Up / signal forced + +#define REG_STATUS 0x0008 // device status R + +#define REG_EERD 0x0014 // EEPROM / R + +#define REG_ICR 0x00C0 // interrupt cause / (reading clears) / R +#define REG_IMS 0x00D0 // interrupt mask / R/W + +// RECEIVE + +#define REG_RCTL 0x0100 // Receive Control R/W +#define REG_RDBAL 0x2800 +#define REG_RDBAH 0x2804 +#define REG_RDLEN 0x2808 +#define REG_RDH 0x2810 +#define REG_RDT 0x2818 + +#define REG_MTA 0x5200 // multicast table array + +/// TRANSMIT + +#define REG_TCTL 0x0400 // Transmit Control R/W +#define REG_TDBAL 0x3800 +#define REG_TDBAH 0x3804 +#define REG_TDLEN 0x3808 +#define REG_TDH 0x3810 +#define REG_TDT 0x3818 + +// check? +#define TSTA_DD (1 << 0) // Descriptor Done +/* +/// #define INTEL_VEND 0x8086 // Vendor ID for Intel #define E1000_DEV 0x100E // Device ID for the e1000 Qemu, Bochs, and VirtualBox emmulated NICs #define E1000_I217 0x153A // Device ID for Intel I217 @@ -13,36 +52,20 @@ // I have gathered those from different Hobby online operating systems instead of getting them one by one from the manual -#define REG_CTRL 0x0000 -#define REG_ICR 0x00C0 // interrupt cause register -#define REG_STATUS 0x0008 -#define REG_EEPROM 0x0014 #define REG_CTRL_EXT 0x0018 -#define REG_IMASK 0x00D0 -#define REG_RCTRL 0x0100 -#define REG_RXDESCLO 0x2800 -#define REG_RXDESCHI 0x2804 -#define REG_RXDESCLEN 0x2808 -#define REG_RXDESCHEAD 0x2810 -#define REG_RXDESCTAIL 0x2818 - -#define REG_TCTRL 0x0400 -#define REG_TXDESCLO 0x3800 -#define REG_TXDESCHI 0x3804 -#define REG_TXDESCLEN 0x3808 -#define REG_TXDESCHEAD 0x3810 -#define REG_TXDESCTAIL 0x3818 -#define REG_RDTR 0x2820 // RX Delay Timer Register + #define REG_RXDCTL 0x3828 // RX Descriptor Control + +#define REG_RDTR 0x2820 // RX Delay Timer Register #define REG_RADV 0x282C // RX Int. Absolute Delay Timer #define REG_RSRPD 0x2C00 // RX Small Packet Detect Interrupt -#define REG_TIPG 0x0410 // Transmit Inter Packet Gap -#define ECTRL_SLU 0x40 //set link up +#define REG_TIPG 0x0410 // Transmit Inter Packet Gap +#define CTRL_SLU 0x40 //set link up #define RCTL_EN (1 << 1) // Receiver Enable @@ -101,22 +124,26 @@ #define TSTA_EC (1 << 1) // Excess Collisions #define TSTA_LC (1 << 2) // Late Collision #define LSTA_TU (1 << 3) // Transmit Underrun +*/ // buffers #define E1000_NUM_RX_DESC 32 #define E1000_NUM_TX_DESC 8 struct e1000_rx_desc { - volatile uint64_t addr; - volatile uint16_t length; - volatile uint16_t checksum; - volatile uint8_t status; - volatile uint8_t errors; - volatile uint16_t special; + volatile uint32_t addr_lo; // 4 + volatile uint32_t addr_hi; // 4 + volatile uint16_t length; // 2 + volatile uint16_t checksum; // 2 + volatile uint8_t status; // 1 + volatile uint8_t errors; // 1 + volatile uint16_t special; // 2 + // sum: 16 byte } __attribute__((packed)); struct e1000_tx_desc { - volatile uint64_t addr; + volatile uint32_t addr_lo; // 4 + volatile uint32_t addr_hi; // 4 volatile uint16_t length; volatile uint8_t cso; volatile uint8_t cmd; @@ -151,6 +178,18 @@ void writeCommand( uint16_t p_address, uint32_t p_value) // } } +void writeCommand16( uint16_t p_address, uint16_t p_value) +{ +// if ( bar_type == 0 ) +// { + (*((volatile uint16_t*)(mem_base+p_address)))=(p_value); +// } +// else +// { + //outportl(io_base, p_address); + //outportl(io_base + 4, p_value); +// } +} uint32_t readCommand( uint16_t p_address) { // if ( bar_type == 0 ) @@ -167,11 +206,11 @@ uint32_t readCommand( uint16_t p_address) bool detectEEProm() { uint32_t val = 0; - writeCommand(REG_EEPROM, 0x1); + writeCommand(REG_EERD, 0x1); for(int i = 0; i < 1000 && ! eerprom_exists; i++) { - val = readCommand( REG_EEPROM); + val = readCommand( REG_EERD); if(val & 0x10) eerprom_exists = true; else @@ -188,13 +227,13 @@ uint32_t eepromRead( uint8_t addr) uint32_t tmp = 0; if ( eerprom_exists) { - writeCommand( REG_EEPROM, (1) | ((uint32_t)(addr) << 8) ); - while( !((tmp = readCommand(REG_EEPROM)) & (1 << 4)) ); + writeCommand( REG_EERD, (1) | ((uint32_t)(addr) << 8) ); + while( !((tmp = readCommand(REG_EERD)) & (1 << 4)) ); } else { - writeCommand( REG_EEPROM, (1) | ((uint32_t)(addr) << 2) ); - while( !((tmp = readCommand(REG_EEPROM)) & (1 << 1)) ); + writeCommand( REG_EERD, (1) | ((uint32_t)(addr) << 2) ); + while( !((tmp = readCommand(REG_EERD)) & (1 << 1)) ); } data = (uint16_t)((tmp >> 16) & 0xFFFF); return data; @@ -240,16 +279,16 @@ void rxinit() // Allocate buffer for receive descriptors. For simplicity, in my case khmalloc returns a virtual address that is identical to it physical mapped address. // In your case you should handle virtual and physical addresses as the addresses passed to the NIC should be physical onesk - uint32_t alloc_pages=1+(sizeof(struct e1000_rx_desc)*E1000_NUM_RX_DESC + 16)/4096; - - ptr = kballoc(alloc_pages); + ptr = kballoc(1); // one page can hold up to 256 descriptors. descs = (struct e1000_rx_desc *)ptr; for(int i = 0; i < E1000_NUM_RX_DESC; i++) { - rx_descs[i] = (struct e1000_rx_desc *)((uint8_t *)descs + i*16); - rx_descs[i]->addr = kballoc(3); // what a waste :( TODO! - rx_descs[i]->status = 0; + rx_descs[i] = descs; + rx_descs[i]->addr_lo = kballoc(1); //TODO: do not waste! + rx_descs[i]->addr_hi = 0; + rx_descs[i]->status = 0; + descs++; } /* @@ -260,66 +299,93 @@ void rxinit() writeCommand(REG_TXDESCHI, (uint32_t)(ptr)); */ - writeCommand(REG_RXDESCLO, ptr); - writeCommand(REG_RXDESCHI, 0); - - writeCommand(REG_RXDESCLEN, E1000_NUM_RX_DESC * 16); - - writeCommand(REG_RXDESCHEAD, 0); - writeCommand(REG_RXDESCTAIL, E1000_NUM_RX_DESC-1); + + writeCommand(REG_RDBAL, ptr); + writeCommand(REG_RDBAH, 0); + + writeCommand(REG_RDLEN, E1000_NUM_RX_DESC * 16); // size of ALL descirptors in bytes + + writeCommand(REG_RDT, E1000_NUM_RX_DESC); // index of one after last descirptor + writeCommand(REG_RDH, 0); // first valid descirptor index + rx_cur = 0; //enable receiving - //uint32_t flags = (2 << 16) | (1 << 25) | (1 << 26) | (1 << 15) | (1 << 5) | (0 << 8) | (0 << 4) | (0 << 3) | ( 1 << 2); - //writeCommand(REG_RCTRL, flags); - writeCommand(REG_RCTRL, RCTL_EN| RCTL_SBP| RCTL_UPE | RCTL_MPE | RCTL_LBM_NONE | RTCL_RDMTS_HALF | RCTL_BAM | RCTL_SECRC | RCTL_BSIZE_2048); - + /* + uint32_t flags = (2 << 16) | (1 << 25) | (1 << 26) + | (1 << 15) | (1 << 5) | (0 << 8) + | (0 << 4) | (0 << 3) | ( 1 << 2) | 1; + */ +// writeCommand(REG_RCTRL, flags); + +// writeCommand(REG_RCTRL, RCTL_EN| RCTL_SBP| RCTL_UPE | RCTL_MPE | RCTL_LBM_NONE | RTCL_RDMTS_HALF | RCTL_BAM | RCTL_SECRC | RCTL_BSIZE_2048); + + + writeCommand(REG_RCTL, + 1<<1 // receive enable // RCTL.EN + |1<<3 // take all unicast + |1<<4 // take all multicast + |1<<15 // take broadcast // RCTL.BAM + |2<<16 // 512 bytes rcv buffers // TCTL.BSIZE + // RDTMS + // MO + // + ); + + + /* + for(int i = 0; i < E1000_NUM_RX_DESC; i++) + { + klog("rx_desc %d (0x%08X) at addr %08X %08X, status= %d",i,rx_descs[i],rx_descs[i]->addr_hi,rx_descs[i]->addr_lo, rx_descs[i]->status); + } + */ } void txinit() -{ +{ uint8_t * ptr; // Allocate buffer for receive descriptors. For simplicity, in my case khmalloc returns a virtual address that is identical to it physical mapped address. // In your case you should handle virtual and physical addresses as the addresses passed to the NIC should be physical ones - - uint32_t alloc_pages=1+(sizeof(struct e1000_tx_desc)*E1000_NUM_TX_DESC + 16)/4096; - ptr = kballoc(alloc_pages); + ptr = kballoc(1); struct e1000_tx_desc *descs=ptr; for(int i = 0; i < E1000_NUM_TX_DESC; i++) { tx_descs[i] = descs++; - tx_descs[i]->addr = 0; + tx_descs[i]->addr_lo = 0; + tx_descs[i]->addr_hi = 0; tx_descs[i]->cmd = 0; tx_descs[i]->status = TSTA_DD; } - writeCommand(REG_TXDESCLO, ptr); //physical here - writeCommand(REG_TXDESCHI, 0); + writeCommand(REG_TDBAL, ptr); + writeCommand(REG_TDBAH, 0); //now setup total length of descriptors - writeCommand(REG_TXDESCLEN, E1000_NUM_TX_DESC * 16); // + writeCommand(REG_TDLEN, E1000_NUM_TX_DESC * 16); // - //setup numbers - writeCommand( REG_TXDESCHEAD, 0); - writeCommand( REG_TXDESCTAIL, 0); - tx_cur = 0; + //setup head and tail + writeCommand( REG_TDH, 0); + writeCommand( REG_TDT, 0); - + tx_cur = 0; + + /* writeCommand(REG_TCTRL, TCTL_EN | TCTL_PSP | (15 << TCTL_CT_SHIFT) | (64 << TCTL_COLD_SHIFT) | TCTL_RTLC); -/* - writeCommand(REG_TCTRL, - 1<<0 // enable transmitter + */ + + writeCommand(REG_TCTL, + 1<<1 // enable transmitter |1<<3 // pad short packets // ,64<<12 // collision distance ); - */ + // This line of code overrides the one before it but I left both to // highlight that the previous one works with e1000 cards, but for the // e1000e cards you should set the TCTRL register as follows. For detailed @@ -327,6 +393,8 @@ void txinit() // of I217 and 82577LM packets will not be sent if the TCTRL is not // configured using the following bits. + // TODO: programm tipg + // //writeCommand(REG_TCTRL, 0b0110000000000111111000011111010); //writeCommand(REG_TIPG, 0x0060200A); @@ -337,11 +405,11 @@ void e1000_handleReceive() uint16_t old_cur; bool got_packet = false; - while((rx_descs[rx_cur]->status & 0x1)) + while((rx_descs[rx_cur]->status !=0)) { got_packet = true; klog("GOT FIRST PACKET WOOOOW"); - uint8_t *buf = (uint8_t *)(uint32_t)rx_descs[rx_cur]->addr; + uint8_t *buf = (uint8_t *)(uint32_t)rx_descs[rx_cur]->addr_lo; uint16_t len = rx_descs[rx_cur]->length; // Here you should inject the received packet into your network stack @@ -349,13 +417,13 @@ void e1000_handleReceive() rx_descs[rx_cur]->status = 0; old_cur = rx_cur; rx_cur = (rx_cur + 1) % E1000_NUM_RX_DESC; - writeCommand(REG_RXDESCTAIL, old_cur ); + writeCommand(REG_RDT, old_cur ); } } int e1000_sendPacket(const void * p_data, uint16_t p_len) { - tx_descs[tx_cur]->addr = p_data; // physical addy of data + tx_descs[tx_cur]->addr_lo = p_data; // physical addy of data tx_descs[tx_cur]->length = p_len; // length in bytes //tx_descs[tx_cur]->cmd = CMD_EOP | CMD_IFCS | CMD_RS | CMD_RPS; tx_descs[tx_cur]->cmd = ((1<<3)|3); @@ -363,7 +431,7 @@ int e1000_sendPacket(const void * p_data, uint16_t p_len) uint8_t old_cur = tx_cur; tx_cur = (tx_cur + 1) % E1000_NUM_TX_DESC; - writeCommand(REG_TXDESCTAIL, tx_cur); + writeCommand(REG_TDT, tx_cur); while(!(tx_descs[old_cur]->status & 0xff)); klog("SENT FIRST PACKET WOOOOW"); return 0; @@ -377,44 +445,60 @@ void enableInterrupt() // writeCommand(REG_IMASK ,0x1F6DC); // writeCommand(REG_IMASK ,0xff & ~4); - writeCommand(REG_IMASK,0xffffffff); +// RXT, RXO, RXDMT,RXSEQ, and LSC suugestef for rec. + writeCommand(REG_IMS, + 1<<6 // RXO // fifo overrun + |1<<7 // RXT0 // receiver timer + |1<<4 // RXDMT0 // min. threshold + |1<<3 // RXSEQ // sequence error + |1<<2 // LSC // link status change + ); +// readCommand(REG_ICR); // clear cause reg? } +// force link up void e1000_linkup() { uint32_t val; val = readCommand(REG_CTRL); - writeCommand(REG_CTRL, val | ECTRL_SLU); + writeCommand(REG_CTRL, val | REG_CTRL_SLU); } void e1000_linkdown() { uint32_t val; val = readCommand(REG_CTRL); - writeCommand(REG_CTRL, val | ~ECTRL_SLU); + writeCommand(REG_CTRL, val | REG_CTRL_SLU); } bool e1000_init(uint32_t base) { klog("init E1000"); - if(base!=0){ mem_base=base; return true;} + klog("interrupt mask: 0x%08X",readCommand(REG_IMS)); + klog("device status: 0x%08X",readCommand(REG_STATUS)); + klog("control: 0x%08X",readCommand(REG_CTRL)); +// uint32_t s=readCommand(REG_CTRL)&~REG_CTRL_LRST; + // klog("set control: 0x%08X",s); + //writeCommand(REG_CTRL,s); + + if(base!=0){ mem_base=base;} detectEEProm(); if (! readMACAddress()) return false; klog("mac : %02x:%02x:%02x:%02x:%02x:%02x",mac[0],mac[1],mac[2],mac[3],mac[4],mac[5],mac[6]); -// e1000_linkup(); + // clear multicast table + for(int i = 0; i < 0x80; i++)writeCommand(REG_MTA + i*4, 0); - for(int i = 0; i < 0x80; i++)writeCommand(0x5200 + i*4, 0); + //e1000_linkup(); enableInterrupt(); txinit(); rxinit(); - klog("E1000 initialized"); return true; @@ -427,16 +511,28 @@ void e1000_irq (int irq) * from each device and must be done before EOI if using the PIC. Without this, the card will spam interrupts as the int-line will stay high. */ - //writeCommand(REG_IMASK, 0x1); //enableInterrupt(); - int status =0; -// uint32_t status = readCommand(REG_ICR); // check interrupt cause register. + + // check interrupt cause register. + // this acknowledges the interrupt at the same time. + uint32_t status = readCommand(REG_ICR); + /* klog("e1000_irq status=%d",status); + klog("rx descriptor head is at: %d", readCommand(REG_RDH)); + klog("rx descriptor tail is at: %d", readCommand(REG_RDT)); + + klog("rx descriptor addr lo: 0x%08X", readCommand(REG_RDBAL)); + klog("rx descriptor addr hi: 0x%08X", readCommand(REG_RDBAH)); + klog("rx descriptor len: 0x%08X", readCommand(REG_RDLEN)); + if(status & 0x1) klog ("transmit descriptor written back"); if(status & 0x2) klog ("transmit queue empty"); if(status & 0x4) klog ("link status change"); if(status & 0x8) klog ("receive sequence error"); + if(status & 1<<6) klog ("fifo overrun"); + */ + if(status & 0x80)e1000_handleReceive(); //... } diff --git a/driver/keyboard.c b/driver/keyboard.c index 90a18c9..d6ce465 100644 --- a/driver/keyboard.c +++ b/driver/keyboard.c @@ -3,6 +3,7 @@ #include "syscalls.h" #include "log.h" #include "e1000.h" +#include "kmalloc.h" #include <stdbool.h> @@ -14,20 +15,41 @@ static bool capslock=false; static uint32_t kb_stream; static char num_syms[]={')','!','@','#','$','%','^','&','*','('}; +int hex_to_dec(char c) +{ + if(c>='0'&&c<='9')return c-'0'; + return c+10-'a'; + +} static void put(uint8_t c) { - uint16_t dat[]={ - 0x00,0xff,0xff,0xff,0xff,0xff,0xff,0x52,0x5,0x50a,0x00,0x02,0x02,0x08,0x06,0x00, - 0x01,0x08,0x00,0x06,0x04,0x00,0x01,0x52,0x5,0x50a,0x00,0x02,0x02,0x0a,0x00,0x02, - 0x00,0xff,0xff,0xff,0xff,0xff,0xff,0x52,0x5,0x50a,0x00,0x02,0x02,0x08,0x06,0x00, - 0x01,0x08,0x00,0x06,0x04,0x00,0x01,0x52,0x5,0x50a,0x00,0x02,0x02,0x0a,0x00,0x02 - }; - - if(c=='p')e1000_sendPacket(dat,64); // packet - if(c=='s')e1000_init(0); // start - if(c=='i')e1000_irq(11); // interrupt - if(c=='u')e1000_linkup(); // up - if(c=='d')e1000_linkdown(); // down + /* +0000 8a b1 aa 7e 4d 00 52 54 00 12 34 56 08 00 45 00 +0010 00 54 1e c0 00 00 40 01 da 1f c0 a8 00 14 c0 a8 +0020 00 65 00 00 ce 07 1f 02 03 b0 bf 79 a9 5b 00 00 +0030 00 00 df 9d 08 00 00 00 00 00 10 11 12 13 14 15 +0040 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 +0050 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 +0060 36 37 +*/ + + static char data_raw[]="8ab1aa7e4d005254001234560800450000541ec000004001da1fc0a80014c0a800650000ce071f0203b0bf79a95b00000000df9d080000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637"; + static uint8_t data[256];//=kballoc(1); + int i=0; + + while(data_raw[i]!=0) + { + uint8_t val=hex_to_dec(data_raw[i])*16+hex_to_dec(data_raw[i+1]); + data[i/2]=val; + i+=2; + } + + + if(c=='p')e1000_sendPacket(data,i/2); // packet +// if(c=='s')e1000_init(0); // start + // if(c=='i')e1000_irq(11); // interrupt + // if(c=='u')e1000_linkup(); // up + //if(c=='d')e1000_linkdown(); // down syscall_generic(SYSCALL_WRITE,kb_stream, (char *)&c , 1, 0); } diff --git a/driver/pci.c b/driver/pci.c index b5e5791..79f3e24 100644 --- a/driver/pci.c +++ b/driver/pci.c @@ -98,6 +98,7 @@ uint16_t pciCheck(uint8_t bus, uint8_t slot) irq = pciConfigReadWord(bus,slot,0,0x3c); uint8_t header = pciConfigReadWord(bus,slot,0,0xd)&0xff; + klog("[%d,%d]: vendor: 0x%x / device: 0x%x",bus,slot,vendor,device); klog("header_typ=%x, %d,pin=%d , irq=%d",header,irq,irq&0xFf00,irq&0xFf); @@ -105,6 +106,11 @@ uint16_t pciCheck(uint8_t bus, uint8_t slot) // check for: E1000 (82540EM). PCI Ethernet Controller if(vendor==0x8086&&device==0x100e) { + uint16_t command = pciConfigReadWord(bus,slot,0,0x04); + pciConfigSet(bus,slot,0,0x04,command|1<<2); + command = pciConfigReadWord(bus,slot,0,0x04); + + klog("enable busmastering / command register: %04X",command); // uint16_t irq=pciConfigReadWord(bus,slot,0,0x3C); // uint16_t irq2=pciConfigReadWord(bus,slot,0,0x3E); // |
