WIP commit, adding support for receiving into a pbuf.
authorDavid Zhu <yuzhu@cs.berkeley.edu>
Mon, 14 Mar 2011 22:42:00 +0000 (15:42 -0700)
committerDavid Zhu <yuzhu@cs.berkeley.edu>
Mon, 2 Apr 2012 22:03:28 +0000 (15:03 -0700)
Makeconfig
kern/arch/i686/e1000.c
kern/arch/i686/e1000.h
kern/arch/i686/nic_common.c
kern/arch/i686/nic_common.h
kern/include/net/dev.h
kern/include/net/pbuf.h
kern/include/ros/syscall.h
kern/src/net/pbuf.c
kern/src/net/udp.c
kern/src/socket.c

index 64c811c..b5bc512 100644 (file)
@@ -33,6 +33,7 @@ CONFIG_PCI_VERBOSE:=               -D__CONFIG_PCI_VERBOSE__
 CONFIG_ETH_AUDIO:=                 -D__CONFIG_ETH_AUDIO__
 CONFIG_KB_CORE0_ONLY:=             -D__CONFIG_KB_CORE0_ONLY__
 CONFIG_KTHREAD_POISON:=            -D__CONFIG_KTHREAD_POISON__
+CONFIG_SOCKET:=                    -D__CONFIG_SOCKET__                                                                         
 
 # Userspace configuration parameters
 # By default, each of these options will be turned off
index 17b23ee..76e3361 100644 (file)
@@ -18,6 +18,7 @@
 #include <arch/smp.h>
 #include <arch/apic.h>
 #include <arch/pci.h>
+#include <arch/nic_common.h>
 #include <arch/e1000.h>
 
 #include <ros/memlayout.h>
@@ -31,7 +32,6 @@
 #include <pmap.h>
 #include <frontend.h>
 #include <arch/frontend.h>
-
 #include <eth_audio.h>
 
 #define NUM_TX_DESCRIPTORS E1000_NUM_TX_DESCRIPTORS
@@ -73,7 +73,8 @@ extern uint32_t packet_buffers_head;
 extern uint32_t packet_buffers_tail;
 spinlock_t packet_buffers_lock;
 
-// Allow us to register our send_frame as the global send_frameuint16_t device_id;
+// Allow us to register our send_frame as the global send_frame
+uint16_t device_id;
 extern int (*send_frame)(const char *CT(len) data, size_t len);
 
 void e1000_dump_rx() {
@@ -119,6 +120,7 @@ void e1000_init() {
        // "Register" our send_frame with the global system
        send_frame = &e1000_send_frame;
        send_pbuf = &e1000_send_pbuf;
+       recv_pbuf = &e1000_recv_pbuf;
 
        // sudo /sbin/ifconfig eth0 up
        eth_up = 1;
@@ -192,9 +194,12 @@ int e1000_scan_pci() {
                e1000_irq = pcidev->irqline;
                e1000_debug("-->IRQ: %u\n", e1000_irq);
                /* Loop over the BARs */
+               /* yz: pci layer should scan these things and put them in a pci_dev struct */
                for (int k = 0; k <= 5; k++) {
                        int reg = 4 + k;
-               result = pcidev_read32(pcidev, reg << 2);       // SHAME!
+           // resource len?
+                                       result = pcidev_read32(pcidev, reg << 2);       // SHAME! why? 
+
                        if (result == 0) // (0 denotes no valid data)
                                continue;
                        // Read the bottom bit of the BAR. 
@@ -293,7 +298,7 @@ uint16_t e1000_read_eeprom(uint32_t offset) {
 void e1000_setup_mac() {
 
        uint16_t eeprom_data = 0;
-        uint32_t mmio_data = 0;
+       uint32_t mmio_data = 0;
 
        /* TODO: WARNING - EXTREMELY GHETTO */
        e1000_debug("-->Setting up MAC addr\n");
@@ -679,9 +684,14 @@ void e1000_interrupt_handler(trapframe_t *tf, void* data) {
                //printk("Interrupt status: %x\n", interrupt_status);
 
                // Check to see if the interrupt was packet based.
+               // TODO: what other kind of interrupts are there? 
                if ((interrupt_status & E1000_ICR_INT_ASSERTED) && (interrupt_status & E1000_ICR_RXT0)) {
                        e1000_interrupt_debug("---->Packet Received\n");
+#ifdef __CONFIG_SOCKET__
+                       e1000_recv_pbuf();
+#else
                        e1000_handle_rx_packet();
+#endif
                }       
                // Clear interrupts     
                interrupt_status = e1000_rr32(E1000_ICR);
@@ -689,7 +699,12 @@ void e1000_interrupt_handler(trapframe_t *tf, void* data) {
        
        // In the event that we got really unlucky and more data arrived after we set 
        //  set the bit last, try one more check
-       e1000_handle_rx_packet();
+       /* What happens if handle_rx_packet is called too many times? */
+#ifdef __CONFIG_SOCKET__
+                       e1000_recv_pbuf();
+#else
+                       e1000_handle_rx_packet();
+#endif
 
        return;
 }
@@ -849,6 +864,115 @@ void e1000_handle_rx_packet() {
        return;
 }
 
+struct pbuf* e1000_recv_pbuf(void) {
+       uint16_t packet_size;
+       uint32_t status;
+       uint32_t head = e1000_rr32(E1000_RDH);
+
+       //printk("Current head is: %x\n", e1000_rr32(E1000_RDH));
+       //printk("Current tail is: %x\n", e1000_rr32(E1000_RDT));
+       
+       // If the HEAD is where we last processed, no new packets.
+       if (head == e1000_rx_index) {
+               e1000_frame_debug("-->Nothing to process. Returning.");
+               return NULL;
+       }
+       
+       // Set our current descriptor to where we last left off.
+       uint32_t rx_des_loop_cur = e1000_rx_index;
+       uint32_t frame_size = 0;
+       uint32_t fragment_size = 0;
+       uint32_t num_frags = 0;
+
+       uint32_t top_fragment = rx_des_loop_cur; 
+       struct e1000_rx_desc rx_desc = rx_des_kva[rx_des_loop_cur];
+       // the parent function verifies STAT_DD
+       struct pbuf* pb = pbuf_alloc(PBUF_RAW, 0, PBUF_MTU);
+       if (!pb){
+               warn("pbuf allocation failed\n");
+               return NULL;
+       }
+
+       do {
+               // Get the descriptor status
+               status = rx_des_kva[rx_des_loop_cur].status;
+
+               // If the status is 0x00, it means we are somehow trying to process 
+               // a packet that hasnt been written by the NIC yet.
+               if (status == 0x0) {
+                       warn("ERROR: E1000: Packet owned by hardware has 0 status value\n");
+                       /* It's possible we are processing a packet that is a fragment
+                        * before the entire packet arrives.  The code currently assumes
+                        * that all of the packets fragments are there, so it assumes the
+                        * next one is ready.  We'll spin until it shows up...  This could
+                        * deadlock, and sucks in general, but will help us diagnose the
+                        * driver's issues.  TODO: determine root cause and fix this shit.*/
+                       while(rx_des_kva[rx_des_loop_cur].status == 0x0)
+                               cpu_relax();
+                       status = rx_des_kva[rx_des_loop_cur].status;
+               }
+       
+               // See how big this fragment is.
+               fragment_size = rx_des_kva[rx_des_loop_cur].length;
+               
+               // If we've looped through the entire ring and not found a terminating packet, bad nic state.
+               // Panic or clear all descriptors? This is a nic hardware error. 
+               if (num_frags && (rx_des_loop_cur == head)) {
+                       e1000_frame_debug("-->ERR: No ending segment found in RX buffer.\n");
+                       panic("RX Descriptor Ring out of sync.");
+               }
+               // Denote that we have at least 1 fragment.
+               num_frags++;
+               // Make sure ownership is correct. Packet owned by the NIC (ready for kernel reading)
+               // is denoted by a 1. Packet owned by the kernel (ready for NIC use) is denoted by 0.
+               if ((status & E1000_RXD_STAT_DD) == 0x0) {
+                       e1000_frame_debug("-->ERR: Current RX descriptor not owned by software. Panic!");
+                       panic("RX Descriptor Ring OWN out of sync");
+               }
+               
+               // Deal with packets too large
+               if ((frame_size + fragment_size) > MAX_FRAME_SIZE) {
+                       e1000_frame_debug("-->ERR: Nic sent %u byte packet. Max is %u\n", frame_size, MAX_FRAME_SIZE);
+                       panic("NIC Sent packets larger than configured.");
+               }
+               // Copy into pbuf allocated for this     
+               // TODO: reuse the pbuf later
+               // real driver uses a pbuf allocated (MTU sized) per descriptor and recycles that
+               // real driver also does not handle fragments.. simply drops them
+               // Reset the descriptor. Reuse current buffer (False means don't realloc).
+               e1000_set_rx_descriptor(rx_des_loop_cur, FALSE);
+               
+               // Note: We mask out fragment sizes at 0x3FFFF. There can be at most 2048 of them.
+               // This can not overflow the uint32_t we allocated for frame size, so
+               // we dont need to worry about mallocing too little then overflowing when we read.
+               frame_size = frame_size + fragment_size;
+               
+               // Advance to the next descriptor
+               rx_des_loop_cur = (rx_des_loop_cur + 1) % NUM_RX_DESCRIPTORS;
+
+       } while ((status & E1000_RXD_STAT_EOP) == 0); // Check to see if we are at the final fragment
+
+       uint32_t copied = 0;
+#if ETH_PAD_SIZE
+       pbuf_header(pb, -ETH_PAD_SIZE); /* drop the padding word */
+       copied += ETH_PAD_SIZE;
+#endif
+
+       void* rx_buffer = pb->payload;
+       
+
+       // rx_des_loop_cur has gone past the top_fragment
+       while (top_fragment != rx_des_loop_cur) {
+               // TODO: if we convert the pbufs to MTU sized pbuf, don't forget to convert this copy to a pbuf copy
+               memcpy(rx_buffer, KADDR(rx_des_kva[rx_des_loop_cur].buffer_addr), fragment_size);
+               copied += fragment_size;
+               top_fragment = (top_fragment + 1) % NUM_RX_DESCRIPTORS;
+       }
+       pb->len += copied;
+       pb->tot_len += copied;
+       return pb;
+}
+
 int e1000_send_pbuf(struct pbuf *p) {
        int len = p->tot_len;
        // print_pbuf(p);
index 084aeb9..4c77541 100644 (file)
 #define E1000_IRQ_CPU          0
 
 #define INTEL_VENDOR_ID                0x8086
-#define INTEL_DEV_ID0          0x100E  // Real E1000
+#define INTEL_DEV_ID0          0x100E  // Real E1000 QEMU emulates this. Linux device driver e1000
+
+/* 
+ * These two are technically supported by the igb driver in linux, since they support more advanced feature set 
+ */
 #define INTEL_DEV_ID1          0x10c9  // 82576
 #define INTEL_DEV_ID2          0x150a  // 82576 NS
 
@@ -49,5 +53,7 @@ void e1000_set_rx_descriptor(uint32_t des_num, uint8_t reset_buffer);
 void e1000_set_tx_descriptor(uint32_t des_num);
 int  e1000_send_frame(const char* data, size_t len);
 int e1000_send_pbuf(struct pbuf *p);
+/* returns a chain of pbuf from the driver */
+struct pbuf* e1000_recv_pbuf();
 
 #endif /* !ROS_INC_E1000_H */
index e02763d..b927c5a 100644 (file)
@@ -19,6 +19,7 @@
 // Means we can only have one network card per system right now...
 int (*send_frame)(const char *data, size_t len);
 int (*send_pbuf)(struct pbuf *p);
+struct pbuf*  (*recv_pbuf)(void);
 
 
 
index 61e92c9..3bf9d26 100644 (file)
@@ -21,6 +21,7 @@
 // Means we can only have one network card per system right now...
 extern int (*send_frame)(const char *data, size_t len);
 extern int (*send_pbuf)(struct pbuf *p);
+extern struct pbuf* (*recv_pbuf)(void);
 
 // Global variables for managing ethernet packets over a nic
 // Again, since these are global for all network cards we are 
index 0652e2b..609cf94 100644 (file)
@@ -6,18 +6,27 @@
 #ifndef ROS_KERN_NET_DEV_H
 #define ROS_KERN_NET_DEV_H
 
+#include <bits/netinet.h>
+#include <stdio.h>
+#include <socket.h>
+#include <ros/common.h>
+
+struct net_device_ops {
+       int (*init)(struct netif *netif);
+       int (*send_frame) (struct netif *netif, const char data, size_t len) ;
+       int (*send_pbuf) (struct netif *netif, const struct pbuf* pb);
+       int (*recv_pbuf) (struct netif *netif, const struct pbuf* pb);
+}
+
 struct netif {
        /* TODO: next netif so we can build a list of them*/
-       struct ip_addr ip_addr;
-       void* init;
-       netif_init_fn input;
-       netif_output_fn send_frame;
-       netif_output_fn send_pbuf;
-       netif_output_raw output_raw;
+       struct in_addr ip_addr;
+       struct in_addr gw;
+       uint16_t mtu;
+       uint8_t mac[6];
+       struct net_device_ops ops;
+       uint8_t eth_up;   // status 
 }; 
 
 
-
-
-
 #endif //ROS_KERN_NET_DEV_H
index a4528d0..c2b1ffd 100644 (file)
@@ -27,7 +27,8 @@ typedef enum {
   PBUF_RAM, /* pbuf data is stored in RAM */
   PBUF_ROM, /* pbuf data is stored in ROM */
   PBUF_REF, /* pbuf comes from the pbuf pool */
-  PBUF_POOL /* pbuf payload refers to RAM */
+  PBUF_POOL, /* pbuf payload refers to RAM */
+       PBUF_MTU  /* pbuf with a fixed MTU size */
 } pbuf_type;
 
 
index 9cd2c5b..cfacf10 100644 (file)
@@ -33,7 +33,6 @@ struct syscall {
 
 /* Temp hack, til the rest of glibc/userspace uses sys/syscall.h */
 #include <sys/syscall.h>
-
 #endif /* ifndef ROS_KERNEL */
 
 #endif /* ROS_INC_SYSCALL_H */
index 2997da2..633309b 100644 (file)
@@ -6,21 +6,30 @@
 #include <slab.h>
 #include <assert.h>
 #include <net/pbuf.h>
+#include <arch/nic_common.h>
 
 
 #define SIZEOF_STRUCT_PBUF (ROUNDUP(sizeof(struct pbuf), ROS_MEM_ALIGN))
+#define SIZEOF_STRUCT_MTU_PBUF SIZEOF_STRUCT_PBUF + ROUNDUP(sizeof(MAX_FRAME_SIZE), ROS_MEM_ALIGN)
 
-// may need checksum later
 struct kmem_cache *pbuf_kcache;
+struct kmem_cache *mtupbuf_kcache;
+
 
 void pbuf_init(void){
+       printk("size of struct pbuf%d, %d \n", SIZEOF_STRUCT_PBUF, sizeof(struct pbuf));
+       printk("alignment %d\n", __alignof__(struct pbuf));
        pbuf_kcache = kmem_cache_create("pbuf", sizeof(struct pbuf),
                                                                        __alignof__(struct pbuf), 0, 0, 0);
+  mtupbuf_kcache = kmem_cache_create("mtupbuf_kcache", SIZEOF_STRUCT_MTU_PBUF, 
+                                                                               __alignof__(struct pbuf), 0, 0, 0);
 }
 
 // not sure about this structure..
 static void pbuf_free_auto(struct kref *kref){
     struct pbuf *p = container_of(kref, struct pbuf, bufref);
+               printd("deleting p %p of type %d\n", p, p->type);
+               
     switch (p->type){
         case PBUF_REF:
             kmem_cache_free(pbuf_kcache, p);
@@ -28,10 +37,13 @@ static void pbuf_free_auto(struct kref *kref){
         case PBUF_RAM:
             kfree(p);
             break;
+                               case PBUF_MTU:
+                                               kmem_cache_free(mtupbuf_kcache,p);
         default:
             panic("Invalid pbuf type");
     }
 }
+
 /**
  * Allocates a pbuf of the given type (possibly a chain for PBUF_POOL type).
  *
@@ -57,6 +69,8 @@ static void pbuf_free_auto(struct kref *kref){
  *             protocol headers. It is assumed that the pbuf is only
  *             being used in a single thread. If the pbuf gets queued,
  *             then pbuf_take should be called to copy the buffer.
+ * - PBUF_MTU: specific to ROS, additional type that comes out of a 
+ *             slab dedicated for the most common size (MTU sized) pbuf.
  *
  * @return the allocated pbuf. If multiple pbufs where allocated, this
  * is the first pbuf of a pbuf chain.
@@ -91,13 +105,25 @@ struct pbuf *pbuf_alloc(pbuf_layer layer, uint16_t length, pbuf_type type)
   }
        
   switch (type) {
-  case PBUF_RAM:
-    /* If pbuf is to be allocated in RAM, allocate memory for it. */
+       case PBUF_MTU:
+               /* special case PBUFs that are of a common size, notice the length has to be 0 in this case */
+               assert(length==0); // TODO: reconsider this
+    /* only allocate memory for the pbuf structure */
+    p = (struct pbuf *)kmem_cache_alloc(mtupbuf_kcache, 0);
+    if (p == NULL) {
+      return NULL;
+    }
+               buf_size = SIZEOF_STRUCT_MTU_PBUF;
+    p->payload = PTRROUNDUP(((void *)((uint8_t *)p + SIZEOF_STRUCT_PBUF + offset)), ROS_MEM_ALIGN);
+               p->next = NULL;
+               p->type = type;
+               p->len = p->tot_len = ROUNDUP(sizeof(MAX_FRAME_SIZE), ROS_MEM_ALIGN);
+               break;
 
-    // why does it have to be aligned? oh so payload is aligned
+       case PBUF_RAM:
+    /* If pbuf is to be allocated in RAM, allocate memory for it. */
                buf_size =  (SIZEOF_STRUCT_PBUF + offset) + MEM_ALIGN_SIZE(length);
     p = (struct pbuf*)kmalloc(buf_size, 0);
-     // p = (struct pbuf*)kmalloc(
 
     if (p == NULL) {
       return NULL;
@@ -119,6 +145,9 @@ struct pbuf *pbuf_alloc(pbuf_layer layer, uint16_t length, pbuf_type type)
     p->next = NULL;
     p->type = type;
     break;
+       case PBUF_POOL:
+               
+               break;  
   default:
     warn("pbuf_alloc: wrong type", 0);
     return NULL;
index 932063e..633d0ce 100644 (file)
@@ -9,7 +9,7 @@
 #include <socket.h>
 #include <net.h>
 #include <sys/queue.h> //TODO: use sys/queue.h rather than implementing
-#include <arch/atomic.h>
+#include <atomic.h>
 
 #include <bits/netinet.h>
 #include <net/ip.h>
index 2b8793d..415fd8e 100644 (file)
@@ -225,6 +225,14 @@ intreg_t sys_sendto(struct proc *p_proc, int fd, const void *buffer, size_t leng
 }
 
 intreg_t sys_recvfrom(struct proc *p, int socket, void *restrict buffer, size_t length, int flags, struct sockaddr *restrict address, socklen_t *restrict address_len){
-       warn("not implemented yet\n");
+       struct socket* sock = getsocket(p, socket);     
+       if (sock == NULL) {
+               set_errno(EBADF);
+               return -1;
+       }
+       if (sock->so_type == SOCK_DGRAM){
+
+       }
+
        return -1;
 }