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.


Updated NE2000 and RTL8139 to conform to interface changes
[palacios.git] / palacios / src / devices / ne2k.c
index e6c12a9..bc51c78 100644 (file)
  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
  */
  
-/*
-* Virtual NE2K Network Card 
-*/
-
-
-
-
-#include <devices/vnic.h>
+#include <devices/pci.h>
 #include <palacios/vmm.h>
-#include <palacios/vmm_types.h>
 #include <palacios/vmm_io.h>
 #include <palacios/vmm_debug.h>
-
-#define DEBUG_NIC
-
-#ifndef DEBUG_NIC
-#undef PrintDebug()
+#include <palacios/vmm_string.h>
+#include <palacios/vmm_dev_mgr.h>
+#include <palacios/vmm_intr.h>
+#include <palacios/vmm_ethernet.h>
+#include <palacios/vm_guest.h>
+#include <palacios/vmm_sprintf.h>
+
+#ifndef V3_CONFIG_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];
-};
-
-struct nic_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];        
+#define NE2K_DEFAULT_IRQ        11
+
+// What the hell is this crap?
+#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 NIC_REG_BASE_PORT       0xc100         /* Command register (for all pages) */
+
+#define NE2K_CMD_OFFSET        0x00
+#define NE2K_DATA_OFFSET       0x10
+#define NE2K_RESET_OFFSET      0x1f
+
+/* 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 */
+
+/* Page 1 registers */
+#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 */
+
+/* Page 3 registers */
+#define EN3_CONFIG0            0x03
+#define EN3_CONFIG1            0x04
+#define EN3_CONFIG2            0x05
+#define EN3_CONFIG3            0x06
+
+
+struct cmd_reg {
+    union {
+       uint8_t val;
+       struct {
+           uint8_t stop        : 1;
+           uint8_t start       : 1;
+           uint8_t tx_pkt      : 1;
+           uint8_t rem_dma_cmd : 3;    /* 0=Not allowed, 1=Read, 2=Write, 3=Send Pkt, 4=Abort/Complete DMA */
+           uint8_t pg_sel      : 2;
+       } __attribute__((packed));
+    } __attribute__((packed));
+} __attribute__((packed));
+
+
+struct intr_status_reg {
+    union {
+       uint8_t val;
+       struct {
+           uint8_t pkt_rx          : 1;
+           uint8_t pkt_tx          : 1;
+           uint8_t rx_err          : 1;
+           uint8_t tx_err          : 1;
+           uint8_t overwrite_warn  : 1;
+           uint8_t cnt_overflow    : 1;
+           uint8_t rem_dma_done    : 1;
+           uint8_t reset_status    : 1;
+       } __attribute__((packed));
+    } __attribute__((packed));
+} __attribute__((packed));
+
+
+struct intr_mask_reg {
+    union {
+       uint8_t val;
+       struct {
+           uint8_t pkt_rx          : 1;
+           uint8_t pkt_tx          : 1;
+           uint8_t rx_err          : 1;
+           uint8_t tx_err          : 1;
+           uint8_t overwrite_warn  : 1;
+           uint8_t cnt_overflow    : 1;
+           uint8_t rem_dma_done    : 1;
+           uint8_t rsvd            : 1;
+       } __attribute__((packed));
+    } __attribute__((packed));
+} __attribute__((packed));
+
+
+struct data_cfg_reg {
+    union {
+       uint8_t val;
+       struct {
+           uint8_t word_trans_sel   : 1;
+           uint8_t byte_order_sel   : 1;
+           uint8_t long_addr_sel    : 1;
+           uint8_t loopback_sel     : 1;
+           uint8_t auto_init_rem    : 1;
+           uint8_t fifo_thresh_sel  : 2;
+           uint8_t rsvd             : 1;
+       } __attribute__((packed));
+    } __attribute__((packed));
+} __attribute__((packed));
+
+
+struct tx_cfg_reg { 
+    union {
+       uint8_t val;
+       struct {
+           uint8_t inhibit_crc     : 1;
+           uint8_t enc_loop_ctrl   : 2;
+           uint8_t auto_tx_disable : 1;
+           uint8_t coll_offset_en  : 1;
+           uint8_t rsvd            : 3;
+       } __attribute__((packed));
+    } __attribute__((packed));
+} __attribute__((packed));
+
+struct tx_status_reg { 
+    union {
+       uint8_t val;
+       struct {
+           uint8_t pkt_tx_ok       : 1;
+           uint8_t rsvd            : 1;
+           uint8_t tx_collision    : 1;
+           uint8_t tx_aborted      : 1;
+           uint8_t carrier_lost    : 1;
+           uint8_t fifo_underrun   : 1;
+           uint8_t cd_heartbeat    : 1;
+           uint8_t oow_collision   : 1;
+       } __attribute__((packed));
+    } __attribute__((packed));
+} __attribute__((packed));
+
+struct rx_cfg_reg { 
+    union {
+       uint8_t val;
+       struct {
+           uint8_t save_pkt_errs    : 1;
+           uint8_t runt_pkt_ok      : 1;
+           uint8_t bcast_ok         : 1;
+           uint8_t mcast_ok         : 1;
+           uint8_t prom_phys_enable : 1;
+           uint8_t mon_mode         : 1;
+           uint8_t rsvd             : 2;
+       } __attribute__((packed));
+    } __attribute__((packed));
+} __attribute__((packed));
+
+
+struct rx_status_reg { 
+    union {
+       uint8_t val;
+       struct {
+           uint8_t pkt_rx_ok        : 1;
+           uint8_t crc_err          : 1;
+           uint8_t frame_align_err  : 1;
+           uint8_t fifo_overrun     : 1;
+           uint8_t missed_pkt       : 1;
+           uint8_t phy_match        : 1;   /* 0=Physical Addr Match, 1=MCAST/BCAST Addr Match */
+           uint8_t rx_disabled      : 1;
+           uint8_t deferring        : 1;
+       } __attribute__((packed));
+    } __attribute__((packed));
+} __attribute__((packed));
+
+
+struct ne2k_registers {
+    struct cmd_reg cmd;
+    struct intr_status_reg isr;
+    struct intr_mask_reg imr;
+    struct data_cfg_reg dcr;
+    struct tx_cfg_reg tcr;
+    struct tx_status_reg tsr;
+    struct rx_cfg_reg rcr;
+    struct rx_status_reg rsr;  
+
+    uint8_t      pgstart;      /* page start reg */
+    uint8_t      pgstop;       /* page stop reg */
+    uint8_t      boundary;     /* boundary ptr */
+    uint8_t      tpsr;         /* tx page start addr */
+    uint8_t      ncr;          /* number of collisions */
+    uint8_t      fifo;         /* FIFO... */
+
+    uint8_t      curpag;       /* current page */
+    uint8_t      rnpp;         /* rem next pkt ptr */
+    uint8_t      lnpp;         /* local next pkt ptr */
+
+    uint8_t      cntr0;        /* counter 0 (frame alignment errors) */
+    uint8_t      cntr1;        /* counter 1 (CRC Errors) */
+    uint8_t      cntr2;        /* counter 2 (missed pkt errors) */
+
+    union {                    /* current local DMA Addr */
+       uint16_t     clda;
+       struct {
+           uint8_t clda0;
+           uint8_t clda1;
+       } __attribute__((packed));
+    } __attribute__((packed));
+
+
+    union {                    /* current remote DMA addr */
+       uint16_t     crda;
+       struct {
+           uint8_t crda0;
+           uint8_t crda1;
+       } __attribute__((packed));
+    } __attribute__((packed));
+
+
+    union {                    /* Remote Start Addr Reg */
+       uint16_t     rsar;
+       struct {
+           uint8_t rsar0;
+           uint8_t rsar1;
+       } __attribute__((packed));
+    } __attribute__((packed));
+
+
+    union {                    /* TX Byte count Reg */
+       uint16_t     tbcr;
+       struct {
+           uint8_t tbcr0;
+           uint8_t tbcr1;
+       } __attribute__((packed));
+    } __attribute__((packed));
+
+    union {                    /* Remote Byte count Reg */
+       uint16_t     rbcr;
+       struct {
+           uint8_t rbcr0;
+           uint8_t rbcr1;
+       } __attribute__((packed));
+    } __attribute__((packed));
+
+    union {                    /* Address counter? */
+       uint16_t     addcnt;
+       struct {
+           uint8_t addcnt0;
+           uint8_t addcnt1;
+       } __attribute__((packed));
+    } __attribute__((packed));
 };
 
-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;     \
-       })
-
 
+struct ne2k_state {
+    struct v3_vm_info * vm;
+    struct pci_device * pci_dev;
+    struct vm_device * pci_bus;
+    struct vm_device * dev;
 
+    struct ne2k_registers context;
+    uint8_t mem[NE2K_MEM_SIZE];
 
-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);
+    uint8_t mcast_addr[8];
+    uint8_t mac[ETH_ALEN];
 
-    //    if ((addr < NE2K_PMEM_START) || (addr > NE2K_MEM_SIZE))
+    struct nic_statistics statistics;
 
-    switch (length) {
-       case 1: {
-           uchar_t val = *(uchar_t *)src;
-           
-       }
-       case 2:
-       case 4:
-    }
+    struct v3_dev_net_ops *net_ops;
+    void * backend_data;
+};
 
-}
+static int ne2k_update_irq(struct ne2k_state * nic_state) {
+    struct pci_device * pci_dev = nic_state->pci_dev;
 
+    if ((nic_state->context.isr.val & nic_state->context.imr.val) & 0x7f) {
+       if (pci_dev == NULL){
+           v3_raise_virq(&(nic_state->vm->cores[0]), NE2K_DEFAULT_IRQ);
+       } else {            
+           v3_pci_raise_irq(nic_state->pci_bus, 0, nic_state->pci_dev);
+       }
 
-static void vnic_mem_writeb(struct nic_context * nic_state, 
-                           uint32_t addr,
-                           uint32_t val) {
-    uchar_t tmp = (uchar_t) (val & 0x000000ff);
+       nic_state->statistics.rx_interrupts ++;
 
-    if ( (addr < 32) || 
-        ((addr >= NE2K_PMEM_START && addr < NE2K_MEM_SIZE) ) {
-        nic_state->mem[addr] = tmp;
+       PrintDebug("NE2000: Raise IRQ\n");
     }
 
-    PrintDebug("wmem addr: %x val: %x\n", addr, val);
+    return 0;
 }
 
-static void vnic_mem_writew(struct nic_context * nic_state, 
-                           uint32_t addr,
-                           uint32_t val) {
+static int tx_one_pkt(struct ne2k_state * nic_state, uchar_t *pkt, uint32_t length) {
+       
+#ifdef V3_CONFIG_DEBUG_NE2K
+    PrintDebug("NE2000: Send Packet:\n");
+    v3_hexdump(pkt, length, NULL, 0);
+#endif    
 
-    addr &= ~1; //XXX: check exact behaviour if not even
+    if(nic_state->net_ops->send(pkt, length, nic_state->backend_data) >= 0){
+       nic_state->statistics.tx_pkts ++;
+       nic_state->statistics.tx_bytes += length;
 
-    if ( (addr < 32) ||
-        ((addr >= NE2K_PMEM_START && addr) < NE2K_MEM_SIZE)) {
-        *(ushort_t *)(nic_state->mem + addr) = cpu2le16(val);
+       return 0;
     }
+       
+    nic_state->statistics.tx_dropped ++;
 
-    PrintDebug("wmem addr: %x val: %x\n", addr, val);
+    return -1;
 }
 
-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
+static int ne2k_rxbuf_full(struct ne2k_registers * regs) {
+    int empty;
+    int index;
+    int boundary;
 
-    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);
-}
+    index = regs->curpag << 8;
+    boundary = regs->boundary << 8;
 
-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];
+    if (index < boundary) {
+        empty = boundary - index;
     } else {
-        return 0xff;
+        empty = ((regs->pgstop - regs->pgstart) << 8) - (index - boundary);
     }
-}
-
-static ushort_t vnic_mem_readw(struct nic_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;
+    if (empty < (ETHERNET_PACKET_LEN + 4)) {
+        return 1;
     }
+
+    return 0;
 }
 
-static uint32_t vnic_mem_readl(struct nic_context * nic_state, uint32_t addr) {
-    PrintDebug("rmem addr: %x\n", addr);
+#define MIN_BUF_SIZE 60
 
-    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;
+// This needs to be completely redone...
+static int rx_one_pkt(struct ne2k_state * nic_state, const uchar_t * pkt,  uint32_t length) {
+    struct ne2k_registers * regs = (struct ne2k_registers *)&(nic_state->context);
+    uchar_t * p;
+    uint32_t total_len;
+    uint32_t next;
+    uint32_t len;
+    uint32_t index;
+    uint32_t empty;
+    uint32_t start;
+    uint32_t stop;
+
+    start = regs->pgstart << 8;
+    stop = regs->pgstop << 8;
+   
+    if (regs->cmd.stop) {
+       return -1;
     }
-}
 
+    if (ne2k_rxbuf_full(regs)) {
+       PrintError("Ne2k: received buffer overflow\n");
+       return -1;
+    }
 
+    //packet too small, expand it
+    if (length < MIN_BUF_SIZE) {
+        uchar_t buf[MIN_BUF_SIZE];
 
+        memcpy(buf, pkt, length);
+        memset(buf + length, 0, MIN_BUF_SIZE - length);
+        pkt = buf;
+        length = MIN_BUF_SIZE;
+    }
 
-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;
+    index = regs->curpag << 8;
 
-    PrintDebug("====VNIC: Dumping state Begin ==========\n");
-    PrintDebug("Registers:\n");
+    //header, 4 bytes
+    total_len = length + 4;
 
-    p = (uchar_t *)&nic_state->regs;
-    for (i = 0; i < sizeof(struct nic_regs); i++) {
-       PrintDebug("Regs[i] = 0x%2x\n", (int)p[i]);     
-    }
+    //address for next packet (4 bytes for CRC)
+    next = index + ((total_len + 4 + 255) & ~0xff);
 
-    PrintDebug("Memory:\n");   
-    
-    for (i = 0; i < 32; i++) {
-        PrintDebug("0x%02x ", nic_state->mem[i]);
+    if (next >= stop) {
+        next -= (stop - start);
     }
 
-    PrintDebug("\n");
-    PrintDebug("====VNIC: Dumping state End==========\n");
-}
+    p = nic_state->mem + index;
+    regs->rsr.val = 0;
+    regs->rsr.pkt_rx_ok = 1;
 
-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;
+    if (pkt[0] & 0x01) {
+        regs->rsr.phy_match = 1; /* TODO: Check this back */
+    }
 
-    int isr = ((nic_state->regs.isr & nic_state->regs.imr) & 0x7f);
+    p[0] = regs->rsr.val;
+    p[1] = next >> 8;
+    p[2] = total_len;
+    p[3] = total_len >> 8;
+    index += 4;
 
-    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);
-    }   
-}
+    while (length > 0) {
+       if (index <= stop) {
+           empty = stop - index;
+       } else {
+           empty = 0;
+       }
 
-static void init_vnic_context(struct vm_device * dev) {
-    struct nic_context *nic_state = (struct nic_context *)dev->private_data;
-    int i;
-    uchar_t mac[6] = {0x52, 0x54, 0x0, 0x12, 0x34, 0x56};
+       len = length;
 
-    nic_state->vm = dev->vm;
+       if (len > empty) {
+           len = empty;
+       }
 
-    nic_state->regs.isr = ENISR_RESET;
-    nic_state->regs.imr = 0x00;
-    nic_state->regs.cmd = 0x22;
+       memcpy(nic_state->mem + index, pkt, len);
+       pkt += len;
+       index += len;
 
-    for (i = 0; i < 6; i++) {
-       nic_state->regs.macaddr[i] = nic_state->mac[i] = mac[i];
-    }
+       if (index == stop) {
+           index = start;
+       }
 
-    for (i = 0; i < 8; i++) {
-       nic_state->regs.mult[i] = 0xff;
+       length -= len;
     }
 
-    for(i = 0; i < 32; i++) {
-        nic_state->mem[i] = 0xff;
-    }
+    regs->curpag = next >> 8;
 
-    memcpy(nic_state->mem, nic_state->mac, 6);
-    nic_state->mem[14] = 0x57;
-    nic_state->mem[15] = 0x57;
+    regs->isr.pkt_rx = 1;
+    ne2k_update_irq(nic_state);
 
-    dump_state(dev);
+    return 0;
 }
 
 
-static int vnic_send_packet(struct vm_device *dev, uchar_t *pkt, int length) {
-    int i;
+static int ne2k_rx(uint8_t * buf, uint32_t size, void * private_data){
+    struct ne2k_state * nic_state = (struct ne2k_state *)private_data;
   
-    PrintDebug("\nVNIC: Sending Packet\n");
-
-    for (i = 0; i < length; i++) {
-       PrintDebug("%x ",pkt[i]);
+#ifdef V3_CONFIG_DEBUG_NE2K
+    PrintDebug("\nNe2k: Packet Received:\n");
+    v3_hexdump(buf, size, NULL, 0);
+#endif    
+
+    if(!rx_one_pkt(nic_state, buf, size)){
+       nic_state->statistics.rx_pkts ++;
+       nic_state->statistics.rx_bytes += size;
+       
+       return 0;
     }
 
-    PrintDebug("\n");
+    nic_state->statistics.rx_dropped ++;
        
-    return V3_SEND_PKT(pkt, length);
+    return -1;
 }
 
 
-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);
-
-    static const uchar_t brocast_mac[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+static inline void mem_writeb(struct ne2k_state * nic_state, 
+                       uint32_t addr, 
+                       uint32_t val) {
+    uchar_t tmp = (uchar_t) (val & 0x000000ff);
 
-    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??
-        }
+    if ((addr < 32) || (addr >= NE2K_PMEM_START && addr < NE2K_MEM_SIZE)) {
+        nic_state->mem[addr] = tmp;
     }
-
-    return current_vnic;
 }
 
-static int vnic_rxbuf_full(struct vm_device * dev) {
-    int empty, index, boundary;
-    struct nic_context * nic_state = (struct nic_context *)dev->private_data;
-
-    index = nic_state->regs.curpag << 8;
-    boundary = nic_state->regs.boundary << 8;
-    if (index < boundary) {
-        empty = boundary - index;
-    } else {
-        empty = ((nic_state->regs.pgstop - nic_state->regs.pgstart) << 8) - (index - boundary);
-    }
+static inline void mem_writew(struct ne2k_state * nic_state, 
+                           uint32_t addr,
+                           uint32_t val) {
+    addr &= ~1;
 
-    if (empty < (MAX_ETH_FRAME_SIZE + 4)) {
-        return 1;
+    if ((addr < 32) || (addr >= NE2K_PMEM_START && addr < NE2K_MEM_SIZE)) {
+        *(uint16_t *)(nic_state->mem + addr) = val;
     }
-
-    return 0;
 }
 
-#define MIN_BUF_SIZE 60
+static inline void mem_writel(struct ne2k_state * nic_state,
+                           uint32_t addr,
+                           uint32_t val) {
+    addr &= ~1;
 
-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;
-    uchar_t buf[60];
-    uint32_t start = nregs->pgstart << 8;
-    uint32_t stop = nregs->pgstop << 8;
-        
-    //PrintDebug("VNIC: received packet, len=%d\n", length);
-   
-    if (nregs->cmd & NE2K_STOP) {
-       return;
+    if ((addr < 32) || (addr >= NE2K_PMEM_START && addr < NE2K_MEM_SIZE)) {
+        *(uint32_t *)(nic_state->mem + addr) = val;
     }
+}
 
-    if (vnic_rxbuf_full(dev)){
-       PrintDebug("VNIC: received buffer overflow\n");
-        return;
+static inline uint8_t  mem_readb(struct ne2k_state * nic_state, uint32_t addr) {
+       
+    if ((addr < 32) || (addr >= NE2K_PMEM_START && addr < NE2K_MEM_SIZE)) {
+        return nic_state->mem[addr];
+    } else {
+        return 0xff;
     }
+}
 
-    // if too small buffer, expand it
-    if (length < MIN_BUF_SIZE) {
-        memcpy(buf, pkt, length);
-        memset(buf + length, 0, MIN_BUF_SIZE - length);
+static inline uint16_t mem_readw(struct ne2k_state * nic_state, uint32_t addr) {
+    addr &= ~1;
 
-        pkt = buf;
+    if ((addr < 32) || (addr >= NE2K_PMEM_START && addr < NE2K_MEM_SIZE)) {
+        return *(uint16_t *)(nic_state->mem + addr);
+    } else {
+        return 0xffff;
+    }
+}
 
-        length = MIN_BUF_SIZE;
+static uint32_t mem_readl(struct ne2k_state * nic_state, uint32_t addr) {
+    addr &= ~1;
+
+    if ((addr < 32) || (addr >= NE2K_PMEM_START && addr < NE2K_MEM_SIZE)) {
+        return *(uint32_t *)(nic_state->mem + addr);
+    } else {
+        return 0xffffffff;
     }
+}
 
-    index = nregs->curpag << 8;
 
-    // 4 bytes header 
-    total_len = length + 4;
+static void dma_update( struct ne2k_state * nic_state, int len) {                      
+    struct ne2k_registers * regs = (struct ne2k_registers *)&(nic_state->context);
 
-    // address for next packet (4 bytes for CRC)
-    next = index + ((total_len + 4 + 255) & ~0xff);
+    regs->rsar += len;
 
-    if (next >= stop) {
-        next -= stop - start;
+    // wrap
+    if (regs->rsar == regs->pgstop) {
+        regs->rsar = regs->pgstart;
     }
 
-    p = nic_state->mem + index;
-    nregs->rsr = ENRSR_RXOK;
-
-    if (pkt[0] & 0x01) {
-        nregs->rsr |= ENRSR_PHY;
+    if (regs->rbcr <= len) {
+        regs->rbcr = 0;
+        regs->isr.rem_dma_done = 1;
+        ne2k_update_irq(nic_state);
+    } else {
+        regs->rbcr -= len;
     }
+}
 
-    p[0] = nregs->rsr;
-    p[1] = next >> 8;
-    p[2] = total_len;
-    p[3] = total_len >> 8;
+static int ne2k_data_read(struct guest_info * core, 
+                         uint16_t port, 
+                         void * dst, 
+                         uint_t length, 
+                         void * private_data) {
+    struct ne2k_state * nic_state = (struct ne2k_state *)private_data;
+    uint32_t val;
+    struct ne2k_registers * regs = (struct ne2k_registers *)&(nic_state->context);
 
-    index += 4;
+    // current dma address
+    uint32_t addr = regs->rsar;
 
-    while (length > 0) {
-        if (index <= stop) {
-            empty = stop - index;
-       } else {
-           empty = 0;
-       }
+    switch (length){
+       case 1:
+           val = mem_readb(nic_state, addr);
+           break;
+       case 2:
+           val = mem_readw(nic_state, addr);
+           break;
+       case 4:
+           val = mem_readl(nic_state, addr);
+           break;
+       default:
+           PrintError("ne2k_data_read error: invalid length %d\n", length);
+           val = 0x0;
+    }
+    
+    dma_update(nic_state, length);
+    memcpy(dst, &val, length);
 
-        len = length;
+    PrintDebug("NE2000 read: port:0x%x (%u bytes): 0x%x", port & 0x1f, length, val);
 
-        if (len > empty) {
-            len = empty;
-       }
+    return length;
+}
 
-        memcpy(nic_state->mem + index, pkt, len);
-        pkt += len;
-        index += len;
+static int ne2k_data_write(struct guest_info * core, 
+                          uint16_t port, 
+                          void * src, 
+                          uint_t length, 
+                          void * private_data) {
+    struct ne2k_state * nic_state = (struct ne2k_state *)private_data;
+    uint32_t val;
+    struct ne2k_registers * regs = (struct ne2k_registers *)&(nic_state->context);
+       
+    uint32_t addr = regs->rsar;
+       
+    if (regs->rbcr == 0) {
+       return length;
+    }
 
-        if (index == stop) {
-            index = start;
-       }
+    memcpy(&val, src, length);
 
-        length -= len;
+    switch (length) {
+       case 1:
+           mem_writeb(nic_state, addr, val);
+           break;
+       case 2:
+           mem_writew(nic_state, addr, val);
+           break;
+       case 4:
+           mem_writel(nic_state, addr, val);
+           break;
+       default:
+           PrintError("NE2000 port write error: invalid length %d\n", length);
     }
+    
+    dma_update(nic_state, length);
 
-    nregs->curpag = next >> 8;
-
-    nregs->isr |= ENISR_RX;
-    vnic_update_irq(dev);
+    PrintDebug("NE2000: Write port:0x%x (%u bytes): 0x%x\n", port & 0x1f, length, val);
+    
+    return length;
 }
 
-// =====begin here
-#if 0
-void pci_vnic_init(PCIBus * bus, NICInfo * nd, int devfn)
-{
-    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;
-
-    pci_conf[0x00] = 0xec; // Realtek 8029
-    pci_conf[0x01] = 0x10;
-    pci_conf[0x02] = 0x29;
-    pci_conf[0x03] = 0x80;
-    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_register_io_region(&d->dev, 0, 0x100,
-                           PCI_ADDRESS_SPACE_IO, ne2000_map);
-    s = &d->ne2000;
-
-    s->irq = d->dev.irq[0];
-
-    s->pci_dev = (PCIDevice *)d;
-
-    memcpy(s->macaddr, nd->macaddr, 6);
-
-    ne2000_reset(s);
-
-    s->vc = qemu_new_vlan_client(nd->vlan, ne2000_receive,
-                                 ne2000_can_receive, s);
-
-    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]);
-
-    /* XXX: instance number ? */
-    register_savevm("ne2000", 0, 3, ne2000_save, ne2000_load, s);
-}
-#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]);
-  }
+static void ne2k_init_state(struct ne2k_state * nic_state) {
 
-  dev = get_rx_dev(pkt);
 
-  if (dev == NULL) {
-      return 0;
-  }
+    /* Not sure what this is about....  */
+    memset(nic_state->mem, 0xff, 32); 
+       
+    memcpy(nic_state->mem, nic_state->mac, ETH_ALEN);
+    memset(nic_state->mcast_addr, 0xff, sizeof(nic_state->mcast_addr));
+    nic_state->mem[14] = 0x57;
+    nic_state->mem[15] = 0x57;
 
-  PrintDebug("\n");
+    /* initiate registers */
+    nic_state->context.isr.reset_status = 1;
+    nic_state->context.imr.val = 0x00;
+    nic_state->context.cmd.val = 0x22;
+}
 
-  for(i = 0; i < size; i++) {
-      PrintDebug("%x ", pkt[i]);
-  }
+static int reset_device(struct ne2k_state * nic_state) {  
+    ne2k_init_state(nic_state);
 
-  vnic_receive(dev, pkt, size);
+    PrintDebug("NE2000: Reset device\n");
 
-  return 0;
+    return 0;
 }
 
+//for 0xc11f port
+static int ne2k_reset_port_read(struct guest_info * core, 
+                               uint16_t port, 
+                               void * dst, 
+                               uint_t length, 
+                               void * private_data) {
+    struct ne2k_state * nic_state = (struct ne2k_state *)private_data;
 
-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;
-    int index;
-       
-    if (length == 1) {
-       memcpy(&val, src, 1);
-    } else {
-       PrintDebug("vnic_write error: length %d\n", length);  
-       return length;
-    }
-       
-    port &= 0x1f;
-       
-    PrintDebug("vnic_write: port:0x%x (%u bytes): 0x%x\n", port, length, (int)val);
-       
-    if (port == EN0_COMMAND) {
-        nic_state->regs.cmd = val;
-       
-        if (!(val & NE2K_STOP)) {
-            nic_state->regs.isr &= ~ENISR_RESET; 
+    memset(dst, 0, length);
+    reset_device(nic_state);
 
-            if ((val & (NE2K_DMAREAD | NE2K_DMAWRITE)) &&
-               nic_state->regs.rbcr == 0) {
-                nic_state->regs.isr |= ENISR_RDC;
-                vnic_update_irq(dev);
-            }
+    return length;
+}
 
+static int ne2k_reset_port_write(struct guest_info * core, 
+                                uint16_t port, 
+                                void * src, 
+                                uint_t length, 
+                                void * private_data) {
 
-            if (val & NE2K_TRANSMIT) {
-                index = (nic_state->regs.tpsr << 8);
+    return length;
+}
 
-                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);
-                }
 
-                nic_state->regs.tsr = ENTSR_PTX;
-                nic_state->regs.isr |= ENISR_TX;
-                nic_state->regs.cmd &= ~NE2K_TRANSMIT;
+static int ne2k_cmd_write(struct guest_info * core, 
+                         uint16_t port, 
+                         void * src, 
+                         uint_t length, 
+                         void * private_data) {
+    struct ne2k_state * nic_state = (struct ne2k_state *)private_data;
+    struct ne2k_registers * regs = (struct ne2k_registers *)&(nic_state->context);
 
-                vnic_update_irq(dev);
-            }
-        }
+    if (length != 1) {
+       PrintError("Invalid write length to NE2000 Command register\n");
+       return -1;
+    }
 
-    } 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;
-           }
+    regs->cmd.val = *(uint8_t *)src;
 
-       } 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;
+    if (!(regs->cmd.stop)) {
+       regs->isr.reset_status = 0;
+       
+       // if ((send pkt) && (dma byte count == 0)) 
+       if ((regs->cmd.rem_dma_cmd & 0x3) && (regs->rbcr == 0)) {
+           regs->isr.rem_dma_done = 1;
+           ne2k_update_irq(nic_state);
+       }
+       
+       if (regs->cmd.tx_pkt) {
+           int offset = (regs->tpsr << 8);
+           
+           if (offset >= NE2K_PMEM_END) {
+               offset -= NE2K_PMEM_SIZE;
            }
 
-       } 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 (offset + regs->tbcr <= NE2K_PMEM_END) {
+               tx_one_pkt(nic_state, nic_state->mem + offset, regs->tbcr);
            }
+
+           regs->tsr.val = 0;        /* clear the tx status reg */
+           regs->tsr.pkt_tx_ok = 1;  /* indicate successful tx */
+
+           regs->isr.pkt_tx = 1;     /* irq due to pkt tx */
+           regs->cmd.tx_pkt = 0;     /* reset cmd bit  */
+           
+           ne2k_update_irq(nic_state);
        }
+    } else {
+       /* stop the controller */
     }
 
-    //dump_state(dev);
-       
     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;
-
-    struct nic_context *nic_state = (struct nic_context* )dev->private_data;
+static int ne2k_cmd_read(struct guest_info * core, 
+                        uint16_t port, 
+                        void * dst, 
+                        uint_t length, 
+                        void * private_data) {
+    struct ne2k_state * nic_state = (struct ne2k_state *)private_data;
 
-    if (length > 1) {
-       PrintDebug("vnic_read error: length %d\n", length);
-       valurn length;
+    if (length != 1) {
+       PrintError("Invalid read length to NE2000 Command register\n");
+       return -1;
     }
 
-    port &= 0x1f;
+    *(uint8_t *)dst = nic_state->context.cmd.val;
 
-    if (port == EN0_COMMAND) {
-        val = 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;
-                   break;
-               case EN0_CLDAHI:
-                   val = (nic_state->regs.clda & 0xff00) >> 8;
-                   break;
-               case EN0_BOUNDARY:
-                   val = nic_state->regs.boundary;
-                   break;
-               case EN0_TSR:
-                   val = nic_state->regs.tsr;
-                   break;
-               case EN0_NCR:
-                   val = nic_state->regs.ncr;
-                   break;
-               case EN0_FIFO:
-                   val = nic_state->regs.fifo;
-                   break;
-               case EN0_ISR:
-                   val = nic_state->regs.isr;
-                   vnic_update_irq(dev);
-                   break;
-               case EN0_CRDALO:
-                   val = nic_state->regs.crda & 0x00ff;
-                   break;
-               case EN0_CRDAHI:
-                   val = (nic_state->regs.crda & 0xff00) >> 8;
-                   break;
-               case EN0_RSR:
-                   val = nic_state->regs.rsr;
-                   break;
-               case EN0_COUNTER0:
-                   val = nic_state->regs.cntr & 0x000000ff;
-                   break;
-               case EN0_COUNTER1:
-                   val = (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;
-           }
+    PrintDebug("ne2k_read: port:0x%x  val: 0x%x\n", port, *(uint8_t *)dst);
+    return length;
+}
 
-        } else if (page == 1) {
-
-           switch(port) {
-               case EN1_PHYS ... EN1_PHYS + 5:
-                   val = nic_state->regs.phys[port - EN1_PHYS];
-                   break;
-               case EN1_CURPAG:
-                   val = nic_state->regs.curpag;
-                   break;
-               case EN1_MULT ... EN1_MULT + 7:
-                   val = nic_state->regs.mult[port - EN1_MULT];
-                   break;
-               default:
-                   PrintDebug("vnic_read error: invalid port:0x%x\n", port);
-                   val = 0x00;
-                   break;
-           }
+static int ne2k_std_write(struct guest_info * core, 
+                         uint16_t port, 
+                         void * src, 
+                         uint_t length, 
+                         void * private_data) {
+    struct ne2k_state * nic_state = (struct ne2k_state *)private_data;
+    struct ne2k_registers * regs = (struct ne2k_registers *)&(nic_state->context);
+    int idx = port & 0x1f;
+    uint8_t page = regs->cmd.pg_sel;
+
+    if (length != 1){
+       PrintError("NE2000 port write error: length %d port 0x%xnot equal to 1\n", length, port);  
+       return -1;
+    }
 
-       } else if (page == 2) {
-
-           switch(port) {
-               case EN2_STARTPG:
-                   val = nic_state->regs.pgstart;
-                   break;
-               case EN2_STOPPG:
-                   val = nic_state->regs.pgstop;
-                   break;
-               case EN2_RNPR:
-                   val = nic_state->regs.rnpp;
-                   break;
-               case EN2_LNRP:
-                   val = nic_state->regs.lnpp;
-                   break;
-               case EN2_TPSR:
-                   val = nic_state->regs.tpsr;
-                   break;
-               case EN2_ACNT0:
-                   val = nic_state->regs.addcnt & 0x00ff;
-                   break;
-               case EN2_ACNT1: 
-                   val = (nic_state->regs.addcnt & 0xff00) >> 8;
-                   break;
-               case EN2_RCR:
-                   val = nic_state->regs.rcr;
-                   break;
-               case EN2_TCR:
-                   val = nic_state->regs.tcr;
-                   break;
-               case EN2_DCR:
-                   val = nic_state->regs.dcr;
-                   break;
-               case EN2_IMR:
-                   val = nic_state->regs.imr;
-                   break;
-               default:
-                   PrintDebug("vnic_read error: invalid port:0x%x\n", port);
-                   val = 0x00;
-                   break;
-           }
+    uint8_t val = *(uint8_t *)src;
+       
+    PrintDebug("NE2000: write port:0x%x val: 0x%x\n", port, (uint8_t)val);
+    
+    if (page == 0) {
+       switch (idx) {
+           case EN0_STARTPG:
+               regs->pgstart = val;
+               break;
+           case EN0_STOPPG:
+               regs->pgstop = val;
+               break;
+           case EN0_BOUNDARY:
+               regs->boundary = val;
+               break;
+           case EN0_TPSR:
+               regs->tpsr = val;
+               break;
+           case EN0_TCNTLO:
+               regs->tbcr0 = val;
+               break;
+           case EN0_TCNTHI:
+               regs->tbcr1 = val;
+               break;
+           case EN0_ISR:
+               regs->isr.val &= ~(val & 0x7f);
+               ne2k_update_irq(nic_state);
+               break;
+           case EN0_RSARLO:
+               regs->rsar0 = val;
+               break;
+           case EN0_RSARHI:
+               regs->rsar1 = val;
+               break;
+           case EN0_RCNTLO:
+               regs->rbcr0 = val;
+               break;
+           case EN0_RCNTHI:
+               regs->rbcr1 = val;
+               break;
+           case EN0_RXCR:
+               regs->rcr.val = val;
+               break;
+           case EN0_TXCR:
+               regs->tcr.val = val;
+               break;
+           case EN0_DCFG:
+               regs->dcr.val = val;
+               break;  
+           case EN0_IMR:
+               regs->imr.val = val;
+               ne2k_update_irq(nic_state);
+               break;
+
+           default:
+               PrintError("NE2000 port write error: invalid port:0x%x\n", port);
+               return -1;
+       }
+    } else if (page == 1) {
+       switch (idx) {
+           case EN1_PHYS ... EN1_PHYS + ETH_ALEN -1:
+               nic_state->mac[port - EN1_PHYS] = val;
+               break;
+           case EN1_CURPAG:
+               regs->curpag = val;
+               break;
+           case EN1_MULT ... EN1_MULT + 7:
+               nic_state->mcast_addr[port - EN1_MULT] = val;
+               break;
+               
+           default:
+               PrintError("NE2000 write port error: invalid port:0x%x\n", port);
+               return -1;
        }
+    } else if (page == 2) {
+       switch (idx) {
+           case EN2_LDMA0:
+               regs->clda0 = val;
+               break;
+           case EN2_LDMA1:
+               regs->clda1 = val;
+               break;
+           case EN2_RNPR:
+               regs->rnpp = val;
+               break;
+           case EN2_LNRP:
+               regs->lnpp = val;
+               break;
+           case EN2_ACNT0:
+               regs->addcnt0 = val;
+               break;
+           case EN2_ACNT1: 
+               regs->addcnt1 = val;
+               break;
+               
+           default:
+               PrintError("NE2000 write port error: invalid port:0x%x\n", port);
+               return -1;
+       }
+    } else {
+       PrintError("NE2000: Invalid Register Page Value\n");
+       return -1;
     }
 
-    memcpy(dst, &val, 1);
-
-    PrintDebug("vnic_read: port:0x%x (%u bytes): 0x%x\n", port,length, (uint32_t)val);
-
-    //dump_state(dev);
 
     return length;
-
+       
 }
 
+static int ne2k_std_read(struct guest_info * core, 
+                        uint16_t port, 
+                        void * dst, 
+                        uint_t length, 
+                        void * private_data) {
+    struct ne2k_state * nic_state = (struct ne2k_state *)private_data;
+    struct ne2k_registers * regs = (struct ne2k_registers *)&(nic_state->context);
+    uint16_t index = port & 0x1f;
+    uint8_t page = regs->cmd.pg_sel;
 
-
-
-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 (length > 1) {
+       PrintError("ne2k_read error: length %d\n", length);
+       return length;
     }
 
-    if (nic_state->regs.rbcr <= len) {
-        nic_state->regs.rbcr = 0;
-        nic_state->regs.isr |= ENISR_RDC;
-
-        vnic_update_irq(dev);
+    if (page == 0) {
+       switch (index) {                
+           case EN0_CLDALO:
+               *(uint8_t *)dst = regs->clda0;
+               break;
+           case EN0_CLDAHI:
+               *(uint8_t *)dst = regs->clda1;
+               break;
+           case EN0_BOUNDARY:
+               *(uint8_t *)dst = regs->boundary;
+               break;
+           case EN0_TSR:
+               *(uint8_t *)dst = regs->tsr.val;
+               break;
+           case EN0_NCR:
+               *(uint8_t *)dst = regs->ncr;
+               break;
+           case EN0_FIFO:
+               *(uint8_t *)dst = regs->fifo;
+               break;
+           case EN0_ISR:
+               *(uint8_t *)dst = regs->isr.val;
+               ne2k_update_irq(nic_state);
+               break;
+           case EN0_CRDALO:
+               *(uint8_t *)dst = regs->crda0;
+               break;
+           case EN0_CRDAHI:
+               *(uint8_t *)dst = regs->crda1;
+               break;
+           case EN0_RSR:
+               *(uint8_t *)dst = regs->rsr.val;
+               break;
+           case EN0_COUNTER0:
+               *(uint8_t *)dst = regs->cntr0;
+               break;
+           case EN0_COUNTER1:
+               *(uint8_t *)dst = regs->cntr1;
+               break;  
+           case EN0_COUNTER2:
+               *(uint8_t *)dst = regs->cntr2;
+               break;
+               
+           default:
+               PrintError("NE2000 port read error: invalid port:0x%x\n", port);
+               return -1;
+       }
+    } else if (page == 1) {
+       switch (index) {
+           case EN1_PHYS ... EN1_PHYS + ETH_ALEN -1:
+               *(uint8_t *)dst = nic_state->mac[index - EN1_PHYS];
+               break;
+           case EN1_CURPAG:
+               *(uint8_t *)dst = regs->curpag;
+               break;
+           case EN1_MULT ... EN1_MULT + 7:
+               *(uint8_t *)dst = nic_state->mcast_addr[index - EN1_MULT];
+               break;
+               
+           default:
+               PrintError("ne2k_read error: invalid port:0x%x\n", port);
+               return -1;
+       }
+    } else if (page == 2) {
+       switch (index) {
+           case EN2_STARTPG:
+               *(uint8_t *)dst = regs->pgstart;
+               break;
+           case EN2_STOPPG:
+               *(uint8_t *)dst = regs->pgstop;
+               break;
+           case EN2_RNPR:
+               *(uint8_t *)dst = regs->rnpp;
+               break;
+           case EN2_LNRP:
+               *(uint8_t *)dst = regs->lnpp;
+               break;
+           case EN2_TPSR:
+               *(uint8_t *)dst = regs->tpsr;
+               break;
+           case EN2_ACNT0:
+               *(uint8_t *)dst = regs->addcnt0;
+               break;
+           case EN2_ACNT1: 
+               *(uint8_t *)dst = regs->addcnt1;
+               break;
+           case EN2_RCR:
+               *(uint8_t *)dst = regs->rcr.val;
+               break;
+           case EN2_TCR:
+               *(uint8_t *)dst = regs->tcr.val;
+               break;
+           case EN2_DCR:
+               *(uint8_t *)dst = regs->dcr.val;
+               break;
+           case EN2_IMR:
+               *(uint8_t *)dst = regs->imr.val;
+               break;
+           default:
+               PrintError("NE2000 port read error: invalid port:0x%x\n", port);
+               return -1;
+       }
     } else {
-        nic_state->regs.rbcr -= len;
+       PrintError("NE2000 port read: Invalid Register Page Value\n");
+       return -1;
     }
+
+    PrintDebug("NE2000 port read: port:0x%x  val: 0x%x\n", port, *(uint8_t *)dst);
+
+    return length;
 }
 
 
-//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;
+static int ne2k_pci_write(struct guest_info * core, 
+                         uint16_t port, 
+                         void * src, 
+                         uint_t length, 
+                         void * private_data) {
+    uint16_t idx = port & 0x1f;
+    int ret;
 
-    switch (length) {
-       case 1:
-           val = vnic_mem_readb(nic_state, addr);
+    switch (idx) {
+       case NE2K_CMD_OFFSET:
+           ret =  ne2k_cmd_write(core, port, src, length, private_data);
            break;
-       case 2:
-           val = vnic_mem_readw(nic_state, addr);
+       case NE2K_CMD_OFFSET+1 ... NE2K_CMD_OFFSET+15:
+           ret = ne2k_std_write(core, port, src, length, private_data);
            break;
-       case 4:
-           val = vnic_mem_readl(nic_state, addr);
+       case NE2K_DATA_OFFSET:
+           ret = ne2k_data_write(core, port, src, length, private_data);
+           break;
+       case NE2K_RESET_OFFSET:
+           ret = ne2k_reset_port_write(core, port, src, length, private_data);
            break;
+
        default:
-           PrintDebug("vnic_data_read error: invalid length %d\n", length);
-           val = 0x0;
+           PrintError("NE2000 port write error: invalid port:0x%x\n", port);
+           return -1;
     }
 
-    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;
+    return ret;
 }
 
-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);
+static int ne2k_pci_read(struct guest_info * core, 
+                        uint16_t port, 
+                        void * dst, 
+                        uint_t length, 
+                        void * private_data) {
+    uint16_t idx = port & 0x1f;
+    int ret;
+
+    switch (idx) {
+       case NE2K_CMD_OFFSET:
+           ret =  ne2k_cmd_read(core, port, dst, length, private_data);
            break;
-       case 2:
-           vnic_mem_writew(nic_state, addr, val);
+       case NE2K_CMD_OFFSET+1 ... NE2K_CMD_OFFSET+15:
+           ret = ne2k_std_read(core, port, dst, length, private_data);
            break;
-       case 4:
-           vnic_mem_writel(nic_state, addr, val);
+       case NE2K_DATA_OFFSET:
+           ret = ne2k_data_read(core, port, dst, length, private_data);
+           break;
+       case NE2K_RESET_OFFSET:
+           ret = ne2k_reset_port_read(core, port, dst, length, private_data);
            break;
+
        default:
-           PrintDebug("nic_data_write error: invalid length %d\n", length);
+           PrintError("NE2000 port read error: invalid port:0x%x\n", port);
+           return -1;
     }
-       
-    vnic_dma_update(dev, length);
 
-    PrintDebug("vnic_write: port:0x%x (%u bytes): 0x%x\n", port & 0x1f,length, val);
-                       
-    return length;
+    return ret;
+
+
 }
 
-static int vnic_reset_device(struct vm_device * dev) {
-  
-    PrintDebug("vnic: reset device\n");
+static int pci_config_update(uint_t reg_num, 
+                            void * src, 
+                            uint_t length,
+                            void * private_data) {
+    PrintDebug("PCI Config Update\n");
 
-    init_vnic_context(dev);
+    /* Do we need this? */
 
     return 0;
 }
 
 
-//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;
+static int register_dev(struct ne2k_state * nic_state) 
+{
+    int i;
 
-    PrintDebug("vnic_read: port:0x%x (%u bytes): 0x%x\n", port,length, val);
-    memcpy(dst, &val, length);
+    if (nic_state->pci_bus != NULL) {
+       struct v3_pci_bar bars[6];
+       struct pci_device * pci_dev = NULL;
 
-    vnic_reset_device(dev);
+       PrintDebug("NE2000: PCI Enabled\n");
 
-    return length;
-}
+       for (i = 0; i < 6; i++) {
+           bars[i].type = PCI_BAR_NONE;
+       }
 
-static int vnic_reset_port_write(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
-    uint32_t val = 0;
+       bars[0].type = PCI_BAR_IO;
+       bars[0].default_base_port = NIC_REG_BASE_PORT;
+       bars[0].num_ports = 256;
 
-    PrintDebug("vnic_write: port:0x%x (%u bytes): 0x%x\n", port,length, val);
-    memcpy(&val, src, length);
-                       
-    return length;
-}
+       bars[0].io_read = ne2k_pci_read;
+       bars[0].io_write = ne2k_pci_write;
+       bars[0].private_data = nic_state;
 
-
-static int vnic_start_device(struct vm_device * dev) {
-    PrintDebug("vnic: start device\n");  
-    return 0;
-}
+       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);
 
 
-static int vnic_stop_device(struct vm_device * dev) {
-    PrintDebug("vnic: stop device\n");
-    return 0;
-}
+       if (pci_dev == NULL) {
+           PrintError("NE2000: 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;
 
-static void  init_phy_network() {      
-    V3_REGISTER_PKT_DELIVERY(&netif_input);
-}
+       pci_dev->config_header.subclass = 0x00;
+       pci_dev->config_header.class = 0x02;
+       pci_dev->config_header.header_type = 0x00;
 
-static int vnic_init_device(struct vm_device * dev) {
-  int i;
+       pci_dev->config_header.intr_line = 11;
+       pci_dev->config_header.intr_pin = 1;
 
-  PrintDebug("vnic: init_device\n");
+       nic_state->pci_dev = pci_dev;
+    }else {
+       PrintDebug("NE2000: Not attached to PCI\n");
 
-  init_phy_network();
-  init_vnic_context(dev);
+       v3_dev_hook_io(nic_state->dev, NIC_REG_BASE_PORT , &ne2k_cmd_read, &ne2k_cmd_write);
 
-  current_vnic = dev;  
+       for (i = 1; i < 16; i++){       
+           v3_dev_hook_io(nic_state->dev, NIC_REG_BASE_PORT + i, &ne2k_std_read, &ne2k_std_write);
+       }
 
-  for (i = 0; i < 16; i++) {   
-      v3_dev_hook_io(dev, NIC_BASE_ADDR + i, &vnic_ioport_read, &vnic_ioport_write);
-  }
+       v3_dev_hook_io(nic_state->dev, NIC_REG_BASE_PORT + NE2K_DATA_OFFSET, &ne2k_data_read, &ne2k_data_write);
+       v3_dev_hook_io(nic_state->dev, NIC_REG_BASE_PORT + NE2K_RESET_OFFSET, &ne2k_reset_port_read, &ne2k_reset_port_write);
+    }
 
-  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);
 
-  return 0;
+    return 0;
 }
 
+static int connect_fn(struct v3_vm_info * info, 
+                     void * frontend_data, 
+                     struct v3_dev_net_ops * ops, 
+                     v3_cfg_tree_t * cfg, 
+                     void * private_data) {
+    struct ne2k_state * nic_state = (struct ne2k_state *)frontend_data;
+
+    ne2k_init_state(nic_state);
+    register_dev(nic_state);
 
+    nic_state->net_ops = ops;
+    nic_state->backend_data = private_data;    
 
-static int vnic_deinit_device(struct vm_device * dev) {
+    ops->recv = ne2k_rx;
+    ops->poll = NULL;
+    memcpy(ops->config.fnt_mac, nic_state->mac, ETH_ALEN);
+
+    return 0;
+}
+
+
+static int ne2k_free(struct ne2k_state * nic_state) {
     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);
+    /* dettached from backend */
 
-    //vnic_reset_device(dev);
-  
+    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_REG_BASE_PORT + NE2K_DATA_OFFSET);
+       v3_dev_unhook_io(nic_state->dev, NIC_REG_BASE_PORT + NE2K_RESET_OFFSET);
+    }else {
+       /* unregistered from PCI? */
+    }
+
+    V3_Free(nic_state);
+       
     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,
+static struct v3_device_ops dev_ops = {
+    .free = (int (*)(void *))ne2k_free,
 };
 
 
-struct vm_device * v3_create_vnic() {
-    struct nic_context * nic_state = V3_Malloc(sizeof(struct nic_context));
+static int ne2k_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
+    struct vm_device * pci_bus = v3_find_dev(vm, v3_cfg_val(cfg, "bus"));
+    struct ne2k_state * nic_state = NULL;
+    char * dev_id = v3_cfg_val(cfg, "ID");
+    char * macstr = v3_cfg_val(cfg, "mac");
+
+    nic_state  = (struct ne2k_state *)V3_Malloc(sizeof(struct ne2k_state));
+    memset(nic_state, 0, sizeof(struct ne2k_state));
+
+    nic_state->pci_bus = pci_bus;
+    nic_state->vm = vm;
+
+    if (macstr != NULL && !str2mac(macstr, nic_state->mac)) {
+       PrintDebug("NE2000: Mac specified %s\n", macstr);
+    }else {
+       PrintDebug("NE2000: MAC not specified\n");
+       random_ethaddr(nic_state->mac);
+    }
 
-    //memset(nic_state, 0, sizeof(struct nic_context));
+    struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, nic_state);
 
-    //PrintDebug("VNIC internal at %x\n",(int)nic_state);
+    if (dev == NULL) {
+       PrintError("NE2000: Could not attach device %s\n", dev_id);
+       V3_Free(nic_state);
+       return -1;
+    }
 
-    struct vm_device *device = v3_create_device("VNIC", &dev_ops, nic_state);
+    nic_state->dev = dev;
 
-    return device;
+    if (v3_dev_add_net_frontend(vm, dev_id, connect_fn, (void *)nic_state) == -1) {
+       PrintError("NE2000: Could not register %s as net frontend\n", dev_id);
+       v3_remove_device(dev);
+       V3_Free(nic_state);
+       return -1;
+    }
+           
+    return 0;
 }
 
+device_register("NE2000", ne2k_init)