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.


Update virtual NE2000
Lei Xia [Sun, 19 Apr 2009 15:26:41 +0000 (10:26 -0500)]
palacios/build/Makefile
palacios/include/devices/ne2k.h
palacios/src/devices/ne2k.c

index 4e8c8e3..7319a6f 100644 (file)
@@ -203,6 +203,14 @@ DEBUG_SECTIONS := $(DEBUG_SECTIONS) -UDEBUG_DEV_MGR
 endif
 endif
 
+ifeq ($(DEBUG_NE2K),1)
+DEBUG_SECTIONS := $(DEBUG_SECTIONS) -DDEBUG_NE2K
+else 
+ifeq ($(DEBUG_NE2K),0)
+DEBUG_SECTIONS := $(DEBUG_SECTIONS) -UDEBUG_NE2K
+endif
+endif
+
 #DEBUG_SECTIONS := $(DEBUG_SECTIONS) -DTEST_NE2K
 
 ifeq ($(DEBUG),1)
@@ -334,6 +342,7 @@ DEVICES_OBJS := \
        devices/ram_hd.o \
        devices/i440fx.o \
        devices/piix3.o \
+       devices/ne2k.o  \
 
 #      devices/cdrom.o \
 #      devices/ramdisk.o \
index c1a9a6f..7f016b4 100644 (file)
@@ -7,8 +7,8 @@
  * and the University of New Mexico.  You can find out more at 
  * http://www.v3vee.org
  *
- * Copyright (c) 2008, Lei Xia <lxia@northwestern.edu> 
- * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
+ * Copyright (c) 2009, Lei Xia <lxia@northwestern.edu> 
+ * Copyright (c) 2009, The V3VEE Project <http://www.v3vee.org> 
  * All rights reserved.
  *
  * Author: Lei Xia <lxia@northwestern.edu>
  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
  */
 
-#ifndef __VNIC_H_
-#define __VNIC_H_
+#ifndef __NE2K_H_
+#define __NE2K_H_
 
 #include <palacios/vm_dev.h>
+#include <palacios/vmm_types.h>
 
-#define NIC_BASE_ADDR  0xc100
+#define NE2K_DEF_BASE_ADDR     0xc100
 
-#define NIC_IRQ        11              /* Interrupt channel */
+#define NE2K_DEF_IRQ           11
 
-#define MAX_ETH_FRAME_SIZE 1514
+#define MAX_ETH_FRAME_SIZE      1514
 
-#define NE2K_PMEM_SIZE    (32 * 1024)
-#define NE2K_PMEM_START   (16 * 1024)
-#define NE2K_PMEM_END     (NE2K_PMEM_SIZE + NE2K_PMEM_START)
-#define NE2K_MEM_SIZE     NE2K_PMEM_END
+#define NE2K_PMEM_SIZE          (32*1024)
+#define NE2K_PMEM_START         (16*1024)
+#define NE2K_PMEM_END           (NE2K_PMEM_SIZE+NE2K_PMEM_START)
+#define NE2K_MEM_SIZE           NE2K_PMEM_END
 
-#define EN0_COMMAND (0x00)  // The command register (for all pages) 
-
-#define NIC_DATA_PORT (0x10)  // The data read/write port
-
-#define NIC_RESET_PORT (0x1f)  // The data read/write port
+#define EN0_COMMAND             0x00   //Command register (for all pages) 
+#define NIC_DATA_PORT          0x10    //Data read/write port
+#define NIC_RESET_PORT                 0x1f    //Data read/write port
 
 // Page 0 registers
-#define EN0_CLDALO     (0x01)    // Low byte of current local dma addr  RD 
-#define EN0_STARTPG    (0x01)  // Starting page of ring bfr WR 
-#define EN0_CLDAHI     (0x02)  // High byte of current local dma addr  RD 
-#define EN0_STOPPG     (0x02)    //Ending page +1 of ring bfr WR 
-#define EN0_BOUNDARY   (0x03)    //Boundary page of ring bfr RD WR 
-#define EN0_TSR                (0x04)  //Transmit status reg RD 
-#define EN0_TPSR       (0x04)  //Transmit starting page WR 
-#define EN0_NCR                (0x05)  //Number of collision reg RD 
-#define EN0_TCNTLO     (0x05)  //Low  byte of tx byte count WR 
-#define EN0_FIFO       (0x06)  //FIFO RD 
-#define EN0_TCNTHI     (0x06)         //High byte of tx byte count WR 
-#define EN0_ISR                (0x07)  //Interrupt status reg RD WR 
-#define EN0_CRDALO     (0x08)  //low byte of current remote dma address RD 
-#define EN0_RSARLO     (0x08)  //Remote start address reg 0 
-#define EN0_CRDAHI     (0x09)  //high byte, current remote dma address RD 
-#define EN0_RSARHI     (0x09)  //Remote start address reg 1 
-#define EN0_RCNTLO     (0x0a)  //Remote byte count reg WR 
-#define EN0_RTL8029ID0 (0x0a)  //Realtek ID byte #1 RD 
-#define EN0_RCNTHI     (0x0b)  //Remote byte count reg WR 
-#define EN0_RTL8029ID1 (0x0b)  //Realtek ID byte #2 RD 
-#define EN0_RSR                (0x0c)  //rx status reg RD 
-#define EN0_RXCR       (0x0c)  //RX configuration reg WR 
-#define EN0_TXCR       (0x0d)  //TX configuration reg WR 
-#define EN0_COUNTER0   (0x0d)  //Rcv alignment error counter RD 
-#define EN0_DCFG       (0x0e)  //Data configuration reg WR 
-#define EN0_COUNTER1   (0x0e)  //Rcv CRC error counter RD 
-#define EN0_IMR                (0x0f)   //Interrupt mask reg WR 
-#define EN0_COUNTER2   (0x0f)  //Rcv missed frame error counter RD 
+#define EN0_CLDALO             0x01    //Low byte of current local dma addr  RD 
+#define EN0_STARTPG            0x01    //Starting page of ring bfr WR 
+#define EN0_CLDAHI             0x02    //High byte of current local dma addr  RD 
+#define EN0_STOPPG             0x02    //Ending page +1 of ring bfr WR 
+#define EN0_BOUNDARY           0x03    //Boundary page of ring bfr RD WR 
+#define EN0_TSR                        0x04    //Transmit status reg RD 
+#define EN0_TPSR               0x04    //Transmit starting page WR 
+#define EN0_NCR                        0x05    //Number of collision reg RD 
+#define EN0_TCNTLO             0x05    //Low  byte of tx byte count WR 
+#define EN0_FIFO               0x06    //FIFO RD 
+#define EN0_TCNTHI             0x06    //High byte of tx byte count WR 
+#define EN0_ISR                        0x07    //Interrupt status reg RD WR 
+#define EN0_CRDALO             0x08    //low byte of current remote dma address RD 
+#define EN0_RSARLO             0x08    //Remote start address reg 0 
+#define EN0_CRDAHI             0x09    //high byte, current remote dma address RD 
+#define EN0_RSARHI             0x09    //Remote start address reg 1 
+#define EN0_RCNTLO             0x0a    //Remote byte count reg WR 
+#define EN0_RTL8029ID0         0x0a    //Realtek ID byte #1 RD 
+#define EN0_RCNTHI             0x0b    //Remote byte count reg WR 
+#define EN0_RTL8029ID1         0x0b    //Realtek ID byte #2 RD 
+#define EN0_RSR                        0x0c    //rx status reg RD 
+#define EN0_RXCR               0x0c    //RX configuration reg WR 
+#define EN0_TXCR               0x0d    //TX configuration reg WR 
+#define EN0_COUNTER0           0x0d    //Rcv alignment error counter RD 
+#define EN0_DCFG               0x0e    //Data configuration reg WR 
+#define EN0_COUNTER1           0x0e    //Rcv CRC error counter RD 
+#define EN0_IMR                        0x0f    //Interrupt mask reg WR 
+#define EN0_COUNTER2           0x0f    //Rcv missed frame error counter RD 
 
 //Page 1 registers
-#define EN1_PHYS        (0x01)
-#define EN1_CURPAG      (0x07)
-#define EN1_MULT        (0x08)
+#define EN1_PHYS               0x01
+#define EN1_CURPAG                     0x07
+#define EN1_MULT                       0x08
 
 //Page 2 registers
-#define EN2_STARTPG     (0x01) //Starting page of ring bfr RD 
-#define EN2_STOPPG     (0x02)  //Ending page +1 of ring bfr RD 
-#define EN2_LDMA0  (0x01)   //Current Local DMA Address 0 WR 
-#define EN2_LDMA1  (0x02)   //Current Local DMA Address 1 WR 
-#define EN2_RNPR  (0x03)   //Remote Next Packet Pointer RD WR 
-#define EN2_TPSR  (0x04)    //Transmit Page Start Address RD 
-#define EN2_LNRP  (0x05)   // Local Next Packet Pointer RD WR 
-#define EN2_ACNT0  (0x06)  // Address Counter Upper WR 
-#define EN2_ACNT1  (0x07)  // Address Counter Lower WR 
-#define EN2_RCR  (0x0c)  // Receive Configuration Register RD 
-#define EN2_TCR  (0x0d)  // Transmit Configuration Register RD 
-#define EN2_DCR  (0x0e)  // Data Configuration Register RD 
-#define EN2_IMR  (0x0f)  // Interrupt Mask Register RD 
+#define EN2_STARTPG            0x01    //Starting page of ring bfr RD 
+#define EN2_STOPPG             0x02    //Ending page +1 of ring bfr RD 
+#define EN2_LDMA0              0x01    //Current Local DMA Address 0 WR 
+#define EN2_LDMA1              0x02    //Current Local DMA Address 1 WR 
+#define EN2_RNPR               0x03    //Remote Next Packet Pointer RD WR 
+#define EN2_TPSR               0x04            //Transmit Page Start Address RD 
+#define EN2_LNRP               0x05    //Local Next Packet Pointer RD WR 
+#define EN2_ACNT0              0x06    //Address Counter Upper WR 
+#define EN2_ACNT1              0x07    //Address Counter Lower WR 
+#define EN2_RCR                0x0c    //Receive Configuration Register RD 
+#define EN2_TCR                0x0d    //Transmit Configuration Register RD 
+#define EN2_DCR                0x0e    //Data Configuration Register RD 
+#define EN2_IMR                0x0f    //Interrupt Mask Register RD 
 
 //Page 3 registers
-#define EN3_CONFIG0     (0x03)
-#define EN3_CONFIG1     (0x04)
-#define EN3_CONFIG2     (0x05)
-#define EN3_CONFIG3     (0x06)
+#define EN3_CONFIG0            0x03
+#define EN3_CONFIG1            0x04
+#define EN3_CONFIG2            0x05
+#define EN3_CONFIG3            0x06
 
 //Bits in EN0_ISR - Interrupt status register
-#define ENISR_RX       0x01    //Receiver, no error 
-#define ENISR_TX       0x02    //Transmitter, no error 
-#define ENISR_RX_ERR   0x04    //Receiver, with error 
-#define ENISR_TX_ERR   0x08    //Transmitter, with error 
-#define ENISR_OVER     0x10    //Receiver overwrote the ring 
-#define ENISR_COUNTERS 0x20    //Counters need emptying 
-#define ENISR_RDC      0x40    //remote dma complete 
-#define ENISR_RESET    0x80    //Reset completed 
-#define ENISR_ALL      0x3f    //Interrupts we will enable 
+#define ENISR_RX               0x01    //Receiver, no error 
+#define ENISR_TX               0x02    //Transmitter, no error 
+#define ENISR_RX_ERR           0x04    //Receiver, with error 
+#define ENISR_TX_ERR           0x08    //Transmitter, with error 
+#define ENISR_OVER             0x10    //Receiver overwrote the ring 
+#define ENISR_COUNTERS         0x20    //Counters need emptying 
+#define ENISR_RDC              0x40    //remote dma complete 
+#define ENISR_RESET            0x80    //Reset completed 
+#define ENISR_ALL              0x3f    //Interrupts we will enable 
 
 //Bits in received packet status byte and EN0_RSR
-#define ENRSR_RXOK     0x01    //Received a good packet 
-#define ENRSR_CRC      0x02    //CRC error 
-#define ENRSR_FAE      0x04    //frame alignment error 
-#define ENRSR_FO       0x08    //FIFO overrun 
-#define ENRSR_MPA      0x10    //missed pkt 
-#define ENRSR_PHY      0x20    //physical/multicast address 
-#define ENRSR_DIS      0x40    //receiver disable. set in monitor mode 
-#define ENRSR_DEF      0x80    //deferring 
+#define ENRSR_RXOK             0x01    //Received a good packet 
+#define ENRSR_CRC              0x02    //CRC error 
+#define ENRSR_FAE              0x04    //frame alignment error 
+#define ENRSR_FO               0x08    //FIFO overrun 
+#define ENRSR_MPA              0x10    //missed pkt 
+#define ENRSR_PHY              0x20    //physical/multicast address 
+#define ENRSR_DIS              0x40    //receiver disable. set in monitor mode 
+#define ENRSR_DEF              0x80    //deferring 
 
 //Transmitted packet status, EN0_TSR
-#define ENTSR_PTX 0x01 //Packet transmitted without error 
-#define ENTSR_ND  0x02 //The transmit wasn't deferred. 
-#define ENTSR_COL 0x04 //The transmit collided at least once. 
-#define ENTSR_ABT 0x08  //The transmit collided 16 times, and was deferred. 
-#define ENTSR_CRS 0x10 //The carrier sense was lost. 
-#define ENTSR_FU  0x20  //A "FIFO underrun" occurred during transmit. 
-#define ENTSR_CDH 0x40 //The collision detect "heartbeat" signal was lost. 
-#define ENTSR_OWC 0x80  //There was an out-of-window collision. 
+#define ENTSR_PTX              0x01    //Packet transmitted without error 
+#define ENTSR_ND               0x02    //The transmit wasn't deferred. 
+#define ENTSR_COL              0x04    //The transmit collided at least once. 
+#define ENTSR_ABT              0x08    //The transmit collided 16 times, and was deferred. 
+#define ENTSR_CRS              0x10    //The carrier sense was lost. 
+#define ENTSR_FU               0x20    //A "FIFO underrun" occurred during transmit. 
+#define ENTSR_CDH              0x40    //The collision detect "heartbeat" signal was lost. 
+#define ENTSR_OWC              0x80    //There was an out-of-window collision. 
 
 //command, Register accessed at EN0_COMMAND
-#define NE2K_STOP 0x01
-#define NE2K_START 0x02
-#define NE2K_TRANSMIT 0x04
-#define NE2K_DMAREAD   0x08    /* Remote read */
-#define NE2K_DMAWRITE  0x10    /* Remote write  */
-#define NE2K_DMASEND     0x18
-#define NE2K_ABORTDMA  0x20    /* Abort/Complete DMA */
-#define NE2K_PAGE0     0x00    /* Select page chip registers */
-#define NE2K_PAGE1     0x40    /* using the two high-order bits */
-#define NE2K_PAGE2     0x80
-#define NE2K_PAGE    0xc0
-
-struct vm_device *v3_create_vnic();
+#define NE2K_STOP              0x01
+#define NE2K_START             0x02
+#define NE2K_TRANSMIT          0x04
+#define NE2K_DMAREAD           0x08    //Remote read
+#define NE2K_DMAWRITE          0x10    //Remote write
+#define NE2K_DMASEND           0x18
+#define NE2K_ABORTDMA          0x20    //Abort/Complete DMA
+#define NE2K_PAGE0             0x00    //Select page chip registers
+#define NE2K_PAGE1             0x40    //using the two high-order bits
+#define NE2K_PAGE2             0x80
+#define NE2K_PAGE              0xc0
+
+struct ne2k_regs {
+    uchar_t cmd;
+    uchar_t pgstart;
+    uchar_t pgstop;
+    ushort_t clda;
+    uchar_t boundary;
+    uchar_t tsr;
+    uchar_t tpsr;
+    uchar_t ncr;
+    ushort_t tbcr;
+    uchar_t fifo;
+    uchar_t isr;
+    ushort_t crda;
+    ushort_t rsar;
+    ushort_t rbcr;
+    uchar_t rsr;
+    uchar_t rcr;
+    uint_t cntr;
+    uchar_t tcr;
+    uchar_t dcr;
+    uchar_t imr;
+    
+    uchar_t phys[6]; //mac address 
+    uchar_t curpag;
+    uchar_t mult[8]; //multicast mask array 
+    uchar_t rnpp;
+    uchar_t lnpp;
+    ushort_t addcnt;
+    
+    uchar_t macaddr[6];
+};
+
+struct vm_device *v3_create_ne2k();
 
 #endif
index e6c12a9..431c590 100644 (file)
 * Virtual NE2K Network Card 
 */
 
-
-
-
-#include <devices/vnic.h>
+#include <devices/pci.h>
+#include <devices/ne2k.h>
 #include <palacios/vmm.h>
 #include <palacios/vmm_types.h>
 #include <palacios/vmm_io.h>
 #include <palacios/vmm_debug.h>
+#include <palacios/vmm_string.h>
 
-#define DEBUG_NIC
-
-#ifndef DEBUG_NIC
-#undef PrintDebug()
+#ifndef DEBUG_NE2K
+#undef PrintDebug
 #define PrintDebug(fmts, args...)
 #endif
 
-typedef enum {NIC_READY, NIC_REG_POSTED} nic_state_t;
-
-struct nic_regs {
-    uchar_t cmd;
-    uchar_t pgstart;
-    uchar_t pgstop;
-    ushort_t clda;
-    uchar_t boundary;
-    uchar_t tsr;
-    uchar_t tpsr;
-    uchar_t ncr;
-    ushort_t tbcr;
-    uchar_t fifo;
-    uchar_t isr;
-    ushort_t crda;
-    ushort_t rsar;
-    ushort_t rbcr;
-    uchar_t rsr;
-    uchar_t rcr;
-    uint32_t cntr;
-    uchar_t tcr;
-    uchar_t dcr;
-    uchar_t imr;
-    
-    uchar_t phys[6]; // mac address 
-    uchar_t curpag;
-    uchar_t mult[8]; // multicast mask array 
-    uchar_t rnpp;
-    uchar_t lnpp;
-    ushort_t addcnt;
-    
-    uchar_t macaddr[6];
-};
+//#define TEST_PERFORMANCE 0
 
-struct nic_context{
-    struct guest_info * vm;
+typedef enum {NIC_READY, NIC_REG_POSTED} nic_state_t;
 
+struct ne2k_context{
+    struct guest_info *vm;
     nic_state_t dev_state;
 
-    struct nic_regs regs;
-
-    uchar_t mac[6]; //the mac address of this nic
-
-    uchar_t mem[NE2K_MEM_SIZE];        
+    struct ne2k_regs regs;
+    uchar_t mac[6];
+    uchar_t mem[NE2K_MEM_SIZE];
+    struct pci_device *pci_dev;
+    struct vm_device *pci;
 };
 
-struct vm_device * current_vnic;
-
-#define compare_mac(src, dst) ({               \
-           ( (src[0] == dst[0]) &&             \
-             (src[1] == dst[1]) &&             \
-             (src[2] == dst[2]) &&             \
-             (src[3] == dst[3]) &&             \
-             (src[4] == dst[4]) &&             \
-             (src[5] == dst[5]) ) ? 1 : 0;     \
-       })
-
-
-
-
-static int vnic_mem_write(struct nic_context * nic_state, 
-                         uint32_t addr,
-                         uint_t length) {
-    
-    PrintDebug("wmem addr: %x val: %x\n", addr, val);
-
-    //    if ((addr < NE2K_PMEM_START) || (addr > NE2K_MEM_SIZE))
-
-    switch (length) {
-       case 1: {
-           uchar_t val = *(uchar_t *)src;
-           
-       }
-       case 2:
-       case 4:
-    }
-
-}
-
-
-static void vnic_mem_writeb(struct nic_context * nic_state, 
-                           uint32_t addr,
-                           uint32_t val) {
-    uchar_t tmp = (uchar_t) (val & 0x000000ff);
+#define NUM_NE2K 10
 
-    if ( (addr < 32) || 
-        ((addr >= NE2K_PMEM_START && addr < NE2K_MEM_SIZE) ) {
-        nic_state->mem[addr] = tmp;
-    }
+struct vm_device *ne2ks[NUM_NE2K];     //the array of virtual network cards
 
-    PrintDebug("wmem addr: %x val: %x\n", addr, val);
-}
+static int nic_no = 0;
 
-static void vnic_mem_writew(struct nic_context * nic_state, 
-                           uint32_t addr,
-                           uint32_t val) {
-
-    addr &= ~1; //XXX: check exact behaviour if not even
+#if TEST_PERFORMANCE
+static uint32_t exit_num = 0;
+static uint32_t int_num = 0; 
+#endif
 
-    if ( (addr < 32) ||
-        ((addr >= NE2K_PMEM_START && addr) < NE2K_MEM_SIZE)) {
-        *(ushort_t *)(nic_state->mem + addr) = cpu2le16(val);
-    }
+#define compare_mac(src, dst) ({ \
+       ((src[0] == dst[0]) && \
+         (src[1] == dst[1]) && \
+         (src[2] == dst[2]) && \
+         (src[3] == dst[3]) && \
+         (src[4] == dst[4]) && \
+         (src[5] == dst[5]))? 1:0; \
+       })
 
-    PrintDebug("wmem addr: %x val: %x\n", addr, val);
-}
+extern int V3_Send_pkt(uchar_t *buf, int length);
+extern int V3_Register_pkt_event(int (*netif_input)(uchar_t * pkt, uint_t size));
 
-static void vnic_mem_writel(struct nic_context * nic_state,
-                           uint32_t addr,
-                           uint32_t val) {
-    addr &= ~1; // XXX: check exact behaviour if not even
+#ifdef DEBUG_NE2K
+static void dump_state(struct vm_device *dev)
+{
+  int i;
+  uchar_t *p;
+  struct ne2k_context *nic_state = (struct ne2k_context *)dev->private_data;
 
-    if ( (addr < 32) ||
-        ( (addr >= NE2K_PMEM_START) && (addr < NE2K_MEM_SIZE) ) ) {
-        *(uint32_t *)(nic_state->mem + addr) = cpu2le32(val);
-    }
-    
-    PrintDebug("wmem addr: %x val: %x\n", addr, val);
-}
+  PrintDebug("====NE2000: Dumping state Begin ==========\n");
+  PrintDebug("Registers:\n");
 
-static uchar_t vnic_mem_readb(struct nic_context * nic_state, uint32_t addr) {
-    PrintDebug("rmem addr: %x\n", addr);
-       
-    if ( (addr < 32) ||
-        ( (addr >= NE2K_PMEM_START) && (addr < NE2K_MEM_SIZE)) ) {
-        return nic_state->mem[addr];
-    } else {
-        return 0xff;
-    }
+  p = (uchar_t *)&nic_state->regs;
+  for(i = 0; i < sizeof(struct ne2k_regs); i++)
+     PrintDebug("Regs[%d] = 0x%2x\n", i, (int)p[i]);   
+  
+  PrintDebug("Memory:\n");     
+  for(i = 0; i < 32; i++)
+        PrintDebug("0x%02x ", nic_state->mem[i]);
+  PrintDebug("\n");
+  PrintDebug("====NE2000: Dumping state End==========\n");
 }
+#endif
 
-static ushort_t vnic_mem_readw(struct nic_context * nic_state, uint32_t addr) {
-    PrintDebug("rmem addr: %x\n", addr);
+#if 0
+//no-pci version
+static void ne2k_update_irq(struct vm_device *dev)
+{
+    int isr;
+    struct ne2k_context *nic_state = (struct ne2k_context *)dev->private_data;
+    struct guest_info *guest = dev->vm;
        
-    addr &= ~1; //XXX: check exact behaviour if not even 
+    isr = ((nic_state->regs.isr & nic_state->regs.imr) & 0x7f);
 
-    if ( (addr < 32) ||
-         ( (addr >= NE2K_PMEM_START) && (addr < NE2K_MEM_SIZE))) {
-        return (ushort_t)le16_to_cpu((ushort_t *)(nic_state->mem + addr));
-    } else {
-        return 0xffff;
-    }
+    if ((isr & 0x7f) != 0x0) {
+       v3_raise_irq(guest, NIC_DEF_IRQ);
+       PrintDebug("Ne2k: RaiseIrq: isr: 0x%02x imr: 0x%02x\n", nic_state->regs.isr, nic_state->regs.imr);
+    }   
 }
 
-static uint32_t vnic_mem_readl(struct nic_context * nic_state, uint32_t addr) {
-    PrintDebug("rmem addr: %x\n", addr);
-
-    addr &= ~1; //XXX: check exact behaviour if not even
+#endif
 
-    if ( (addr < 32) ||
-         ( (addr >= NE2K_PMEM_START && addr < NE2K_MEM_SIZE))) {
-        return (uint32_t)le32_to_cpu((uint32_t *)(nic_state->mem + addr));
+#if 1
+//pci version
+static void ne2k_update_irq(struct vm_device *dev)
+{
+    int isr;
+    struct ne2k_context *nic_state = (struct ne2k_context *)dev->private_data;
+    struct pci_device *pdev = nic_state->pci_dev;
+    int irqline = 0;
+
+    if (pdev == NULL){
+               PrintDebug("Ne2k: Device %p is not attached to any PCI Bus\n", nic_state);
+               irqline = NE2K_DEF_IRQ;
     } else {
-        return 0xffffffff;
-    }
-}
-
-
-
-
-static void dump_state(struct vm_device * dev) {
-    int i = 0;
-    uchar_t * p = NULL;
-    struct nic_context * nic_state = (struct nic_context *)dev->private_data;
-
-    PrintDebug("====VNIC: Dumping state Begin ==========\n");
-    PrintDebug("Registers:\n");
-
-    p = (uchar_t *)&nic_state->regs;
-    for (i = 0; i < sizeof(struct nic_regs); i++) {
-       PrintDebug("Regs[i] = 0x%2x\n", (int)p[i]);     
+               irqline = pdev->config_header.intr_line;
     }
-
-    PrintDebug("Memory:\n");   
+       
+    isr = ((nic_state->regs.isr & nic_state->regs.imr) & 0x7f);
     
-    for (i = 0; i < 32; i++) {
-        PrintDebug("0x%02x ", nic_state->mem[i]);
+    if (irqline == 0){
+               PrintError("Ne2k: IRQ_LINE: %d\n", irqline);
+               return;
     }
 
-    PrintDebug("\n");
-    PrintDebug("====VNIC: Dumping state End==========\n");
-}
-
-static void vnic_update_irq(struct vm_device * dev) {
-    struct nic_context * nic_state = (struct nic_context *)dev->private_data;
-    struct guest_info * guest = dev->vm;
-
-    int isr = ((nic_state->regs.isr & nic_state->regs.imr) & 0x7f);
+    PrintDebug("Ne2k: RaiseIrq: isr: 0x%02x imr: 0x%02x\n", nic_state->regs.isr, nic_state->regs.imr);
+    PrintDebug("ne2k_update_irq: irq_line: %d\n", irqline);
 
     if ((isr & 0x7f) != 0x0) {
-       v3_raise_irq(guest, NIC_IRQ);
-       PrintDebug("VNIC: RaiseIrq: isr: 0x%02x imr: 0x%02x\n", nic_state->regs.isr, nic_state->regs.imr);
+       v3_raise_irq(nic_state->vm, irqline);
+       PrintDebug("Ne2k: RaiseIrq: isr: 0x%02x imr: 0x%02x\n", nic_state->regs.isr, nic_state->regs.imr);
+
+       #if TEST_PERFORMANCE
+       if ((++int_num) % 50 == 0)
+            PrintError("Ne2k: Total Exit: %d, INT: %d\n", (int)exit_num, int_num);
+       #endif
     }   
 }
 
-static void init_vnic_context(struct vm_device * dev) {
-    struct nic_context *nic_state = (struct nic_context *)dev->private_data;
+#endif
+
+static void init_ne2k_context(struct vm_device *dev)
+{
+    struct ne2k_context *nic_state = (struct ne2k_context *)dev->private_data;
     int i;
-    uchar_t mac[6] = {0x52, 0x54, 0x0, 0x12, 0x34, 0x56};
+    uchar_t mac[6] = {0x52, 0x54, 0x0, 0x12, 0x34, (0x60 + nic_no)};
 
     nic_state->vm = dev->vm;
 
@@ -244,13 +163,13 @@ static void init_vnic_context(struct vm_device * dev) {
     nic_state->regs.imr = 0x00;
     nic_state->regs.cmd = 0x22;
 
-    for (i = 0; i < 6; i++) {
+    for (i = 0; i < 5; i++)
        nic_state->regs.macaddr[i] = nic_state->mac[i] = mac[i];
-    }
 
-    for (i = 0; i < 8; i++) {
-       nic_state->regs.mult[i] = 0xff;
-    }
+    nic_state->regs.macaddr[5] = nic_state->mac[5] = mac[5] + nic_no;
+
+    for (i = 0; i < 8; i++)
+        nic_state->regs.mult[i] = 0xff;
 
     for(i = 0; i < 32; i++) {
         nic_state->mem[i] = 0xff;
@@ -260,179 +179,184 @@ static void init_vnic_context(struct vm_device * dev) {
     nic_state->mem[14] = 0x57;
     nic_state->mem[15] = 0x57;
 
+#ifdef DEBUG_NE2K
     dump_state(dev);
-}
+#endif
 
+}
 
-static int vnic_send_packet(struct vm_device *dev, uchar_t *pkt, int length) {
+static int ne2k_send_packet(struct vm_device *dev, uchar_t *pkt, int length)
+{
     int i;
   
-    PrintDebug("\nVNIC: Sending Packet\n");
-
-    for (i = 0; i < length; i++) {
-       PrintDebug("%x ",pkt[i]);
-    }
+    PrintDebug("\nNe2k: Sending Packet\n");
 
+    for (i = 0; i<length; i++)
+           PrintDebug("%x ",pkt[i]);
     PrintDebug("\n");
        
-    return V3_SEND_PKT(pkt, length);
+    return V3_Send_pkt(pkt, length);
 }
 
-
-struct vm_device * get_rx_dev(uchar_t * dst_mac) {
-    struct nic_context * nic_state = (struct nic_context *)current_vnic->private_data;
-    struct nic_regs * nregs = &(nic_state->regs);
+//TODO: Support Broadcast and Multicast 
+static struct vm_device * get_rx_dev(uchar_t *dst_mac)
+{
+    struct ne2k_context *nic_state;
+    struct ne2k_regs *nregs;
+    int i;
 
     static const uchar_t brocast_mac[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 
-    if (nregs->rcr & 0x10) {
-        // promiscuous model    
-    } else {
-        if (compare_mac(dst_mac,  brocast_mac)) { //broadcast address
-            if (!(nregs->rcr & 0x04)) {
-                return NULL;
-           }
-        } else if (dst_mac[0] & 0x01) {
-            // multicast packet, not fully done here
-            // ==========
-            if (!(nregs->rcr & 0x08)) {
-                return NULL;
-           }
-        } else if (!compare_mac(dst_mac, nic_state->mac)) {
-            return NULL;
-        } else {
-            // TODO: ELSE??
-        }
+    for (i = 0; i < NUM_NE2K; i++){
+               if (ne2ks[i] != NULL) {
+                       nic_state = (struct ne2k_context *)ne2ks[i]->private_data;
+                       nregs = &(nic_state->regs);
+                       
+                       if (nregs->rcr & 0x10) {//broadcast packets, not correct here
+                                return ne2ks[i];   
+                       } else {
+                        if (compare_mac(dst_mac,  brocast_mac) && (nregs->rcr & 0x04)) //broadcast address
+                                               return ne2ks[i];
+                                if (dst_mac[0] & 0x01) {
+                                   // multicast packet, not done here
+                                   // ==========
+                                   if (nregs->rcr & 0x08)
+                                               return ne2ks[i];
+                                } 
+                               if (compare_mac(dst_mac, nic_state->mac))
+                                               return ne2ks[i];   
+                     }
+              }
     }
 
-    return current_vnic;
+    return NULL;
 }
 
-static int vnic_rxbuf_full(struct vm_device * dev) {
+static int ne2k_rxbuf_full(struct vm_device *dev)
+{
     int empty, index, boundary;
-    struct nic_context * nic_state = (struct nic_context *)dev->private_data;
+    struct ne2k_context *nic_state = (struct ne2k_context *)dev->private_data;
 
     index = nic_state->regs.curpag << 8;
     boundary = nic_state->regs.boundary << 8;
-    if (index < boundary) {
+    if (index < boundary)
         empty = boundary - index;
-    } else {
+    else
         empty = ((nic_state->regs.pgstop - nic_state->regs.pgstart) << 8) - (index - boundary);
-    }
-
-    if (empty < (MAX_ETH_FRAME_SIZE + 4)) {
+       
+    if (empty < (MAX_ETH_FRAME_SIZE + 4))
         return 1;
-    }
-
+       
     return 0;
 }
 
 #define MIN_BUF_SIZE 60
 
-static void vnic_receive(struct vm_device * dev, const uchar_t * pkt, int length) {
-    struct nic_context * nic_state = (struct nic_context *)dev->private_data;
-    struct nic_regs * nregs = &(nic_state->regs);
-
-    uchar_t * p = NULL;
-    uint32_t total_len = 0; 
-    uint32_t next = 0;
-    uint32_t len = 0;
-    uint32_t index = 0;
-    uint32_t empty = 0;
+static void ne2k_receive(struct vm_device *dev, const uchar_t *pkt, int length)
+{
+    struct ne2k_context *nic_state = (struct ne2k_context *)dev->private_data;
+    struct ne2k_regs *nregs = &(nic_state->regs);
+    uchar_t *p;
+    uint32_t total_len, next, len, index, empty;
     uchar_t buf[60];
-    uint32_t start = nregs->pgstart << 8;
-    uint32_t stop = nregs->pgstop << 8;
-        
-    //PrintDebug("VNIC: received packet, len=%d\n", length);
+    uint32_t start, stop;
+
+    start = nregs->pgstart << 8;
+    stop = nregs->pgstop << 8;
    
-    if (nregs->cmd & NE2K_STOP) {
-       return;
-    }
+    if (nregs->cmd & NE2K_STOP)
+        return;
 
-    if (vnic_rxbuf_full(dev)){
-       PrintDebug("VNIC: received buffer overflow\n");
+    if (ne2k_rxbuf_full(dev)){
+        PrintError("Ne2k: received buffer overflow\n");
         return;
     }
 
-    // if too small buffer, expand it
+    //packet too small, expand it
     if (length < MIN_BUF_SIZE) {
         memcpy(buf, pkt, length);
         memset(buf + length, 0, MIN_BUF_SIZE - length);
-
         pkt = buf;
-
         length = MIN_BUF_SIZE;
     }
 
     index = nregs->curpag << 8;
-
-    // 4 bytes header 
+    //header, 4 bytes
     total_len = length + 4;
-
-    // address for next packet (4 bytes for CRC)
+    //address for next packet (4 bytes for CRC)
     next = index + ((total_len + 4 + 255) & ~0xff);
-
-    if (next >= stop) {
+    if (next >= stop)
         next -= stop - start;
-    }
 
     p = nic_state->mem + index;
     nregs->rsr = ENRSR_RXOK;
 
-    if (pkt[0] & 0x01) {
+    if (pkt[0] & 0x01)
         nregs->rsr |= ENRSR_PHY;
-    }
-
+       
     p[0] = nregs->rsr;
     p[1] = next >> 8;
     p[2] = total_len;
     p[3] = total_len >> 8;
-
     index += 4;
 
     while (length > 0) {
-        if (index <= stop) {
+        if (index <= stop)
             empty = stop - index;
-       } else {
-           empty = 0;
-       }
-
+        else
+            empty = 0;
         len = length;
-
-        if (len > empty) {
+        if (len > empty)
             len = empty;
-       }
-
         memcpy(nic_state->mem + index, pkt, len);
         pkt += len;
         index += len;
-
-        if (index == stop) {
+        if (index == stop)
             index = start;
-       }
-
         length -= len;
     }
-
     nregs->curpag = next >> 8;
 
     nregs->isr |= ENISR_RX;
-    vnic_update_irq(dev);
+    ne2k_update_irq(dev);
 }
 
-// =====begin here
-#if 0
-void pci_vnic_init(PCIBus * bus, NICInfo * nd, int devfn)
+static int ne2k_hook_iospace(struct vm_device *vmdev, addr_t base_addr, int size, int type, void *data);
+
+static struct pci_device * pci_ne2k_init(struct vm_device *vmdev, 
+                               struct vm_device *pci,  
+                               int bus_no, 
+                               int dev_num,
+                               int fn_num,
+                               int (*io_read)(ushort_t port, void * dst, uint_t length, struct vm_device * dev),
+                               int (*io_write)(ushort_t port, void * src, uint_t length, struct vm_device * dev))
 {
-    PCINE2000State * d = NULL;
-    NE2000State * s  = NULL;
-    uint8_t * pci_conf = NULL;
-    struct pci_device * pdev = pci_register_device(bus,
-                                                  "NE2000", sizeof(PCINE2000State),
-                                                  devfn,
-                                                  NULL, NULL);
-    pci_conf = d->dev.config;
+    uchar_t *pci_conf;
+    struct pci_device *pdev;
+    struct v3_pci_bar ne2k_bar;
+
+    ne2k_bar.type = PCI_BAR_IO;
+    ne2k_bar.num_ports = 0x100;
+    ne2k_bar.default_base_port = 0xc100;
+    ne2k_bar.io_read = io_read;
+    ne2k_bar.io_write = io_write;
+  
+    pdev = v3_pci_register_device(vmdev, 
+                                                               PCI_STD_DEVICE, 
+                                                               bus_no, 
+                                                               dev_num, 
+                                                               fn_num,
+                                                               "NE2000", 
+                                                               &ne2k_bar, 
+                                                               NULL, NULL, NULL, vmdev);
+
+    if (pdev == NULL){
+       PrintError("NIC: Register to PCI bus failed\n");
+       return NULL;
+    }
 
+    pci_conf = pdev->config_space;
+       
     pci_conf[0x00] = 0xec; // Realtek 8029
     pci_conf[0x01] = 0x10;
     pci_conf[0x02] = 0x29;
@@ -441,565 +365,738 @@ void pci_vnic_init(PCIBus * bus, NICInfo * nd, int devfn)
     pci_conf[0x0b] = 0x02;
     pci_conf[0x0e] = 0x00; // header_type
     pci_conf[0x3d] = 1; // interrupt pin 0
+    pci_conf[0x3c] = 11;
+
+    pdev->vm_dev = vmdev;
+    
+    return pdev;
+}
+
+static int netif_input(uchar_t * pkt, uint_t size)
+{
+  uint_t i;
+  struct vm_device *dev;
+  
+  PrintDebug("\nNe2k: Packet Received:\nSource:");
+  for (i = 6; i < 12; i++) {
+       PrintDebug("%x ", pkt[i]);
+  }
 
-    pci_register_io_region(&d->dev, 0, 0x100,
-                           PCI_ADDRESS_SPACE_IO, ne2000_map);
-    s = &d->ne2000;
+  dev = get_rx_dev(pkt); //TODO: handle multiple destination packets
 
-    s->irq = d->dev.irq[0];
+  if (dev == NULL) 
+       return 0;
 
-    s->pci_dev = (PCIDevice *)d;
+  PrintDebug("\n");
+  for(i= 0; i<size; i++)
+       PrintDebug("%x ", pkt[i]);
+  
+  ne2k_receive(dev, pkt, size);
 
-    memcpy(s->macaddr, nd->macaddr, 6);
+  return 0;
+}
 
-    ne2000_reset(s);
 
-    s->vc = qemu_new_vlan_client(nd->vlan, ne2000_receive,
-                                 ne2000_can_receive, s);
+static inline uint16_t cpu2le16(uint16_t val)
+{
+    uint16_t p;
+    uchar_t *p1 = (uchar_t *)&p;
 
-    snprintf(s->vc->info_str, sizeof(s->vc->info_str),
-             "ne2000 pci macaddr=%02x:%02x:%02x:%02x:%02x:%02x",
-             s->macaddr[0],
-             s->macaddr[1],
-             s->macaddr[2],
-             s->macaddr[3],
-             s->macaddr[4],
-             s->macaddr[5]);
+    p1[0] = val;
+    p1[1] = val >> 8;
 
-    /* XXX: instance number ? */
-    register_savevm("ne2000", 0, 3, ne2000_save, ne2000_load, s);
+    return p;
 }
-#endif
-//End Here====================================
 
-static int netif_input(uchar_t * pkt, uint_t size) {
-  uint_t i;
-  struct vm_device * dev = NULL;
-  
-  PrintDebug("\nVNIC: Packet Received:\nSource:");
-  
-  for (i = 6; i < 12; i++) {
-      PrintDebug("%x ", pkt[i]);
-  }
 
-  dev = get_rx_dev(pkt);
+static inline uint32_t cpu2le32(uint32_t val)
+{
+    uint32_t p;
+    uchar_t *p1 = (uchar_t *)&p;
 
-  if (dev == NULL) {
-      return 0;
-  }
+    p1[0] = val;
+    p1[1] = val >> 8;
+    p1[2] = val >> 16;
+    p1[3] = val >> 24;
 
-  PrintDebug("\n");
+    return p;
+}
 
-  for(i = 0; i < size; i++) {
-      PrintDebug("%x ", pkt[i]);
-  }
+static inline uint16_t le16_to_cpu(const uint16_t *p)
+{
+    const uchar_t *p1 = (const uchar_t *)p;
+    return p1[0] | (p1[1] << 8);
+}
+
+static inline uint32_t le32_to_cpu(const uint32_t *p)
+{
+    const uchar_t *p1 = (const uchar_t *)p;
+    return p1[0] | (p1[1] << 8) | (p1[2] << 16) | (p1[3] << 24);
+}
+
+static void 
+ne2k_mem_writeb(struct ne2k_context *nic_state, 
+                       uint32_t addr,
+                       uint32_t val)
+{
+    uchar_t tmp;
+
+    tmp = (uchar_t) (val & 0x000000ff);
+    if (addr < 32 || (addr >= NE2K_PMEM_START && addr < NE2K_MEM_SIZE)) {
+        nic_state->mem[addr] = tmp;
+    }
+
+    PrintDebug("wmem addr: %x val: %x\n", addr, val);
+}
+
+static void 
+ne2k_mem_writew(struct ne2k_context *nic_state, 
+                       uint32_t addr,
+                       uint32_t val)
+{
+    addr &= ~1; //XXX: check exact behaviour if not even
+    if (addr < 32 ||
+        (addr >= NE2K_PMEM_START && addr < NE2K_MEM_SIZE)) {
+        *(ushort_t *)(nic_state->mem + addr) = cpu2le16(val);
+    }
+
+    PrintDebug("wmem addr: %x val: %x\n", addr, val);
+}
+
+static void 
+ne2k_mem_writel(struct ne2k_context *nic_state,
+                       uint32_t addr,
+                       uint32_t val)
+{
+    addr &= ~1; // XXX: check exact behaviour if not even
+    if (addr < 32 ||
+        (addr >= NE2K_PMEM_START && addr < NE2K_MEM_SIZE)) {
+        *(uint32_t *)(nic_state->mem + addr) = cpu2le32(val);
+    }
+
+    PrintDebug("wmem addr: %x val: %x\n", addr, val);
+}
+
+static uchar_t 
+ne2k_mem_readb(struct ne2k_context *nic_state, uint32_t addr)
+{
+    PrintDebug("rmem addr: %x\n", addr);
+       
+    if (addr < 32 ||
+        (addr >= NE2K_PMEM_START && addr < NE2K_MEM_SIZE)) {
+        return nic_state->mem[addr];
+    } else {
+        return 0xff;
+    }
+}
+
+static ushort_t
+ne2k_mem_readw(struct ne2k_context *nic_state, uint32_t addr)
+{
+    PrintDebug("rmem addr: %x\n", addr);
+       
+    addr &= ~1; //XXX: check exact behaviour if not even 
+    if (addr < 32 ||
+        (addr >= NE2K_PMEM_START && addr < NE2K_MEM_SIZE)) {
+        return (ushort_t)le16_to_cpu((ushort_t *)(nic_state->mem + addr));
+    } else {
+        return 0xffff;
+    }
+}
+
+static uint32_t 
+ne2k_mem_readl(struct ne2k_context *nic_state, uint32_t addr)
+{
+    PrintDebug("rmem addr: %x\n", addr);
 
-  vnic_receive(dev, pkt, size);
+    addr &= ~1; //XXX: check exact behaviour if not even
+    if (addr < 32 ||
+        (addr >= NE2K_PMEM_START && addr < NE2K_MEM_SIZE)) {
+        return (uint32_t)le32_to_cpu((uint32_t *)(nic_state->mem + addr));
+    } else {
+        return 0xffffffff;
+    }
+}
+
+static void 
+ne2k_dma_update(struct vm_device *dev, int len)
+{              
+    struct ne2k_context *nic_state = (struct ne2k_context *)dev->private_data;
+       
+    nic_state->regs.rsar += len;
+    // wrap
+    if (nic_state->regs.rsar == nic_state->regs.pgstop)
+        nic_state->regs.rsar = nic_state->regs.pgstart;
+
+    if (nic_state->regs.rbcr <= len) {
+        nic_state->regs.rbcr = 0;
+        nic_state->regs.isr |= ENISR_RDC;
+        ne2k_update_irq(dev);
+    } else {
+        nic_state->regs.rbcr -= len;
+    }
+}
+
+
+//for data port read/write
+static int ne2k_data_read(ushort_t port,
+                       void * dst,
+                       uint_t length,
+                       struct vm_device *dev)
+{
+       uint32_t val;
+       struct ne2k_context *nic_state = (struct ne2k_context *)dev->private_data;
+
+       // current dma address
+       uint32_t addr = nic_state->regs.rsar;
+
+       switch(length){
+               case 1:
+                       val = ne2k_mem_readb(nic_state, addr);
+                       break;
+               case 2:
+                       val = ne2k_mem_readw(nic_state, addr);
+                       break;
+               case 4:
+                       val = ne2k_mem_readl(nic_state, addr);
+                       break;
+               default:
+                       PrintError("ne2k_data_read error: invalid length %d\n", length);
+                       val = 0x0;
+       }
+
+       ne2k_dma_update(dev, length);
+
+       memcpy(dst, &val, length);
+
+       PrintDebug("ne2k_read: port:0x%x (%u bytes): 0x%x", port & 0x1f,length, val);
+
+       #if TEST_PERFORMANCE
+       if ((++exit_num) % 50 == 0)
+       PrintError("Ne2k-Ne2k: Total Exit: %d, INT: %d\n", (int)exit_num, int_num);
+       #endif
+
+       return length;
+}
+
+static int ne2k_data_write(ushort_t port,
+                                                       void * src,
+                                                       uint_t length,
+                                                       struct vm_device *dev)
+{
+       uint32_t val;
+       struct ne2k_context *nic_state = (struct ne2k_context *)dev->private_data;
+
+       if (nic_state->regs.rbcr == 0)
+               return length;
+
+       memcpy(&val, src, length);
+
+       uint32_t addr = nic_state->regs.rsar;
+       
+       switch (length){
+               case 1:
+                       ne2k_mem_writeb(nic_state, addr, val);
+                       break;
+               case 2:
+                       ne2k_mem_writew(nic_state, addr, val);
+                       break;
+               case 4:
+                       ne2k_mem_writel(nic_state, addr, val);
+                       break;
+               default:
+                       PrintError("nic_data_write error: invalid length %d\n", length);
+               }
+       
+       ne2k_dma_update(dev, length);
+
+       PrintDebug("ne2k_write: port:0x%x (%u bytes): 0x%x\n", port & 0x1f,length, val);
+
+       #if TEST_PERFORMANCE
+       if ((++exit_num) % 50 == 0)
+               PrintError("Ne2k-Ne2k: Total Exit: %d, INT: %d\n", (int)exit_num, int_num);
+       #endif
+                       
+       return length;
+}
+
+static int ne2k_reset_device(struct vm_device * dev)
+{
+  
+  PrintDebug("vnic: reset device\n");
+
+  init_ne2k_context(dev);
 
   return 0;
 }
 
 
-static int vnic_ioport_write(ushort_t port,
-                            void * src,
-                            uint_t length,
-                            struct vm_device * dev) {
-    uchar_t  page = 0;
-    struct nic_context *nic_state = (struct nic_context* )dev->private_data;
-    uchar_t val = 0;
+//for 0xc11f port
+static int ne2k_reset_port_read(ushort_t port,
+                                                       void * dst,
+                                                       uint_t length,
+                                                      struct vm_device *dev)
+{
+       uint32_t val = 0x0;
+
+       memcpy(dst, &val, length);
+
+       PrintDebug("ne2k_read: port:0x%x (%u bytes): 0x%x\n", port,length, val);
+
+       ne2k_reset_device(dev);
+
+       #if TEST_PERFORMANCE
+       if ((++exit_num) % 50 == 0)
+               PrintError("Ne2k-Ne2k: Total Exit: %d, INT: %d\n", (int)exit_num, int_num);
+       #endif
+
+       return length;
+}
+
+static int ne2k_reset_port_write(ushort_t port,
+                                                       void * src,
+                                                       uint_t length,
+                                                       struct vm_device *dev)
+{
+       uint32_t val;
+
+       memcpy(&val, src, length);
+
+       PrintDebug("ne2k_write: port:0x%x (%u bytes): 0x%x\n", port,length, val);
+
+       #if TEST_PERFORMANCE
+       if ((++exit_num) % 50 == 0)
+               PrintError("Ne2k-Ne2k: Total Exit: %d, INT: %d\n", (int)exit_num, int_num);
+       #endif
+                       
+       return length;
+}
+
+static int ne2k_ioport_write(ushort_t port,
+                       void * src,
+                       uint_t length,
+                       struct vm_device *dev)
+{
+    uchar_t  page;
+    struct ne2k_context *nic_state = (struct ne2k_context* )dev->private_data;
+    uchar_t val;
     int index;
        
     if (length == 1) {
-       memcpy(&val, src, 1);
+         memcpy(&val, src, 1);
     } else {
-       PrintDebug("vnic_write error: length %d\n", length);  
-       return length;
+         PrintError("ne2k_write error: length %d\n", length);  
+         return length;
     }
+
+    PrintDebug("ne2k_write: port:0x%x  val: 0x%x\n", port, (int)val);
        
     port &= 0x1f;
-       
-    PrintDebug("vnic_write: port:0x%x (%u bytes): 0x%x\n", port, length, (int)val);
-       
+
+    if (port == 0x10)
+               return ne2k_data_write(port, src, length, dev);
+
+    if (port == 0x1f)
+               return ne2k_reset_port_write(port, src, length, dev);
+               
     if (port == EN0_COMMAND) {
         nic_state->regs.cmd = val;
-       
         if (!(val & NE2K_STOP)) {
             nic_state->regs.isr &= ~ENISR_RESET; 
-
             if ((val & (NE2K_DMAREAD | NE2K_DMAWRITE)) &&
-               nic_state->regs.rbcr == 0) {
+                       nic_state->regs.rbcr == 0) {
                 nic_state->regs.isr |= ENISR_RDC;
-                vnic_update_irq(dev);
+                ne2k_update_irq(dev);
             }
-
-
             if (val & NE2K_TRANSMIT) {
                 index = (nic_state->regs.tpsr << 8);
-
-                if (index >= NE2K_PMEM_END) {
+                if (index >= NE2K_PMEM_END)
                     index -= NE2K_PMEM_SIZE;
-               }
-
                 if (index + nic_state->regs.tbcr <= NE2K_PMEM_END) {
-                    vnic_send_packet(dev, nic_state->mem + index, nic_state->regs.tbcr);
+                    ne2k_send_packet(dev, nic_state->mem + index, nic_state->regs.tbcr);
                 }
-
                 nic_state->regs.tsr = ENTSR_PTX;
                 nic_state->regs.isr |= ENISR_TX;
                 nic_state->regs.cmd &= ~NE2K_TRANSMIT;
-
-                vnic_update_irq(dev);
+                ne2k_update_irq(dev);
             }
         }
-
     } else {
         page = nic_state->regs.cmd >> 6;
-
-        if (page == 0){
-
-           switch(port) {
-               case EN0_STARTPG:
-                   nic_state->regs.pgstart = val;
-                   break;
-               case EN0_STOPPG:
-                   nic_state->regs.pgstop = val;
-                   break;
-               case EN0_BOUNDARY:
-                   nic_state->regs.boundary = val;
-                   break;
-               case EN0_TPSR:
-                   nic_state->regs.tpsr = val;
-                   break;
-               case EN0_TCNTLO:
-                   nic_state->regs.tbcr = (nic_state->regs.tbcr & 0xff00) | val;
-                   break;
-               case EN0_TCNTHI:
-                   nic_state->regs.tbcr = (nic_state->regs.tbcr & 0x00ff) | (val << 8);
-                   break;
-               case EN0_ISR:
-                   nic_state->regs.isr &= ~(val & 0x7f);
-                   vnic_update_irq(dev);
-                   break;
-               case EN0_RSARLO:
-                   nic_state->regs.rsar = (nic_state->regs.rsar & 0xff00) | val;
-                   break;
-               case EN0_RSARHI:
-                   nic_state->regs.rsar = (nic_state->regs.rsar & 0x00ff) | (val << 8);
-                   break;
-               case EN0_RCNTLO:
-                   nic_state->regs.rbcr = (nic_state->regs.rbcr & 0xff00) | val;
-                   break;
-               case EN0_RCNTHI:
-                   nic_state->regs.rbcr = (nic_state->regs.rbcr & 0x00ff) | (val << 8);
-                   break;
-               case EN0_RXCR:
-                   nic_state->regs.rcr = val;
-                   break;
-               case EN0_TXCR:
-                   nic_state->regs.tcr = val;
-               case EN0_DCFG:
-                   nic_state->regs.dcr = val;
-                   break;      
-               case EN0_IMR:
-                   nic_state->regs.imr = val;
-                   vnic_update_irq(dev);
-                   break;
-               default:
-                   PrintDebug("vnic_write error: invalid port:0x%x\n", port);
-                   break;
-           }
-
-       } else if (page == 1) {
-
-           switch(port) {
-               case EN1_PHYS ... EN1_PHYS + 5:
-                   nic_state->regs.phys[port - EN1_PHYS] = val;
-                   break;
-               case EN1_CURPAG:
-                   nic_state->regs.curpag = val;
-                   break;
-               case EN1_MULT ... EN1_MULT + 7:
-                   nic_state->regs.mult[port - EN1_MULT] = val;
-                   break;
-               default:
-                   PrintDebug("vnic_write error: invalid port:0x%x\n", port);
-                   break;
-           }
-
-       } else if (page == 2) {
-
-           switch(port) {
-               case EN2_LDMA0:
-                   nic_state->regs.clda = (nic_state->regs.clda & 0xff00) | val;
-                   break;
-               case EN2_LDMA1:
-                   nic_state->regs.clda = (nic_state->regs.clda & 0x00ff) | (val << 8);
-                   break;
-               case EN2_RNPR:
-                   nic_state->regs.rnpp = val;
-                   break;
-               case EN2_LNRP:
-                   nic_state->regs.lnpp = val;
-                   break;
-               case EN2_ACNT0:
-                   nic_state->regs.addcnt = (nic_state->regs.addcnt & 0xff00) | val;
-                   break;
-               case EN2_ACNT1: 
-                   nic_state->regs.addcnt = (nic_state->regs.addcnt & 0x00ff) | (val << 8);
-                   break;
-               default:
-                   PrintDebug("vnic_write error: invalid port:0x%x\n", port);
-                   break;
-           }
-       }
+        if(page == 0){
+               switch(port) {
+                       case EN0_STARTPG:
+                           nic_state->regs.pgstart = val;
+                           break;
+                       case EN0_STOPPG:
+                           nic_state->regs.pgstop = val;
+                           break;
+                       case EN0_BOUNDARY:
+                           nic_state->regs.boundary = val;
+                           break;
+                        case EN0_TPSR:
+                           nic_state->regs.tpsr = val;
+                           break;
+                        case EN0_TCNTLO:
+                           nic_state->regs.tbcr = (nic_state->regs.tbcr & 0xff00) | val;
+                           break;
+                       case EN0_TCNTHI:
+                           nic_state->regs.tbcr = (nic_state->regs.tbcr & 0x00ff) | (val << 8);
+                           break;
+                        case EN0_ISR:
+                           nic_state->regs.isr &= ~(val & 0x7f);
+                           ne2k_update_irq(dev);
+                           break;
+                        case EN0_RSARLO:
+                           nic_state->regs.rsar = (nic_state->regs.rsar & 0xff00) | val;
+                           break;
+                       case EN0_RSARHI:
+                           nic_state->regs.rsar = (nic_state->regs.rsar & 0x00ff) | (val << 8);
+                           break;
+                        case EN0_RCNTLO:
+                           nic_state->regs.rbcr = (nic_state->regs.rbcr & 0xff00) | val;
+                           break;
+                       case EN0_RCNTHI:
+                           nic_state->regs.rbcr = (nic_state->regs.rbcr & 0x00ff) | (val << 8);
+                           break;
+                       case EN0_RXCR:
+                           nic_state->regs.rcr = val;
+                           break;
+                        case EN0_TXCR:
+                            nic_state->regs.tcr = val;
+                       case EN0_DCFG:
+                           nic_state->regs.dcr = val;
+                           break;      
+                       case EN0_IMR:
+                           nic_state->regs.imr = val;
+                            //PrintError("ne2k_write error: write IMR:0x%x\n", (int)val);
+                           ne2k_update_irq(dev);
+                           break;
+                        default:
+                            PrintError("ne2k_write error: invalid port:0x%x\n", port);
+                            break;
+                       }
+               }
+        if(page == 1){
+               switch(port) {
+                       case EN1_PHYS ... EN1_PHYS + 5:
+                           nic_state->regs.phys[port - EN1_PHYS] = val;
+                           break;
+                       case EN1_CURPAG:
+                           nic_state->regs.curpag = val;
+                           break;
+                       case EN1_MULT ... EN1_MULT + 7:
+                           // PrintError("ne2k_write error: write EN_MULT:0x%x\n", (int)val);
+                           nic_state->regs.mult[port - EN1_MULT] = val;
+                           break;
+                        default:
+                            PrintError("ne2k_write error: invalid port:0x%x\n", port);
+                            break;
+                       }
+               }
+       if(page == 2){
+               switch(port) {
+                        case EN2_LDMA0:
+                           nic_state->regs.clda = (nic_state->regs.clda & 0xff00) | val;
+                           break;
+                        case EN2_LDMA1:
+                           nic_state->regs.clda = (nic_state->regs.clda & 0x00ff) | (val << 8);
+                           break;
+                        case EN2_RNPR:
+                           nic_state->regs.rnpp = val;
+                           break;
+                        case EN2_LNRP:
+                           nic_state->regs.lnpp = val;
+                           break;
+                        case EN2_ACNT0:
+                           nic_state->regs.addcnt = (nic_state->regs.addcnt & 0xff00) | val;
+                           break;
+                        case EN2_ACNT1: 
+                           nic_state->regs.addcnt = (nic_state->regs.addcnt & 0x00ff) | (val << 8);
+                           break;
+                        default:
+                           PrintError("ne2k_write error: invalid port:0x%x\n", port);
+                           break;
+                       }
+               }
     }
 
-    //dump_state(dev);
-       
+    #if TEST_PERFORMANCE
+    if ((++exit_num) % 50 == 0)
+       PrintError("Ne2k-Ne2k: Total Exit: %d, INT: %d\n", (int)exit_num, int_num);
+    #endif
+
     return length;
        
 }
 
-static int vnic_ioport_read(ushort_t port, void * dst, uint_t length, struct vm_device *dev) {
-    uchar_t page = 0;
-    int val = 0;
+static int ne2k_ioport_read(ushort_t port,
+                       void * dst,
+                       uint_t length,
+                       struct vm_device *dev)
+{
+    uchar_t page, ret, offset;
 
-    struct nic_context *nic_state = (struct nic_context* )dev->private_data;
+    struct ne2k_context *nic_state = (struct ne2k_context* )dev->private_data;
 
     if (length > 1) {
-       PrintDebug("vnic_read error: length %d\n", length);
-       valurn length;
+          PrintError("ne2k_read error: length %d\n", length);
+          return length;
     }
 
+    offset = port;
     port &= 0x1f;
 
+    if (port == 0x10)
+               return ne2k_data_read(port, dst, length, dev);
+
+    if (port == 0x1f)
+               return ne2k_reset_port_read(port, dst, length, dev);
+
     if (port == EN0_COMMAND) {
-        val = nic_state->regs.cmd;
+        ret = nic_state->regs.cmd;
     } else {
         page = nic_state->regs.cmd >> 6;
-
-        if (page == 0) {
-
-            switch (port) {            
-               case EN0_CLDALO:
-                   val = nic_state->regs.clda & 0x00ff;
+        if (page == 0){
+            switch(port) {             
+                case EN0_CLDALO:
+                   ret = nic_state->regs.clda & 0x00ff;
                    break;
                case EN0_CLDAHI:
-                   val = (nic_state->regs.clda & 0xff00) >> 8;
+                   ret = (nic_state->regs.clda & 0xff00) >> 8;
                    break;
                case EN0_BOUNDARY:
-                   val = nic_state->regs.boundary;
+                   ret = nic_state->regs.boundary;
                    break;
-               case EN0_TSR:
-                   val = nic_state->regs.tsr;
+                case EN0_TSR:
+                   ret = nic_state->regs.tsr;
                    break;
-               case EN0_NCR:
-                   val = nic_state->regs.ncr;
+                case EN0_NCR:
+                   ret = nic_state->regs.ncr;
                    break;
                case EN0_FIFO:
-                   val = nic_state->regs.fifo;
+                   ret = nic_state->regs.fifo;
                    break;
-               case EN0_ISR:
-                   val = nic_state->regs.isr;
-                   vnic_update_irq(dev);
+                case EN0_ISR:
+                   ret = nic_state->regs.isr;
+                   ne2k_update_irq(dev);
                    break;
-               case EN0_CRDALO:
-                   val = nic_state->regs.crda & 0x00ff;
+                case EN0_CRDALO:
+                   ret = nic_state->regs.crda & 0x00ff;
                    break;
                case EN0_CRDAHI:
-                   val = (nic_state->regs.crda & 0xff00) >> 8;
+                   ret = (nic_state->regs.crda & 0xff00) >> 8;
                    break;
                case EN0_RSR:
-                   val = nic_state->regs.rsr;
+                   ret = nic_state->regs.rsr;
                    break;
-               case EN0_COUNTER0:
-                   val = nic_state->regs.cntr & 0x000000ff;
-                   break;
+                case EN0_COUNTER0:
+                    ret = nic_state->regs.cntr & 0x000000ff;
+                    break;
                case EN0_COUNTER1:
-                   val = (nic_state->regs.cntr & 0x0000ff00) >> 8;
-                   break;      
+                   ret = (nic_state->regs.cntr & 0x0000ff00) >> 8;
+                    break;     
                case EN0_COUNTER2:
-                   val = (nic_state->regs.cntr & 0x00ff0000) >> 16;
-                   break;
-               default:
-                   PrintDebug("vnic_read error: invalid port:0x%x\n", port);
-                   val = 0x00;
-                   break;
-           }
-
-        } else if (page == 1) {
-
-           switch(port) {
+                   ret = (nic_state->regs.cntr & 0x00ff0000) >> 16;
+                    break;
+                default:
+                    PrintError("ne2k_read error: invalid port:0x%x\n", port);
+                    ret = 0x00;
+                    break;
+           }
+        }
+        if (page == 1){
+           switch(port) {
                case EN1_PHYS ... EN1_PHYS + 5:
-                   val = nic_state->regs.phys[port - EN1_PHYS];
+                   ret = nic_state->regs.phys[port - EN1_PHYS];
                    break;
                case EN1_CURPAG:
-                   val = nic_state->regs.curpag;
+                   ret = nic_state->regs.curpag;
                    break;
                case EN1_MULT ... EN1_MULT + 7:
-                   val = nic_state->regs.mult[port - EN1_MULT];
+                   ret = nic_state->regs.mult[port - EN1_MULT];
                    break;
-               default:
-                   PrintDebug("vnic_read error: invalid port:0x%x\n", port);
-                   val = 0x00;
-                   break;
-           }
-
-       } else if (page == 2) {
-
-           switch(port) {
-               case EN2_STARTPG:
-                   val = nic_state->regs.pgstart;
+                default:
+                    PrintError("ne2k_read error: invalid port:0x%x\n", port);
+                    ret = 0x00;
+                    break;
+           }
+        }
+        if (page == 2){
+           switch(port) {
+                case EN2_STARTPG:
+                   ret = nic_state->regs.pgstart;
                    break;
-               case EN2_STOPPG:
-                   val = nic_state->regs.pgstop;
+                case EN2_STOPPG:
+                   ret = nic_state->regs.pgstop;
                    break;
-               case EN2_RNPR:
-                   val = nic_state->regs.rnpp;
+                case EN2_RNPR:
+                   ret = nic_state->regs.rnpp;
                    break;
-               case EN2_LNRP:
-                   val = nic_state->regs.lnpp;
+                case EN2_LNRP:
+                   ret = nic_state->regs.lnpp;
                    break;
-               case EN2_TPSR:
-                   val = nic_state->regs.tpsr;
+                case EN2_TPSR:
+                   ret = nic_state->regs.tpsr;
                    break;
-               case EN2_ACNT0:
-                   val = nic_state->regs.addcnt & 0x00ff;
+                case EN2_ACNT0:
+                   ret = nic_state->regs.addcnt & 0x00ff;
                    break;
-               case EN2_ACNT1: 
-                   val = (nic_state->regs.addcnt & 0xff00) >> 8;
+                case EN2_ACNT1: 
+                   ret = (nic_state->regs.addcnt & 0xff00) >> 8;
                    break;
-               case EN2_RCR:
-                   val = nic_state->regs.rcr;
+                case EN2_RCR:
+                   ret = nic_state->regs.rcr;
                    break;
-               case EN2_TCR:
-                   val = nic_state->regs.tcr;
+                case EN2_TCR:
+                   ret = nic_state->regs.tcr;
                    break;
-               case EN2_DCR:
-                   val = nic_state->regs.dcr;
+                case EN2_DCR:
+                   ret = nic_state->regs.dcr;
                    break;
-               case EN2_IMR:
-                   val = nic_state->regs.imr;
+                case EN2_IMR:
+                   ret = nic_state->regs.imr;
                    break;
-               default:
-                   PrintDebug("vnic_read error: invalid port:0x%x\n", port);
-                   val = 0x00;
+                default:
+                   PrintError("ne2k_read error: invalid port:0x%x\n", port);
+                   ret = 0x00;
                    break;
-           }
-       }
+           }
+        }
     }
 
-    memcpy(dst, &val, 1);
+    memcpy(dst, &ret, 1);
 
-    PrintDebug("vnic_read: port:0x%x (%u bytes): 0x%x\n", port,length, (uint32_t)val);
+    PrintDebug("ne2k_read: port:0x%x  val: 0x%x\n", offset, (int)ret);
 
-    //dump_state(dev);
+    #if TEST_PERFORMANCE
+    if ((++exit_num) % 50 == 0)
+       PrintError("Ne2k-Ne2k: Total Exit: %d, INT: %d\n", (int)exit_num, int_num);
+    #endif
 
     return length;
 
 }
 
 
-
-
-static void vnic_dma_update(struct vm_device * dev, int len) {         
-    struct nic_context *nic_state = (struct nic_context *)dev->private_data;
-       
-    nic_state->regs.rsar += len;
-    // wrap
-
-    if (nic_state->regs.rsar == nic_state->regs.pgstop) {
-        nic_state->regs.rsar = nic_state->regs.pgstart;
-    }
-
-    if (nic_state->regs.rbcr <= len) {
-        nic_state->regs.rbcr = 0;
-        nic_state->regs.isr |= ENISR_RDC;
-
-        vnic_update_irq(dev);
-    } else {
-        nic_state->regs.rbcr -= len;
-    }
-}
-
-
-//for data port read/write
-static int vnic_data_read(ushort_t port,
-                         void * dst,
-                         uint_t length,
-                         struct vm_device * dev) {
-    uint32_t val = 0;
-    struct nic_context *nic_state = (struct nic_context *)dev->private_data;
-
-    // current dma address
-    uint32_t addr = nic_state->regs.rsar;
-
-    switch (length) {
-       case 1:
-           val = vnic_mem_readb(nic_state, addr);
-           break;
-       case 2:
-           val = vnic_mem_readw(nic_state, addr);
-           break;
-       case 4:
-           val = vnic_mem_readl(nic_state, addr);
-           break;
-       default:
-           PrintDebug("vnic_data_read error: invalid length %d\n", length);
-           val = 0x0;
-    }
-
-    vnic_dma_update(dev, length);
-
-    memcpy(dst, &val, length);
-
-    PrintDebug("vnic_read: port:0x%x (%u bytes): 0x%x", port & 0x1f, length, val);
-
-    return length;
+static int ne2k_start_device(struct vm_device *dev)
+{
+  PrintDebug("vnic: start device\n");
+  
+  return 0;
 }
 
-static int vnic_data_write(ushort_t port,
-                          void * src,
-                          uint_t length,
-                          struct vm_device * dev) {
-    uint32_t val = 0;
-    struct nic_context * nic_state = (struct nic_context *)dev->private_data;
-
-    uint32_t addr = nic_state->regs.rsar;
-
-    if (nic_state->regs.rbcr == 0) {
-       return length;
-    }
-
-    memcpy(&val, src, length);
-
-    //determine the starting address of reading/writing
-    //addr= ??
-       
-    switch (length) {
-       case 1:
-           vnic_mem_writeb(nic_state, addr, val);
-           break;
-       case 2:
-           vnic_mem_writew(nic_state, addr, val);
-           break;
-       case 4:
-           vnic_mem_writel(nic_state, addr, val);
-           break;
-       default:
-           PrintDebug("nic_data_write error: invalid length %d\n", length);
-    }
-       
-    vnic_dma_update(dev, length);
-
-    PrintDebug("vnic_write: port:0x%x (%u bytes): 0x%x\n", port & 0x1f,length, val);
-                       
-    return length;
-}
 
-static int vnic_reset_device(struct vm_device * dev) {
+static int ne2k_stop_device(struct vm_device *dev)
+{
+  PrintDebug("vnic: stop device\n");
   
-    PrintDebug("vnic: reset device\n");
-
-    init_vnic_context(dev);
-
-    return 0;
+  return 0;
 }
 
+static void  init_global_setting()
+{      
+  int i;
+  
+  V3_Register_pkt_event(&netif_input);
+  
+  for (i = 0; i < NUM_NE2K; i++)
+       ne2ks[i] = NULL;
 
-//for 0xc11f port
-static int vnic_reset_port_read(ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
-    uint32_t val = 0;
-
-    PrintDebug("vnic_read: port:0x%x (%u bytes): 0x%x\n", port,length, val);
-    memcpy(dst, &val, length);
-
-    vnic_reset_device(dev);
-
-    return length;
 }
 
-static int vnic_reset_port_write(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
-    uint32_t val = 0;
+static int ne2k_hook_iospace(struct vm_device *vmdev, addr_t base_addr, int size, int type, void *data)
+{
+  int i;
 
-    PrintDebug("vnic_write: port:0x%x (%u bytes): 0x%x\n", port,length, val);
-    memcpy(&val, src, length);
-                       
-    return length;
-}
+  if (base_addr <= 0)
+       return -1;
 
+  PrintDebug("In NIC%d: Hook IO space starting from %x\n", nic_no, (int) base_addr);
 
-static int vnic_start_device(struct vm_device * dev) {
-    PrintDebug("vnic: start device\n");  
-    return 0;
-}
+  for (i = 0; i < 16; i++){    
+       v3_dev_hook_io(vmdev, base_addr + i, &ne2k_ioport_read, &ne2k_ioport_write);
+  }
+  v3_dev_hook_io(vmdev, base_addr + NIC_DATA_PORT, &ne2k_data_read, &ne2k_data_write);
+  v3_dev_hook_io(vmdev, base_addr + NIC_RESET_PORT, &ne2k_reset_port_read, &ne2k_reset_port_write);
 
+  return 0;
 
-static int vnic_stop_device(struct vm_device * dev) {
-    PrintDebug("vnic: stop device\n");
-    return 0;
 }
 
-static void  init_phy_network() {      
-    V3_REGISTER_PKT_DELIVERY(&netif_input);
-}
+static int ne2k_init_device(struct vm_device * vmdev) 
+{
+  struct vm_device *pci = NULL;
+  struct pci_device *pdev = NULL;
+  struct ne2k_context *nic_state = (struct ne2k_context *)vmdev->private_data;
 
-static int vnic_init_device(struct vm_device * dev) {
-  int i;
+  PrintDebug("ne2k%d: init_device\n",  nic_no);
 
-  PrintDebug("vnic: init_device\n");
+  if (nic_no == 0) // only initiate once
+       init_global_setting();
 
-  init_phy_network();
-  init_vnic_context(dev);
+  init_ne2k_context(vmdev);
 
-  current_vnic = dev;  
+  pci = nic_state->pci;
 
-  for (i = 0; i < 16; i++) {   
-      v3_dev_hook_io(dev, NIC_BASE_ADDR + i, &vnic_ioport_read, &vnic_ioport_write);
+  if (pci != NULL) {
+       PrintDebug("Ne2k: attach ne2k to the pci %p\n", pci);
+       pdev = pci_ne2k_init(vmdev, pci, 0, -1, 0,  &ne2k_ioport_read, &ne2k_ioport_write);
+       if (pdev == NULL)
+               PrintError("Ne2k: initiate failure, failure to attach ne2k to the bus %p\n", pci);
+  } else {
+       PrintError("Ne2k: Failure to initiate Ne2k , no pci\n");
+       ne2k_hook_iospace(vmdev, NE2K_DEF_BASE_ADDR, 100, 0, NULL);
   }
 
-  v3_dev_hook_io(dev, NIC_BASE_ADDR + NIC_DATA_PORT, &vnic_data_read, &vnic_data_write);
-  v3_dev_hook_io(dev, NIC_BASE_ADDR + NIC_RESET_PORT, &vnic_reset_port_read, &vnic_reset_port_write);
+  nic_state->pci_dev = pdev;  
+  ne2ks[nic_no ++] = vmdev;
+
+  #ifdef DEBUG_NE2K
+  dump_state(vmdev);
+  #endif
 
   return 0;
 }
 
 
 
-static int vnic_deinit_device(struct vm_device * dev) {
-    int i;
+static int ne2k_deinit_device(struct vm_device *vmdev)
+{
+  int i;
   
-    for (i = 0; i < 16; i++){          
-       v3_dev_unhook_io(dev, NIC_BASE_ADDR + i);
-    }
-
-    v3_dev_unhook_io(dev, NIC_BASE_ADDR + NIC_DATA_PORT);
-    v3_dev_unhook_io(dev, NIC_BASE_ADDR + NIC_RESET_PORT);
+  for (i = 0; i<16; i++){              
+       v3_dev_unhook_io(vmdev, NE2K_DEF_BASE_ADDR + i);
+  }
 
-    //vnic_reset_device(dev);
+  v3_dev_unhook_io(vmdev, NE2K_DEF_BASE_ADDR + NIC_DATA_PORT);
+  v3_dev_unhook_io(vmdev, NE2K_DEF_BASE_ADDR + NIC_RESET_PORT);
   
-    return 0;
+  return 0;
 }
 
 
 static struct vm_device_ops dev_ops = { 
-    .init = vnic_init_device, 
-    .deinit = vnic_deinit_device,
-    .reset = vnic_reset_device,
-    .start = vnic_start_device,
-    .stop = vnic_stop_device,
+  .init = ne2k_init_device, 
+  .deinit = ne2k_deinit_device,
+  .reset = ne2k_reset_device,
+  .start = ne2k_start_device,
+  .stop = ne2k_stop_device,
 };
 
 
-struct vm_device * v3_create_vnic() {
-    struct nic_context * nic_state = V3_Malloc(sizeof(struct nic_context));
+struct vm_device *v3_create_ne2k(struct vm_device *pci) 
+{
+  struct ne2k_context * nic_state = V3_Malloc(sizeof(struct ne2k_context));
+
+  memset(nic_state, 0, sizeof(struct ne2k_context));
 
-    //memset(nic_state, 0, sizeof(struct nic_context));
+  PrintDebug("NE2K internal at %p\n", (void *)nic_state);
 
-    //PrintDebug("VNIC internal at %x\n",(int)nic_state);
+  nic_state->pci = pci;
 
-    struct vm_device *device = v3_create_device("VNIC", &dev_ops, nic_state);
+  struct vm_device *device = v3_create_device("NE2K", &dev_ops, nic_state);
 
-    return device;
+  return device;
 }