diff --git a/hw/e1000.c b/hw/e1000.c
index 532efdc..d02c8aa 100644
--- a/hw/e1000.c
+++ b/hw/e1000.c
@@ -57,6 +57,9 @@ static int debugflags = DBGBIT(TXERR) | DBGBIT(GENERAL);
 #define PNPMMIO_SIZE      0x20000
 #define MIN_BUF_SIZE      60 /* Min. octets in an ethernet frame sans FCS */
 
+#define REG_IOADDR 0x0
+#define REG_IODATA 0x4
+
 /*
  * HW models:
  *  E1000_DEV_ID_82540EM works with Windows and Linux
@@ -82,6 +85,8 @@ typedef struct E1000State_st {
     NICState *nic;
     NICConf conf;
     int mmio_index;
+    int ioport_base;
+    uint32_t ioport_reg[2];
 
     uint32_t mac_reg[0x8000];
     uint16_t phy_reg[0x20];
@@ -149,13 +154,7 @@ static const char phy_regcap[0x20] = {
     [PHY_ID2] = PHY_R,		[M88E1000_PHY_SPEC_STATUS] = PHY_R
 };
 
-static void
-ioport_map(PCIDevice *pci_dev, int region_num, pcibus_t addr,
-           pcibus_t size, int type)
-{
-    DBGOUT(IO, "e1000_ioport_map addr=0x%04"FMT_PCIBUS
-           " size=0x%08"FMT_PCIBUS"\n", addr, size);
-}
+static void e1000_reset(void *opaque);
 
 static void
 set_interrupt_cause(E1000State *s, int index, uint32_t val)
@@ -201,6 +200,11 @@ rxbufsize(uint32_t v)
 static void
 set_ctrl(E1000State *s, int index, uint32_t val)
 {
+    DBGOUT(IO, "set ctrl = %08x\n", val);
+    if (val & E1000_CTRL_RST) {
+        s->mac_reg[CTRL] = val;
+        e1000_reset(s);
+    }
     /* RST is self clearing */
     s->mac_reg[CTRL] = val & ~E1000_CTRL_RST;
 }
@@ -623,7 +627,7 @@ e1000_can_receive(VLANClientState *nc)
 {
     E1000State *s = DO_UPCAST(NICState, nc, nc)->opaque;
 
-    return (s->mac_reg[RCTL] & E1000_RCTL_EN);
+    return (s->mac_reg[RCTL] & E1000_RCTL_EN && s->mac_reg[RDLEN] != 0);
 }
 
 static ssize_t
@@ -666,6 +670,11 @@ e1000_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
         size -= 4;
     }
 
+    if (s->mac_reg[RDLEN] == 0) {
+        DBGOUT(RX, "receive descriptor buffer not set\n");
+        return -1;
+    }
+
     rdh_start = s->mac_reg[RDH];
     do {
         if (s->mac_reg[RDH] == s->mac_reg[RDT] && s->check_rxov) {
@@ -847,6 +856,60 @@ static void (*macreg_writeops[])(E1000State *, int, uint32_t) = {
 enum { NWRITEOPS = ARRAY_SIZE(macreg_writeops) };
 
 static void
+e1000_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
+{
+    E1000State *s = opaque;
+
+    if (addr == s->ioport_base + REG_IOADDR) {
+        DBGOUT(IO, "e1000_ioport_writel write base: 0x%04x\n", val);
+        s->ioport_reg[REG_IOADDR] = val & 0xfffff;
+    } else if (addr == (s->ioport_base + REG_IODATA)) {
+        unsigned int index = (s->ioport_reg[REG_IOADDR] & 0x1ffff) >> 2;
+
+#ifdef TARGET_WORDS_BIGENDIAN
+        val = bswap32(val);
+#endif
+        DBGOUT(IO, "e1000_ioport_writel %x: 0x%04x\n", index, val);
+
+        if (index < NWRITEOPS && macreg_writeops[index]) {
+            macreg_writeops[index](s, index, val);
+        } else if (index < NREADOPS && macreg_readops[index]) {
+            DBGOUT(IO, "e1000_ioport_writel RO %x: 0x%04x\n", index << 2, val);
+        } else {
+            DBGOUT(UNKNOWN, "IO unknown write index=0x%08x,val=0x%08x\n",
+                   index, val);
+        }
+    } else {
+        DBGOUT(UNKNOWN, "IO unknown write addr=0x%08x,val=0x%08x\n",
+               addr, val);
+    }
+}
+
+static uint32_t
+e1000_ioport_readl(void *opaque, uint32_t addr)
+{
+    E1000State *s = opaque;
+
+    if (addr == s->ioport_base + REG_IOADDR) {
+        return s->ioport_reg[REG_IOADDR] & 0xfffff;
+    } else if (addr == (s->ioport_base + REG_IODATA)) {
+        unsigned int index = (s->ioport_reg[REG_IOADDR] & 0x1ffff) >> 2;
+
+        if (index < NREADOPS && macreg_readops[index]) {
+            uint32_t val = macreg_readops[index](s, index);
+#ifdef TARGET_WORDS_BIGENDIAN
+            val = bswap32(val);
+#endif
+            return val;
+        }
+        DBGOUT(UNKNOWN, "IO unknown read addr=0x%08x\n", index<<2);
+    } else {
+        DBGOUT(UNKNOWN, "IO unknown read addr=0x%08x\n", addr);
+    }
+    return 0;
+}
+
+static void
 e1000_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
 {
     E1000State *s = opaque;
@@ -1031,6 +1094,30 @@ static const uint32_t mac_reg_init[] = {
 
 /* PCI interface */
 
+static void
+e1000_ioport_map(PCIDevice *pci_dev, int region_num, pcibus_t addr,
+                 pcibus_t size, int type)
+{
+    E1000State *d = DO_UPCAST(E1000State, dev, pci_dev);
+
+    DBGOUT(IO, "e1000_ioport_map addr=0x%04" FMT_PCIBUS
+           " size=0x%08" FMT_PCIBUS "\n", addr, size);
+
+    d->ioport_base = addr;
+
+    /* Writes that are less than 32 bits are ignored on IOADDR.
+     * For the Flash access, a write can be less than 32 bits for
+     * IODATA register, but is not handled.
+     */
+
+    register_ioport_read(addr, size, 1, e1000_ioport_readl, d);
+
+    register_ioport_read(addr, size, 2, e1000_ioport_readl, d);
+
+    register_ioport_write(addr, size, 4, e1000_ioport_writel, d);
+    register_ioport_read(addr, size, 4, e1000_ioport_readl, d);
+}
+
 static CPUWriteMemoryFunc * const e1000_mmio_write[] = {
     e1000_mmio_writeb,	e1000_mmio_writew,	e1000_mmio_writel
 };
@@ -1085,6 +1172,7 @@ static void e1000_reset(void *opaque)
 {
     E1000State *d = opaque;
 
+    memset(d->ioport_reg, 0, sizeof d->ioport_reg);
     memset(d->phy_reg, 0, sizeof d->phy_reg);
     memmove(d->phy_reg, phy_reg_init, sizeof phy_reg_init);
     memset(d->mac_reg, 0, sizeof d->mac_reg);
@@ -1131,7 +1219,7 @@ static int pci_e1000_init(PCIDevice *pci_dev)
                            PCI_BASE_ADDRESS_SPACE_MEMORY, e1000_mmio_map);
 
     pci_register_bar((PCIDevice *)d, 1, IOPORT_SIZE,
-                           PCI_BASE_ADDRESS_SPACE_IO, ioport_map);
+                           PCI_BASE_ADDRESS_SPACE_IO, e1000_ioport_map);
 
     memmove(d->eeprom_data, e1000_eeprom_template,
         sizeof e1000_eeprom_template);
