From: Lei Xia Date: Sun, 19 Apr 2009 15:26:41 +0000 (-0500) Subject: Update virtual NE2000 X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?p=palacios.git;a=commitdiff_plain;h=dd7ea495f8177d9594526263440ed67afa8f8e64 Update virtual NE2000 --- diff --git a/palacios/build/Makefile b/palacios/build/Makefile index 4e8c8e3..7319a6f 100644 --- a/palacios/build/Makefile +++ b/palacios/build/Makefile @@ -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 \ diff --git a/palacios/include/devices/ne2k.h b/palacios/include/devices/ne2k.h index c1a9a6f..7f016b4 100644 --- a/palacios/include/devices/ne2k.h +++ b/palacios/include/devices/ne2k.h @@ -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 - * Copyright (c) 2008, The V3VEE Project + * Copyright (c) 2009, Lei Xia + * Copyright (c) 2009, The V3VEE Project * All rights reserved. * * Author: Lei Xia @@ -17,128 +17,159 @@ * redistribute, and modify it as specified in the file "V3VEE_LICENSE". */ -#ifndef __VNIC_H_ -#define __VNIC_H_ +#ifndef __NE2K_H_ +#define __NE2K_H_ #include +#include -#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 diff --git a/palacios/src/devices/ne2k.c b/palacios/src/devices/ne2k.c index e6c12a9..431c590 100644 --- a/palacios/src/devices/ne2k.c +++ b/palacios/src/devices/ne2k.c @@ -21,222 +21,141 @@ * Virtual NE2K Network Card */ - - - -#include +#include +#include #include #include #include #include +#include -#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; iprivate_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; imacaddr, 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; }