Built a basic framework for sending ethernet packets from userland. Switched from...
authorPaul Pearce <pearce@eecs.berkeley.edu>
Sat, 13 Jun 2009 04:50:39 +0000 (21:50 -0700)
committerKevin Klues <klueska@eecs.berkeley.edu>
Wed, 1 Jul 2009 20:32:50 +0000 (13:32 -0700)
Built a syscall framework called sys_eth_write/read that sends and receives packets. It does this by (stupidly) wrapping the data to send with
hard coded ETH/IP/UDP headers, and pushing it out on the NIC. There is currently no mechinism for receiving packets, as userland interrupts are not
working, and those are required for incoming notification. This current version will send properly formatted UDP packets out on the wire.

I also modified newlib_backend to use this new medium, and (for debugging) reenabled the hacks on isatty and fstat to make printf not go over the wire.

I also merged back in the code to switch  to the user enviroment, and run matrix.c.

.gitignore
include/rl8168.h
include/ros/syscall.h
kern/src/Makefrag
kern/src/manager.c
kern/src/rl8168.c
kern/src/syscall.c
user/parlib/inc/parlib.h
user/parlib/src/newlib_backend.c
user/parlib/src/syscall.c

index 4d280de..319d2a2 100644 (file)
@@ -13,3 +13,4 @@ hdd.img
 Makelocal
 ne2k*
 .textmate*
+.DS_*
index b2a6fa3..9c6ec4b 100644 (file)
 
 #include <arch/types.h>
 #include <trap.h>
+#include <pmap.h>
+
+#define nic_debug(...)  cprintf(__VA_ARGS__)  
+#define nic_interrupt_debug(...)  cprintf(__VA_ARGS__)  
+#define nic_packet_debug(...)  cprintf(__VA_ARGS__)  
+
+
+#define MK_CONFIG_ADDR(BUS, DEV, FUNC, REG) (unsigned long)( (BUS << 16) | (DEV << 11) | \
+                                                             (FUNC << 8) | REG  | \
+                                                             ((uint32_t)0x80000000))
+#define PCI_CONFIG_ADDR     0xCF8
+#define PCI_CONFIG_DATA     0xCFC
+
+#define REALTEK_VENDOR_ID   0x10ec
+#define INVALID_VENDOR_ID   0xFFFF
+#define REALTEK_DEV_ID      0x8168
+
+#define PCI_IO_MASK         0xFFF8
+#define PCI_MEM_MASK        0xFFFFFFF0
+#define PCI_IRQ_MASK           0xFF
+#define PCI_VENDOR_MASK                0xFFFF
+#define PCI_DEVICE_OFFSET      0x10
+#define PCI_IRQ_REG                    0x3c
+
+#define PCI_MAX_BUS                    256
+#define PCI_MAX_DEV                    32
+#define PCI_BAR_IO_MASK                0x1
+
+#define RL_CTRL_RESET_MASK  0x10
+#define RL_CTRL_RXTX_MASK      0x0C
+
+#define RL_HWREV_REG           0x40
+#define RL_HWREV_MASK          0x7C800000
+
+#define RL_MAC_OFFSET          0x0
+
+#define RL_CTRL_REG         0x37
+#define RL_IM_REG                      0x3c
+#define RL_IS_REG                      0x3E
+#define RL_EP_CTRL_REG         0x50
+#define RL_RX_CFG_REG          0x44
+#define RL_TX_CFG_REG          0x40
+#define RL_RX_MXPKT_REG     0xDA
+#define RL_TX_MXPKT_REG     0xEC
+#define RL_RX_DES_REG       0xE4
+#define RL_TX_DES_REG       0x20
+#define RL_TX_CTRL_REG         0x38                    
+
+#define RL_RX_MAX_SIZE         0x1000 // This is in units of bytes. 0x1000 = 4096
+
+// !!!!!!!!! need to verify the 128byte nature of this field. Spec says it could be 32 for some chips.
+#define RL_TX_MAX_SIZE         0x20   // This is in units of 128bytes, 128 * 0x20 = 4096
+#define RL_EP_CTRL_UL_MASK     0xC0
+#define RL_EP_CTRL_L_MASK      0x00
+
+#define RL_TX_SEND_MASK                0x40
+
+// NOTE: THESE SHOULD BE BROKEN DOWN INTO A SERIES OF BITS TO REPERSENT THE VARIOUS OPTIONS
+// AND THEN THE MASK SHOULD BE DEFINED TO BE AN OR OF THOSE BITS. THIS IS A QUICK HACK JOB.
+#define RL_RX_CFG_MASK         0x0000E70F  // RXFTH: unlimited, MXDMA: unlimited, AAP: set (promisc. mode set)
+#define RL_TX_CFG_MASK         0x3000700  // IFG: normal, MXDMA: unlimited.  crc appended
+
+
+#define RL_INT_SERR                    0x8000
+#define RL_INT_TIMEOUT         0x4000
+#define RL_INT_SWINT           0x0100
+#define RL_INT_TDU                     0x0080
+#define RL_INT_FOVW                    0x0040
+#define RL_INT_LINKCHG         0x0020
+#define RL_INT_RDU                     0x0010
+#define RL_INT_TERR                    0x0008
+#define RL_INT_TOK                     0x0004
+#define RL_INT_RERR                    0x0002
+#define RL_INT_ROK                     0x0001
+
+#define RL_INTERRUPT_MASK      RL_INT_LINKCHG | RL_INT_TOK | RL_INT_ROK | RL_INT_SWINT
+
+#define DES_OWN_MASK           0x80000000
+#define DES_EOR_MASK           0x40000000
+#define DES_RX_SIZE_MASK       0x3FFF
+#define DES_FS_MASK                    0x20000000
+#define DES_LS_MASK                    0x10000000
+
+#define DES_MAR_MASK           0x08000000
+#define DES_PAM_MASK           0x04000000
+#define DES_BAR_MASK           0x02000000
+
+#define DES_TX_IP_CHK_MASK  0x40000
+#define DES_TX_UDP_CHK_MASK 0x20000
+#define DES_TX_TCP_CHK_MASK 0x10000
+
+
+#define KERNEL_IRQ_OFFSET      32
+
+#define MINIMUM_PACKET_SIZE 14
+#define MAX_PACKET_SIZE                PGSIZE
+#define PACKET_HEADER_SIZE  20 + 8 + 18 //IP UDP ETH
+#define MAX_PACKET_DATA                PGSIZE - PACKET_HEADER_SIZE
+// This number needs verification! Also, this is a huge hack, as the driver shouldnt care about UDP/IP etc.
 
 void init_nic(void);
 void nic_interrupt_handler(trapframe_t *tf, void* data);
 int scan_pci(void);
 void read_mac(void);
 void setup_interrupts(void);
-void setup_rx_descriptors(void);
+void setup_descriptors(void);
 void configure_nic(void);
 void poll_rx_descriptors(void);
 void nic_handle_rx_packet(void);
-
+void set_rx_descriptor(uint32_t des_num);
+void set_tx_descriptor(uint32_t des_num);
+void process_packet(page_t *packet, uint16_t packet_size, uint32_t command);
+int send_packet(const char *data, size_t len);
+const char *packet_wrap(const char* data, size_t len);
+void zero_page(page_t *page);
+void dump_page(page_t *page);
 
 #endif /* !ROS_INC_REALTEK_H */
index 7fbbafc..dcc7ec4 100644 (file)
@@ -19,6 +19,8 @@ enum
        SYS_env_destroy,
        SYS_serial_write,
        SYS_serial_read,
+       SYS_eth_read,
+       SYS_eth_write,
 
        SYS_endofcalls //Should always be last
 };
index 625b491..61c3e6d 100644 (file)
@@ -36,7 +36,7 @@ KERN_SRCFILES := $(KERN_SRC_DIR)/entry.S \
                  $(KERN_SRC_DIR)/readline.c \
                  $(KERN_SRC_DIR)/string.c \
                  $(KERN_SRC_DIR)/timer.c \
-                 $(KERN_SRC_DIR)/kmalloc.c
+                 $(KERN_SRC_DIR)/kmalloc.c \
                  $(KERN_SRC_DIR)/rl8168.c
 
 # Only build files if they exist.
index 9e87df7..5bab07f 100644 (file)
 void manager(void)
 {
        static uint8_t progress = 0;
-       
+       env_t *env_batch[64];
+    if(progress == 0) {
+            progress++;
+            env_batch[0] = ENV_CREATE(parlib_matrix);
+            env_run(env_batch[0]);
+    }
+
        switch (progress++) {
                case 0:
                        printk("Beginning Tests\n");
index 2324402..3f5bb11 100644 (file)
  *
  * This is an ongoing work in progress. Main thing is we need a kernel interface for PCI
  * devices and network devices, that we can hook into, instead of providing arbitary functions
+ *
+ * One of the big things we need to change is the page allocation. Right now we use a page as the max
+ * size of a packet. This needs to change. We do it this way right now because that is really our only 
+ * allocation mechnism. I don't want to write some sort of kalloc just for the net driver, so until
+ * that exists, I'll use a page per packet buffer.
  */
 
-#define nic_debug(...)  cprintf(__VA_ARGS__)  
-#define nic_interrupt_debug(...)  cprintf(__VA_ARGS__)  
-
-
-#define MK_CONFIG_ADDR(BUS, DEV, FUNC, REG) (unsigned long)( (BUS << 16) | (DEV << 11) | \
-                                                             (FUNC << 8) | REG  | \
-                                                             ((uint32_t)0x80000000))
-#define PCI_CONFIG_ADDR     0xCF8
-#define PCI_CONFIG_DATA     0xCFC
-
-#define REALTEK_VENDOR_ID   0x10ec
-#define INVALID_VENDOR_ID   0xFFFF
-#define REALTEK_DEV_ID      0x8168
-
-#define PCI_IO_MASK         0xFFF8
-#define PCI_MEM_MASK        0xFFFFFFF0
-#define PCI_IRQ_MASK           0xFF
-#define PCI_VENDOR_MASK                0xFFFF
-#define PCI_DEVICE_OFFSET      0x10
-#define PCI_IRQ_REG                    0x3c
-
-#define PCI_MAX_BUS                    256
-#define PCI_MAX_DEV                    32
-#define PCI_BAR_IO_MASK                0x1
-
-#define RL_CTRL_RESET_MASK  0x10
-#define RL_CTRL_RXTX_MASK      0x0C
-
-#define RL_HWREV_REG           0x40
-#define RL_HWREV_MASK          0x7C800000
-
-#define RL_MAC_OFFSET          0x0
-
-#define RL_CTRL_REG         0x37
-#define RL_IM_REG                      0x3c
-#define RL_IS_REG                      0x3E
-#define RL_EP_CTRL_REG         0x50
-#define RL_RX_CTRL_REG      0x44
-#define RL_TX_CTRL_REG      0x40
-#define RL_RX_MXPKT_REG     0xDA
-#define RL_TX_MXPKT_REG     0xEC
-#define RL_RX_DES_REG       0xE4
-#define RL_TX_DES_REG       0x20
-
-#define RL_RX_MAX_SIZE         0x1000 // This is in units of bytes. 0x1000 = 4096
-#define RL_TX_MAX_SIZE         0x20   // This is in units of 128bytes, 128 * 0x20 = 4096
-#define RL_EP_CTRL_UL_MASK     0xC0
-#define RL_EP_CTRL_L_MASK      0x00
-
-// NOTE: THESE SHOULD BE BROKEN DOWN INTO A SERIES OF BITS TO REPERSENT THE VARIOUS OPTIONS
-// AND THEN THE MASK SHOULD BE DEFINED TO BE AN OR OF THOSE BITS. THIS IS A QUICK HACK JOB.
-#define RL_RX_CFG_MASK         0x0000E70F  // RXFTH: unlimited, MXDMA: unlimited, AAP: set (promisc. mode set)
-#define RL_TX_CFG_MASK         0x03000700  // IFG: normal, MXDMA: unlimited
-#define RL_INTERRUPT_MASK      0xFFFF      // All enabled
-
-
-
-#define RL_INT_SERR                    0x8000
-#define RL_INT_TIMEOUT         0x4000
-#define RL_INT_SWINT           0x0100
-#define RL_INT_TDU                     0x0080
-#define RL_INT_FOVW                    0x0040
-#define RL_INT_LINKCHG         0x0020
-#define RL_INT_RDU                     0x0010
-#define RL_INT_TERR                    0x0008
-#define RL_INT_TOK                     0x0004
-#define RL_INT_RERR                    0x0002
-#define RL_INT_ROK                     0x0001
-
-
-#define DES_OWN_MASK           0x80000000
-#define DES_EOR_MASK           0x40000000
-#define DES_SIZE_MASK          0x3FFF
-#define DES_FS_MASK                    0x20000000
-#define DES_LS_MASK                    0x10000000
-
-#define KERNEL_IRQ_OFFSET      32
 
 
 struct Descriptor
@@ -121,23 +49,27 @@ struct Descriptor
                  high_buf; /* high 32-bits of physical buffer address */
 };
 
+int rx_buffer_len = PGSIZE;
+int num_of_rx_descriptors = PGSIZE/sizeof(struct Descriptor);
+
+int tx_buffer_len = PGSIZE;
+int num_of_tx_descriptors = PGSIZE/sizeof(struct Descriptor);
+
 
 uint32_t io_base_addr = 0;
 uint32_t irq = 0;
 char mac_address[6];
 
-int rx_buffer_len = PGSIZE;
-int num_of_rx_descriptors = PGSIZE/sizeof(struct Descriptor);
-
 struct Descriptor *rx_des_kva;
 struct Descriptor *rx_des_pa;
 
 struct Descriptor *tx_des_kva;
 struct Descriptor *tx_des_pa;
 
-struct Descriptor *rx_des_cur;
-struct Descriptor *tx_des_cur;
+uint32_t rx_des_cur = 0;
+uint32_t tx_des_cur = 0;
 
+int eth_up = 0;
 
 int scan_pci() {
        
@@ -218,9 +150,9 @@ void read_mac() {
        for (int i = 0; i < 6; i++)
           mac_address[i] = inb(io_base_addr + RL_MAC_OFFSET + i); 
        
-       nic_debug("-->DEVICE MAC: %x:%x:%x:%x:%x:%x\n", 0xFF & mac_address[0], 0xFF & mac_address[1],   
-                                                       0xFF & mac_address[2], 0xFF & mac_address[3],   
-                                                    0xFF & mac_address[4], 0xFF & mac_address[5]);
+       nic_debug("-->DEVICE MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", 0xFF & mac_address[0], 0xFF & mac_address[1],       
+                                                                   0xFF & mac_address[2], 0xFF & mac_address[3],       
+                                                                0xFF & mac_address[4], 0xFF & mac_address[5]);
        return;
 }
 
@@ -251,14 +183,17 @@ void setup_interrupts() {
        enable_irq();
 }
 
-void setup_rx_descriptors() {
+void setup_descriptors() {
        
-       nic_debug("-->Setting up rx descriptors.\n");
+       nic_debug("-->Setting up tx/rx descriptors.\n");
        
        page_t *rx_des_page = NULL, *tx_des_page = NULL;
                        
-       page_alloc(&rx_des_page);
-       page_alloc(&tx_des_page);
+       if (page_alloc(&rx_des_page) < 0) panic("Can't allocate page for RX Ring");
+       if (page_alloc(&tx_des_page) < 0) panic("Can't allocate page for TX Ring");
+       
+       // extra page_alloc needed because of the strange page_alloc thing
+       if (page_alloc(&tx_des_page) < 0) panic("Can't allocate page for TX Ring");
        
        rx_des_kva = page2kva(rx_des_page);
        tx_des_kva = page2kva(tx_des_page);
@@ -266,21 +201,34 @@ void setup_rx_descriptors() {
        rx_des_pa = page2pa(rx_des_page);
        tx_des_pa = page2pa(tx_des_page);
 
-       
+
     for (int i = 0; i < num_of_rx_descriptors; i++) 
-    {
-        if (i == (num_of_rx_descriptors - 1)) /* Last descriptor? if so, set the EOR bit */
-                       rx_des_kva[i].command = (DES_OWN_MASK | DES_EOR_MASK | (rx_buffer_len & DES_SIZE_MASK));
-        else
-                       rx_des_kva[i].command = (DES_OWN_MASK | (rx_buffer_len & DES_SIZE_MASK));
+               set_rx_descriptor(i);
+               
+       for (int i = 0; i < num_of_tx_descriptors; i++) 
+               set_tx_descriptor(i);
+}
+
+void set_rx_descriptor(uint32_t des_num) {
+       
+       if (des_num == (num_of_rx_descriptors - 1)) /* Last descriptor? if so, set the EOR bit */
+               rx_des_kva[des_num].command = (DES_OWN_MASK | DES_EOR_MASK | (rx_buffer_len & DES_RX_SIZE_MASK));
+       else
+               rx_des_kva[des_num].command = (DES_OWN_MASK | (rx_buffer_len & DES_RX_SIZE_MASK));
                
-               page_t *rx_buf_page;
-               page_alloc(&rx_buf_page);
-        rx_des_kva[i].low_buf = page2pa(rx_buf_page); 
-               //.high_buf used if we do 64bit.
-    }
+       page_t *rx_buf_page;
+       if (page_alloc(&rx_buf_page) < 0) panic ("Can't allocate page for RX Buffer");
 
-       rx_des_cur = rx_des_kva;
+       rx_des_kva[des_num].low_buf = page2pa(rx_buf_page);
+       //.high_buf used if we do 64bit.
+}
+
+void set_tx_descriptor(uint32_t des_num) {
+       
+       tx_des_kva[des_num].command = 0;
+       
+       if (des_num == (num_of_tx_descriptors - 1)) /* Last descriptor? if so, set the EOR bit */
+               tx_des_kva[des_num].command = DES_EOR_MASK;
 }
 
 void configure_nic() {
@@ -288,16 +236,20 @@ void configure_nic() {
        nic_debug("-->Configuring Device.\n");
 
        outb(io_base_addr + RL_EP_CTRL_REG, RL_EP_CTRL_UL_MASK);                // Unlock EPPROM CTRL REG
-       outl(io_base_addr + RL_RX_CTRL_REG, RL_RX_CFG_MASK);                    // Configure RX
-       outl(io_base_addr + RL_TX_CTRL_REG, RL_TX_CFG_MASK);                    // Configure TX
+       outl(io_base_addr + RL_TX_CFG_REG, RL_RX_CFG_MASK);                     // Configure RX
+       
     outw(io_base_addr + RL_RX_MXPKT_REG, RL_RX_MAX_SIZE);                      // Set max RX Packet Size
     outb(io_base_addr + RL_TX_MXPKT_REG, RL_TX_MAX_SIZE);                      // Set max TX Packet Size
 
        // Note: These are the addresses the physical device will use, so we need the physical addresses of the rings
     outl(io_base_addr + RL_TX_DES_REG, (unsigned long)tx_des_pa);      // Set TX Des Ring Start Addr
+
     outl(io_base_addr + RL_RX_DES_REG, (unsigned long)rx_des_pa);      // Set RX Des Ring Start Addr
 
-    outb(io_base_addr + RL_CTRL_REG, RL_CTRL_RXTX_MASK);                       // Enable RX and TX in the CTRL Reg
+       // Can't configure TX until enabled in ctrl reg. From spec sheet.
+       outb(io_base_addr + RL_CTRL_REG, RL_CTRL_RXTX_MASK);                    // Enable RX and TX in the CTRL Reg
+       outl(io_base_addr + RL_TX_CFG_REG, RL_TX_CFG_MASK);                     // Configure TX
+
     outl(io_base_addr + RL_EP_CTRL_REG, RL_EP_CTRL_L_MASK);            // Unlock the EPPROM Ctrl REG
        
        return;
@@ -317,7 +269,7 @@ void poll_rx_descriptors() {
                                                                                rx_des_kva[i].command & DES_OWN_MASK, 
                                                                                ((rx_des_kva[i].command & DES_FS_MASK) != 0),
                                                                                ((rx_des_kva[i].command & DES_LS_MASK) != 0),
-                                                                               rx_des_kva[i].command & DES_SIZE_MASK);                         
+                                                                               rx_des_kva[i].command & DES_RX_SIZE_MASK);                              
                        }
                }
        }
@@ -328,15 +280,44 @@ void poll_rx_descriptors() {
 void init_nic() {
        
        if (scan_pci() < 0) return;
+       eth_up = 1;
        read_mac();
        setup_interrupts();
-       setup_rx_descriptors();
+       setup_descriptors();
        configure_nic();
 
-       poll_rx_descriptors();
+/*
+       udelay(3000000);
+       for (int i = 0; i < 10; i++)  {
+               send_packet("                    HELLO THERE", 32);
+               udelay(3000000);
+       }
+*/
+
+/*  This code is for nic stats
+       page_t *p;
+       page_alloc(&p);
+       
+       uint32_t low = 0;
+       uint32_t high = 0;
+       
+       low = page2pa(p);
+       low = low | 0x8;
+       
+       outl(io_base_addr + 0x10, low);
+       outl(io_base_addr + 0x14, 0x00);
+       
+       udelay(3000000);
+       dump_page(p);
+*/
+
+       //poll_rx_descriptors();
+       udelay(3000000);
                                
        // Trigger sw based nic interrupt
-       //outb(io_base_addr + 0x38, 0x1);
+       outb(io_base_addr + 0x38, 0x1);
+       udelay(3000000);
+       
        //nic_debug("Triggered NIC interrupt.\n");
        
        return;
@@ -346,17 +327,17 @@ void init_nic() {
 // We also need to figure out whats up with different core interrupts
 void nic_interrupt_handler(trapframe_t *tf, void* data) {
        
-       nic_interrupt_debug("\nNic interrupt!\n");
+       nic_interrupt_debug("\nNic interrupt on core %u!\n", lapic_get_id());
        
        // Read the offending interrupt(s)
        uint16_t interrupt_status = inw(io_base_addr + RL_IS_REG);
 
-       // We can have multiple interrupts fire at once
-       // I've personally seen this. I saw RL_INT_LINKCHG and RL_INT_ROK fire at the same time.
+       // We can have multiple interrupts fire at once. I've personally seen this.
        // This means we need to handle this as a series of independent if's
        
        if (interrupt_status & RL_INT_ROK) {
                nic_interrupt_debug("-->RX OK\n");
+               nic_handle_rx_packet();
        }       
        
        if (interrupt_status & RL_INT_RERR) {
@@ -402,10 +383,266 @@ void nic_interrupt_handler(trapframe_t *tf, void* data) {
        nic_interrupt_debug("\n");
                
        // Clear interrupts     
-       outw(io_base_addr + RL_IS_REG, RL_INTERRUPT_MASK);
+       outw(io_base_addr + RL_IS_REG, 0xFFFF);
+       return;
+}
+
+void process_packet(page_t *packet, uint16_t packet_size, uint32_t command) {
+       uint32_t packet_kva = page2kva(packet);
+       
+       nic_packet_debug("-->Command: %x\n", command);
+       nic_packet_debug("-->Size: %u\n", packet_size);
+       
+       if (packet_size < MINIMUM_PACKET_SIZE) {
+               nic_packet_debug("-->Packet too small. Discarding.\n");
+               
+               page_free(packet);
+               return;
+       }
+       
+       char dest_mac[6];
+       char source_mac[6];
+       char eth_type[2];
+       
+       for (int i = 0; i < 6; i++) {
+               dest_mac[i] = ((char*)packet_kva)[i];
+       }
+       
+       for (int i = 0; i < 6; i++) {
+               source_mac[i] = ((char*)packet_kva)[i+6];
+       }
+       
+       eth_type[0] = ((char*)packet_kva)[12];
+       eth_type[1] = ((char*)packet_kva)[13];
+       
+       if (command & DES_MAR_MASK) {
+               nic_packet_debug("-->Multicast Packet.\n");
+       }
+       
+       if (command & DES_PAM_MASK) {
+               nic_packet_debug("-->Physical Address Matched.\n");
+       }
+       
+       if (command & DES_BAR_MASK) {
+               nic_packet_debug("-->Broadcast Packet.\n");
+       }
+       
+       // Note: DEST comes before SRC in the ethernet frame, but that 
+       
+       nic_packet_debug("-->DEST   MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", 0xFF & dest_mac[0], 0xFF & dest_mac[1],      
+                                                                          0xFF & dest_mac[2], 0xFF & dest_mac[3],      
+                                                                       0xFF & dest_mac[4], 0xFF & dest_mac[5]);
+       
+       nic_packet_debug("-->SOURCE MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", 0xFF & source_mac[0], 0xFF & source_mac[1],  
+                                                                          0xFF & source_mac[2], 0xFF & source_mac[3],  
+                                                                       0xFF & source_mac[4], 0xFF & source_mac[5]);
+
+       nic_packet_debug("-->ETHR MODE: %02x%02x\n", 0xFF & eth_type[0], 0xFF & eth_type[1]);
+               
        return;
 }
 
 void nic_handle_rx_packet() {
+       
+       uint32_t current_command = rx_des_kva[rx_des_cur].command;
+       uint16_t packet_size;
+       page_t *rx_buf_page_dirty;              // Packets page with data
+       
+       nic_packet_debug("-->RX Des: %u\n", rx_des_cur);
+       
+       // Make sure we are processing from the start of a packet segment
+       if (!(current_command & DES_FS_MASK)) {
+               nic_packet_debug("-->ERR: Current RX descriptor not marked with FS mask. Panic!");
+               panic("RX Descriptor Ring FS out of sync");
+       }
+       
+       // NOTE: We are currently configured that the max packet size is large enough to fit inside 1 descriptor buffer,
+       // So we should never be in a situation where a packet spans multiple descriptors.
+       // When we change this, this should operate in a loop until the LS mask is found
+       // Loop would begin here.
+                       
+       // Make sure we own the current packet. Kernel ownership is denoted by a 0. Nic by a 1.
+       if (current_command & DES_OWN_MASK) {
+               nic_packet_debug("-->ERR: Current RX descriptor not owned by kernel. Panic!");
+               panic("RX Descriptor Ring OWN out of sync");
+       }
+               
+       // Make sure if we are at the end of the buffer, the des is marked as end
+       if ((rx_des_cur == (num_of_rx_descriptors - 1)) && !(current_command & DES_EOR_MASK)) {
+               nic_packet_debug("-->ERR: Last RX descriptor not marked with EOR mask. Panic!\n");
+               panic("RX Descriptor Ring EOR Missing");
+       }
+       
+       // This is ensuring packets only span 1 descriptor, since our packet size cant exceed the buffer of 1 descriptor
+       if (!(current_command & DES_LS_MASK)) {
+               nic_packet_debug("-->ERR: Current RX descriptor not marked with LS mask. Panic!");
+               panic("RX Descriptor Ring LS out of sync");
+       }
+       
+       // Get the packet data
+       rx_buf_page_dirty = pa2page(rx_des_kva[rx_des_cur].low_buf);
+       packet_size = rx_des_kva[rx_des_cur].command & DES_RX_SIZE_MASK;
+       
+       // Reset the command register, allocate a new page, and set it
+       set_rx_descriptor(rx_des_cur);
+       
+       // Advance to the next descriptor
+       rx_des_cur = (rx_des_cur + 1) % num_of_rx_descriptors;
+       
+       // Chew on the packet data. This function is responsible for deallocating the memory space.
+       process_packet(rx_buf_page_dirty, packet_size, current_command);
+               
        return;
 }
+
+// Idealy, once we get the packet sizing right, we'd generate multiple descriptors to fit the current packet.
+// However, we can't do that now since the max packet size is 1 page, and thats the max buffer size, too.
+int send_packet(const char *data, size_t len) {
+
+       if (tx_des_kva[tx_des_cur].command & DES_OWN_MASK) {
+               nic_packet_debug("-->TX Ring Buffer Full!\n");
+               return -1;
+       }
+       
+       // THIS IS A HACK. MAX PACKET SIZE NEEDS TO BE FIXED BASED ON THE 128/32 QUESTION DEFINED AT THE TOP
+       // AS WELL AS THE FACT THAT THE MAX PACKET SIZE INCLUDES THINGS LIKE CRC, AND MAY INCLUDE SRC MAC DEST MAC AND PREAMBLE!
+       // IF THE MAX PACKET SIZE INCLUDES THOSE, THIS NEEDS TO BE ADJUSTED BASED ON THAT. 
+       // IN OTHER WORDS, PLEASE PLEASE PLEASE FIX THIS.
+       if (len > MAX_PACKET_SIZE) {
+               nic_packet_debug("-->Packet Too Large!\n");
+               return -1;
+       }
+       
+       page_t *tx_buf_page;
+       if (page_alloc(&tx_buf_page) < 0) {
+               nic_packet_debug("Can't allocate page for TX Buffer");
+               return -1;
+       }
+
+       tx_des_kva[tx_des_cur].low_buf = page2pa(tx_buf_page);
+       
+       memcpy(page2kva(tx_buf_page), data, len);
+
+       tx_des_kva[tx_des_cur].command = tx_des_kva[tx_des_cur].command | len | DES_OWN_MASK | DES_FS_MASK | DES_LS_MASK;
+       tx_des_kva[tx_des_cur].command = tx_des_kva[tx_des_cur].command | DES_TX_IP_CHK_MASK | DES_TX_UDP_CHK_MASK | DES_TX_TCP_CHK_MASK;
+       
+       
+       tx_des_cur = (tx_des_cur + 1) % num_of_tx_descriptors;
+       
+       nic_packet_debug("-->Sent packet.\n");
+       
+       
+       outb(io_base_addr + RL_TX_CTRL_REG, RL_TX_SEND_MASK);
+       
+       
+       
+       return len;
+}
+
+// This function is a complete temp hack
+const char *packet_wrap(const char* data, size_t len) {
+       
+       #define htons(A) ((((uint16_t)(A) & 0xff00) >> 8) | \
+                           (((uint16_t)(A) & 0x00ff) << 8))
+       #define htonl(A) ((((uint32_t)(A) & 0xff000000) >> 24) | \
+                           (((uint32_t)(A) & 0x00ff0000) >> 8)  | \
+                           (((uint32_t)(A) & 0x0000ff00) << 8)  | \
+                           (((uint32_t)(A) & 0x000000ff) << 24))
+
+       #define ntohs  htons
+       #define ntohl  htohl
+
+       
+       
+       struct ETH_Header
+       {
+               char dest_mac[6];
+               char source_mac[6];
+               uint16_t eth_type;
+       };
+
+       
+       struct IP_Header
+       {
+               uint32_t ip_opts0;
+               uint32_t ip_opts1;
+               uint32_t ip_opts2;
+               uint32_t source_ip;
+               uint32_t dest_ip;
+       };
+       
+       struct UDP_Header
+       {
+               uint16_t source_port;
+               uint16_t dest_port;
+               uint16_t length;
+               uint16_t checksum;
+       };      
+       
+       // Hard coded to paul's laptop's mac
+       char dest_mac_address[6] = {0x00, 0x23, 0x32, 0xd5, 0xae, 0x82};
+       
+       uint32_t source_ip = 0xC0A8000A; // 192.168.0.10
+       uint32_t dest_ip   = 0xC0A8000B; // 192.168.0.11
+       
+       if (len > MAX_PACKET_DATA) {
+               nic_packet_debug("Bad packet size for packet wrapping");
+               return NULL;
+       }
+       
+       page_t *wrap_page;
+       char* wrap_kva;
+       
+       if (page_alloc(&wrap_page) < 0) {
+               nic_packet_debug("Can't allocate page for packet wrapping");
+               return NULL;
+       }
+       
+       wrap_kva = page2kva(wrap_page);
+       
+       struct ETH_Header *eth_header = (struct ETH_Header*) wrap_kva;
+       struct IP_Header *ip_header = (struct IP_Header*) (wrap_kva + sizeof(struct ETH_Header));
+       struct UDP_Header *udp_header = (struct UDP_Header*) (wrap_kva + sizeof(struct ETH_Header) + sizeof(struct IP_Header));
+       
+       // Setup eth data
+       for (int i = 0; i < 6; i++) 
+               eth_header->dest_mac[i] = dest_mac_address[i];
+               
+       for (int i = 0; i < 6; i++) 
+               eth_header->source_mac[i] = mac_address[i];
+               
+       eth_header->eth_type = htons(0x0800);
+       
+       // Setup IP data
+       ip_header->ip_opts0 = htonl((4<<28) | (5 << 24) | (len + 28));
+       ip_header->ip_opts1 = 0;
+       ip_header->ip_opts2 = 0x00110a;
+       ip_header->source_ip = htonl(source_ip);
+       ip_header->dest_ip = htonl(dest_ip);
+       
+       // Setup UDP Data
+       udp_header->source_port = htons(44443);
+       udp_header->dest_port = htons(44444);
+       udp_header->length = htons(8 + len);
+       udp_header->checksum = 0;
+       
+       memcpy (wrap_kva + PACKET_HEADER_SIZE, data, len);
+               
+       return wrap_kva;        
+}
+
+void zero_page(page_t *page) {
+       char *page_kva = page2kva(page);
+       
+       for (int i = 0; i < PGSIZE; i++ ) 
+               page_kva[i] = 0;
+}
+
+void dump_page(page_t *page) {
+       char *page_kva = page2kva(page);
+       
+       for (int i = 0; i < PGSIZE; i++ ) 
+               cprintf("%02x", page_kva[i]);   
+       cprintf("\n");
+}
\ No newline at end of file
index 0018394..4e51b99 100644 (file)
@@ -10,6 +10,7 @@
 #include <arch/timer.h>
 #include <ros/error.h>
 
+#include <rl8168.h>
 #include <string.h>
 #include <assert.h>
 #include <env.h>
@@ -71,6 +72,50 @@ static ssize_t sys_serial_read(env_t* e, char *DANGEROUS buf, size_t len)
        #endif
 }
 
+static ssize_t sys_eth_write(env_t* e, const char *DANGEROUS buf, size_t len) 
+{ 
+       extern int eth_up;
+       
+       if (eth_up) {
+               
+               char *COUNT(len) _buf = user_mem_assert(e, buf, len, PTE_U);
+               int total_sent = 0;
+               int just_sent = 0;
+               int cur_packet_len = 0;
+               while (total_sent != len) {
+                       cur_packet_len = ((len - total_sent) > MAX_PACKET_DATA) ? MAX_PACKET_DATA : (len - total_sent);
+                       
+                       just_sent = send_packet(packet_wrap(buf + total_sent, cur_packet_len), cur_packet_len + PACKET_HEADER_SIZE);
+                       
+                       if (just_sent < 0)
+                               return -1; // This should be an error code of its own
+                       total_sent += cur_packet_len;
+               }
+               
+               return (ssize_t)len;
+               
+       }
+       else
+               return -E_INVAL;
+}
+
+static ssize_t sys_eth_read(env_t* e, char *DANGEROUS buf, size_t len) 
+{/*
+       #ifdef SERIAL_IO
+           char *COUNT(len) _buf = user_mem_assert(e, buf, len, PTE_U);
+               size_t bytes_read = 0;
+               int c;
+               while((c = serial_read_byte()) != -1) {
+                       buf[bytes_read++] = (uint8_t)c;
+                       if(bytes_read == len) break;
+               }
+               return (ssize_t)bytes_read;
+       #else
+               return -E_INVAL;
+       #endif*/
+               return 0;
+}
+
 // Invalidate the cache of this core
 static void sys_cache_invalidate(void)
 {
@@ -238,6 +283,10 @@ intreg_t syscall(env_t* e, uint32_t syscallno, uint32_t a1, uint32_t a2,
                        return sys_serial_write(e, (char *DANGEROUS)a1, (size_t)a2);
                case SYS_serial_read:
                        return sys_serial_read(e, (char *DANGEROUS)a1, (size_t)a2);
+               case SYS_eth_write:
+                       return sys_eth_write(e, (char *DANGEROUS)a1, (size_t)a2);
+               case SYS_eth_read:
+                       return sys_eth_read(e, (char *DANGEROUS)a1, (size_t)a2);        
                case SYS_cache_invalidate:
                        sys_cache_invalidate();
                        return 0;
index f27c2a6..3403b3f 100644 (file)
@@ -24,6 +24,8 @@ ssize_t     sys_cputs(const uint8_t *s, size_t len);
 uint16_t    sys_cgetc(void);
 ssize_t     sys_serial_write(void* buf, size_t len); 
 ssize_t     sys_serial_read(void* buf, size_t len);
+ssize_t     sys_eth_write(void* buf, size_t len); 
+ssize_t     sys_eth_read(void* buf, size_t len);
 envid_t     sys_getenvid(void);
 envid_t     sys_getcpuid(void);
 void        sys_env_destroy(envid_t);
index 1e347de..0c894bc 100644 (file)
@@ -119,9 +119,9 @@ int fstat(int file, struct stat *st)
        st->st_mode = S_IFCHR;
        
        // stdout hack
-//     if (file == 1)
-//             st->st_mode = 8592;
-//     return 0;
+       if (file == 1)
+               st->st_mode = 8592;
+       return 0;
 
 
        // Allocate a new buffer of proper size
@@ -182,9 +182,9 @@ int isatty(int file)
        debug_in_out("ISATTY\n");
 
        // Cheap hack to avoid sending serial comm for stuff we know
-//     if ((STDIN_FILENO == file) || (STDOUT_FILENO == file) 
-//                                 || (STDERR_FILENO == file))
-//             return 1;
+       if ((STDIN_FILENO == file) || (STDOUT_FILENO == file) 
+                                 || (STDERR_FILENO == file))
+               return 1;
 
        
        // Allocate a new buffer of proper size
@@ -451,7 +451,8 @@ int read_from_channel(char * buf, int len, int peek)
        //                      Also, watch out for CONNECTION TERMINATED
        int total_read = 0;
 
-       int just_read = sys_serial_read(buf, len);
+       //int just_read = sys_serial_read(buf, len);
+       int just_read = sys_eth_read(buf, len);
 
 
        if (just_read < 0) return just_read;
@@ -460,7 +461,9 @@ int read_from_channel(char * buf, int len, int peek)
        total_read += just_read;
 
        while (total_read != len) {
-               just_read = sys_serial_read(buf + total_read, len - total_read);
+               //just_read = sys_serial_read(buf + total_read, len - total_read);
+               just_read = sys_eth_read(buf + total_read, len - total_read);
+               
 
                if (just_read == -1) return -1;
                total_read += just_read;
@@ -785,6 +788,8 @@ ssize_t write(int file, void *ptr, size_t len) {
  */
 int write_to_channel(char * msg, int len)
 {
-       return sys_serial_write((char*)msg, len);
+       //return sys_serial_write((char*)msg, len);
+       return sys_eth_write((char*)msg, len);
+       
 }
 
index cab3792..c4f643b 100644 (file)
@@ -35,8 +35,7 @@ static intreg_t syscall_trap(uint16_t num, intreg_t a1,
                              intreg_t a2, intreg_t a3,
                              intreg_t a4, intreg_t a5)
 {
-       intreg_t ret;
-
+       debug("duh!\n");
        // Generic system call: pass system call number in AX,
        // up to five parameters in DX, CX, BX, DI, SI.
        // Interrupt kernel with T_SYSCALL.
@@ -111,3 +110,15 @@ ssize_t sys_serial_read(void* buf, size_t len)
 {
        return syscall(SYS_serial_read, (intreg_t)buf, len, 0, 0, 0);
 }
+
+//Write a buffer over ethernet
+ssize_t sys_eth_write(void* buf, size_t len) 
+{
+       return syscall(SYS_eth_write, (intreg_t)buf, len, 0, 0, 0);
+}
+
+//Read a buffer via ethernet
+ssize_t sys_eth_read(void* buf, size_t len) 
+{
+       return syscall(SYS_eth_read, (intreg_t)buf, len, 0, 0, 0);
+}