⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 e1000.c

📁 xen虚拟机源代码安装包
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * QEMU e1000 emulation * * Nir Peleg, Tutis Systems Ltd. for Qumranet Inc. * Copyright (c) 2008 Qumranet * Based on work done by: * Copyright (c) 2007 Dan Aloni * Copyright (c) 2004 Antony T Curtis * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */#include "vl.h"#include "e1000_hw.h"#define DEBUG#ifdef DEBUGenum {    DEBUG_GENERAL,	DEBUG_IO,	DEBUG_MMIO,	DEBUG_INTERRUPT,    DEBUG_RX,		DEBUG_TX,	DEBUG_MDIC,	DEBUG_EEPROM,    DEBUG_UNKNOWN,	DEBUG_TXSUM,	DEBUG_TXERR,	DEBUG_RXERR,    DEBUG_RXFILTER,	DEBUG_NOTYET,};#define DBGBIT(x)	(1<<DEBUG_##x)static int debugflags = DBGBIT(TXERR) | DBGBIT(GENERAL);#define	DBGOUT(what, fmt, params...) do { \    if (debugflags & DBGBIT(what)) \        fprintf(stderr, "e1000: " fmt, ##params); \    } while (0)#else#define	DBGOUT(what, fmt, params...) do {} while (0)#endif#define IOPORT_SIZE       0x40#define PNPMMIO_SIZE      0x20000/* * HW models: *  E1000_DEV_ID_82540EM works with Windows and Linux *  E1000_DEV_ID_82573L OK with windoze and Linux 2.6.22, *	appears to perform better than 82540EM, but breaks with Linux 2.6.18 *  E1000_DEV_ID_82544GC_COPPER appears to work; not well tested *  Others never tested */enum { E1000_DEVID = E1000_DEV_ID_82540EM };/* * May need to specify additional MAC-to-PHY entries -- * Intel's Windows driver refuses to initialize unless they match */enum {    PHY_ID2_INIT = E1000_DEVID == E1000_DEV_ID_82573L ?		0xcc2 :                   E1000_DEVID == E1000_DEV_ID_82544GC_COPPER ?	0xc30 :                   /* default to E1000_DEV_ID_82540EM */	0xc20};typedef struct E1000State_st {    PCIDevice dev;    VLANClientState *vc;    NICInfo *nd;    uint32_t instance;    uint32_t mmio_base;    int mmio_index;    uint32_t mac_reg[0x8000];    uint16_t phy_reg[0x20];    uint16_t eeprom_data[64];    uint32_t rxbuf_size;    uint32_t rxbuf_min_shift;    int check_rxov;    struct e1000_tx {        unsigned char header[256];        unsigned char data[0x10000];        uint16_t size;        unsigned char sum_needed;        uint8_t ipcss;        uint8_t ipcso;        uint16_t ipcse;        uint8_t tucss;        uint8_t tucso;        uint16_t tucse;        uint8_t hdr_len;        uint16_t mss;        uint32_t paylen;        uint16_t tso_frames;        char tse;        char ip;        char tcp;        char cptse;     //current packet tse bit    } tx;    struct {        uint32_t val_in;	// shifted in from guest driver        uint16_t bitnum_in;        uint16_t bitnum_out;        uint16_t reading;        uint32_t old_eecd;    } eecd_state;} E1000State;#define	defreg(x)	x = (E1000_##x>>2)enum {    defreg(CTRL),	defreg(EECD),	defreg(EERD),	defreg(GPRC),    defreg(GPTC),	defreg(ICR),	defreg(ICS),	defreg(IMC),    defreg(IMS),	defreg(LEDCTL),	defreg(MANC),	defreg(MDIC),    defreg(MPC),	defreg(PBA),	defreg(RCTL),	defreg(RDBAH),    defreg(RDBAL),	defreg(RDH),	defreg(RDLEN),	defreg(RDT),    defreg(STATUS),	defreg(SWSM),	defreg(TCTL),	defreg(TDBAH),    defreg(TDBAL),	defreg(TDH),	defreg(TDLEN),	defreg(TDT),    defreg(TORH),	defreg(TORL),	defreg(TOTH),	defreg(TOTL),    defreg(TPR),	defreg(TPT),	defreg(TXDCTL),	defreg(WUFC),    defreg(RA),		defreg(MTA),	defreg(CRCERRS),};enum { PHY_R = 1, PHY_W = 2, PHY_RW = PHY_R | PHY_W };static char phy_regcap[0x20] = {    [PHY_STATUS] = PHY_R,	[M88E1000_EXT_PHY_SPEC_CTRL] = PHY_RW,    [PHY_ID1] = PHY_R,		[M88E1000_PHY_SPEC_CTRL] = PHY_RW,    [PHY_CTRL] = PHY_RW,	[PHY_1000T_CTRL] = PHY_RW,    [PHY_LP_ABILITY] = PHY_R,	[PHY_1000T_STATUS] = PHY_R,    [PHY_AUTONEG_ADV] = PHY_RW,	[M88E1000_RX_ERR_CNTR] = PHY_R,    [PHY_ID2] = PHY_R,};static voidioport_map(PCIDevice *pci_dev, int region_num, uint32_t addr,           uint32_t size, int type){    DBGOUT(IO, "e1000_ioport_map addr=0x%04x size=0x%08x\n", addr, size);}static voidset_interrupt_cause(E1000State *s, int index, uint32_t val){    if (val)        val |= E1000_ICR_INT_ASSERTED;    s->mac_reg[ICR] = val;    pci_set_irq(&s->dev, 0, (s->mac_reg[IMS] & s->mac_reg[ICR]) != 0);}static voidset_ics(E1000State *s, int index, uint32_t val){    DBGOUT(INTERRUPT, "set_ics %x, ICR %x, IMR %x\n", val, s->mac_reg[ICR],        s->mac_reg[IMS]);    set_interrupt_cause(s, 0, val | s->mac_reg[ICR]);}static intrxbufsize(uint32_t v){    v &= E1000_RCTL_BSEX | E1000_RCTL_SZ_16384 | E1000_RCTL_SZ_8192 |         E1000_RCTL_SZ_4096 | E1000_RCTL_SZ_2048 | E1000_RCTL_SZ_1024 |         E1000_RCTL_SZ_512 | E1000_RCTL_SZ_256;    switch (v) {    case E1000_RCTL_BSEX | E1000_RCTL_SZ_16384:        return 16384;    case E1000_RCTL_BSEX | E1000_RCTL_SZ_8192:        return 8192;    case E1000_RCTL_BSEX | E1000_RCTL_SZ_4096:        return 4096;    case E1000_RCTL_SZ_1024:        return 1024;    case E1000_RCTL_SZ_512:        return 512;    case E1000_RCTL_SZ_256:        return 256;    }    return 2048;}static voidset_rx_control(E1000State *s, int index, uint32_t val){    s->mac_reg[RCTL] = val;    s->rxbuf_size = rxbufsize(val);    s->rxbuf_min_shift = ((val / E1000_RCTL_RDMTS_QUAT) & 3) + 1;    DBGOUT(RX, "RCTL: %d, mac_reg[RCTL] = 0x%x\n", s->mac_reg[RDT],           s->mac_reg[RCTL]);}static voidset_mdic(E1000State *s, int index, uint32_t val){    uint32_t data = val & E1000_MDIC_DATA_MASK;    uint32_t addr = ((val & E1000_MDIC_REG_MASK) >> E1000_MDIC_REG_SHIFT);    if ((val & E1000_MDIC_PHY_MASK) >> E1000_MDIC_PHY_SHIFT != 1) // phy #        val = s->mac_reg[MDIC] | E1000_MDIC_ERROR;    else if (val & E1000_MDIC_OP_READ) {        DBGOUT(MDIC, "MDIC read reg 0x%x\n", addr);        if (!(phy_regcap[addr] & PHY_R)) {            DBGOUT(MDIC, "MDIC read reg %x unhandled\n", addr);            val |= E1000_MDIC_ERROR;        } else            val = (val ^ data) | s->phy_reg[addr];    } else if (val & E1000_MDIC_OP_WRITE) {        DBGOUT(MDIC, "MDIC write reg 0x%x, value 0x%x\n", addr, data);        if (!(phy_regcap[addr] & PHY_W)) {            DBGOUT(MDIC, "MDIC write reg %x unhandled\n", addr);            val |= E1000_MDIC_ERROR;        } else            s->phy_reg[addr] = data;    }    s->mac_reg[MDIC] = val | E1000_MDIC_READY;    set_ics(s, 0, E1000_ICR_MDAC);}static uint32_tget_eecd(E1000State *s, int index){    uint32_t ret = E1000_EECD_PRES|E1000_EECD_GNT | s->eecd_state.old_eecd;    DBGOUT(EEPROM, "reading eeprom bit %d (reading %d)\n",           s->eecd_state.bitnum_out, s->eecd_state.reading);    if (!s->eecd_state.reading ||        ((s->eeprom_data[(s->eecd_state.bitnum_out >> 4) & 0x3f] >>          ((s->eecd_state.bitnum_out & 0xf) ^ 0xf))) & 1)        ret |= E1000_EECD_DO;    return ret;}static voidset_eecd(E1000State *s, int index, uint32_t val){    uint32_t oldval = s->eecd_state.old_eecd;    s->eecd_state.old_eecd = val & (E1000_EECD_SK | E1000_EECD_CS |            E1000_EECD_DI|E1000_EECD_FWE_MASK|E1000_EECD_REQ);    if (!(E1000_EECD_SK & (val ^ oldval)))	// no clock edge        return;    if (!(E1000_EECD_SK & val)) {		// falling edge        s->eecd_state.bitnum_out++;        return;    }    if (!(val & E1000_EECD_CS)) {		// rising, no CS (EEPROM reset)        memset(&s->eecd_state, 0, sizeof s->eecd_state);        return;    }    s->eecd_state.val_in <<= 1;    if (val & E1000_EECD_DI)        s->eecd_state.val_in |= 1;    if (++s->eecd_state.bitnum_in == 9 && !s->eecd_state.reading) {        s->eecd_state.bitnum_out = ((s->eecd_state.val_in & 0x3f)<<4)-1;        s->eecd_state.reading = (((s->eecd_state.val_in >> 6) & 7) ==            EEPROM_READ_OPCODE_MICROWIRE);    }    DBGOUT(EEPROM, "eeprom bitnum in %d out %d, reading %d\n",           s->eecd_state.bitnum_in, s->eecd_state.bitnum_out,           s->eecd_state.reading);}static uint32_tflash_eerd_read(E1000State *s, int x){    unsigned int index, r = s->mac_reg[EERD] & ~E1000_EEPROM_RW_REG_START;    if ((index = r >> E1000_EEPROM_RW_ADDR_SHIFT) > EEPROM_CHECKSUM_REG)        return 0;    return (s->eeprom_data[index] << E1000_EEPROM_RW_REG_DATA) |           E1000_EEPROM_RW_REG_DONE | r;}static unsigned intdo_cksum(uint8_t *dp, uint8_t *de){    unsigned int bsum[2] = {0, 0}, i, sum;    for (i = 1; dp < de; bsum[i^=1] += *dp++)        ;    sum = (bsum[0] << 8) + bsum[1];    sum = (sum >> 16) + (sum & 0xffff);    return ~(sum + (sum >> 16));}static voidputsum(uint8_t *data, uint32_t n, uint32_t sloc, uint32_t css, uint32_t cse){    if (cse && cse < n)        n = cse + 1;    if (sloc < n-1)        cpu_to_be16wu((uint16_t *)(data + sloc),                      do_cksum(data + css, data + n));}static voidxmit_seg(E1000State *s){    uint16_t len, *sp;    unsigned int frames = s->tx.tso_frames, css, sofar, n;    struct e1000_tx *tp = &s->tx;    if (tp->tse && tp->cptse) {        css = tp->ipcss;        DBGOUT(TXSUM, "frames %d size %d ipcss %d\n",               frames, tp->size, css);        if (tp->ip) {		// IPv4            cpu_to_be16wu((uint16_t *)(tp->data+css+2),                          tp->size - css);            cpu_to_be16wu((uint16_t *)(tp->data+css+4),                          be16_to_cpup((uint16_t *)(tp->data+css+4))+frames);        } else			// IPv6            cpu_to_be16wu((uint16_t *)(tp->data+css+4),                          tp->size - css);        css = tp->tucss;        len = tp->size - css;        DBGOUT(TXSUM, "tcp %d tucss %d len %d\n", tp->tcp, css, len);        if (tp->tcp) {            sofar = frames * tp->mss;            cpu_to_be32wu((uint32_t *)(tp->data+css+4),	// seq                be32_to_cpup((uint32_t *)(tp->data+css+4))+sofar);            if (tp->paylen - sofar > tp->mss)                tp->data[css + 13] &= ~9;		// PSH, FIN        } else	// UDP            cpu_to_be16wu((uint16_t *)(tp->data+css+4), len);        if (tp->sum_needed & E1000_TXD_POPTS_TXSM) {            // add pseudo-header length before checksum calculation            sp = (uint16_t *)(tp->data + tp->tucso);            cpu_to_be16wu(sp, be16_to_cpup(sp) + len);        }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -