On Sun, Aug 26, 2007 at 02:25:57PM +0200, Triggered wrote: > Dan Aloni schreef: > > Hello, > > > > Is anyone interested in a patch for an unstable, though working e1000 > > emulation for > > QEMU? It is aimed for this chip-set version: > > > > 0e:00.0 Ethernet controller: Intel Corporation 82573L Gigabit Ethernet > > Controller > > > > I originally created it very recently to provide a virtual NIC that > > supports Jumbo > > packets. Unfortunately it appears that the tun driver doesn't implement > > change_mtu() so it didn't integrate very well with qemu-kvm. > > > I am very interested in a patch for Gbit-capable network card. > Please post a patch!
Okay, just a few notes: * Sorry for sending this rather badly written patch, I have loads of other stuff at the moment. I hope that it serves as a ground for further development, though. * It depends on the e1000_hw.h header from a the Linux kernel driver (look in drivers/net/e1000), I haven't included this header in the patch. * As far as I've seen, ICMP ping works, but TCP doesn't (I think it is because this emulator implementation doesn't do the off-load of packet checksuming, as the guest expects) * Several up/downs of the interface while it is working seem to cause guest memory corruption. Haven't looked into this yet. Have fun hacking! diff --git a/qemu/Makefile.target b/qemu/Makefile.target index aeee2af..9363e22 100644 --- a/qemu/Makefile.target +++ b/qemu/Makefile.target @@ -372,7 +372,7 @@ VL_OBJS+= scsi-disk.o cdrom.o lsi53c895a.o VL_OBJS+= usb.o usb-hub.o usb-linux.o usb-hid.o usb-ohci.o usb-msd.o # PCI network cards -VL_OBJS+= ne2000.o rtl8139.o pcnet.o +VL_OBJS+= ne2000.o rtl8139.o pcnet.o e1000.o # PCI Hypercall VL_OBJS+= hypercall.o diff --git a/qemu/hw/e1000.c b/qemu/hw/e1000.c new file mode 100644 index 0000000..7e3c014 --- /dev/null +++ b/qemu/hw/e1000.c @@ -0,0 +1,695 @@ +/* + * QEMU e1000 emulation + * + * Copyright (c) 2007 Dan Aloni + * Based on work done by: + * Copyright (c) 2004 Antony T Curtis + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + +#include "vl.h" + +#define E1000_DEBUG +#define E1000_DEBUG_UNK +//#define E1000_DEBUG_CSR +//#define E1000_DEBUG_RMD +//#define E1000_DEBUG_TMD +//#define E1000_DEBUG_MATCH + +#ifdef E1000_DEBUG +#define EDBGOUT(fmt, params...) fprintf(stderr, "e1000: " fmt, ##params) +#else +#define EDBGOUT(fmt, params...) do {} while (0) +#endif + +#ifdef E1000_DEBUG_UNK +#define EDBGUNKOUT(fmt, params...) EDBGOUT(fmt, ##params) +#else +#define EDBGUNKOUT(fmt, params...) do {} while (0) +#endif + + +#define E1000_IOPORT_SIZE 0x40 +#define E1000_PNPMMIO_SIZE 0x60000 + +#include "e1000_hw.h" + +typedef struct e1000_vmhw_st e1000_vmhw; + +struct e1000_eeprom { + unsigned short raw[64]; +}; + +struct e1000_vmhw_st { + PCIDevice dev; + PCIDevice *pci_dev; + VLANClientState *vc; + NICInfo *nd; + uint32_t mmio_base; + uint32_t interrupt_mask; + uint32_t eeprom_semaphore; + uint32_t mdic; + + uint32_t icr; + uint32_t tdlen; + uint64_t tdb; + uint32_t tdt; + uint32_t tdh; + + uint32_t rdlen; + uint64_t rdb; + uint32_t rdt; + uint32_t rdh; + uint32_t rctl; + uint32_t receive_buf_size; + + uint16_t phy_regs[0x20]; + + struct e1000_eeprom eeprom_data; + int eeprom_offset_to_read; + int mmio_index, rap, isr, lnkst; + void *dma_opaque; +}; + +static void e1000_ioport_map(PCIDevice *pci_dev, int region_num, + uint32_t addr, uint32_t size, int type) +{ + EDBGOUT("e1000_ioport_map addr=0x%04x size=0x%08x\n", addr, size); +} + +static void e1000_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + EDBGOUT("e1000_mmio_writeb addr=%p val=0x%08x\n", (void *)addr, val); +} + +static uint32_t e1000_mmio_readb(void *opaque, target_phys_addr_t addr) +{ + EDBGOUT("e1000_mmio_readb addr=%p\n", (void *)addr); + return 0; +} + +static void e1000_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + EDBGOUT("e1000_mmio_writew addr=0x%08x val=0x%04x\n", addr, val); +} + +static uint32_t e1000_mmio_readw(void *opaque, target_phys_addr_t addr) +{ + EDBGOUT("e1000_mmio_readw addr=0x%08x\n", addr); + return 0; +} + +void e1000_update_interrupt(struct e1000_vmhw_st *s) +{ + if ((~s->interrupt_mask) & s->icr) { + EDBGOUT("update interrupt 0x%08x\n", (~s->interrupt_mask) & s->icr); + } + pci_set_irq(&s->dev, 0, ((~s->interrupt_mask) & s->icr) != 0); +} + +void e1000_clear_interrupt_mask(struct e1000_vmhw_st *s, uint32_t val) +{ + s->interrupt_mask = val; + e1000_update_interrupt(s); +} + +void e1000_set_interrupt_mask(struct e1000_vmhw_st *s, uint32_t val) +{ + s->interrupt_mask = ~val; + e1000_update_interrupt(s); +} + +void e1000_set_interrupt_cause(struct e1000_vmhw_st *s, uint32_t val) +{ + if (val != 0) { + if (val & E1000_ICR_LSC) { + EDBGOUT("mocking up a link\n"); + /* Trick the driver to think there's a link */ + s->phy_regs[PHY_STATUS] = 0x796d; + } + val |= E1000_ICR_INT_ASSERTED; + } + s->icr = val; + e1000_update_interrupt(s); +} + +uint32_t e1000_get_receive_control(struct e1000_vmhw_st *s) +{ + return s->rctl; +} + +void e1000_set_receive_control(struct e1000_vmhw_st *s, uint32_t val) +{ + uint32_t reg_buf_size; + + s->rctl = val; + s->receive_buf_size = 2048; + + reg_buf_size = val & 0x00030000; + + if (val & E1000_RCTL_BSEX) { + switch (reg_buf_size) { + case E1000_RCTL_SZ_16384: + s->receive_buf_size = 16384; + break; + case E1000_RCTL_SZ_8192: + s->receive_buf_size = 8192; + break; + case E1000_RCTL_SZ_4096: + s->receive_buf_size = 4096; + break; + } + } else { + switch (reg_buf_size) { + case E1000_RCTL_SZ_2048: + s->receive_buf_size = 2048; + break; + case E1000_RCTL_SZ_1024: + s->receive_buf_size = 1024; + break; + case E1000_RCTL_SZ_512: + s->receive_buf_size = 512; + break; + case E1000_RCTL_SZ_256: + s->receive_buf_size = 256; + break; + } + } + + EDBGOUT("RDT: %d, rctl = 0x%x\n", s->rdt, s->rctl); +} + +uint32_t e1000_get_interrupt_cause(struct e1000_vmhw_st *s) +{ + uint32_t icr = s->icr; + e1000_set_interrupt_cause(s, 0); + return icr; +} + +uint32_t e1000_get_control(struct e1000_vmhw_st *s) +{ + uint32_t reg; + + reg = (E1000_CTRL_SWDPIN2 | E1000_CTRL_SWDPIN0 | E1000_CTRL_SPD_1000 | + E1000_CTRL_SLU | E1000_CTRL_LRST); + + /* 00140248 */ + + EDBGOUT("e1000_mmio_readl CTRL val=0x%08x\n", reg); + + return reg; +} + +void e1000_set_control(struct e1000_vmhw_st *s, uint32_t val) +{ + EDBGOUT("e1000_mmio_write CTRL val=0x%08x\n", val); +} + +void e1000_set_eeprom_semaphore(struct e1000_vmhw_st *s, uint32_t val) +{ + s->eeprom_semaphore = val; +} + +uint32_t e1000_get_eeprom_semaphore(struct e1000_vmhw_st *s) +{ + return s->eeprom_semaphore; +} + +void e1000_set_mdic(struct e1000_vmhw_st *s, uint32_t val) +{ + uint32_t phy_addr; + uint32_t reg_addr; + uint32_t reg_value; + + reg_value = val & E1000_MDIC_DATA_MASK; + reg_addr = ((val & E1000_MDIC_REG_MASK) >> E1000_MDIC_REG_SHIFT); + phy_addr = ((val & E1000_MDIC_PHY_MASK) >> E1000_MDIC_PHY_SHIFT); + + if (phy_addr != 1) + goto exit; + + s->mdic = val; + + if (val & E1000_MDIC_OP_READ) { + EDBGOUT("MDIC read reg 0x%x\n", reg_addr); + + switch (reg_addr) { + case PHY_STATUS: + case PHY_ID1: + case PHY_ID2: + case PHY_CTRL: + case M88E1000_PHY_SPEC_CTRL: + case M88E1000_EXT_PHY_SPEC_CTRL: + case PHY_AUTONEG_ADV: + case PHY_1000T_CTRL: + s->mdic |= s->phy_regs[reg_addr] | E1000_MDIC_READY; + return; + default: + EDBGOUT("MDIC read reg unhandled\n"); + break; + } + } else if (val & E1000_MDIC_OP_WRITE) { + EDBGOUT("MDIC write reg 0x%x, value 0x%x\n", reg_addr, reg_value); + switch (reg_addr) { + case M88E1000_PHY_SPEC_CTRL: + case M88E1000_EXT_PHY_SPEC_CTRL: + case PHY_CTRL: + case PHY_AUTONEG_ADV: + case PHY_1000T_CTRL: + s->phy_regs[reg_addr] = reg_value; + s->mdic |= E1000_MDIC_READY; + return; + default: + EDBGOUT("MDIC write reg unhandled\n"); + break; + } + } + + exit: + s->mdic |= E1000_MDIC_ERROR; +} + +uint32_t e1000_get_mdic(struct e1000_vmhw_st *s) +{ + return s->mdic; +} + +uint32_t e1000_get_status(struct e1000_vmhw_st *s) +{ + uint32_t reg; + reg = 0x80000000; + reg |= E1000_STATUS_GIO_MASTER_ENABLE | + E1000_STATUS_ASDV | E1000_STATUS_MTXCKOK | + E1000_STATUS_SPEED_1000; + + reg |= E1000_STATUS_FD | E1000_STATUS_LU; + return reg; +} + +uint32_t e1000_get_flash_control(struct e1000_vmhw_st *s) +{ + uint32_t reg = 0; + + reg = 0x08 << E1000_EECD_SECVAL_SHIFT; + reg |= 0x10000; + reg |= 3 << E1000_EECD_SIZE_EX_SHIFT; + reg |= E1000_EECD_PRES; + reg |= E1000_EECD_SIZE; + reg |= E1000_EECD_FWE_DIS; + reg |= E1000_EECD_DO; + + //EDBGOUT("ECD: %08x\n", reg); + + return reg; +} + +uint32_t e1000_get_management_control(struct e1000_vmhw_st *s) +{ + return (E1000_MANC_EN_MNG2HOST | + E1000_MANC_RCV_TCO_EN | + E1000_MANC_ARP_EN | + E1000_MANC_0298_EN | + E1000_MANC_RMCP_EN); +} + +void e1000_flash_eerd_write(struct e1000_vmhw_st *s, uint32_t val) +{ + s->eeprom_offset_to_read = val; +} + +uint32_t e1000_flash_eerd_read(struct e1000_vmhw_st *s) +{ + unsigned int index; + + index = (s->eeprom_offset_to_read - E1000_EEPROM_RW_REG_START) >> E1000_EEPROM_RW_ADDR_SHIFT; + + if (index >= 0 && index <= EEPROM_CHECKSUM_REG) { + uint32_t reg; + reg = s->eeprom_data.raw[index]; + reg <<= E1000_EEPROM_RW_REG_DATA; + reg |= E1000_EEPROM_RW_REG_DONE | (s->eeprom_offset_to_read - E1000_EEPROM_RW_REG_START); + return reg; + } + + return 0; +} + +void e1000_set_transmit_descriptor(struct e1000_vmhw_st *s, uint32_t val) +{ + uint32_t index; + target_phys_addr_t base; + struct e1000_tx_desc desc; + char packet_data[0x8000]; + unsigned int packet_size; + unsigned int split_size; + + s->tdt = val; + packet_size = 0; + + while (s->tdh != s->tdt) { + index = s->tdh; + + base = s->tdb + sizeof(struct e1000_tx_desc) * index; + memset(&desc, 0, sizeof(desc)); + cpu_physical_memory_read(base, (void *)&desc, sizeof(desc)); + + EDBGOUT("index %d: %p : %x %x\n", index, + (void *)desc.buffer_addr, desc.lower.data, desc.upper.data); + + split_size = desc.lower.flags.length; + + if (split_size) { + cpu_physical_memory_read(desc.buffer_addr, (void *)&packet_data[packet_size], + split_size); + packet_size += split_size; + } + + desc.upper.data |= E1000_TXD_STAT_DD; + cpu_physical_memory_write(base, &desc, sizeof(desc)); + + if (desc.lower.data & E1000_TXD_CMD_EOP) { + EDBGOUT("packet whose size is %d\n", packet_size); + qemu_send_packet(s->vc, packet_data, packet_size); + packet_size = 0; + } + + s->tdh++; + + if (base == s->tdb + s->tdlen - sizeof(desc)) + s->tdh = 0; + } +} + +static void e1000_receive(void *opaque, const uint8_t *buf, int size) +{ + struct e1000_vmhw_st *s = opaque; + struct e1000_rx_desc desc; + target_phys_addr_t base; + unsigned int index; + + + EDBGOUT("e1000_receive: %d\n", size); + + if (!(s->rctl & E1000_RCTL_EN)) + return; + + if (s->rdh == s->rdt) + return; + + if (size > s->receive_buf_size) { + EDBGOUT("packet too large for buffers (%d > %d)\n", + size, s->receive_buf_size); + return; + } + + size += 4; /* for the header */ + index = s->rdh; + base = s->rdb + sizeof(desc) * index; + cpu_physical_memory_read(base, (void *)&desc, sizeof(desc)); + cpu_physical_memory_write(desc.buffer_addr, (void *)buf, size); + desc.length = size; + desc.status |= E1000_RXD_STAT_DD; + desc.status |= E1000_RXD_STAT_EOP; + cpu_physical_memory_write(base, (void *)&desc, sizeof(desc)); + + s->rdh++; + if (base == s->rdb + s->rdlen - sizeof(desc)) + s->rdh = 0; + + e1000_set_interrupt_cause(s, E1000_ICS_RXDMT0); +} + +void e1000_set_receive_descriptor(struct e1000_vmhw_st *s, uint32_t val) +{ + s->rdt = val; +} + +static int e1000_can_receive(void *opaque) +{ + struct e1000_vmhw_st *s = opaque; + + if (!(s->rctl & E1000_RCTL_EN)) + return 1; + + if (s->rdh == s->rdt) + return 1; + + return 0; +} + +static void e1000_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + struct e1000_vmhw_st *s = opaque; + + switch (addr - s->mmio_base) { + case E1000_TDLEN: + s->tdlen = val; + break; + case E1000_TDBAH: + s->tdb &= 0x00000000ffffffff; + s->tdb |= ((uint64_t)val) << 32; + break; + case E1000_TDBAL: + s->tdb &= 0xffffffff00000000; + s->tdb |= val; + break; + case E1000_TDH: + s->tdh = val; + break; + case E1000_TDT: + e1000_set_transmit_descriptor(s, val); + break; + + case E1000_RDLEN: + s->rdlen = val; + break; + case E1000_RDBAH: + s->rdb &= 0x00000000ffffffff; + s->rdb |= ((uint64_t)val) << 32; + break; + case E1000_RDBAL: + s->rdb &= 0xffffffff00000000; + s->rdb |= val; + break; + case E1000_RDH: + s->rdh = val; + break; + case E1000_RDT: + e1000_set_receive_descriptor(s, val); + break; + + case E1000_STATUS: + EDBGOUT("e1000_mmio_writel STATUS 0x%04x\n", val); + break; + case E1000_CTRL: + e1000_set_control(s, val); + break; + case E1000_SWSM: + e1000_set_eeprom_semaphore(s, val); + break; + case E1000_IMC: + e1000_clear_interrupt_mask(s, val); + break; + case E1000_IMS: + e1000_set_interrupt_mask(s, val); + break; + case E1000_MDIC: + e1000_set_mdic(s, val); + break; + case E1000_ICR: + EDBGOUT("e1000_mmio_writel ICR val=0x%08x\n", val); + break; + case E1000_ICS: + e1000_set_interrupt_cause(s, val); + break; + case E1000_RCTL: + e1000_set_receive_control(s, val); + break; + case E1000_TCTL: + EDBGOUT("e1000_mmio_writel TCTL val=0x%08x\n", val); + break; + case E1000_EERD: + e1000_flash_eerd_write(s, val); + break; + default: + EDBGUNKOUT("MMIO unknown write addr=0x%08x,val=0x%08x\n", addr - s->mmio_base, val); + break; + } + +} + +static uint32_t e1000_mmio_readl(void *opaque, target_phys_addr_t addr) +{ + struct e1000_vmhw_st *s = opaque; + + switch (addr - s->mmio_base) { + case E1000_CRCERRS ... E1000_ICRXOC: + /* statistics - return zero for now */ + return 0; + case E1000_TDH: + return s->tdh; + case E1000_CTRL: + return e1000_get_control(s); + case E1000_STATUS: + return e1000_get_status(s); + case E1000_SWSM: + return e1000_get_eeprom_semaphore(s); + case E1000_ICR: + return e1000_get_interrupt_cause(s); + case E1000_MDIC: + return e1000_get_mdic(s); + case E1000_EECD: + return e1000_get_flash_control(s); + case E1000_EERD: + return e1000_flash_eerd_read(s); + case E1000_MANC: + return e1000_get_management_control(s); + case E1000_RCTL: + return e1000_get_receive_control(s); + default: + EDBGUNKOUT("MMIO unknown read addr=0x%08x\n", addr - s->mmio_base); + break; + } + + return 0; +} + +struct e1000_eeprom e1000_eeprom_template = { .raw = { + 0x0000, 0x0000, 0x0000, 0x0d30, 0xf746, 0x00f4, 0xffff, 0xffff, + 0xffff, 0xffff, 0x026b, 0x108c, 0x15d9, 0x108c, 0x8086, 0x83df, + 0x0008, 0x2000, 0x7e14, 0x0048, 0x1000, 0x00d8, 0x0000, 0x2700, + 0x6cc9, 0x3150, 0x0722, 0x040b, 0x0984, 0x0000, 0xc000, 0x0706, + 0x1008, 0x0000, 0x0f04, 0x7fff, 0x4d01, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0x0100, 0x4000, 0x121c, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x0000, +}}; + +static void e1000_common_init(e1000_vmhw *d, NICInfo *nd, const char *info_str) +{ + uint16_t checksum = 0; + int i; + + d->nd = nd; + d->eeprom_data = e1000_eeprom_template; + d->eeprom_data.raw[0] = (nd->macaddr[1] << 8) | nd->macaddr[0]; + d->eeprom_data.raw[1] = (nd->macaddr[3] << 8) | nd->macaddr[2]; + d->eeprom_data.raw[2] = (nd->macaddr[5] << 8) | nd->macaddr[4]; + for (i=0; i < EEPROM_CHECKSUM_REG; i++) + checksum += d->eeprom_data.raw[i]; + checksum = (uint16_t) EEPROM_SUM - checksum; + d->eeprom_data.raw[EEPROM_CHECKSUM_REG] = checksum; + + d->phy_regs[PHY_CTRL] = 0x1140; + d->phy_regs[PHY_STATUS] = 0x7949; + d->phy_regs[PHY_ID1] = 0x141; + d->phy_regs[PHY_ID2] = 0xcc2; + d->phy_regs[PHY_1000T_CTRL] = 0x0e00; + d->phy_regs[M88E1000_PHY_SPEC_CTRL] = 0x360; + d->phy_regs[M88E1000_EXT_PHY_SPEC_CTRL] = 0x0d60; + d->phy_regs[PHY_AUTONEG_ADV] = 0xde1; + d->rctl = 0; + + d->interrupt_mask = ~0; + + EDBGOUT("eeprom checksum: 0x%04x\n", checksum); + + d->vc = qemu_new_vlan_client(nd->vlan, e1000_receive, + e1000_can_receive, d); + + snprintf(d->vc->info_str, sizeof(d->vc->info_str), + "e1000 macaddr=%02x:%02x:%02x:%02x:%02x:%02x", + d->nd->macaddr[0], + d->nd->macaddr[1], + d->nd->macaddr[2], + d->nd->macaddr[3], + d->nd->macaddr[4], + d->nd->macaddr[5]); +} + +/* PCI interface */ + +static CPUWriteMemoryFunc *e1000_mmio_write[] = { + (CPUWriteMemoryFunc *)&e1000_mmio_writeb, + (CPUWriteMemoryFunc *)&e1000_mmio_writew, + (CPUWriteMemoryFunc *)&e1000_mmio_writel +}; + +static CPUReadMemoryFunc *e1000_mmio_read[] = { + (CPUReadMemoryFunc *)&e1000_mmio_readb, + (CPUReadMemoryFunc *)&e1000_mmio_readw, + (CPUReadMemoryFunc *)&e1000_mmio_readl +}; + +static void e1000_mmio_map(PCIDevice *pci_dev, int region_num, + uint32_t addr, uint32_t size, int type) +{ + e1000_vmhw *d = (e1000_vmhw *)pci_dev; + + EDBGOUT("e1000_mmio_map addr=0x%08x 0x%08x\n", addr, size); + + d->mmio_base = addr; + cpu_register_physical_memory(addr, E1000_PNPMMIO_SIZE, d->mmio_index); +} + +void pci_e1000_init(PCIBus *bus, NICInfo *nd, int devfn) +{ + e1000_vmhw *d; + uint8_t *pci_conf; + + d = (e1000_vmhw *)pci_register_device(bus, "e1000", sizeof(e1000_vmhw), + devfn, NULL, NULL); + + pci_conf = d->dev.config; + + *(uint16_t *)&pci_conf[0x00] = cpu_to_le16(0x8086); + *(uint16_t *)&pci_conf[0x02] = cpu_to_le16(0x109a); + *(uint16_t *)&pci_conf[0x04] = cpu_to_le16(0x0407); + *(uint16_t *)&pci_conf[0x06] = cpu_to_le16(0x0010); + pci_conf[0x08] = 0x03; + pci_conf[0x09] = 0x00; + pci_conf[0x0a] = 0x00; // ethernet network controller + pci_conf[0x0b] = 0x02; + + pci_conf[0x0c] = 0x10; + pci_conf[0x0d] = 0x00; + pci_conf[0x0e] = 0x00; + pci_conf[0x0f] = 0x00; + + *(uint32_t *)&pci_conf[0x10] = cpu_to_le32(0xe0300000); + *(uint32_t *)&pci_conf[0x14] = cpu_to_le32(0x00000000); + + pci_conf[0x3d] = 1; // interrupt pin 0 + pci_conf[0x3e] = 0x00; + pci_conf[0x3f] = 0x00; + + /* Handler for memory-mapped I/O */ + d->mmio_index = + cpu_register_io_memory(0, e1000_mmio_read, e1000_mmio_write, d); + + pci_register_io_region((PCIDevice *)d, 0, E1000_PNPMMIO_SIZE, + PCI_ADDRESS_SPACE_MEM, e1000_mmio_map); + + pci_register_io_region((PCIDevice *)d, 1, E1000_IOPORT_SIZE, + PCI_ADDRESS_SPACE_IO, e1000_ioport_map); + + e1000_common_init(d, nd, "e1000"); +} diff --git a/qemu/hw/pci.c b/qemu/hw/pci.c index b895f98..6d3be5c 100644 --- a/qemu/hw/pci.c +++ b/qemu/hw/pci.c @@ -552,6 +552,8 @@ void pci_nic_init(PCIBus *bus, NICInfo *nd, int devfn) pci_rtl8139_init(bus, nd, devfn); } else if (strcmp(nd->model, "pcnet") == 0) { pci_pcnet_init(bus, nd, devfn); + } else if (strcmp(nd->model, "e1000") == 0) { + pci_e1000_init(bus, nd, devfn); } else { fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd->model); exit (1); -- Dan Aloni XIV LTD, http://www.xivstorage.com da-x (at) monatomic.org, dan (at) xiv.co.il