Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Clean of virtio NIC, vnet-bridge code
Lei Xia [Wed, 16 Feb 2011 22:36:09 +0000 (16:36 -0600)]
add RTL8139 virtual network device

palacios/include/palacios/vmm_ethernet.h
palacios/include/palacios/vmm_vnet.h
palacios/src/devices/Kconfig
palacios/src/devices/Makefile
palacios/src/devices/lnx_virtio_nic.c
palacios/src/devices/lnx_virtio_vnet.c
palacios/src/devices/rtl8139.c
palacios/src/devices/vnet_nic.c
palacios/src/palacios/vmm_packet.c

index f5e9822..06dde7b 100644 (file)
@@ -30,7 +30,6 @@
 
 #include <palacios/vmm.h>
 
-
 struct nic_statistics {
     uint64_t tx_pkts;
     uint64_t tx_bytes;
@@ -109,6 +108,105 @@ static inline void random_ethaddr(uint8_t * addr)
     addr [0] |= 0x02;  /* set local assignment bit (IEEE802) */
 }
 
+/*-
+ *  CRC32 code derived from work by Gary S. Brown.
+ *
+ *
+ *  First, the polynomial itself and its table of feedback terms.  The
+ *  polynomial is
+ *  X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0
+ *
+ *  Note that we take it "backwards" and put the highest-order term in
+ *  the lowest-order bit.  The X^32 term is "implied"; the LSB is the
+ *  X^31 term, etc.  The X^0 term (usually shown as "+1") results in
+ *  the MSB being 1
+ *
+ *  Note that the usual hardware shift register implementation, which
+ *  is what we're using (we're merely optimizing it by doing eight-bit
+ *  chunks at a time) shifts bits into the lowest-order term.  In our
+ *  implementation, that means shifting towards the right.  Why do we
+ *  do it this way?  Because the calculated CRC must be transmitted in
+ *  order from highest-order term to lowest-order term.  UARTs transmit
+ *  characters in order from LSB to MSB.  By storing the CRC this way
+ *  we hand it to the UART in the order low-byte to high-byte; the UART
+ *  sends each low-bit to hight-bit; and the result is transmission bit
+ *  by bit from highest- to lowest-order term without requiring any bit
+ *  shuffling on our part.  Reception works similarly
+ *
+ *  The feedback terms table consists of 256, 32-bit entries.  Notes
+ *
+ *      The table can be generated at runtime if desired; code to do so
+ *      is shown later.  It might not be obvious, but the feedback
+ *      terms simply represent the results of eight shift/xor opera
+ *      tions for all combinations of data and CRC register values
+ *
+ *      The values must be right-shifted by eight bits by the "updcrc
+ *      logic; the shift must be unsigned (bring in zeroes).  On some
+ *      hardware you could probably optimize the shift in assembler by
+ *      using byte-swap instructions
+ *      polynomial $edb88320
+ *
+ *
+ */
+static uint32_t crc32_tab[] = {
+    0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
+    0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+    0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
+    0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+    0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+    0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+    0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
+    0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+    0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
+    0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+    0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
+    0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+    0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
+    0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+    0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+    0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+    0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
+    0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+    0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
+    0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+    0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
+    0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+    0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
+    0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+    0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+    0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+    0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
+    0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+    0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
+    0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+    0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
+    0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+    0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
+    0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+    0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+    0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+    0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
+    0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+    0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
+    0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+    0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
+    0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+    0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
+};
+
+static inline uint32_t v3_crc32(uint32_t crc, uint8_t *buf, int size)
+{
+    const uint8_t *p;
+
+    p = buf;
+    crc = crc ^ ~0U;
+
+    while (size--){
+       crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
+    }
+
+    return crc ^ ~0U;
+}
 
 #endif
 
index 03d2298..5410af9 100644 (file)
@@ -101,9 +101,6 @@ struct v3_vnet_dev_ops {
                struct v3_vnet_pkt * pkt, 
                void * dev_data);
     void (*poll) (struct v3_vm_info * vm, void * dev_data);
-
-    void (*start_tx)(void * dev_data);
-    void (*stop_tx)(void * dev_data);
 };
 
 int v3_init_vnet(void);        
index 671625f..b4bccb7 100644 (file)
@@ -181,6 +181,19 @@ config DEBUG_NE2K
        help 
          Enable debugging for the NE2K
 
+config RTL8139
+        bool "RTL8139"
+        depends on EXPERIMENTAL
+        default n
+        help
+          Includes the Virtual RTL8139 network card
+
+config DEBUG_RTL8139
+        bool "RTL8139 debugging"
+        default n
+        depends on RTL8139 && DEBUG_ON
+        help
+          Enable debugging for the RTL8139
 
 config NIC_BRIDGE
         bool "Enable Direct Bridge to Host network"
index cdce9ea..2e4a6d6 100644 (file)
@@ -25,6 +25,7 @@ obj-$(CONFIG_DISK_MODEL) += disk_model.o
 obj-$(CONFIG_NIC_BRIDGE) += nic_bridge.o
 
 obj-$(CONFIG_NE2K) += ne2k.o
+obj-$(CONFIG_RTL8139) += rtl8139.o
 
 obj-$(CONFIG_TMPDISK) += tmpdisk.o
 obj-$(CONFIG_RAMDISK) += ramdisk.o 
index 529ce02..da6644e 100644 (file)
 #define PrintDebug(fmt, args...)
 #endif
 
-#define VIRTIO_NET_S_LINK_UP   1       /* Link is up */
 #define VIRTIO_NET_MAX_BUFSIZE (sizeof(struct virtio_net_hdr) + (64 << 10))
 
 
 struct virtio_net_hdr {
        uint8_t flags;
-
-#define VIRTIO_NET_HDR_GSO_NONE                0       /* Not a GSO frame */
+       
        uint8_t gso_type;
        uint16_t hdr_len;               /* Ethernet + IP + tcp/udp hdrs */
        uint16_t gso_size;              /* Bytes to append to hdr_len per frame */
@@ -53,8 +51,6 @@ struct virtio_net_hdr {
 }__attribute__((packed));
 
 
-/* This is the version of the header to use when the MRG_RXBUF
- * feature has been negotiated. */
 struct virtio_net_hdr_mrg_rxbuf {
        struct virtio_net_hdr hdr;
        uint16_t num_buffers;   /* Number of merged rx buffers */
@@ -70,13 +66,8 @@ struct virtio_net_hdr_mrg_rxbuf {
 #define VIRTIO_NET_F_GSO       6       /* Host handles pkts w/ any GSO type */
 #define VIRTIO_NET_F_HOST_TSO4 11      /* Host can handle TSOv4 in. */
 
-/* this is not how virtio supposed to be,
- * we may need a separately implemented virtio_pci
- * In order to make guest to get virtio MAC from host
- * I added it here  -- Lei
- */
- #define VIRTIO_NET_CONFIG 20  
-
+/* Port to get virtio config */
+#define VIRTIO_NET_CONFIG 20  
 
 struct virtio_net_config
 {
@@ -100,12 +91,9 @@ struct virtio_net_state {
     struct pci_device * pci_dev; 
     int io_range_size;
     
-    struct virtio_queue rx_vq;         /* idx 0, pkts to guest */
-    struct virtio_queue tx_vq;         /* idx 1, pkts from guest */
-    struct virtio_queue ctrl_vq;       /* idx 2 */
-
-    int buffed_rx;
-    int tx_disabled;                   /* stop TX pkts from guest */
+    struct virtio_queue rx_vq;         /* idx 0*/
+    struct virtio_queue tx_vq;         /* idx 1*/
+    struct virtio_queue ctrl_vq;       /* idx 2*/
 
     struct nic_statistics statistics;
 
@@ -117,16 +105,6 @@ struct virtio_net_state {
     struct list_head dev_link;
 };
 
-/* virtio nic error type */
-#define ERR_VIRTIO_OTHER  1
-#define ERR_VIRTIO_RXQ_FULL  2
-#define ERR_VIRTIO_RXQ_NOSET  3
-#define ERR_VIRTIO_TXQ_NOSET 4
-#define ERR_VIRTIO_TXQ_FULL 5
-#define ERR_VIRTIO_TXQ_DISABLED 6
-
-
-
 
 static int virtio_init_state(struct virtio_net_state * virtio) 
 {
@@ -161,13 +139,10 @@ static int virtio_init_state(struct virtio_net_state * virtio)
         PrintError("Virtio NIC: Failure to init locks for net_state\n");
     }
 
-    virtio->buffed_rx = 0;
-
     return 0;
 }
 
-static int 
-pkt_tx(struct guest_info * core, 
+static int tx_one_pkt(struct guest_info * core, 
        struct virtio_net_state * virtio, 
        struct vring_desc * buf_desc) 
 {
@@ -175,8 +150,8 @@ pkt_tx(struct guest_info * core,
     uint32_t len = buf_desc->length;
 
     if (v3_gpa_to_hva(core, buf_desc->addr_gpa, (addr_t *)&(buf)) == -1) {
-       PrintError("Could not translate buffer address\n");
-       return -ERR_VIRTIO_OTHER;
+       PrintDebug("Could not translate buffer address\n");
+       return -1;
     }
 
     if(virtio->net_ops->send(buf, len, virtio->backend_data) >= 0){
@@ -235,52 +210,37 @@ static inline void disable_cb(struct virtio_queue *queue) {
 }
 
 
-/* interrupt the guest, so the guest core get EXIT to Palacios
- * this happens when there are either incoming pkts for the guest
- * or the guest can start TX pkts again */
+/* interrupt the guest, so the guest core get EXIT to Palacios */
 static inline void notify_guest(struct virtio_net_state * virtio){
     v3_interrupt_cpu(virtio->virtio_dev->vm, virtio->virtio_dev->vm->cores[0].cpu_id, 0);
 }
 
 
-/* guest free some pkts from rx queue */
-static int handle_rx_kick(struct guest_info *core, 
+/* guest free some pkts for rx queue */
+static int handle_rx_queue_kick(struct guest_info * core, 
                          struct virtio_net_state * virtio) 
 {
-    unsigned long flags;
-
-    flags = v3_lock_irqsave(virtio->rx_lock);
-
-    if(virtio->net_ops->start_rx != NULL){
-       virtio->net_ops->start_rx(virtio->backend_data);
-    }
-    //disable_cb(&virtio->rx_vq);
-
-    v3_unlock_irqrestore(virtio->rx_lock, flags);
-       
     return 0;
 }
 
 
-static int handle_ctrl(struct guest_info *core, 
+static int handle_ctrl(struct guest_info * core, 
                       struct virtio_net_state * virtio) {
        
     return 0;
 }
 
-static int handle_pkt_tx(struct guest_info *core, 
+static int handle_pkt_tx(struct guest_info * core, 
                         struct virtio_net_state * virtio_state) 
 {
-    struct virtio_queue * q = &(virtio_state->tx_vq);
-    struct virtio_net_hdr * hdr = NULL;
-    int recved = 0;
+    struct virtio_queue *q = &(virtio_state->tx_vq);
+    struct virtio_net_hdr *hdr = NULL;
+    int txed = 0;
     unsigned long flags;
 
-    if (!q->ring_avail_addr) 
-       return -ERR_VIRTIO_TXQ_NOSET;
-
-    if(virtio_state->tx_disabled)
-       return -ERR_VIRTIO_TXQ_DISABLED;
+    if (!q->ring_avail_addr) {
+       return -1;
+    }
 
     flags = v3_lock_irqsave(virtio_state->tx_lock);
     while (q->cur_avail_idx != q->avail->index) {
@@ -297,7 +257,7 @@ static int handle_pkt_tx(struct guest_info *core,
            goto exit_error;
        }
 
-       hdr = (struct virtio_net_hdr*)hdr_addr;
+       hdr = (struct virtio_net_hdr *)hdr_addr;
        desc_idx = hdr_desc->next;
 
        if(desc_cnt > 2){
@@ -308,7 +268,7 @@ static int handle_pkt_tx(struct guest_info *core,
        /* here we assumed that one ethernet pkt is not splitted into multiple virtio buffer */
        for (i = 0; i < desc_cnt - 1; i++) {    
            struct vring_desc * buf_desc = &(q->desc[desc_idx]);
-           if (pkt_tx(core, virtio_state, buf_desc) == -1) {
+           if (tx_one_pkt(core, virtio_state, buf_desc) == -1) {
                PrintError("Error handling nic operation\n");
                goto exit_error;
            }
@@ -318,18 +278,17 @@ static int handle_pkt_tx(struct guest_info *core,
        }
 
        q->used->ring[q->used->index % q->queue_size].id = q->avail->ring[q->cur_avail_idx % q->queue_size];
-       q->used->ring[q->used->index % q->queue_size].length = req_len; // What do we set this to????
+       q->used->ring[q->used->index % q->queue_size].length = req_len; /* What do we set this to???? */
        q->used->index ++;
        
        q->cur_avail_idx ++;
+
+       txed ++;
     }
 
     v3_unlock_irqrestore(virtio_state->tx_lock, flags);
-
-    if(!recved)
-       return 0;
        
-    if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
+    if (txed && !(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
        v3_pci_raise_irq(virtio_state->virtio_dev->pci_bus, 0, virtio_state->pci_dev);
        virtio_state->virtio_cfg.pci_isr = 0x1;
 
@@ -341,7 +300,7 @@ static int handle_pkt_tx(struct guest_info *core,
 exit_error:
        
     v3_unlock_irqrestore(virtio_state->tx_lock, flags);
-    return -ERR_VIRTIO_OTHER;
+    return -1;
 }
 
 
@@ -415,11 +374,9 @@ static int virtio_io_write(struct guest_info *core,
            switch (queue_idx) {
                case 0:
                    virtio_setup_queue(core, virtio, &virtio->rx_vq, pfn, page_addr);
-                   //disable_cb(&virtio->rx_vq);
                    break;
                case 1:
                    virtio_setup_queue(core, virtio, &virtio->tx_vq, pfn, page_addr);
-                   //disable_cb(&virtio->tx_vq);
                    break;
                case 2:
                    virtio_setup_queue(core, virtio, &virtio->ctrl_vq, pfn, page_addr);
@@ -442,15 +399,18 @@ static int virtio_io_write(struct guest_info *core,
            {
                uint16_t queue_idx = *(uint16_t *)src;                  
                if (queue_idx == 0){
-                   handle_rx_kick(core, virtio);
+                   if(handle_rx_queue_kick(core, virtio) == -1){
+                       PrintError("Could not handle Virtio NIC rx kick\n");
+                       return -1;
+                   }
                } else if (queue_idx == 1){
                    if (handle_pkt_tx(core, virtio) == -1) {
-                       PrintError("Could not handle NIC Notification\n");
+                       PrintError("Could not handle Virtio NIC tx kick\n");
                        return -1;
                    }
                } else if (queue_idx == 2){
                    if (handle_ctrl(core, virtio) == -1) {
-                       PrintError("Could not handle NIC Notification\n");
+                       PrintError("Could not handle Virtio NIC ctrl kick\n");
                        return -1;
                    }
                } else {
@@ -462,7 +422,6 @@ static int virtio_io_write(struct guest_info *core,
        case VIRTIO_STATUS_PORT:
            virtio->virtio_cfg.status = *(uint8_t *)src;
            if (virtio->virtio_cfg.status == 0) {
-               PrintDebug("Resetting device\n");
                virtio_init_state(virtio);
            }
            break;
@@ -566,38 +525,29 @@ static int virtio_io_read(struct guest_info *core,
 }
 
 
+/* receiving raw ethernet pkt from backend */
 static int virtio_rx(uint8_t * buf, uint32_t size, void * private_data) {
     struct virtio_net_state * virtio = (struct virtio_net_state *)private_data;
     struct virtio_queue * q = &(virtio->rx_vq);
     struct virtio_net_hdr_mrg_rxbuf hdr;
     uint32_t hdr_len = sizeof(struct virtio_net_hdr_mrg_rxbuf);
-    uint32_t data_len = size;
+    uint32_t data_len;
     uint32_t offset = 0;
     unsigned long flags;
-    int ret_val = -ERR_VIRTIO_OTHER;
-    int raw = 1;
 
 #ifndef CONFIG_DEBUG_VIRTIO_NET
-   {
-       PrintDebug("Virtio-NIC: virtio_rx: size: %d\n", size);  
-       //v3_hexdump(buf, size, NULL, 0);
-   }
+    PrintDebug("Virtio-NIC: virtio_rx: size: %d\n", size);     
+    v3_hexdump(buf, size, NULL, 0);
 #endif
 
     flags = v3_lock_irqsave(virtio->rx_lock);
 
-    if (!raw)
-       data_len -= hdr_len;
-
-    if (!raw)
-        memcpy(&hdr, buf, sizeof(struct virtio_net_hdr_mrg_rxbuf));
-    else
-        memset(&hdr, 0, sizeof(struct virtio_net_hdr_mrg_rxbuf));
+    data_len = size;
+    memset(&hdr, 0, sizeof(struct virtio_net_hdr_mrg_rxbuf));
 
     if (q->ring_avail_addr == 0) {
-       PrintError("Queue is not set\n");
-       ret_val = -ERR_VIRTIO_RXQ_NOSET;
-       goto exit;
+       PrintDebug("Queue is not set\n");
+       goto err_exit;
     }
 
     if (q->cur_avail_idx != q->avail->index){
@@ -608,8 +558,8 @@ static int virtio_rx(uint8_t * buf, uint32_t size, void * private_data) {
 
        hdr_desc = &(q->desc[hdr_idx]);
        if (v3_gpa_to_hva(&(virtio->virtio_dev->vm->cores[0]), hdr_desc->addr_gpa, &(hdr_addr)) == -1) {
-           PrintError("Could not translate receive buffer address\n");
-           goto exit;
+           PrintDebug("Could not translate receive buffer address\n");
+           goto err_exit;
        }
        hdr.num_buffers = 1;
        memcpy((void *)hdr_addr, &hdr, sizeof(struct virtio_net_hdr_mrg_rxbuf));
@@ -636,45 +586,31 @@ static int virtio_rx(uint8_t * buf, uint32_t size, void * private_data) {
        q->used->index++;
        q->cur_avail_idx++;
 
-       /* if there are certain num of pkts in the RX queue, notify guest 
-         * so guest will exit to palacios
-         * when it returns, guest gets the virtio rx interrupt */
-       if((++virtio->buffed_rx > q->queue_size/5) &&
-           (q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
-           if(virtio->virtio_dev->vm->cores[0].cpu_id != V3_Get_CPU()){
-                 notify_guest(virtio);
-           }
-           virtio->buffed_rx = 0;
-       }
-
        virtio->statistics.rx_pkts ++;
        virtio->statistics.rx_bytes += size;
     } else {
        virtio->statistics.rx_dropped ++;
        
-       /* RX queue is full,  tell backend to stop RX on this device */
-       virtio->net_ops->stop_rx(virtio->backend_data);
-       enable_cb(&virtio->rx_vq);
-       
-       ret_val = -ERR_VIRTIO_RXQ_FULL;
-       goto exit;
+       goto err_exit;
     }
 
     if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
        PrintDebug("Raising IRQ %d\n",  virtio->pci_dev->config_header.intr_line);
+       
        v3_pci_raise_irq(virtio->virtio_dev->pci_bus, 0, virtio->pci_dev);
        virtio->virtio_cfg.pci_isr = 0x1;
-
        virtio->statistics.interrupts ++;
     }
 
-    ret_val = offset;
+    v3_unlock_irqrestore(virtio->rx_lock, flags);
 
-exit:
+    return 0;
+
+err_exit:
 
     v3_unlock_irqrestore(virtio->rx_lock, flags);
  
-    return ret_val;
+    return -1;
 }
 
 static int virtio_free(struct virtio_dev_state * virtio) {
@@ -700,45 +636,12 @@ static struct v3_device_ops dev_ops = {
 };
 
 
-/* TODO: Issue here: which vm info it needs? calling VM or the device's own VM? */
 static void virtio_nic_poll(struct v3_vm_info * vm, void * data){
     struct virtio_net_state * virtio = (struct virtio_net_state *)data;
        
     handle_pkt_tx(&(vm->cores[0]), virtio);
 }
 
-static void virtio_start_tx(void * data){
-    struct virtio_net_state * virtio = (struct virtio_net_state *)data;
-    unsigned long flags;
-
-    flags = v3_lock_irqsave(virtio->tx_lock);
-    virtio->tx_disabled = 0;
-
-    /* notify the device's guest to start sending pkt */
-    if(virtio->virtio_dev->vm->cores[0].cpu_id != V3_Get_CPU()){
-       notify_guest(virtio);
-    }
-    v3_unlock_irqrestore(virtio->tx_lock, flags);      
-}
-
-static void virtio_stop_tx(void * data){
-    struct virtio_net_state * virtio = (struct virtio_net_state *)data;
-    unsigned long flags;
-
-    flags = v3_lock_irqsave(virtio->tx_lock);
-    virtio->tx_disabled = 1;
-
-    /* stop the guest to exit to palacios for sending pkt? */
-    if(virtio->virtio_dev->vm->cores[0].cpu_id != V3_Get_CPU()){
-       disable_cb(&virtio->tx_vq);
-    }
-
-    v3_unlock_irqrestore(virtio->tx_lock, flags);
-}
-
-       
-
-
 static int register_dev(struct virtio_dev_state * virtio, 
                        struct virtio_net_state * net_state) 
 {
@@ -755,8 +658,9 @@ static int register_dev(struct virtio_dev_state * virtio,
        net_state->io_range_size <<= 1;
     }
        
-    // this is to account for any low order bits being set in num_ports
-    // if there are none, then num_ports was already a power of 2 so we shift right to reset it
+    /* this is to account for any low order bits being set in num_ports
+      * if there are none, then num_ports was already a power of 2 so we shift right to reset it
+      */
     if ((num_ports & ((net_state->io_range_size >> 1) - 1)) == 0) {
        net_state->io_range_size >>= 1;
     }
@@ -828,8 +732,6 @@ static int connect_fn(struct v3_vm_info * info,
 
     ops->recv = virtio_rx;
     ops->poll = virtio_nic_poll;
-    ops->start_tx = virtio_start_tx;
-    ops->stop_tx = virtio_stop_tx;
     ops->frontend_data = net_state;
     memcpy(ops->fnt_mac, virtio->mac, ETH_ALEN);
 
index 9e10784..b4b7342 100644 (file)
@@ -75,7 +75,6 @@ struct virtio_vnet_state {
 #define VNET_ADD_LINK 21
 #define VNET_DEL_LINK 22
 
-// structure of the vnet command header
 struct vnet_ctrl_hdr {
     uint8_t cmd_type;
     uint32_t num_cmds;
@@ -123,8 +122,6 @@ static int get_desc_count(struct virtio_queue * q, int index) {
 }
 
 
-
-
 static int handle_cmd_kick(struct guest_info * core, 
                           struct virtio_vnet_state * vnet_state) {
     struct virtio_queue * q = &(vnet_state->queue[0]);
@@ -143,7 +140,6 @@ static int handle_cmd_kick(struct guest_info * core,
        uint8_t * status_ptr = NULL;
        uint8_t status = 0;
 
-
        PrintDebug("VNET Bridge: CMD: Descriptor Count=%d, index=%d, desc_idx=%d\n", desc_cnt, q->cur_avail_idx % QUEUE_SIZE, desc_idx);
 
        if (desc_cnt < 3) {
@@ -160,8 +156,7 @@ static int handle_cmd_kick(struct guest_info * core,
 
        desc_idx = hdr_desc->next;
        
-       if (hdr->cmd_type == VNET_ADD_ROUTE) {
-           
+       if (hdr->cmd_type == VNET_ADD_ROUTE) {   
            for (i = 0; i < hdr->num_cmds; i++) {
                uint8_t tmp_status = 0;
                struct v3_vnet_route * route = NULL;
@@ -173,26 +168,21 @@ static int handle_cmd_kick(struct guest_info * core,
                    return -1;
                }
 
-               // add route
-               PrintDebug("VNET Bridge: Adding VNET Route\n");
-
                tmp_status = v3_vnet_add_route(*route);
-
-               PrintDebug("VNET Route Added\n");
-
                if (tmp_status != 0) {
                    PrintError("Error adding VNET ROUTE\n");
+                       
                    status = tmp_status;
                }
 
+               PrintDebug("VNET Route Added\n");
+
                xfer_len += buf_desc->length;
                desc_idx = buf_desc->next;
            }
 
        } 
 
-
-
        status_desc = &(q->desc[desc_idx]);
 
        if (v3_gpa_to_hva(core, status_desc->addr_gpa, (addr_t *)&status_ptr) == -1) {
@@ -235,6 +225,7 @@ static int vnet_pkt_input_cb(struct v3_vm_info * vm,
        
     if (q->ring_avail_addr == 0) {
        PrintError("Queue is not set\n");
+       
        goto exit;
     }
 
@@ -244,7 +235,6 @@ static int vnet_pkt_input_cb(struct v3_vm_info * vm,
        struct vnet_bridge_pkt * virtio_pkt = NULL;
 
        pkt_desc = &(q->desc[pkt_idx]);
-       PrintDebug("VNET Bridge RX: buffer desc len: %d\n", pkt_desc->length);
 
        if (v3_gpa_to_hva(&(vm->cores[0]), pkt_desc->addr_gpa, (addr_t *)&(virtio_pkt)) == -1) {
            PrintError("Could not translate buffer address\n");
@@ -282,7 +272,7 @@ exit:
     return ret_val;
 }
 
-static int handle_pkt_kick(struct guest_info * core, 
+static int do_tx_pkts(struct guest_info * core, 
                           struct virtio_vnet_state * vnet_state) 
 {
     struct virtio_queue * q = &(vnet_state->queue[XMIT_QUEUE]);
@@ -298,8 +288,6 @@ static int handle_pkt_kick(struct guest_info * core,
        struct vnet_bridge_pkt * virtio_pkt = NULL;
 
        pkt_desc = &(q->desc[desc_idx]);
-
-       PrintDebug("VNET Bridge: Handle TX desc buf_len: %d\n", pkt_desc->length);
        
        if (v3_gpa_to_hva(core, pkt_desc->addr_gpa, (addr_t *)&(virtio_pkt)) == -1) {
            PrintError("Could not translate buffer address\n");
@@ -343,15 +331,13 @@ static void vnet_virtio_poll(struct v3_vm_info * vm, void * private_data){
     struct virtio_vnet_state * vnet_state = (struct virtio_vnet_state *)private_data;
 
     if(vm == vnet_state->vm){  
-       handle_pkt_kick(&(vm->cores[0]), vnet_state);
+       do_tx_pkts(&(vm->cores[0]), vnet_state);
     }
 }
 
-static int handle_rx_kick(struct guest_info *core, 
+static int handle_rx_queue_kick(struct guest_info *core, 
                          struct virtio_vnet_state * vnet_state) 
-{
-    //v3_vnet_enable_bridge();
-       
+{      
     return 0;
 }
 
@@ -451,13 +437,13 @@ static int vnet_virtio_io_write(struct guest_info * core,
                    return -1;
                }
            } else if (queue_idx == 1) {
-               if (handle_pkt_kick(core, vnet_state) == -1){
+               if (do_tx_pkts(core, vnet_state) == -1){
                    PrintError("Could not handle Virtio VNET TX\n");
                    return -1;
                }
                PrintError("Notify on TX\n");
            } else if (queue_idx == 2) {
-               if (handle_rx_kick(core, vnet_state) == -1){
+               if (handle_rx_queue_kick(core, vnet_state) == -1){
                    PrintError("Could not handle Virtio RX buffer refills Kick\n");
                    return -1;
                }
index 2867208..199d0d7 100644 (file)
  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
  */
 
-#include <devices/ethernet.h>
 #include <devices/pci.h>
 #include <palacios/vmm.h>
 #include <palacios/vmm_types.h>
 #include <palacios/vmm_io.h>
 #include <palacios/vmm_debug.h>
 #include <palacios/vm_guest_mem.h>
+#include <palacios/vmm_ethernet.h>
+#include <palacios/vmm_sprintf.h>
+
 
 
 #ifndef CONFIG_DEBUG_RTL8139
 #define PrintDebug(fmts, args...)
 #endif
 
-
-
-#define NIC_BASE_ADDR  0xc100
-#define NIC_IRQ                11
-
-#define RTL8139_IDR0    (0x00)         /* ID Registers */
-#define RTL8139_IDR1    (0x01)
-#define RTL8139_IDR2    (0x02)
-#define RTL8139_IDR3    (0x03)
-#define RTL8139_IDR4    (0x04)
-#define RTL8139_IDR5    (0x05)
-
-#define RTL8139_MAR0    (0x08) /* Mulicast Registers*/
-#define RTL8139_MAR1    (0x09)
-#define RTL8139_MAR2    (0x0a)
-#define RTL8139_MAR3    (0x0b)
-#define RTL8139_MAR4    (0x0c)
-#define RTL8139_MAR5    (0x0d)
-#define RTL8139_MAR6    (0x0e)
-#define RTL8139_MAR7    (0x0f)
+#define RTL8139_IDR0    (0x00) /* ID Registers start, len 6*1bytes */
+#define RTL8139_MAR0    (0x08) /* Mulicast Registers start, len 8*1bytes */
 
 #define RTL8139_TSD0    (0x10) /* Tx Status of Descriptors */
 #define RTL8139_TSD1    (0x14)
@@ -83,7 +67,7 @@
 #define RTL8139_CONFIG4 (0x5a)
 #define RTL8139_MULINT  (0x5c) /* Multiple Intrpt Select */
 #define RTL8139_RERID   (0x5e) 
-#define RTL8139_TSAD    (0x60) /* Tx Status of All Descriptors */
+#define RTL8139_TXSAD    (0x60)        /* Tx Status of All Descriptors */
 #define RTL8139_BMCR    (0x62) /* Basic Mode Control Register */
 #define RTL8139_BMSR    (0x64) /* Basic Mode Status Register */
 #define RTL8139_ANAR    (0x66) /* Auto-Negotiation Advertisement Register */
 #define RTL8139_TW_PARM (0x7c) /* Twister parameter */
 #define RTL8139_PHY2_PARM   (0x80)
 
-#define RTL8139_CRC0    (0x84) /* Power Management CRC Reg for wakeup frame */
-#define RTL8139_CRC1    (0x85)
-#define RTL8139_CRC2    (0x86)
-#define RTL8139_CRC3    (0x87)
-#define RTL8139_CRC4    (0x88)
-#define RTL8139_CRC5    (0x89)
-#define RTL8139_CRC6    (0x8a)
-#define RTL8139_CRC7    (0x8b)
+#define RTL8139_CRC0    (0x84) /* Power Management CRC Reg for wakeup frame 8*1bytes */
 
 #define RTL8139_Wakeup0        (0x8c)  /* Power Management wakeup frame */
 #define RTL8139_Wakeup1        (0x94)
 
 typedef enum {NIC_READY, NIC_REG_POSTED} nic_state_t;
 
-enum TxStatusBits
-{
-    TSD_Own = 0x2000,
-    TSD_Tun = 0x4000,
-    TSD_Tok = 0x8000,
-    TSD_Cdh = 0x10000000,
-    TSD_Owc = 0x20000000,
-    TSD_Tabt = 0x40000000,
-    TSD_Crs = 0x80000000,
+enum TxStatusBits {
+    TSD_Own = 1<<13,
+    TSD_Tun = 1<<14,
+    TSD_Tok = 1<<15,
+    TSD_Cdh = 1<<28,
+    TSD_Owc = 1<<29,
+    TSD_Tabt = 1<<30,
+    TSD_Crs = 1<<31,
 };
 
+/* Transmit Status Register (TSD0-3) Offset: 0x10-0x1F */
+struct tx_status_reg {
+    union {
+       uint16_t val;
+       struct {
+           uint16_t size     : 13;
+           uint8_t own     : 1;
+           uint8_t tun     : 1;
+           uint8_t tok     : 1;        
+           uint8_t er_tx_th   : 6;
+           uint8_t reserved    : 2;
+           uint8_t ncc            : 4;
+           uint8_t cdh : 1;
+           uint8_t owc : 1;
+           uint8_t tabt        : 1;
+           uint8_t crs : 1;
+       } __attribute__((packed));
+    } __attribute__((packed));
+} __attribute__((packed));
+
+
 enum RxStatusBits {
-    Rx_Multicast = 0x8000,
-    Rx_Physical = 0x4000,
-    Rx_Broadcast = 0x2000,
-    Rx_BadSymbol = 0x0020,
-    Rx_Runt = 0x0010,
-    Rx_TooLong = 0x0008,
-    Rx_CRCErr = 0x0004,
-    Rx_BadAlign = 0x0002,
-    Rx_StatusOK = 0x0001,
+    Rx_Multicast = 1<<15,
+    Rx_Physical = 1<<14,
+    Rx_Broadcast = 1<<13,
+    Rx_BadSymbol = 1<<5,
+    Rx_Runt = 1<<4,
+    Rx_TooLong = 1<<3,
+    Rx_CRCErr = 1<<2,
+    Rx_BadAlign = 1<<1,
+    Rx_OK = 1<<0,
 };
 
 
+/* Receive Status Register in RX Packet Header */
+struct rx_status_reg {
+    union {
+       uint16_t val;
+       struct {
+           uint8_t rx_ok     : 1;
+           uint8_t rx_bad_align     : 1;
+           uint8_t rx_crc_err     : 1;
+           uint8_t rx_too_long     : 1;        
+           uint8_t rx_runt     : 1;
+           uint8_t rx_bad_sym  : 1;
+           uint8_t reserved    : 7;
+           uint8_t rx_brdcast  : 1;
+           uint8_t rx_phys     : 1;
+           uint8_t rx_multi    : 1;
+       } __attribute__((packed));
+    } __attribute__((packed));
+} __attribute__((packed));
+
+
+/* ERSR - Early Rx Status Register Offset: 0x36*/
+struct errx_status_reg{
+    union {
+       uint8_t val;
+       struct {
+           uint8_t er_rx_ok     : 1;
+           uint8_t er_rx_ovw     : 1;
+           uint8_t er_rx_bad_pkt     : 1;
+           uint8_t er_rx_good     : 1; 
+           uint8_t reserved    : 4;
+       } __attribute__((packed));
+    } __attribute__((packed));
+} __attribute__((packed));
+
+
 /* Transmit Status of All Descriptors (TSAD) Register */
 enum TSAD_bits {
- TSAD_TOK3 = 1<<15, // TOK bit of Descriptor 3
- TSAD_TOK2 = 1<<14, // TOK bit of Descriptor 2
- TSAD_TOK1 = 1<<13, // TOK bit of Descriptor 1
- TSAD_TOK0 = 1<<12, // TOK bit of Descriptor 0
- TSAD_TUN3 = 1<<11, // TUN bit of Descriptor 3
- TSAD_TUN2 = 1<<10, // TUN bit of Descriptor 2
- TSAD_TUN1 = 1<<9, // TUN bit of Descriptor 1
- TSAD_TUN0 = 1<<8, // TUN bit of Descriptor 0
- TSAD_TABT3 = 1<<07, // TABT bit of Descriptor 3
- TSAD_TABT2 = 1<<06, // TABT bit of Descriptor 2
- TSAD_TABT1 = 1<<05, // TABT bit of Descriptor 1
- TSAD_TABT0 = 1<<04, // TABT bit of Descriptor 0
- TSAD_OWN3 = 1<<03, // OWN bit of Descriptor 3
- TSAD_OWN2 = 1<<02, // OWN bit of Descriptor 2
- TSAD_OWN1 = 1<<01, // OWN bit of Descriptor 1
- TSAD_OWN0 = 1<<00, // OWN bit of Descriptor 0
+    TSAD_TOK3 = 1<<15, /* TOK bits of Descriptors*/
+    TSAD_TOK2 = 1<<14, 
+    TSAD_TOK1 = 1<<13, 
+    TSAD_TOK0 = 1<<12, 
+    TSAD_TUN3 = 1<<11, /* TUN bits of Descriptors */
+    TSAD_TUN2 = 1<<10, 
+    TSAD_TUN1 = 1<<9, 
+    TSAD_TUN0 = 1<<8,
+    TSAD_TABT3 = 1<<7, /* TABT bits of Descriptors */
+    TSAD_TABT2 = 1<<6,
+    TSAD_TABT1 = 1<<5,
+    TSAD_TABT0 = 1<<4,
+    TSAD_OWN3 = 1<<3, /* OWN bits of Descriptors */
+    TSAD_OWN2 = 1<<2,
+    TSAD_OWN1 = 1<<1, 
+    TSAD_OWN0 = 1<<0,
 };
 
-enum ISRBits
-{
-    ISR_Rok = 0x1,
-    ISR_Rer = 0x2,
-    ISR_Tok = 0x4,
-    ISR_Ter = 0x8,
-    ISR_Rxovw = 0x10,
-    ISR_Pun = 0x20,
-    ISR_Fovw = 0x40,
-    ISR_Lenchg = 0x2000,
-    ISR_Timeout = 0x4000,
-    ISR_Serr = 0x8000,
+
+/* Transmit Status of All Descriptors (TSAD) Register Offset: 0x60-0x61*/
+struct txsad_reg {
+    union {
+       uint16_t val;
+       struct {
+           uint8_t own0     : 1;
+           uint8_t own1     : 1;
+           uint8_t own2     : 1;
+           uint8_t own3     : 1;       
+           uint8_t tabt0       : 1;
+           uint8_t tabt1       : 1;
+           uint8_t tabt2       : 1;
+           uint8_t tabt3       : 1;
+           uint8_t tun0        : 1;
+           uint8_t tun1        : 1;
+           uint8_t tun2        : 1;
+           uint8_t tun3        : 1;
+           uint8_t tok0        : 1;
+           uint8_t tok1        : 1;
+           uint8_t tok2        : 1;
+           uint8_t tok3        : 1;
+       } __attribute__((packed));
+    } __attribute__((packed));
+} __attribute__((packed));
+
+
+
+enum ISRBits {
+    ISR_Rok = 1<<0,
+    ISR_Rer = 1<<1,
+    ISR_Tok = 1<<2,
+    ISR_Ter = 1<<3,
+    ISR_Rxovw = 1<<4,
+    ISR_Pun = 1<<5,
+    ISR_Fovw = 1<<6,
+    ISR_Lenchg = 1<<13,
+    ISR_Timeout = 1<<14,
+    ISR_Serr = 1<<15,
 };
 
-enum CMDBits
-{
-    CMD_Bufe = 0x1,
-    CMD_Te = 0x4,
-    CMD_Re = 0x8,
-    CMD_Rst = 0x10,
+/* 
+ * Interrupt Status Register (ISR) Offset: ox3e-0x3f
+ * Interrupt Mask Register (IMR 0x3c-0x3d) shares the same structure
+ */
+struct isr_imr_reg {
+    union {
+       uint16_t val;
+       struct {
+           uint8_t rx_ok       :1;
+           uint8_t rx_err     : 1;
+           uint8_t tx_ok        : 1;
+           uint8_t tx_err          : 1;
+           uint8_t rx_ovw          : 1;
+           uint8_t pun_linkchg          : 1;
+           uint8_t rx_fifo_ovw  : 1;
+           uint8_t reservd:     6;
+           uint8_t lenchg  :1;
+           uint8_t timeout   :1;
+           uint8_t syserr  :1;
+       } __attribute__((packed));
+    } __attribute__((packed));
+} __attribute__((packed));
+
+enum CMDBits {
+    CMD_Bufe = 1<<0,
+    CMD_Te = 1<<2,
+    CMD_Re = 1<<3,
+    CMD_Rst = 1<<4,
 };
 
+
+/* Commmand Register Offset: 0x37 */
+struct cmd_reg {
+    union {
+       uint8_t val;
+       struct {
+           uint8_t cmd_bufe      : 1;
+           uint8_t reservd_1        : 1;
+           uint8_t cmd_te          : 1;
+           uint8_t cmd_re          : 1;
+           uint8_t cmd_rst          : 1;
+           uint8_t reservd_2  : 3;
+       } __attribute__((packed));
+    } __attribute__((packed));
+} __attribute__((packed));
+
+
+
+
 enum CMD9346Bits {
-       CMD9346_Lock = 0x00,
-       CMD9346_Unlock = 0xC0,
+    CMD9346_Lock = 0x00,
+    CMD9346_Unlock = 0xC0,
 };
 
+
+
+/* 93C46 Commmand Register Offset: 0x50 */
+struct cmd9346_reg {
+    union {
+       uint8_t val;
+       struct {
+           uint8_t eedo      : 1;
+           uint8_t eedi        : 1;
+           uint8_t eesk          : 1;
+           uint8_t eecs          : 1;
+           uint8_t reserved    : 2;
+           uint8_t eem  : 2;
+       } __attribute__((packed));
+    } __attribute__((packed));
+} __attribute__((packed));
+
+
+
 // Bits in TxConfig.
 enum TXConfig_bits{
 
         /* Interframe Gap Time. Only TxIFG96 doesn't violate IEEE 802.3 */
-      TxIFGShift = 24,
-      TxIFG84 = (0 << TxIFGShift),    /* 8.4us / 840ns (10 / 100Mbps) */
-      TxIFG88 = (1 << TxIFGShift),    /* 8.8us / 880ns (10 / 100Mbps) */
-      TxIFG92 = (2 << TxIFGShift),    /* 9.2us / 920ns (10 / 100Mbps) */
-      TxIFG96 = (3 << TxIFGShift),    /* 9.6us / 960ns (10 / 100Mbps) */
-
-       TxLoopBack = (1 << 18) | (1 << 17), /* enable loopback test mode */
-       TxCRC = (1 << 16),      /* DISABLE appending CRC to end of Tx packets */
-       TxClearAbt = (1 << 0),  /* Clear abort (WO) */
-       TxDMAShift = 8,         /* DMA burst value (0-7) is shifted this many bits */
-       TxRetryShift = 4,       /* TXRR value (0-15) is shifted this many bits */
-
-       TxVersionMask = 0x7C800000, /* mask out version bits 30-26, 23 */
+    TxIFGShift = 24,
+    TxIFG84 = (0 << TxIFGShift),    /* 8.4us / 840ns (10 / 100Mbps) */
+    TxIFG88 = (1 << TxIFGShift),    /* 8.8us / 880ns (10 / 100Mbps) */
+    TxIFG92 = (2 << TxIFGShift),    /* 9.2us / 920ns (10 / 100Mbps) */
+    TxIFG96 = (3 << TxIFGShift),    /* 9.6us / 960ns (10 / 100Mbps) */
+
+    TxLoopBack = (1 << 18) | (1 << 17), /* enable loopback test mode */
+    TxCRC = (1 << 16), /* DISABLE appending CRC to end of Tx packets */
+    TxClearAbt = (1 << 0),     /* Clear abort (WO) */
+    TxDMAShift = 8,            /* DMA burst value (0-7) is shifted this many bits */
+    TxRetryShift = 4,  /* TXRR value (0-15) is shifted this many bits */
+
+    TxVersionMask = 0x7C800000, /* mask out version bits 30-26, 23 */
 };
 
+
+/* Transmit Configuration Register (TCR) Offset: 0x40-0x43 */
+struct tx_config_reg {
+    union {
+       uint32_t val;
+       struct {
+           uint8_t clr_abort   :1;
+           uint8_t reserved_1     : 3;
+           uint8_t tx_retry_cnt        : 4;
+           uint8_t max_dma          : 3;
+           uint8_t reserved_2          : 5;
+           uint8_t tx_crc          : 1;
+           uint8_t loop_test  : 2;
+           uint8_t reservd_3:     3;
+           uint8_t hw_verid_b  :2;
+           uint8_t ifg   :2;
+           uint8_t hw_verid_a  :5;
+           uint8_t reservd_4  :1;
+       } __attribute__((packed));
+    } __attribute__((packed));
+} __attribute__((packed));
+
+
+
+
 enum CSCRBits {
     CSCR_Testfun = 1<<15, /* 1 = Auto-neg speeds up internal timer, WO, def 0 */
     CSCR_LD  = 1<<9,  /* Active low TPI link disable signal. When low, TPI still transmits link pulses and TPI stays in good link state. def 1*/
@@ -247,16 +391,68 @@ enum CSCRBits {
     CSCR_PASS_SCR = 1<<0, /* Bypass Scramble, def 0*/
 };
 
+
+/* CS Configuration Register (CSCR) Offset: 0x74-0x75 */
+struct cscr_reg {
+    union {
+       uint16_t val;
+       struct {
+           uint8_t pass_scr    :1;
+           uint8_t reserved_1     : 1;
+           uint8_t con_status_en        : 1;
+           uint8_t con_status          : 1;
+           uint8_t reserved_2          : 1;
+           uint8_t f_connect          : 1;
+           uint8_t f_link_100  : 1;
+           uint8_t jben:     1;
+           uint8_t heart_beat  :1;
+           uint8_t ld   :1;
+           uint8_t reservd_3  :5;
+           uint8_t test_fun  :1;
+       } __attribute__((packed));
+    } __attribute__((packed));
+} __attribute__((packed));
+
+
 /* Bits in RxConfig. */
 enum rx_mode_bits {
-       AcceptErr = 0x20,
-       AcceptRunt = 0x10,
-       AcceptBroadcast = 0x08,
-       AcceptMulticast = 0x04,
-       AcceptMyPhys = 0x02,
-       AcceptAllPhys = 0x01,
+    AcceptErr = 0x20,
+    AcceptRunt = 0x10,
+    AcceptBroadcast = 0x08,
+    AcceptMulticast = 0x04,
+    AcceptMyPhys = 0x02,
+    AcceptAllPhys = 0x01,
 };
 
+
+/* Receive Configuration Register (RCR) Offset: 0x44-0x47 */
+struct rx_config_reg {
+    union {
+       uint32_t val;
+       struct {
+           uint8_t all_phy   : 1;
+           uint8_t my_phy      : 1;
+           uint8_t all_multi     : 1;
+           uint8_t all_brdcast        : 1;
+           uint8_t acpt_runt          : 1;
+           uint8_t acpt_err          : 1;
+           uint8_t reserved_1          : 1;
+           uint8_t wrap  : 1;
+           uint8_t max_dma:     3;
+           uint8_t rx_buf_len  :2;
+           uint8_t rx_fifo_thresd   :3;
+           uint8_t rer8  :1;
+           uint8_t mul_er_intr  :1;
+           uint8_t reserved_2          : 6;
+           uint8_t eraly_rx_thresd   :4;
+           uint8_t reserved_3          : 4;
+       } __attribute__((packed));
+    } __attribute__((packed));
+} __attribute__((packed));
+
+
+
+
 #define RTL8139_PCI_REVID_8139      0x10
 
 #define SET_MASKED(input, mask, curr) \
@@ -283,8 +479,7 @@ enum Chip9346Operation
     Chip9346_op_write_disable = 0x00, /* 00 00zzzz */
 };
 
-enum Chip9346Mode
-{
+enum Chip9346Mode {
     Chip9346_none = 0,
     Chip9346_enter_command_mode,
     Chip9346_read_command,
@@ -293,8 +488,7 @@ enum Chip9346Mode
     Chip9346_data_write_all, /* to input register, then filling contents */
 };
 
-struct EEprom9346
-{
+struct EEprom9346 {
     uint16_t contents[EEPROM_9346_SIZE];
     int      mode;
     uint32_t tick;
@@ -361,8 +555,7 @@ struct rtl8139_regs {
 
 
 
-struct rtl8139_state
-{      
+struct rtl8139_state { 
     nic_state_t dev_state;
 
     struct v3_vm_info * vm;
@@ -385,55 +578,21 @@ struct rtl8139_state
     void * backend_data;
 };
 
-
-static void rtl8139_reset(struct vm_device *dev);
-
-static void dump_state(struct vm_device *dev)
-{
-    struct nic_context *nic_state = (struct nic_context *)dev->private_data;
-    PrintDebug("====RTL8139: Dumping State Begin==========\n");
-    PrintDebug("Registers\n");
-    int i;
-    uchar_t *reg;
-       reg = (uchar_t *)&nic_state->regs;
-
-    for(i = 0; i < sizeof(struct nic_regs); i++)
-    {
-        PrintDebug("Register[%d] = 0x%2x\n", i, (int)reg[i]);
-    }
-
-    PrintDebug("====RTL8139: Dumping State End==========\n");
-}
-
-static void rtl8139_update_irq(struct rtl8139_state *nic_state)
-{
-    struct pci_device *pdev = nic_state->pci_dev;
-    int irq_line;
-
-    irq_line = pdev->configs[PCI_INTERRUPT_LINE];
+static inline void rtl8139_update_irq(struct rtl8139_state * nic_state) {
     int isr = ((nic_state->regs.isr & nic_state->regs.imr) & 0xffff);
 
-    if(isr & 0xffff)
-    {
-        if (irq_line != 0){
-               v3_raise_irq(dev->vm, irq_line);
-               PrintDebug("VNIC: RaiseIrq %d: isr: 0x%04x imr : 0x%04x\n", irq_line, nic_state->regs.isr, nic_state->regs.imr);
-        } else {
-             PrintError("RTL8139: IRQ_Line: %d\n", irq_line);
-        }
+    if(isr & 0xffff){
+       v3_pci_raise_irq(nic_state->pci_bus, 0, nic_state->pci_dev);
+       nic_state->statistic.interrupts ++;
     }
 }
 
-#if 1
-
-static void prom9346_decode_command(struct EEprom9346 *eeprom, uint8_t command)
-{
+static void prom9346_decode_command(struct EEprom9346 * eeprom, uint8_t command) {
     PrintDebug("RTL8139: eeprom command 0x%02x\n", command);
 
-    switch (command & Chip9346_op_mask)
-    {
+    switch (command & Chip9346_op_mask) {
         case Chip9346_op_read:
-        {
+       {
             eeprom->address = command & EEPROM_9346_ADDR_MASK;
             eeprom->output = eeprom->contents[eeprom->address];
             eeprom->eedo = 0;
@@ -456,8 +615,7 @@ static void prom9346_decode_command(struct EEprom9346 *eeprom, uint8_t command)
         break;
         default:
             eeprom->mode = Chip9346_none;
-            switch (command & Chip9346_op_ext_mask)
-            {
+            switch (command & Chip9346_op_ext_mask) {
                 case Chip9346_op_write_enable:
                     PrintDebug("RTL8139: eeprom write enabled\n");
                     break;
@@ -468,23 +626,20 @@ static void prom9346_decode_command(struct EEprom9346 *eeprom, uint8_t command)
                     PrintDebug("RTL8139: eeprom write disabled\n");
                     break;
             }
-            break;
+        break;
     }
 }
 
-static void prom9346_shift_clock(struct EEprom9346 *eeprom)
-{
+static void prom9346_shift_clock(struct EEprom9346 * eeprom) {
     int bit = eeprom->eedi?1:0;
 
     ++ eeprom->tick;
 
     PrintDebug("eeprom: tick %d eedi=%d eedo=%d\n", eeprom->tick, eeprom->eedi, eeprom->eedo);
 
-    switch (eeprom->mode)
-    {
+    switch (eeprom->mode) {
         case Chip9346_enter_command_mode:
-            if (bit)
-            {
+            if (bit) {
                 eeprom->mode = Chip9346_read_command;
                 eeprom->tick = 0;
                 eeprom->input = 0;
@@ -494,8 +649,7 @@ static void prom9346_shift_clock(struct EEprom9346 *eeprom)
 
         case Chip9346_read_command:
             eeprom->input = (eeprom->input << 1) | (bit & 1);
-            if (eeprom->tick == 8)
-            {
+            if (eeprom->tick == 8) {
                 prom9346_decode_command(eeprom, eeprom->input & 0xff);
             }
             break;
@@ -503,8 +657,7 @@ static void prom9346_shift_clock(struct EEprom9346 *eeprom)
         case Chip9346_data_read:
             eeprom->eedo = (eeprom->output & 0x8000)?1:0;
             eeprom->output <<= 1;
-            if (eeprom->tick == 16)
-            {
+            if (eeprom->tick == 16){
 #if 1
         // the FreeBSD drivers (rl and re) don't explicitly toggle
         // CS between reads (or does setting Cfg9346 to 0 count too?),
@@ -529,8 +682,7 @@ static void prom9346_shift_clock(struct EEprom9346 *eeprom)
 
         case Chip9346_data_write:
             eeprom->input = (eeprom->input << 1) | (bit & 1);
-            if (eeprom->tick == 16)
-            {
+            if (eeprom->tick == 16) {
                 PrintDebug("RTL8139: eeprom write to address 0x%02x data=0x%04x\n",
                        eeprom->address, eeprom->input);
 
@@ -543,8 +695,7 @@ static void prom9346_shift_clock(struct EEprom9346 *eeprom)
 
         case Chip9346_data_write_all:
             eeprom->input = (eeprom->input << 1) | (bit & 1);
-            if (eeprom->tick == 16)
-            {
+            if (eeprom->tick == 16) {
                 int i;
                 for (i = 0; i < EEPROM_9346_SIZE; i++)
                 {
@@ -564,20 +715,19 @@ static void prom9346_shift_clock(struct EEprom9346 *eeprom)
     }
 }
 
-static int prom9346_get_wire(struct vm_device *dev)
-{
-    struct nic_context *nic_state = (struct nic_context *)dev->private_data;
+static int prom9346_get_wire(struct rtl8139_state * nic_state) {
     struct EEprom9346 *eeprom = &(nic_state->eeprom);
 
-    if (!eeprom->eecs)
+    if (eeprom->eecs == 0)
         return 0;
 
     return eeprom->eedo;
 }
 
-static void prom9346_set_wire(struct vm_device *dev, int eecs, int eesk, int eedi)
-{
-    struct nic_context *nic_state = (struct nic_context *)dev->private_data;
+static void prom9346_set_wire(struct rtl8139_state * nic_state, 
+                             int eecs, 
+                             int eesk, 
+                             int eedi) {
     struct EEprom9346 *eeprom = &(nic_state->eeprom);
     uint8_t old_eecs = eeprom->eecs;
     uint8_t old_eesk = eeprom->eesk;
@@ -589,8 +739,7 @@ static void prom9346_set_wire(struct vm_device *dev, int eecs, int eesk, int eed
     PrintDebug("eeprom: +++ wires CS=%d SK=%d DI=%d DO=%d\n",
                  eeprom->eecs, eeprom->eesk, eeprom->eedi, eeprom->eedo);
 
-    if (!old_eecs && eecs)
-    {
+    if (old_eecs == 0 && eecs) {
         /* Synchronize start */
         eeprom->tick = 0;
         eeprom->input = 0;
@@ -600,23 +749,90 @@ static void prom9346_set_wire(struct vm_device *dev, int eecs, int eesk, int eed
         PrintDebug("=== eeprom: begin access, enter command mode\n");
     }
 
-    if (!eecs)
-    {
+    if (eecs == 0) {
         PrintDebug("=== eeprom: end access\n");
         return;
     }
 
-    if (!old_eesk && eesk)
-    {
+    if (!old_eesk && eesk) {
         /* SK front rules */
         prom9346_shift_clock(eeprom);
     }
 }
 
-static void rtl8139_9346cr_write(struct vm_device *dev, uint32_t val)
-{
-    struct nic_context *nic_state = (struct nic_context *)dev->private_data;
 
+static inline void rtl8139_reset_rxbuf(struct rtl8139_state * nic_state, uint32_t bufsize) {
+    nic_state->rx_bufsize = bufsize;
+    nic_state->regs.capr = 0;
+    nic_state->regs.cbr = 0;
+}
+
+
+static void rtl8139_reset(struct rtl8139_state *nic_state) {
+    struct rtl8139_regs *regs = &(nic_state->regs);
+    int i;
+
+    PrintDebug("Rtl8139: Reset\n");
+
+    /* restore MAC address */
+    memcpy(regs->id, nic_state->mac, ETH_ALEN);
+    memset(regs->mult, 0xff, 8);
+
+    rtl8139_update_irq(nic_state);
+
+    // prepare eeprom
+    nic_state->eeprom.contents[0] = 0x8129;
+       
+    // PCI vendor and device ID
+    nic_state->eeprom.contents[1] = 0x10ec;
+    nic_state->eeprom.contents[2] = 0x8139;
+    //Mac address
+    nic_state->eeprom.contents[7] = nic_state->mac[0] | nic_state->mac[1] << 8;
+    nic_state->eeprom.contents[8] = nic_state->mac[2] | nic_state->mac[3] << 8;
+    nic_state->eeprom.contents[9] = nic_state->mac[4] | nic_state->mac[5] << 8;
+
+    for (i = 0; i < 4; ++i) {
+        regs->tsd[i] = TSD_Own;
+    }
+
+    rtl8139_reset_rxbuf(nic_state, 1024*8);
+
+    /* ACK the reset */
+    regs->tcr = 0;
+
+    regs->tcr |= ((0x1d << 26) | (0x1 << 22)); // RTL-8139D
+    regs->rerid = RTL8139_PCI_REVID_8139;
+
+    regs->cmd = CMD_Rst; //RxBufEmpty bit is calculated on read from ChipCmd 
+
+    regs->config[0] = 0x0 | (1 << 4); // No boot ROM 
+    regs->config[1] = 0xC; //IO mapped and MEM mapped registers available
+    //regs->config[1] = 0x4; //Only IO mapped registers available
+    regs->config3[0] = 0x1; // fast back-to-back compatible
+    regs->config3[1] = 0x0;
+    regs->config5 = 0x0;
+       
+    regs->cscr = CSCR_F_LINK_100 | CSCR_HEART_BIT | CSCR_LD;
+
+    //0x3100 : 100Mbps, full duplex, autonegotiation.  0x2100 : 100Mbps, full duplex
+    regs->bmcr = 0x1000; // autonegotiation
+
+    regs->bmsr  = 0x7809;
+    regs->bmsr |= 0x0020; // autonegotiation completed
+    regs->bmsr |= 0x0004; // link is up
+
+    regs->anar = 0x05e1;     // all modes, full duplex
+    regs->anlpar = 0x05e1;   // all modes, full duplex
+    regs->aner = 0x0001;     // autonegotiation supported
+
+    // reset timer and disable timer interrupt
+    regs->tctr = 0;
+    regs->timer_int = 0;
+}
+
+
+
+static void rtl8139_9346cr_write(struct rtl8139_state * nic_state, uint32_t val) {
     val &= 0xff;
 
     PrintDebug("RTL8139: 9346CR write val=0x%02x\n", val);
@@ -632,32 +848,26 @@ static void rtl8139_9346cr_write(struct vm_device *dev, uint32_t val)
         int eecs = (eeprom_val & 0x08)?1:0;
         int eesk = (eeprom_val & 0x04)?1:0;
         int eedi = (eeprom_val & 0x02)?1:0;
-        prom9346_set_wire(dev, eecs, eesk, eedi);
+        prom9346_set_wire(nic_state, eecs, eesk, eedi);
     } else if (opmode == 0x40) {
         /* Reset.  */
         val = 0;
-        rtl8139_reset(dev);
+        rtl8139_reset(nic_state);
     }
 
     nic_state->regs.cmd9346 = val;
 }
 
-static uint32_t rtl8139_9346cr_read(struct vm_device *dev)
-{
-    struct nic_context *nic_state = (struct nic_context *)dev->private_data;
+static uint32_t rtl8139_9346cr_read(struct rtl8139_state * nic_state) {
     uint32_t ret = nic_state->regs.cmd9346;
     uint32_t opmode = ret & 0xc0;
 
-    if (opmode == 0x80)
-    {
+    if (opmode == 0x80) {
         /* eeprom access */
-        int eedo = prom9346_get_wire(dev);
-        if (eedo)
-        {
+        int eedo = prom9346_get_wire(nic_state);
+        if (eedo){
             ret |=  0x01;
-        }
-        else
-        {
+        } else {
             ret &= ~0x01;
         }
     }
@@ -667,44 +877,34 @@ static uint32_t rtl8139_9346cr_read(struct vm_device *dev)
     return ret;
 }
 
-#endif
-
-static int rtl8139_receiver_enabled(struct vm_device *dev)
-{
-    struct nic_context *nic_state = (struct nic_context *)(dev->private_data);
 
+static inline int rtl8139_receiver_enabled(struct rtl8139_state * nic_state) {
     return nic_state->regs.cmd & CMD_Re;
 }
 
-static int rtl8139_rxwrap(struct vm_device *dev)
-{
-    struct nic_context *nic_state = (struct nic_context *)(dev->private_data);
-
+static inline int rtl8139_rxwrap(struct rtl8139_state * nic_state) {
     // wrapping enabled; assume 1.5k more buffer space if size < 64K
     return (nic_state->regs.rcr & (1 << 7));
 }
 
-static void rtl8139_rxbuf_write(struct vm_device *dev, const void *buf, int size)
-{
-    struct nic_context *nic_state = (struct nic_context *)(dev->private_data);
-    struct nic_regs *regs = &(nic_state->regs);
+static void rtl8139_rxbuf_write(struct rtl8139_state * nic_state, 
+                               const void * buf, 
+                               int size) {
+    struct rtl8139_regs *regs = &(nic_state->regs);
     int wrap;
     addr_t guestpa, host_rxbuf;
 
     guestpa = (addr_t)regs->rbstart;
-    guest_pa_to_host_va(dev->vm, guestpa, &host_rxbuf);   
+    v3_gpa_to_hva(&(nic_state->vm->cores[0]), guestpa, &host_rxbuf);   
 
     //wrap to the front of rx buffer
-    if (regs->cbr + size > nic_state->rx_bufsize)
-    {
+    if (regs->cbr + size > nic_state->rx_bufsize){
         wrap = MOD2(regs->cbr + size, nic_state->rx_bufsize);
 
-        if (wrap && !(nic_state->rx_bufsize < 64*1024 && rtl8139_rxwrap(dev)))
-        {
+        if (wrap && !(nic_state->rx_bufsize < 64*1024 && rtl8139_rxwrap(nic_state))){
             PrintDebug("RTL8139: rx packet wrapped in buffer at %d\n", size-wrap);
 
-            if (size > wrap)
-            {
+            if (size > wrap){
                 memcpy((void *)(host_rxbuf + regs->cbr), buf, size-wrap);
             }
 
@@ -727,8 +927,7 @@ static void rtl8139_rxbuf_write(struct vm_device *dev, const void *buf, int size
 #define POLYNOMIAL 0x04c11db6
 
 /* From FreeBSD */
-static int compute_mcast_idx(const uint8_t *ep)
-{
+static inline int compute_mcast_idx(const uint8_t *ep) {
     uint32_t crc;
     int carry, i, j;
     uint8_t b;
@@ -740,94 +939,88 @@ static int compute_mcast_idx(const uint8_t *ep)
             carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01);
             crc <<= 1;
             b >>= 1;
-            if (carry)
+            if (carry){
                 crc = ((crc ^ POLYNOMIAL) | carry);
+           }
         }
     }
     return (crc >> 26);
 }
-static void vnic_receive(struct vm_device *dev, const uchar_t *pkt, uint_t length)
-{
-    struct nic_context *nic_state = (struct nic_context *)dev->private_data;
-    struct nic_regs *regs = &(nic_state->regs);
+
+
+static int rx_one_pkt(struct rtl8139_state * nic_state, 
+                     uint8_t * pkt, 
+                     uint32_t len){
+    struct rtl8139_regs *regs = &(nic_state->regs);
     uint_t rxbufsize = nic_state->rx_bufsize;
     uint32_t header, val;
     uint8_t bcast_addr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 
     if (regs->rcr & AcceptAllPhys) {
-        PrintDebug("RTL8139: packet received in promiscuous mode\n");
+       PrintDebug("RTL8139: packet received in promiscuous mode\n");
     } else {
-        if (!memcmp(pkt,  bcast_addr, 6)) {
-            if (!(regs->rcr & AcceptBroadcast))
-            {
-                PrintDebug("RTL8139: broadcast packet rejected\n");
-                return;
-            }
-            header |= Rx_Broadcast;
-            PrintDebug("RTL8139: broadcast packet received\n");
-        } else if (pkt[0] & 0x01) {
+       if (!memcmp(pkt,  bcast_addr, 6)) {
+           if (!(regs->rcr & AcceptBroadcast)){
+               PrintDebug("RTL8139: broadcast packet rejected\n");
+               return -1;
+           }
+           header |= Rx_Broadcast;
+           PrintDebug("RTL8139: broadcast packet received\n");
+       } else if (pkt[0] & 0x01) {
             // multicast
-            if (!(regs->rcr & AcceptMulticast))
-            {
+            if (!(regs->rcr & AcceptMulticast)){
                 PrintDebug("RTL8139: multicast packet rejected\n");
-                return;
+                return -1;
             }
 
             int mcast_idx = compute_mcast_idx(pkt);
 
-            if (!(regs->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7))))
-            {
+            if (!(regs->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7)))){
                 PrintDebug("RTL8139: multicast address mismatch\n");
-                return;
+                return -1;
             }
             header |= Rx_Multicast;
             PrintDebug("RTL8139: multicast packet received\n");
-        } else if (regs->id[0] == pkt[0] &&
-                   regs->id[1] == pkt[1] &&
-                   regs->id[2] == pkt[2] &&
-                   regs->id[3] == pkt[3] &&
-                   regs->id[4] == pkt[4] &&
-                   regs->id[5] == pkt[5]) {
-            if (!(regs->rcr & AcceptMyPhys))
-            {
+        } else if (!compare_ethaddr(regs->id, pkt)){
+            if (!(regs->rcr & AcceptMyPhys)){
                 PrintDebug("RTL8139: rejecting physical address matching packet\n");
-                return;
+                return -1;
             }
 
             header |= Rx_Physical;
             PrintDebug("RTL8139: physical address matching packet received\n");
         } else {
             PrintDebug("RTL8139: unknown packet\n");
-            return;
+            return -1;
         }
     }
 
     if(1){
-        PrintDebug("RTL8139: in ring Rx mode\n");
+       PrintDebug("RTL8139: in ring Rx mode\n");
 
-        int avail = MOD2(rxbufsize + regs->capr - regs->cbr, rxbufsize);
+       int avail = MOD2(rxbufsize + regs->capr - regs->cbr, rxbufsize);
 
-        if (avail != 0 && length + 8 >= avail)
-        {
+        if (avail != 0 && len + 8 >= avail){
             PrintError("rx overflow: rx buffer length %d head 0x%04x read 0x%04x === available 0x%04x need 0x%04x\n",
-                   rxbufsize, regs->cbr, regs->capr, avail, length + 8);
+                   rxbufsize, regs->cbr, regs->capr, avail, len + 8);
 
             regs->isr |= ISR_Rxovw;
             ++ regs->mpc;
-            rtl8139_update_irq(dev);
-            return;
+            rtl8139_update_irq(nic_state);
+            return -1;
         }
 
-        header |= Rx_StatusOK;
-        header |= ((length << 16) & 0xffff0000);
+        header |= Rx_OK;
+        header |= ((len << 16) & 0xffff0000);
 
-        rtl8139_rxbuf_write(dev, (uint8_t *)&header, 4);
+        rtl8139_rxbuf_write(nic_state, (uint8_t *)&header, 4);
 
-        rtl8139_rxbuf_write(dev, pkt, length);
+        rtl8139_rxbuf_write(nic_state, pkt, len);
 
-        val = V3_Crc32(0, (char *)pkt, length);
+        /* CRC checksum */
+        val = v3_crc32(0, pkt, len);
 
-        rtl8139_rxbuf_write(dev, (uint8_t *)&val, 4);
+        rtl8139_rxbuf_write(nic_state, (uint8_t *)&val, 4);
 
         // correct buffer write pointer 
         regs->cbr = MOD2((regs->cbr + 3) & ~0x3, rxbufsize);
@@ -838,48 +1031,43 @@ static void vnic_receive(struct vm_device *dev, const uchar_t *pkt, uint_t lengt
 
     regs->isr |= ISR_Rok;
 
-    nic_state->pkts_rcvd++;
+    nic_state->statistic.rx_pkts ++;
+    nic_state->statistic.rx_bytes += len;
        
-    rtl8139_update_irq(dev);   
+    rtl8139_update_irq(nic_state);   
+
+    return 0;
 }
 
-static int netif_input(uchar_t *pkt, uint_t size)
-{
-    PrintDebug("RTL8139: packet received!\n");
+static int rtl8139_rx(uint8_t * pkt, uint32_t len, void * private_data) {
+    struct rtl8139_state *nic_state = (struct rtl8139_state *)private_data;
 
-    if (!rtl8139_receiver_enabled(current_vnic)){
-               PrintDebug("RTL8139: receiver disabled\n");
-               return 0;
+    if (!rtl8139_receiver_enabled(nic_state)){
+       PrintDebug("RTL8139: receiver disabled\n");
+       nic_state->statistic.rx_dropped ++;
+               
+       return 0;
+    }
+       
+    if(rx_one_pkt(nic_state, pkt, len) >= 0){
+       nic_state->statistic.rx_pkts ++;
+       nic_state->statistic.rx_bytes += len;
+    }else {
+       nic_state->statistic.rx_dropped ++;
     }
-    vnic_receive(current_vnic, pkt, size);
 
     return 0;
 }
 
-static void rtl8139_reset_rxbuf(struct vm_device *dev, uint32_t bufsize)
-{
-    struct nic_context *nic_state = (struct nic_context *)(dev->private_data);
-    struct nic_regs *regs = &(nic_state->regs);
-       
-    nic_state->rx_bufsize = bufsize;
-    regs->capr  = 0;
-    regs->cbr = 0;
-}
-
-static void rtl8139_rcr_write(struct vm_device *dev, uint32_t val)
-{
-    struct nic_context *nic_state = (struct nic_context *)(dev->private_data);
-
+static void rtl8139_rcr_write(struct rtl8139_state * nic_state, uint32_t val) {
     PrintDebug("RTL8139: RCR write val=0x%08x\n", val);
 
     val = SET_MASKED(val, 0xf0fc0040, nic_state->regs.rcr);
-
     nic_state->regs.rcr = val;
 
 #if 0
     uchar_t rblen = (regs->rcr >> 11) & 0x3;
-    switch(rblen)
-    {
+    switch(rblen) {
         case 0x0:
             rxbufsize = 1024 * 8 + 16;
             break;
@@ -896,100 +1084,11 @@ static void rtl8139_rcr_write(struct vm_device *dev, uint32_t val)
 #endif
 
     // reset buffer size and read/write pointers
-    rtl8139_reset_rxbuf(dev, 8192 << ((nic_state->regs.rcr >> 11) & 0x3));
+    rtl8139_reset_rxbuf(nic_state, 8192 << ((nic_state->regs.rcr >> 11) & 0x3));
 
     PrintDebug("RTL8139: RCR write reset buffer size to %d\n", nic_state->rx_bufsize);
 }
 
-static void rtl8139_reset(struct rtl8139_state *nic_state)
-{
-    struct rtl8139_regs *regs = &(nic_state->regs);
-    int i;
-
-    PrintDebug("Rtl8139: Reset\n");
-
-    /* restore MAC address */
-    memcpy(regs->id, nic_state->mac, ETH_ALEN);
-    memset(regs->mult, 0xff, 8);
-
-    regs->isr = 0;
-    regs->imr = 0;
-
-    rtl8139_update_irq(nic_state);
-
-    // prepare eeprom
-    nic_state->eeprom.contents[0] = 0x8129;
-       
-    // PCI vendor and device ID
-    nic_state->eeprom.contents[1] = 0x10ec;
-    nic_state->eeprom.contents[2] = 0x8139;
-    //Mac address
-    nic_state->eeprom.contents[7] = nic_state->mac[0] | nic_state->mac[1] << 8;
-    nic_state->eeprom.contents[8] = nic_state->mac[2] | nic_state->mac[3] << 8;
-    nic_state->eeprom.contents[9] = nic_state->mac[4] | nic_state->mac[5] << 8;
-
-    for (i = 0; i < 4; ++i)
-    {
-        regs->tsd[i] = TSD_Own;
-    }
-
-    regs->rbstart = 0;
-
-    rtl8139_reset_rxbuf(nic_state, 1024*8);
-
-    /* ACK the reset */
-    regs->tcr = 0;
-
-    regs->tcr |= ((0x1d << 26) | (0x1 << 22)); // RTL-8139D
-    regs->rerid = RTL8139_PCI_REVID_8139;
-
-    regs->cmd = CMD_Rst; //RxBufEmpty bit is calculated on read from ChipCmd 
-
-    regs->config[0] = 0x0 | (1 << 4); // No boot ROM 
-    regs->config[1] = 0xC; //IO mapped and MEM mapped registers available
-    //regs->config[1] = 0x4; //Only IO mapped registers available
-    regs->config3[0] = 0x1; // fast back-to-back compatible
-    regs->config3[1] = 0x0;
-    regs->config5 = 0x0;
-       
-    regs->cscr = CSCR_F_LINK_100 | CSCR_HEART_BIT | CSCR_LD;
-
-    //0x3100 : 100Mbps, full duplex, autonegotiation.  0x2100 : 100Mbps, full duplex
-    regs->bmcr = 0x1000; // autonegotiation
-
-    regs->bmsr  = 0x7809;
-    regs->bmsr |= 0x0020; // autonegotiation completed
-    regs->bmsr |= 0x0004; // link is up
-
-    regs->anar = 0x05e1;     // all modes, full duplex
-    regs->anlpar = 0x05e1;   // all modes, full duplex
-    regs->aner = 0x0001;     // autonegotiation supported
-
-    // reset timer and disable timer interrupt
-    regs->tctr = 0;
-    regs->timer_int = 0;
-
-    nic_state->pkts_rcvd = 0;
-}
-
-static void init_rtl8139_regs(struct rtl8139_state *nic_state)
-{
-    nic_state->regs.imr = 0x00;
-    nic_state->regs.tsd[0] = nic_state->regs.tsd[1] = nic_state->regs.tsd[2] = nic_state->regs.tsd[3] = TSD_Own;
-    nic_state->pkts_rcvd = 0;
-
-    int i;
-    for(i = 0; i < 6; i++)
-        nic_state->regs.id[i] = nic_state->mac_addr[i] = mac[i];
-    for(i = 0; i < 8; i++)
-        nic_state->regs.mult[i] = 0xff;
-
-    nic_state->regs.rerid = RTL8139_PCI_REVID_8139;
-    nic_state->regs.tcr |= ((0x1d << 26) | (0x1 << 22));
-
-    rtl8139_reset(dev);
-}
-
 
 #if 0
 
@@ -1009,69 +1108,40 @@ static int rtl8139_config_writeable(struct vm_device *dev)
 
 #endif
 
-static int rtl8139_transmitter_enabled(struct vm_device *dev)
-{
-    struct nic_context *nic_state = (struct nic_context *)(dev->private_data);
-
+static inline int transmitter_enabled(struct rtl8139_state * nic_state){
     return nic_state->regs.cmd & CMD_Te;
 }
 
-static bool rtl8139_rxbufempty(struct vm_device *dev)
-{
-    struct nic_context *nic_state = (struct nic_context *)(dev->private_data);
-    struct nic_regs *regs = &(nic_state->regs);
+static int rxbufempty(struct rtl8139_state * nic_state){
+    struct rtl8139_regs *regs = &(nic_state->regs);
     int unread;
 
     unread = MOD2(regs->cbr + nic_state->rx_bufsize - regs->capr, nic_state->rx_bufsize);
    
-    if (unread != 0)
-    {
+    if (unread != 0){
         PrintDebug("RTL8139: receiver buffer data available 0x%04x\n", unread);
-        return false;
+        return 0;
     }
 
     PrintDebug("RTL8139: receiver buffer is empty\n");
 
-    return true;
+    return 1;
 }
 
-static uint32_t rtl8139_cmd_read(struct vm_device *dev)
-{
-    struct nic_context *nic_state = (struct nic_context *)(dev->private_data);
-    uint32_t ret = nic_state->regs.cmd;
-
-    if (rtl8139_rxbufempty(dev))
-        ret |= CMD_Bufe;
-
-    PrintDebug("RTL8139: Cmd read val=0x%04x\n", ret);
-
-    return ret;
-}
-
-static void rtl8139_cmd_write(struct vm_device *dev, uint32_t val)
-{
-    struct nic_context *nic_state = (struct nic_context *)(dev->private_data);
-
+static void rtl8139_cmd_write(struct rtl8139_state * nic_state, uint32_t val){
     val &= 0xff;
 
     PrintDebug("RTL8139: Cmd write val=0x%08x\n", val);
 
-    if (val & CMD_Rst)
-    {
+    if (val & CMD_Rst){
         PrintDebug("RTL8139: Cmd reset\n");
-        rtl8139_reset(dev);
+        rtl8139_reset(nic_state);
     }
-    if (val & CMD_Re)
-    {
+    if (val & CMD_Re){
         PrintDebug("RTL8139: Cmd enable receiver\n");
-
-        //s->currCPlusRxDesc = 0;
     }
-    if (val & CMD_Te)
-    {
+    if (val & CMD_Te){
         PrintDebug("RTL8139: Cmd enable transmitter\n");
-
-        //s->currCPlusTxDesc = 0;
     }
 
     val = SET_MASKED(val, 0xe3, nic_state->regs.cmd);
@@ -1080,23 +1150,18 @@ static void rtl8139_cmd_write(struct vm_device *dev, uint32_t val)
     nic_state->regs.cmd = val;
 }
 
-static int rtl8139_send_packet(struct vm_device *dev, int descriptor)
-{
-    struct nic_context *nic_state = (struct nic_context *)(dev->private_data);
-    struct nic_regs *regs = &(nic_state->regs);
+static int tx_one_packet(struct rtl8139_state * nic_state, int descriptor){
+    struct rtl8139_regs *regs = &(nic_state->regs);
     int txsize;
     uint8_t *pkt;
     addr_t pkt_gpa = 0, hostva = 0;
-    int i;
 
-    if (!rtl8139_transmitter_enabled(dev))
-    {
+    if (!transmitter_enabled(nic_state)){
         PrintError("RTL8139: fail to send from descriptor %d: transmitter disabled\n", descriptor);
         return 0;
     }
 
-    if (regs->tsd[descriptor] & TSD_Own)
-    {
+    if (regs->tsd[descriptor] & TSD_Own){
         PrintError("RTL8139: fail to send from descriptor %d: owned by host\n", descriptor);
         return 0;
     }
@@ -1105,51 +1170,46 @@ static int rtl8139_send_packet(struct vm_device *dev, int descriptor)
     pkt_gpa = (addr_t) regs->tsad[descriptor];
 
     PrintDebug("RTL8139: sending %d bytes from guest memory at 0x%08x\n", txsize, regs->tsad[descriptor]);
-
-    guest_pa_to_host_va(dev->vm, (addr_t)pkt_gpa, &hostva);
+       
+    v3_gpa_to_hva(&(nic_state->vm->cores[0]), (addr_t)pkt_gpa, &hostva);
     pkt = (uchar_t *)hostva;
 
-    for(i = 0; i < txsize; i++)
-    {
-        PrintDebug("%x ", pkt[i]);
-    }
-    PrintDebug("\n");
+#ifdef CONFIG_DEBUG_RTL8139
+    v3_hexdump(pkt, txsize, NULL, 0);
+#endif
 
-    if (TxLoopBack == (regs->tcr & TxLoopBack)){ //loopback test
+    if (TxLoopBack == (regs->tcr & TxLoopBack)){ /* loopback test */
         PrintDebug(("RTL8139: transmit loopback mode\n"));
-        vnic_receive(dev, pkt, txsize);
+        rx_one_pkt(nic_state, pkt, txsize);
     } else{       
-           if (V3_SEND_PKT(pkt, txsize) == 0){
-                PrintDebug("RTL8139: Sent %d bytes from descriptor %d\n", txsize, descriptor);
-           } else {
-               PrintError("Rtl8139: Sending packet error: 0x%p\n", pkt);
-           }
+        if (nic_state->net_ops->send(pkt, txsize, nic_state->backend_data) == 0){
+           PrintDebug("RTL8139: Sent %d bytes from descriptor %d\n", txsize, descriptor);
+           nic_state->statistic.tx_pkts ++;
+           nic_state->statistic.tx_bytes += txsize;
+       } else {
+           PrintError("Rtl8139: Sending packet error: 0x%p\n", pkt);
+           nic_state->statistic.tx_dropped ++;
+       }
     }
 
     regs->tsd[descriptor] |= TSD_Tok;
     regs->tsd[descriptor] |= TSD_Own;
 
     nic_state->regs.isr |= ISR_Tok;
-    rtl8139_update_irq(dev);
+    rtl8139_update_irq(nic_state);
 
     return 0;
 }
 
-//write to transmit status registers
-static void rtl8139_tsd_write(struct vm_device *dev, uint8_t descriptor, uint32_t val)
-{ 
-    struct nic_context *nic_state = (struct nic_context *)(dev->private_data);
-
-#if 0
-    if (rtl8139_transmitter_enabled(dev))
-    {
-        PrintDebug("RTL8139: TxStatus write val=0x%08x descriptor=%d\n", val, descriptor);
-
-        nic_state->regs.tsd[descriptor] = val;
-
+/*transmit status registers*/
+static void rtl8139_tsd_write(struct rtl8139_state * nic_state, 
+                             uint8_t descriptor, 
+                             uint32_t val){ 
+    if (!transmitter_enabled(nic_state)){
+        PrintDebug("RTL8139: TxStatus write val=0x%08x descriptor=%d, Transmitter not enabled\n", val, descriptor);
+               
         return;
     }
-#endif
 
     PrintDebug("RTL8139: TSD write val=0x%08x descriptor=%d\n", val, descriptor);
 
@@ -1159,17 +1219,15 @@ static void rtl8139_tsd_write(struct vm_device *dev, uint8_t descriptor, uint32_
 
     nic_state->regs.tsd[descriptor] = val;
 
-    rtl8139_send_packet(dev, descriptor);
+    tx_one_packet(nic_state, descriptor);
 }
 
-//transmit status of all descriptors
-static uint16_t rtl8139_tsad_read(struct vm_device *dev)
-{
+/* transmit status of all descriptors */
+static uint16_t rtl8139_txsad_read(struct rtl8139_state * nic_state){
     uint16_t ret = 0;
-    struct nic_context *nic_state = (struct nic_context *)(dev->private_data);
-    struct nic_regs *regs = &(nic_state->regs);
+    struct rtl8139_regs *regs = &(nic_state->regs);
 
-    ret = ((regs->tsd[3] & TSD_Tok)?TSD_Tok:0)
+    ret = ((regs->tsd[3] & TSD_Tok)?TSAD_TOK3:0)
          |((regs->tsd[2] & TSD_Tok)?TSAD_TOK2:0)
          |((regs->tsd[1] & TSD_Tok)?TSAD_TOK1:0)
          |((regs->tsd[0] & TSD_Tok)?TSAD_TOK0:0)
@@ -1189,41 +1247,16 @@ static uint16_t rtl8139_tsad_read(struct vm_device *dev)
          |((regs->tsd[1] & TSD_Own)?TSAD_OWN1:0)
          |((regs->tsd[0] & TSD_Own)?TSAD_OWN0:0) ;
 
-
-    PrintDebug("RTL8139: tsad read val=0x%04x\n", (int)ret);
+    PrintDebug("RTL8139: txsad read val=0x%04x\n", (int)ret);
 
     return ret;
 }
 
-//interrupt mask register
-static void rtl8139_imr_write(struct vm_device *dev, uint32_t val)
-{
-    struct nic_context *nic_state = (struct nic_context *)(dev->private_data);
-       
-    PrintDebug("RTL8139: IMR write val=0x%04x\n", val);
-
-    /* mask unwriteable bits */
-    val = SET_MASKED(val, 0x1e00, nic_state->regs.imr);
-
-    nic_state->regs.imr = val;
-
-    rtl8139_update_irq(dev);
-}
-
-static void rtl8139_isr_write(struct vm_device *dev, uint32_t val)
-{
-    struct nic_context *nic_state = (struct nic_context *)(dev->private_data);
-    struct nic_regs *regs = &(nic_state->regs);
+static inline void rtl8139_isr_write(struct rtl8139_state * nic_state, uint32_t val) {
+    struct rtl8139_regs *regs = &(nic_state->regs);
 
     PrintDebug("RTL8139: ISR write val=0x%04x\n", val);
 
-#if 0
-
-    // writing to ISR has no effect
-
-    return;
-
-#else
     uint16_t newisr = regs->isr & ~val;
 
     /* mask unwriteable bits */
@@ -1231,767 +1264,498 @@ static void rtl8139_isr_write(struct vm_device *dev, uint32_t val)
 
     /* writing 1 to interrupt status register bit clears it */
     regs->isr = 0;
-    rtl8139_update_irq(dev);
+    rtl8139_update_irq(nic_state);
 
     regs->isr = newisr;
-    rtl8139_update_irq(dev);
-#endif
-}
-
-static uint32_t rtl8139_isr_read(struct vm_device *dev)
-{
-    struct nic_context *nic_state = (struct nic_context *)(dev->private_data);
-    uint32_t ret = (uint32_t)nic_state->regs.isr;
-
-    PrintDebug("RTL8139: ISR read val=0x%04x\n", ret);
-
-#if 0
-    // reading ISR clears all interrupts
-    nic_state->regs.isr = 0;
-
-    rtl8139_update_irq(dev);
-
-#endif
-
-    return ret;
-}
-
-static void rtl8139_capr_write(struct vm_device *dev, uint32_t val)
-{
-    struct nic_context *nic_state = (struct nic_context *)(dev->private_data);
-
-    PrintDebug("RTL8139: CAPR write val=0x%04x\n", val);
-
-    // this value is off by 16
-    nic_state->regs.capr = MOD2(val + 0x10, nic_state->rx_bufsize);
-
-    PrintDebug("RTL 8139: CAPR write: rx buffer length %d head 0x%04x read 0x%04x\n",
-           nic_state->rx_bufsize, nic_state->regs.cbr, nic_state->regs.capr);
-}
-
-static uint32_t rtl8139_capr_read(struct vm_device *dev)
-{
-    struct nic_context *nic_state = (struct nic_context *)(dev->private_data);
-
-    /* this value is off by 16 */
-    uint32_t ret = nic_state->regs.capr - 0x10;
-
-    PrintDebug("RTL8139: CAPR read val=0x%04x\n", ret);
-
-    return ret;
-}
-
-typedef enum {read, write} opr_t; 
-static bool need_hook(int port, opr_t op)
-{
-       if (op == read){ 
-               switch (port) {
-                       case RTL8139_IMR:
-                       case RTL8139_ISR:
-                               return true;
-                       default:
-                               break;
-               }
-       }
-       if (op == write){
-               switch (port) {
-                       case RTL8139_TSD0:
-                       case RTL8139_TSD1:
-                       case RTL8139_TSD2:
-                       case RTL8139_TSD3:
-                       case RTL8139_CR:
-                       case RTL8139_IMR:
-                       case RTL8139_ISR:
-                       case RTL8139_TCR:
-                       case RTL8139_RCR:
-                       case RTL8139_CSCR:
-                       case RTL8139_Config5:
-                               return true;
-                       default:
-                               break;
-               }
-       }
-       
-       return false;
+    rtl8139_update_irq(nic_state);
 }
 
-static int rtl8139_mmio_write(addr_t guest_addr, void * src, uint_t length, void * priv_data)
-{
-    int port;
+static int rtl8139_mmio_write(struct guest_info * core, 
+                             addr_t guest_addr, 
+                             void * src,
+                             uint_t length, 
+                             void * priv_data) {
+    int idx;
     uint32_t val;
-    struct vm_device *dev = (struct vm_device *)priv_data;
-    struct nic_context *nic_state = (struct nic_context *)(dev->private_data);
+    struct rtl8139_state *nic_state = (struct rtl8139_state *)(priv_data);
 
-    port = guest_addr & 0xff;
+    idx = guest_addr & 0xff;
 
     memcpy(&val, src, length);
 
     PrintDebug("rtl8139 mmio write: addr:0x%x (%u bytes): 0x%x\n", (int)guest_addr, length, val);
        
-    switch(port) {
-           case RTL8139_IDR0:
-               nic_state->regs.id[0] = val & 0xff;
-               break;
-           case RTL8139_IDR1:
-               nic_state->regs.id[1] = val & 0xff;
-               break;
-           case RTL8139_IDR2:
-               nic_state->regs.id[2] = val & 0xff;
-               break;
-           case RTL8139_IDR3:
-               nic_state->regs.id[3] = val & 0xff;
-               break;
-           case RTL8139_IDR4:
-               nic_state->regs.id[4] = val & 0xff;
-               break;
-           case RTL8139_IDR5:
-               nic_state->regs.id[5] = val & 0xff;
-               break;
-           case RTL8139_MAR0:
-               nic_state->regs.mult[0] = val & 0xff;
-               break;
-           case RTL8139_MAR1:
-               nic_state->regs.mult[1] = val & 0xff;
-               break;
-           case RTL8139_MAR2:
-               nic_state->regs.mult[2] = val & 0xff;
-               break;
-           case RTL8139_MAR3:
-               nic_state->regs.mult[3] = val & 0xff;
-               break;
-           case RTL8139_MAR4:
-               nic_state->regs.mult[4] = val & 0xff;
-               break;
-           case RTL8139_MAR5:
-               nic_state->regs.mult[5] = val & 0xff;
-               break;
-           case RTL8139_MAR6:
-               nic_state->regs.mult[6] = val & 0xff;
-               break;
-           case RTL8139_MAR7:
-               nic_state->regs.mult[7] = val & 0xff;
-               break;
-           case RTL8139_TSD0:
-           case RTL8139_TSD1:
-           case RTL8139_TSD2:
-           case RTL8139_TSD3:
-               rtl8139_tsd_write(dev, (port - RTL8139_TSD0)/4, val);
-               break;
-           case RTL8139_TSAD0:
-           case RTL8139_TSAD1:
-           case RTL8139_TSAD2:
-           case RTL8139_TSAD3:
-               nic_state->regs.tsad[(port - RTL8139_TSAD0)/4] = val;
-               break;
-           case RTL8139_RBSTART:
-               nic_state->regs.rbstart = val;
-               break;
-           case RTL8139_ERBCR:
-               nic_state->regs.erbcr = val & 0xffff;
-               break;
-           case RTL8139_ERSR:
-               //nic_state->regs.ersr = val & 0xff;
-               nic_state->regs.ersr &= (~val) & 0x0c;
-               break;
-           case RTL8139_CR:
-                 rtl8139_cmd_write(dev, val);
-               break;
-           case RTL8139_CAPR:
-               rtl8139_capr_write(dev, val & 0xffff);
-               break;
-           case RTL8139_CBR: //this is read only =====
-               //nic_state->regs.cbr = val & 0xffff;
-               break;
-           case RTL8139_IMR:
-                 rtl8139_imr_write(dev, val);
-               break;
-           case RTL8139_ISR:
-               rtl8139_isr_write(dev, val);
-               break;
-           case RTL8139_TCR:
-               nic_state->regs.tcr = val;
-               break;
-           case RTL8139_RCR:
-               rtl8139_rcr_write(dev, val);
-                break;
-           case RTL8139_TCTR:
-               nic_state->regs.tctr = 0; //write clear current tick
-               break;
-           case RTL8139_MPC:
-               nic_state->regs.mpc = 0; //clear on write
-               break;
-           case RTL8139_9346CR:
-                 rtl8139_9346cr_write(dev, val);
-               break;
-           case RTL8139_CONFIG0:
-               nic_state->regs.config[0] = val & 0xff;
-               break;
-           case RTL8139_CONFIG1:
-               nic_state->regs.config[1] = val & 0xff;
-               break;
-           case RTL8139_TimerInt:
-               nic_state->regs.timer_int = val;
-               break;
-           case RTL8139_MSR:
-               nic_state->regs.msr = val & 0xff;
-               break;
-           case RTL8139_CONFIG3:
-               nic_state->regs.config3[0] = val & 0xff;
-               break;
-           case RTL8139_CONFIG4:
-               nic_state->regs.config3[1] = val & 0xff;
-               break;
-           case RTL8139_MULINT:
-               nic_state->regs.mulint = val & 0xffff;
-               break;
-           case RTL8139_RERID:
-               nic_state->regs.rerid = val & 0xffff;
-               break;
-           case RTL8139_TSAD:
-               nic_state->regs.txsad = val & 0xffff;
-               break;
-           case RTL8139_BMCR:
-               nic_state->regs.bmcr = val & 0xffff;
-               break;
-           case RTL8139_BMSR:
-               nic_state->regs.bmsr = val & 0xffff;
-               break;
-           case RTL8139_ANAR:
-               nic_state->regs.anar = val & 0xffff;
-               break;
-           case RTL8139_ANLPAR:
-               nic_state->regs.anlpar = val & 0xffff;
-               break;
-           case RTL8139_ANER:
-               nic_state->regs.aner = val & 0xffff;
-               break;
-           case RTL8139_DIS:
-               nic_state->regs.dis = val & 0xffff;
-               break;
-           case RTL8139_FCSC:
-               nic_state->regs.fcsc = val & 0xffff;
-               break;
-           case RTL8139_NWAYTR:
-               nic_state->regs.nwaytr = val & 0xffff;
-               break;
-           case RTL8139_REC:
-               nic_state->regs.rec = val & 0xffff;
-               break;
-           case RTL8139_CSCR:
-               nic_state->regs.cscr = val;
-               break;
-           case RTL8139_PHY1_PARM:
-               nic_state->regs.phy1_parm = val;
-               break;
-           case RTL8139_TW_PARM:
-               nic_state->regs.tw_parm = val & 0xffff;
-               break;
-           case RTL8139_PHY2_PARM:
-               nic_state->regs.phy2_parm = val;
-               break;
-           case RTL8139_CRC0:
-               nic_state->regs.crc[0] = val & 0xff;
-               break;
-           case RTL8139_CRC1:
-               nic_state->regs.crc[1] = val & 0xff;
-               break;
-           case RTL8139_CRC2:
-               nic_state->regs.crc[2] = val & 0xff;
-               break;
-           case RTL8139_CRC3:
-               nic_state->regs.crc[3] = val & 0xff;
-               break;
-           case RTL8139_CRC4:
-               nic_state->regs.crc[4] = val & 0xff;
-               break;
-           case RTL8139_CRC5:
-               nic_state->regs.crc[5] = val & 0xff;
-               break;
-           case RTL8139_CRC6:
-               nic_state->regs.crc[6] = val & 0xff;
-               break;
-           case RTL8139_CRC7:
-               nic_state->regs.crc[7] = val & 0xff;
-               break;
-           case RTL8139_Config5:
-               nic_state->regs.config5 = val & 0xff;
-               break;
-           default:
-               PrintDebug("rtl8139 write error: invalid port: 0x%x\n", port);
+    switch(idx) {
+       case RTL8139_IDR0 ... RTL8139_IDR0 + 5:
+           nic_state->regs.id[idx - RTL8139_IDR0] = val & 0xff;
+           break;
+
+       case RTL8139_MAR0 ... RTL8139_MAR0 + 7:
+           nic_state->regs.mult[idx - RTL8139_MAR0] = val & 0xff;
+           break;
+
+       case RTL8139_TSD0:
+       case RTL8139_TSD1:
+       case RTL8139_TSD2:
+       case RTL8139_TSD3:
+           rtl8139_tsd_write(nic_state, (idx - RTL8139_TSD0)/4, val);
+           break;
+               
+       case RTL8139_TSAD0:
+       case RTL8139_TSAD1:
+       case RTL8139_TSAD2:
+       case RTL8139_TSAD3:
+           nic_state->regs.tsad[(idx - RTL8139_TSAD0)/4] = val;
+           break;
+               
+       case RTL8139_RBSTART:
+           nic_state->regs.rbstart = val;
+           break;
+       case RTL8139_ERBCR:
+           nic_state->regs.erbcr = val & 0xffff;
+           break;
+       case RTL8139_ERSR:
+           //nic_state->regs.ersr = val & 0xff;
+           nic_state->regs.ersr &= (~val) & 0x0c;
+           break;
+       case RTL8139_CR:
+           rtl8139_cmd_write(nic_state, val);
+           break;
+       case RTL8139_CAPR:
+       {
+           val &= 0xffff;
+           /* this value is off by 16 */
+           nic_state->regs.capr = MOD2(val + 0x10, nic_state->rx_bufsize);
+
+           PrintDebug("RTL 8139: CAPR write: rx buffer length %d head 0x%04x read 0x%04x\n",
+           nic_state->rx_bufsize, nic_state->regs.cbr, nic_state->regs.capr);  
+       }
+           break;
+       case RTL8139_CBR: /* read only */
+           //nic_state->regs.cbr = val & 0xffff;
+           break;
+       case RTL8139_IMR:
+       {
+           PrintDebug("RTL8139: IMR write val=0x%04x\n", val);
+
+           /* mask unwriteable bits */
+           val = SET_MASKED(val, 0x1e00, nic_state->regs.imr);
+           nic_state->regs.imr = val;
+           rtl8139_update_irq(nic_state);
+       }
+           break;
+       case RTL8139_ISR:
+           rtl8139_isr_write(nic_state, val);
+           break;
+       case RTL8139_TCR:
+           nic_state->regs.tcr = val;
+           break;
+       case RTL8139_RCR:
+           rtl8139_rcr_write(nic_state, val);
+           break;
+       case RTL8139_TCTR:
+           nic_state->regs.tctr = 0; /* write clear current tick */
+           break;
+       case RTL8139_MPC:
+           nic_state->regs.mpc = 0; /* clear on write */
+           break;
+       case RTL8139_9346CR:
+           rtl8139_9346cr_write(nic_state, val);
+           break;
+       case RTL8139_CONFIG0:
+           nic_state->regs.config[0] = val & 0xff;
+           break;
+       case RTL8139_CONFIG1:
+           nic_state->regs.config[1] = val & 0xff;
+           break;
+       case RTL8139_TimerInt:
+           nic_state->regs.timer_int = val;
+           break;
+       case RTL8139_MSR:
+           nic_state->regs.msr = val & 0xff;
+           break;
+       case RTL8139_CONFIG3:
+           nic_state->regs.config3[0] = val & 0xff;
+           break;
+       case RTL8139_CONFIG4:
+           nic_state->regs.config3[1] = val & 0xff;
+           break;
+               
+       case RTL8139_MULINT:
+           nic_state->regs.mulint = val & 0xffff;
+           break;
+       case RTL8139_RERID:
+           nic_state->regs.rerid = val & 0xffff;
+           break;
+       case RTL8139_TXSAD:
+           nic_state->regs.txsad = val & 0xffff;
+           break;
+       case RTL8139_BMCR:
+           nic_state->regs.bmcr = val & 0xffff;
+           break;
+       case RTL8139_BMSR:
+           nic_state->regs.bmsr = val & 0xffff;
+           break;
+       case RTL8139_ANAR:
+           nic_state->regs.anar = val & 0xffff;
+           break;
+       case RTL8139_ANLPAR:
+           nic_state->regs.anlpar = val & 0xffff;
+           break;
+       case RTL8139_ANER:
+           nic_state->regs.aner = val & 0xffff;
+           break;
+       case RTL8139_DIS:
+           nic_state->regs.dis = val & 0xffff;
+           break;
+       case RTL8139_FCSC:
+           nic_state->regs.fcsc = val & 0xffff;
+           break;
+       case RTL8139_NWAYTR:
+           nic_state->regs.nwaytr = val & 0xffff;
+           break;
+       case RTL8139_REC:
+           nic_state->regs.rec = val & 0xffff;
+           break;
+
+       case RTL8139_CSCR:
+           nic_state->regs.cscr = val;
+           break;
+       case RTL8139_PHY1_PARM:
+           nic_state->regs.phy1_parm = val;
+           break;
+       case RTL8139_TW_PARM:
+           nic_state->regs.tw_parm = val & 0xffff;
+           break;
+       case RTL8139_PHY2_PARM:
+           nic_state->regs.phy2_parm = val;
+           break;
+       case RTL8139_CRC0 ... RTL8139_CRC0 + 7:
+           nic_state->regs.crc[idx - RTL8139_CRC0] = val & 0xff;
+           break;
+
+       case RTL8139_Config5:
+           nic_state->regs.config5 = val & 0xff;
+           break;
+       default:
+           PrintDebug("rtl8139 write error: invalid port: 0x%x\n", idx);
        }
-
-       
-#if TEST_PERFORMANCE
-    if (need_hook(port, read))
-               io_hooked ++;
-    if (( ++io_total) % 50 == 0)
-        PrintError("RTL8139: Total IO: %d, Hooked: %d, INT: %d\n", io_total, io_hooked, int_total);
-#endif
         
     return length;
 }
 
-static int rtl8139_mmio_read(addr_t guest_addr, void * dst, uint_t length, void * priv_data)
-{
-    ulong_t port;
+static int rtl8139_mmio_read(struct guest_info * core, 
+                            addr_t guest_addr, 
+                            void * dst, 
+                            uint_t length, 
+                            void * priv_data) {
+    uint16_t idx;
     uint32_t val;
-    struct vm_device *dev = (struct vm_device *)priv_data;
-    struct nic_context *nic_state = (struct nic_context *)(dev->private_data);
-
-    port = guest_addr & 0xff;
-
-    switch(port) {
-           case RTL8139_IDR0:
-               val = nic_state->regs.id[0];
-               break;
-           case RTL8139_IDR1:
-               val = nic_state->regs.id[1];
-               break;
-           case RTL8139_IDR2:
-               val = nic_state->regs.id[2];
-               break;
-           case RTL8139_IDR3:
-               val = nic_state->regs.id[3];
-               break;
-           case RTL8139_IDR4:
-               val = nic_state->regs.id[4];
-               break;
-           case RTL8139_IDR5:
-               val = nic_state->regs.id[5];
-               break;
-           case RTL8139_MAR0:
-               val = nic_state->regs.mult[0];
-               break;
-           case RTL8139_MAR1:
-               val = nic_state->regs.mult[1];
-               break;
-           case RTL8139_MAR2:
-               val = nic_state->regs.mult[2];
-               break;
-           case RTL8139_MAR3:
-               val = nic_state->regs.mult[3];
-               break;
-           case RTL8139_MAR4:
-               val = nic_state->regs.mult[4];
-               break;
-           case RTL8139_MAR5:
-               val = nic_state->regs.mult[5];
-               break;
-           case RTL8139_MAR6:
-               val = nic_state->regs.mult[6];
-               break;
-           case RTL8139_MAR7:
-               val = nic_state->regs.mult[7];
-               break;
-           case RTL8139_TSD0:
-               val = nic_state->regs.tsd[0];
-               break;
-           case RTL8139_TSD1:
-               val = nic_state->regs.tsd[1];
-               break;
-           case RTL8139_TSD2:
-               val = nic_state->regs.tsd[2];
-               break;
-           case RTL8139_TSD3:
-               val = nic_state->regs.tsd[3];
-               break;
-           case RTL8139_TSAD0:
-               val = nic_state->regs.tsad[0];
-               break;
-           case RTL8139_TSAD1:
-               val = nic_state->regs.tsad[1];
-               break;
-           case RTL8139_TSAD2:
-               val = nic_state->regs.tsad[2];
-               break;
-           case RTL8139_TSAD3:
-               val = nic_state->regs.tsad[3];
-               break;
-           case RTL8139_RBSTART:
-               val = nic_state->regs.rbstart;
-               break;
-           case RTL8139_ERBCR:
-               val = nic_state->regs.erbcr;
-               break;
-           case RTL8139_ERSR:
-               val = nic_state->regs.ersr;
-               break;
-           case RTL8139_CR:
-               val = rtl8139_cmd_read(dev);
-               break;
-           case RTL8139_CAPR:
-               val = rtl8139_capr_read(dev);
-               break;
-           case RTL8139_CBR:
-               val = nic_state->regs.cbr;
-               break;
-           case RTL8139_IMR:
-               val = nic_state->regs.imr;
-               break;
-           case RTL8139_ISR:
-               val = rtl8139_isr_read(dev);
-               break;
-           case RTL8139_TCR:
-               val = nic_state->regs.tcr;
-               break;
-           case RTL8139_RCR:
-               val = nic_state->regs.rcr;
-               break;
-           case RTL8139_TCTR:
-               val = nic_state->regs.tctr;
-               break;
-           case RTL8139_MPC:
-               val = nic_state->regs.mpc;
-               break;
-           case RTL8139_9346CR:
-               val = rtl8139_9346cr_read(dev);
-               break;
-           case RTL8139_CONFIG0:
-               val = nic_state->regs.config[0];
-               break;
-           case RTL8139_CONFIG1:
-               val = nic_state->regs.config[1];
-               break;
-           case RTL8139_TimerInt:
-               val = nic_state->regs.timer_int;
-               break;
-           case RTL8139_MSR:
-               val = nic_state->regs.msr;
-               break;
-           case RTL8139_CONFIG3:
-               val = nic_state->regs.config3[0];
-               break;
-           case RTL8139_CONFIG4:
-               val = nic_state->regs.config3[1];
-               break;
-           case RTL8139_MULINT:
-               val = nic_state->regs.mulint;
-               break;
-           case RTL8139_RERID:
-               val = nic_state->regs.rerid;
-               break;
-           case RTL8139_TSAD: 
-               val = rtl8139_tsad_read(dev);
-               break;
-           case RTL8139_BMCR:
-               val = nic_state->regs.bmcr;
-               break;
-           case RTL8139_BMSR:
-               val = nic_state->regs.bmsr;
-               break;
-           case RTL8139_ANAR:
-               val = nic_state->regs.anar;
-               break;
-           case RTL8139_ANLPAR:
-               val = nic_state->regs.anlpar;
-               break;
-           case RTL8139_ANER:
-               val = nic_state->regs.aner;
-               break;
-           case RTL8139_DIS:
-               val = nic_state->regs.dis;
-               break;
-           case RTL8139_FCSC:
-               val = nic_state->regs.fcsc;
-               break;
-           case RTL8139_NWAYTR:
-               val = nic_state->regs.nwaytr;
-               break;
-           case RTL8139_REC:
-               val = nic_state->regs.rec;
-               break;
-           case RTL8139_CSCR:
-               val = nic_state->regs.cscr;
-               break;
-           case RTL8139_PHY1_PARM:
-               val = nic_state->regs.phy1_parm;
-               break;
-           case RTL8139_TW_PARM:
-               val = nic_state->regs.tw_parm;
-               break;
-           case RTL8139_PHY2_PARM:
-               val = nic_state->regs.phy2_parm;
-               break;
-           case RTL8139_CRC0:
-               val = nic_state->regs.crc[0];
-               break;
-           case RTL8139_CRC1:
-               val = nic_state->regs.crc[1];
-               break;
-           case RTL8139_CRC2:
-               val = nic_state->regs.crc[2];
-               break;
-           case RTL8139_CRC3:
-               val = nic_state->regs.crc[3];
-               break;
-           case RTL8139_CRC4:
-               val = nic_state->regs.crc[4];
-               break;
-           case RTL8139_CRC5:
-               val = nic_state->regs.crc[5];
-               break;
-           case RTL8139_CRC6:
-               val = nic_state->regs.crc[6];
-               break;
-           case RTL8139_CRC7:
-               val = nic_state->regs.crc[7];
-               break;
-           case RTL8139_Config5:
-               val = nic_state->regs.config5;
-               break;
-           default:
-                val = 0x0;
-                break;
+    struct rtl8139_state *nic_state = (struct rtl8139_state *)priv_data;
+
+    idx = guest_addr & 0xff;
+
+    switch(idx) {
+       case RTL8139_IDR0 ... RTL8139_IDR0 + 5:
+           val = nic_state->regs.id[idx - RTL8139_IDR0];
+           break;
+               
+       case RTL8139_MAR0 ... RTL8139_MAR0 + 7:
+           val = nic_state->regs.mult[idx - RTL8139_MAR0];
+           break;
+
+       case RTL8139_TSD0:
+       case RTL8139_TSD1:
+       case RTL8139_TSD2:
+       case RTL8139_TSD3:
+           val = nic_state->regs.tsd[(idx - RTL8139_TSD0)/4];
+           break;
+
+       case RTL8139_TSAD0:
+       case RTL8139_TSAD1:
+       case RTL8139_TSAD2:
+       case RTL8139_TSAD3:
+           val = nic_state->regs.tsad[(idx - RTL8139_TSAD0)/4];
+           break;
+
+       case RTL8139_RBSTART:
+           val = nic_state->regs.rbstart;
+           break;
+       case RTL8139_ERBCR:
+           val = nic_state->regs.erbcr;
+           break;
+       case RTL8139_ERSR:
+           val = nic_state->regs.ersr;
+           break;
+       case RTL8139_CR:
+       {
+           val = nic_state->regs.cmd;
+           if (rxbufempty(nic_state)){
+               val |= CMD_Bufe;
+           }
+       }
+           break;
+       case RTL8139_CAPR:
+           /* this value is off by 16 -- don't know why - Lei*/
+           val = nic_state->regs.capr - 0x10;
+           break;
+       case RTL8139_CBR:
+           val = nic_state->regs.cbr;
+           break;
+       case RTL8139_IMR:
+           val = nic_state->regs.imr;
+           break;
+       case RTL8139_ISR:
+           val = (uint32_t)nic_state->regs.isr;
+           break;
+       case RTL8139_TCR:
+           val = nic_state->regs.tcr;
+           break;
+       case RTL8139_RCR:
+           val = nic_state->regs.rcr;
+           break;
+       case RTL8139_TCTR:
+           val = nic_state->regs.tctr;
+           break;
+       case RTL8139_MPC:
+           val = nic_state->regs.mpc;
+           break;
+       case RTL8139_9346CR:
+           val = rtl8139_9346cr_read(nic_state);
+           break;
+       case RTL8139_CONFIG0:
+           val = nic_state->regs.config[0];
+           break;
+       case RTL8139_CONFIG1:
+           val = nic_state->regs.config[1];
+           break;
+       case RTL8139_TimerInt:
+           val = nic_state->regs.timer_int;
+           break;
+       case RTL8139_MSR:
+           val = nic_state->regs.msr;
+           break;
+       case RTL8139_CONFIG3:
+           val = nic_state->regs.config3[0];
+           break;
+       case RTL8139_CONFIG4:
+           val = nic_state->regs.config3[1];
+           break;
+       case RTL8139_MULINT:
+           val = nic_state->regs.mulint;
+           break;
+       case RTL8139_RERID:
+           val = nic_state->regs.rerid;
+           break;
+       case RTL8139_TXSAD: 
+           val = rtl8139_txsad_read(nic_state);
+           break;
+       case RTL8139_BMCR:
+           val = nic_state->regs.bmcr;
+           break;
+       case RTL8139_BMSR:
+           val = nic_state->regs.bmsr;
+           break;
+       case RTL8139_ANAR:
+           val = nic_state->regs.anar;
+           break;
+       case RTL8139_ANLPAR:
+           val = nic_state->regs.anlpar;
+           break;
+       case RTL8139_ANER:
+           val = nic_state->regs.aner;
+           break;
+       case RTL8139_DIS:
+           val = nic_state->regs.dis;
+           break;
+       case RTL8139_FCSC:
+           val = nic_state->regs.fcsc;
+           break;
+       case RTL8139_NWAYTR:
+           val = nic_state->regs.nwaytr;
+           break;
+       case RTL8139_REC:
+           val = nic_state->regs.rec;
+           break;
+       case RTL8139_CSCR:
+           val = nic_state->regs.cscr;
+           break;
+       case RTL8139_PHY1_PARM:
+           val = nic_state->regs.phy1_parm;
+           break;
+       case RTL8139_TW_PARM:
+           val = nic_state->regs.tw_parm;
+           break;
+       case RTL8139_PHY2_PARM:
+           val = nic_state->regs.phy2_parm;
+           break;
+       case RTL8139_CRC0 ... RTL8139_CRC0 + 7:
+           val = nic_state->regs.crc[idx - RTL8139_CRC0];
+           break;
+       case RTL8139_Config5:
+           val = nic_state->regs.config5;
+           break;
+       default:
+           val = 0x0;
+           break;
     }
 
     memcpy(dst, &val, length);
        
     PrintDebug("rtl8139 mmio read: port:0x%x (%u bytes): 0x%x\n", (int)guest_addr, length, val);
 
-#if TEST_PERFORMANCE
-    if (need_hook(port, read))
-               io_hooked ++;
-    if (( ++io_total) % 50 == 0)
-        PrintError("RTL8139: Total IO: %d, Hooked: %d, INT: %d\n", io_total, io_hooked, int_total);
-#endif
-
     return length;
 }
 
 
-static int rtl8139_ioport_write(struct guest_info * core, uint16_t port, void *src, uint_t length, void * private_data)
-{
-    PrintDebug("rtl8139 pio write: port:0x%x (%u bytes)\n", port, length);
-       
-    rtl8139_mmio_write((addr_t)port, src, length, private_data);
-       
-    return length;
+static int rtl8139_ioport_write(struct guest_info * core,
+                               uint16_t port, 
+                               void *src, 
+                               uint_t length, 
+                               void * private_data) {
+    return rtl8139_mmio_write(core, (addr_t)port, 
+                             src, length, private_data);
 }
 
-static int rtl8139_ioport_read(uint16_t port, void *dst, uint_t length, struct vm_device *dev)
-{
-    PrintDebug("rtl8139 pio read: port:0x%x (%u bytes)\n", port, length);
-
-    rtl8139_mmio_read((addr_t)port, dst, length, (void *)dev);
-    
-    return length;
+static int rtl8139_ioport_read(struct guest_info * core, 
+                              uint16_t port, 
+                              void *dst, 
+                              uint_t length, 
+                              void * private_data) {
+    return rtl8139_mmio_read(core, (addr_t)port, 
+                            dst, length, private_data);
 }
 
-static int rtl8139_reset_device(struct vm_device *dev)
-{
-    struct nic_context *nic_state = (struct nic_context *)dev->private_data;
-    struct nic_regs *regs = &(nic_state->regs);
-    regs->cmd |= CMD_Rst;
-    init_rtl8139(dev);
-    regs->cmd &= ~CMD_Rst;
+
+static int rtl8139_init_state(struct rtl8139_state *nic_state) {
+    PrintDebug("rtl8139: init_state\n");
+       
+    nic_state->regs.tsd[0] = nic_state->regs.tsd[1] = nic_state->regs.tsd[2] = nic_state->regs.tsd[3] = TSD_Own;
+
+    nic_state->regs.rerid = RTL8139_PCI_REVID_8139;
+    nic_state->regs.tcr |= ((0x1d << 26) | (0x1 << 22));
+
+    rtl8139_reset(nic_state);
+
     return 0;
 }
 
-static int rtl8139_start_device(struct vm_device *dev)
-{
-    PrintDebug("rtl8139: start device\n");
-    struct nic_context *nic_state = (struct nic_context *)dev->private_data;
-    struct nic_regs *regs = &(nic_state->regs);
-    regs->cmd |= CMD_Re | CMD_Te;
+
+#if 0
+static inline int rtl8139_reset_device(struct rtl8139_state * nic_state) {
+    nic_state->regs.cmd |= CMD_Rst;
+    rtl8139_init_state(nic_state);
+    nic_state->regs.cmd &= ~CMD_Rst;
+       
     return 0;
 }
 
-static int rtl8139_stop_device(struct vm_device *dev)
-{
-    PrintDebug("rtl8139: stop device\n");
-    struct nic_context *nic_state = (struct nic_context *)dev->private_data;
-    struct nic_regs *regs = &(nic_state->regs);
-    regs->cmd &= ~(CMD_Re | CMD_Te);
+static inline int rtl8139_start_device(struct rtl8139_state * nic_state) {
+    nic_state->regs.cmd |= CMD_Re | CMD_Te;
+       
     return 0;
 }
 
-static void init_phy_network()
-{
-    V3_REGISTER_PKT_DELIVERY(&netif_input);
+static int rtl8139_stop_device(struct rtl8139_state * nic_state) {
+    PrintDebug("rtl8139: stop device\n");
+
+    nic_state->regs.cmd &= ~(CMD_Re | CMD_Te);
+       
+    return 0;
 }
 
-static int rtl8139_hook_iospace(struct vm_device *vmdev, addr_t base_addr, int size, int type, void *data)
-{
+static int rtl8139_hook_iospace(struct rtl8139_state * nic_state, 
+                               addr_t base_addr, 
+                               int size, 
+                               int type, 
+                               void *data) {
     int i;
 
-    if (base_addr <= 0)
-    {
+    if (base_addr <= 0){
        PrintError("In RTL8139: Fail to Hook IO Space, base address 0x%x\n", (int) base_addr);
        return -1;
     }
 
-    if (type == PCI_ADDRESS_SPACE_IO){
+    if (type == PCI_BAR_IO){
        PrintDebug("In RTL8139: Hook IO ports starting from %x, size %d\n", (int) base_addr, size);
 
-       for (i = 0; i < 0xff; i++)
-       {       
-           v3_dev_hook_io(vmdev, base_addr + i, &rtl8139_ioport_read, &rtl8139_ioport_write);
+       for (i = 0; i < 0xff; i++){     
+           v3_dev_hook_io(nic_state->dev, base_addr + i, &rtl8139_ioport_read, &rtl8139_ioport_write);
        }
-    } else if (type == PCI_ADDRESS_SPACE_MEM) {
+    } else if (type == PCI_BAR_MEM32) {
        PrintDebug("In RTL8139: Hook memory space starting from %x, size %d\n", (int) base_addr, size);
        
        //hook memory mapped I/O        
-       v3_hook_full_mem(vmdev->vm, base_addr, base_addr + 0xff,
-                                     &rtl8139_mmio_read, &rtl8139_mmio_write, vmdev);
+       v3_hook_full_mem(nic_state->vm, nic_state->vm->cores[0].cpu_id, base_addr, base_addr + 0xff,
+                                     &rtl8139_mmio_read, &rtl8139_mmio_write, nic_state);
     } else {
        PrintError("In RTL8139: unknown memory type: start %x, size %d\n", (int) base_addr, size);
     }
        
     return 0;
 }
+#endif
 
-static int rtl8139_unhook_iospace()
-{
-
-    return 0;
-}
-
-
-static struct pci_device * rtl8139_pci_init(struct vm_device *vmdev, struct pci_bus *bus, int devfn)
-{
-    uchar_t *pci_conf;
-    struct pci_device *pdev;
+static int register_dev(struct rtl8139_state * nic_state)  {
+    int i;
 
-    pdev = v3_pci_register_device(vmdev, bus, "REALTEK8139", devfn, NULL, NULL);
+    if (nic_state->pci_bus == NULL) {
+       PrintError("RTL8139: Not attached to any PCI bus\n");
 
-    if (pdev == NULL)
-    {
-        PrintError("NIC: Register to PCI bus failed\n");
-        return NULL;
+       return -1;
     }
 
-    pci_conf = pdev->configs;
-       
-    pci_conf[0x00] = 0xec;
-    pci_conf[0x01] = 0x10;
-    pci_conf[0x02] = 0x39;
-    pci_conf[0x03] = 0x81;
-    pci_conf[0x04] = 0x05; /* command = I/O space, Bus Master */
-    pci_conf[0x08] = RTL8139_PCI_REVID_8139; /* PCI revision ID; >=0x20 is for 8139C+ */
-    pci_conf[0x0a] = 0x00; // ethernet network controller
-    pci_conf[0x0b] = 0x02;
-    pci_conf[0x0e] = 0x00; // header_type
-    pci_conf[0x3d] = 1; // interrupt pin 0
-    pci_conf[0x3c] = 12;
-    pci_conf[0x34] = 0xdc;
-
-    pdev->vmdev = vmdev;
-       
-    v3_pci_register_io_region(pdev, 0, 0x100, PCI_ADDRESS_SPACE_IO, &rtl8139_hook_iospace);
-    v3_pci_register_io_region(pdev, 1, 0x100, PCI_ADDRESS_SPACE_MEM, &rtl8139_hook_iospace);
-    
-    return pdev;
-}
+    struct v3_pci_bar bars[6];
+    struct pci_device * pci_dev = NULL;
 
-static int rtl8139_init_state(struct rtl8139_state *nic_state)
-{
-    PrintDebug("rtl8139: init_state\n");
-       
-    init_phy_network();
-    init_rtl8139(dev);
-    current_vnic = dev;
-    bus = v3_get_pcibus(dev->vm, 0);
-
-    if (bus != NULL) 
-    {
-           PrintDebug("Find PCI bus in guest, attach nic to the bus %p\n", bus);
-           pdev = rtl8139_pci_init(dev, bus, -1);
-           if (pdev == NULL)
-                   PrintError("Failure to attach nic to the bus %p\n", bus);
+    for (i = 0; i < 6; i++) {
+       bars[i].type = PCI_BAR_NONE;
     }
 
-    nic_state->pci_dev = pdev;
-
-    //rtl8139_hook_iospace(dev, 0x2000, 0x100, 1, NULL);
-
-    return 0;
-}
+    bars[0].type = PCI_BAR_IO;
+    bars[0].default_base_port = 0xc100;
+    bars[0].num_ports = 0x100;
 
-static int rtl8139_deinit_device(struct vm_device *dev)
-{
-       
-    rtl8139_unhook_iospace(); 
+    bars[0].io_read = rtl8139_ioport_read;
+    bars[0].io_write = rtl8139_ioport_write;
+    bars[0].private_data = nic_state;
 
-    return 0;
-}
-
-static struct vm_device_ops dev_ops =
-{
-    .init = rtl8139_init_device,
-    .deinit = rtl8139_deinit_device,
-    .reset = rtl8139_reset_device,
-    .start = rtl8139_start_device,
-    .stop = rtl8139_stop_device,
-};
-
-struct vm_device *v3_create_rtl8139()
-{
-    struct nic_context *nic_state = V3_Malloc(sizeof(struct nic_context));
-    PrintDebug("rtl8139 internal at %p\n", (void *)nic_state);
-    struct vm_device *dev = v3_create_device("RTL8139", &dev_ops, nic_state);
-    return dev;
-};
-
-
-
-static int register_dev(struct ne2k_state * nic_state) 
-{
-    int i;
-
-    if (nic_state->pci_bus != NULL) {
-       struct v3_pci_bar bars[6];
-       struct pci_device * pci_dev = NULL;
-
-       PrintDebug("NE2000: PCI Enabled\n");
-
-       for (i = 0; i < 6; i++) {
-           bars[i].type = PCI_BAR_NONE;
-       }
-
-       bars[0].type = PCI_BAR_IO;
-       bars[0].default_base_port = NIC_REG_BASE_PORT;
-       bars[0].num_ports = 256;
+/*
+    bars[1].type = PCI_BAR_MEM32;
+    bars[1].default_base_addr = -1;
+    bars[1].num_pages = 1;
 
-       bars[0].io_read = ne2k_pci_read;
-       bars[0].io_write = ne2k_pci_write;
-       bars[0].private_data = nic_state;
+    bars[1].mem_read = rtl8139_mmio_read;
+    bars[1].mem_write = rtl8139_mmio_write;
+    bars[1].private_data = nic_state;
+*/
 
-       pci_dev = v3_pci_register_device(nic_state->pci_bus, PCI_STD_DEVICE, 0, -1, 0, 
-                                        "NE2000", bars,
-                                        pci_config_update, NULL, NULL, nic_state);
+    pci_dev = v3_pci_register_device(nic_state->pci_bus, PCI_STD_DEVICE, 0, -1, 0, 
+                                        "RTL8139", bars,
+                                        NULL, NULL, NULL, nic_state);
 
 
-       if (pci_dev == NULL) {
-           PrintError("NE2000: Could not register PCI Device\n");
-           return -1;
-       }
+    if (pci_dev == NULL) {
+       PrintError("RTL8139: Could not register PCI Device\n");
+       return -1;
+    }
        
-       pci_dev->config_header.vendor_id = 0x10ec;
-       pci_dev->config_header.device_id = 0x8029;
-       pci_dev->config_header.revision = 0x00;
-
-       pci_dev->config_header.subclass = 0x00;
-       pci_dev->config_header.class = 0x02;
-       pci_dev->config_header.header_type = 0x00;
-
-       pci_dev->config_header.intr_line = 11;
-       pci_dev->config_header.intr_pin = 1;
-
-       nic_state->pci_dev = pci_dev;
-    }else {
-       PrintDebug("NE2000: Not attached to PCI\n");
-
-       v3_dev_hook_io(nic_state->dev, NIC_REG_BASE_PORT , &ne2k_cmd_read, &ne2k_cmd_write);
-
-       for (i = 1; i < 16; i++){       
-           v3_dev_hook_io(nic_state->dev, NIC_REG_BASE_PORT + i, &ne2k_std_read, &ne2k_std_write);
-       }
+    pci_dev->config_header.vendor_id = 0x10ec;
+    pci_dev->config_header.device_id = 0x8139;
+    pci_dev->config_header.command = 0x05;
+       
+    pci_dev->config_header.revision = RTL8139_PCI_REVID_8139;
 
-       v3_dev_hook_io(nic_state->dev, NIC_DATA_PORT, &ne2k_data_read, &ne2k_data_write);
-       v3_dev_hook_io(nic_state->dev, NIC_RESET_PORT, &ne2k_reset_port_read, &ne2k_reset_port_write);
-    }
+    pci_dev->config_header.subclass = 0x00;
+    pci_dev->config_header.class = 0x02;
+    pci_dev->config_header.header_type = 0x00;
 
+    pci_dev->config_header.intr_line = 12;
+    pci_dev->config_header.intr_pin = 1;
+    pci_dev->config_space[0x34] = 0xdc;
 
+    nic_state->pci_dev = pci_dev;
+       
     return 0;
 }
 
@@ -2000,7 +1764,7 @@ static int connect_fn(struct v3_vm_info * info,
                      struct v3_dev_net_ops * ops, 
                      v3_cfg_tree_t * cfg, 
                      void * private_data) {
-    struct ne2k_state * nic_state = (struct ne2k_state *)frontend_data;
+    struct rtl8139_state * nic_state = (struct rtl8139_state *)frontend_data;
 
     rtl8139_init_state(nic_state);
     register_dev(nic_state);
@@ -2008,7 +1772,7 @@ static int connect_fn(struct v3_vm_info * info,
     nic_state->net_ops = ops;
     nic_state->backend_data = private_data;    
 
-    ops->recv = ne2k_rx;
+    ops->recv = rtl8139_rx;
     ops->poll = NULL;
     ops->start_tx = NULL;
     ops->stop_tx = NULL;
@@ -2019,23 +1783,12 @@ static int connect_fn(struct v3_vm_info * info,
 }
 
 
-static int rtl8139_free(struct ne2k_state * nic_state) {
-    int i;
+static int rtl8139_free(void * private_data) {
+    struct rtl8139_state * nic_state = (struct rtl8139_state *)private_data;
 
     /* dettached from backend */
 
-    if(nic_state->pci_bus == NULL){
-       for (i = 0; i < 16; i++){               
-           v3_dev_unhook_io(nic_state->dev, NIC_REG_BASE_PORT + i);
-       }
-    
-       v3_dev_unhook_io(nic_state->dev, NIC_DATA_PORT);
-       v3_dev_unhook_io(nic_state->dev, NIC_RESET_PORT);
-    }else {
-       /* unregistered from PCI? */
-    }
-  
-    return 0;
+    /* unregistered from PCI? */
 
     V3_Free(nic_state);
        
@@ -2044,7 +1797,7 @@ static int rtl8139_free(struct ne2k_state * nic_state) {
 
 
 static struct v3_device_ops dev_ops = {
-    .free = (int (*)(void *))rtl8139_free,
+    .free = rtl8139_free,
 };
 
 
@@ -2055,7 +1808,7 @@ static int rtl8139_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
     char * macstr = v3_cfg_val(cfg, "mac");
 
     nic_state  = (struct rtl8139_state *)V3_Malloc(sizeof(struct rtl8139_state));
-    memset(nic_state, 0, sizeof(struct ne2k_state));
+    memset(nic_state, 0, sizeof(struct rtl8139_state));
 
     nic_state->pci_bus = pci_bus;
     nic_state->vm = vm;
index 6a6406c..1831270 100644 (file)
 #define PrintDebug(fmt, args...)
 #endif
 
-
 struct vnet_nic_state {
     struct v3_vm_info * vm;
     struct v3_dev_net_ops net_ops;
     int vnet_dev_id;
 };
 
-/* called by frontend device, 
-  * tell the VNET can start sending pkt to it */
-static void start_rx(void * private_data){
-    //struct vnet_nic_state *vnetnic = (struct vnet_nic_state *)private_data;
-
-    //v3_vnet_enable_device(vnetnic->vnet_dev_id);
-}
-
-/* called by frontend device, 
-  * tell the VNET stop sending pkt to it */
-static void stop_rx(void * private_data){
-    //struct vnet_nic_state *vnetnic = (struct vnet_nic_state *)private_data;
-
-    //v3_vnet_disable_device(vnetnic->vnet_dev_id);
-}
 
 /* called by frontend, send pkt to VNET */
 static int vnet_nic_send(uint8_t * buf, uint32_t len, 
@@ -93,7 +77,7 @@ static int virtio_input(struct v3_vm_info * info,
                                 vnetnic->net_ops.frontend_data);
 }
 
-/* tell frontend device to poll data from guest */
+/* poll data from front-end */
 static void virtio_poll(struct v3_vm_info * info, 
                        void * private_data){
     struct vnet_nic_state *vnetnic = (struct vnet_nic_state *)private_data;
@@ -102,21 +86,6 @@ static void virtio_poll(struct v3_vm_info * info,
 }
 
 
-/* notify the frontend to start sending pkt to VNET*/
-static void start_tx(void * private_data){
-    struct vnet_nic_state *vnetnic = (struct vnet_nic_state *)private_data;
-
-    vnetnic->net_ops.start_tx(vnetnic->net_ops.frontend_data);
-}
-
-/* notify the frontend device to stop sending pkt to VNET*/
-static void stop_tx(void * private_data){
-    struct vnet_nic_state *vnetnic = (struct vnet_nic_state *)private_data;
-
-    vnetnic->net_ops.stop_tx(vnetnic->net_ops.frontend_data);
-}
-
-
 static int vnet_nic_free(struct vnet_nic_state * vnetnic) {
 
     v3_vnet_del_dev(vnetnic->vnet_dev_id);
@@ -133,8 +102,6 @@ static struct v3_device_ops dev_ops = {
 static struct v3_vnet_dev_ops vnet_dev_ops = {
     .input = virtio_input,
     .poll = virtio_poll,
-    .start_tx = start_tx,
-    .stop_tx = stop_tx,
 };
 
 
@@ -156,8 +123,6 @@ static int vnet_nic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
     }
 
     vnetnic->net_ops.send = vnet_nic_send;
-    vnetnic->net_ops.start_rx = start_rx;
-    vnetnic->net_ops.stop_rx = stop_rx;
     vnetnic->vm = vm;
        
     if (v3_dev_connect_net(vm, v3_cfg_val(frontend_cfg, "tag"), 
@@ -173,13 +138,12 @@ static int vnet_nic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
 
     if ((vnet_dev_id = v3_vnet_add_dev(vm, vnetnic->net_ops.fnt_mac, &vnet_dev_ops, (void *)vnetnic)) == -1) {
        PrintError("Vnet-nic device %s fails to registered to VNET\n", dev_id);
+       
        v3_remove_device(dev);
        return 0;
     }
     vnetnic->vnet_dev_id = vnet_dev_id;
 
-    PrintDebug("Vnet-nic device %s registered to VNET\n", dev_id);
-
     return 0;
 }
 
index bd0d2c4..7d90d3e 100644 (file)
 static struct v3_packet_hooks * packet_hooks = 0;
 
 int V3_send_raw(const char * pkt, uint32_t len) {
-    V3_ASSERT(packet_hooks);
-    V3_ASSERT(packet_hooks->send);
+    if(packet_hooks != NULL && packet_hooks->send != NULL){
+       return packet_hooks->send(pkt, len, NULL);
+    }
 
-    return packet_hooks->send(pkt, len, NULL);
+    return -1;
 }
 
 
 int V3_packet_add_recver(const char * mac, struct v3_vm_info * vm){
-    V3_ASSERT(packet_hooks);
-    V3_ASSERT(packet_hooks->add_recver);
+    if(packet_hooks != NULL && packet_hooks->add_recver != NULL){
+        return packet_hooks->add_recver(mac, vm);
+    }
 
-    return packet_hooks->add_recver(mac, vm);
+    return -1;
 }
 
 
 int V3_packet_del_recver(const char * mac, struct v3_vm_info * vm){
-    V3_ASSERT(packet_hooks);
-    V3_ASSERT(packet_hooks->del_recver);
+    if(packet_hooks != NULL && packet_hooks->del_recver != NULL){
+        return packet_hooks->del_recver(mac, vm);
+    }
 
-    return packet_hooks->del_recver(mac, vm);
+    return -1;
 }
 
 void V3_Init_Packet(struct v3_packet_hooks * hooks) {