X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?a=blobdiff_plain;f=palacios%2Fsrc%2Fdevices%2Fne2k.c;h=b4796f70b128cc7f307139fa8621156e685be4a0;hb=e895aea7212e8cd9e1ba9555f3313fbf90f83d7f;hp=e6c12a957abff8effa7318b479575c2914c2ea55;hpb=dff04423dfb6d70291862c33114d845fc418fe71;p=palacios.git diff --git a/palacios/src/devices/ne2k.c b/palacios/src/devices/ne2k.c index e6c12a9..b4796f7 100644 --- a/palacios/src/devices/ne2k.c +++ b/palacios/src/devices/ne2k.c @@ -17,989 +17,1236 @@ * redistribute, and modify it as specified in the file "V3VEE_LICENSE". */ -/* -* Virtual NE2K Network Card -*/ - - - - -#include +#include #include -#include #include #include - -#define DEBUG_NIC - -#ifndef DEBUG_NIC -#undef PrintDebug() +#include +#include +#include +#include +#include +#include + +#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 = -1; + 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; + ops->config.frontend_data = nic_state; + ops->config.fnt_mac = nic_state->mac; + + 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)