X-Git-Url: https://repo.jachan.dev/qemu.git/blobdiff_plain/87ecb68bdf8a3e40ef885ddbb7ca1797dca40ebf..e17ba87c52fc7d4ccfd5074428ce19f1b876ba30:/hw/ne2000.c diff --git a/hw/ne2000.c b/hw/ne2000.c index 92023eb714..78fe14fe1c 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -24,6 +24,8 @@ #include "hw.h" #include "pci.h" #include "net.h" +#include "ne2000.h" +#include "loader.h" /* debug NE2000 card */ //#define DEBUG_NE2000 @@ -115,42 +117,17 @@ #define ENTSR_CDH 0x40 /* The collision detect "heartbeat" signal was lost. */ #define ENTSR_OWC 0x80 /* There was an out-of-window collision. */ -#define NE2000_PMEM_SIZE (32*1024) -#define NE2000_PMEM_START (16*1024) -#define NE2000_PMEM_END (NE2000_PMEM_SIZE+NE2000_PMEM_START) -#define NE2000_MEM_SIZE NE2000_PMEM_END - -typedef struct NE2000State { - uint8_t cmd; - uint32_t start; - uint32_t stop; - uint8_t boundary; - uint8_t tsr; - uint8_t tpsr; - uint16_t tcnt; - uint16_t rcnt; - uint32_t rsar; - uint8_t rsr; - uint8_t rxcr; - uint8_t isr; - uint8_t dcfg; - uint8_t imr; - uint8_t phys[6]; /* mac address */ - uint8_t curpag; - uint8_t mult[8]; /* multicast mask array */ - qemu_irq irq; - PCIDevice *pci_dev; - VLANClientState *vc; - uint8_t macaddr[6]; - uint8_t mem[NE2000_MEM_SIZE]; -} NE2000State; - -static void ne2000_reset(NE2000State *s) +typedef struct PCINE2000State { + PCIDevice dev; + NE2000State ne2000; +} PCINE2000State; + +void ne2000_reset(NE2000State *s) { int i; s->isr = ENISR_RESET; - memcpy(s->mem, s->macaddr, 6); + memcpy(s->mem, &s->c.macaddr, 6); s->mem[14] = 0x57; s->mem[15] = 0x57; @@ -211,9 +188,9 @@ static int ne2000_buffer_full(NE2000State *s) return 0; } -static int ne2000_can_receive(void *opaque) +int ne2000_can_receive(VLANClientState *nc) { - NE2000State *s = opaque; + NE2000State *s = DO_UPCAST(NICState, nc, nc)->opaque; if (s->cmd & E8390_STOP) return 1; @@ -222,9 +199,10 @@ static int ne2000_can_receive(void *opaque) #define MIN_BUF_SIZE 60 -static void ne2000_receive(void *opaque, const uint8_t *buf, int size) +ssize_t ne2000_receive(VLANClientState *nc, const uint8_t *buf, size_t size_) { - NE2000State *s = opaque; + NE2000State *s = DO_UPCAST(NICState, nc, nc)->opaque; + int size = size_; uint8_t *p; unsigned int total_len, next, avail, len, index, mcast_idx; uint8_t buf1[60]; @@ -236,7 +214,7 @@ static void ne2000_receive(void *opaque, const uint8_t *buf, int size) #endif if (s->cmd & E8390_STOP || ne2000_buffer_full(s)) - return; + return -1; /* XXX: check this */ if (s->rxcr & 0x10) { @@ -245,14 +223,14 @@ static void ne2000_receive(void *opaque, const uint8_t *buf, int size) if (!memcmp(buf, broadcast_macaddr, 6)) { /* broadcast address */ if (!(s->rxcr & 0x04)) - return; + return size; } else if (buf[0] & 0x01) { /* multicast */ if (!(s->rxcr & 0x08)) - return; + return size; mcast_idx = compute_mcast_idx(buf); if (!(s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7)))) - return; + return size; } else if (s->mem[0] == buf[0] && s->mem[2] == buf[1] && s->mem[4] == buf[2] && @@ -261,7 +239,7 @@ static void ne2000_receive(void *opaque, const uint8_t *buf, int size) s->mem[10] == buf[5]) { /* match */ } else { - return; + return size; } } @@ -314,9 +292,11 @@ static void ne2000_receive(void *opaque, const uint8_t *buf, int size) /* now we can signal we have received something */ s->isr |= ENISR_RX; ne2000_update_irq(s); + + return size_; } -static void ne2000_ioport_write(void *opaque, uint32_t addr, uint32_t val) +void ne2000_ioport_write(void *opaque, uint32_t addr, uint32_t val) { NE2000State *s = opaque; int offset, page, index; @@ -343,7 +323,7 @@ static void ne2000_ioport_write(void *opaque, uint32_t addr, uint32_t val) index -= NE2000_PMEM_SIZE; /* fail safe: check range on the transmitted length */ if (index + s->tcnt <= NE2000_PMEM_END) { - qemu_send_packet(s->vc, s->mem + index, s->tcnt); + qemu_send_packet(&s->nic->nc, s->mem + index, s->tcnt); } /* signal end of transfer */ s->tsr = ENTSR_PTX; @@ -413,7 +393,7 @@ static void ne2000_ioport_write(void *opaque, uint32_t addr, uint32_t val) } } -static uint32_t ne2000_ioport_read(void *opaque, uint32_t addr) +uint32_t ne2000_ioport_read(void *opaque, uint32_t addr) { NE2000State *s = opaque; int offset, page, ret; @@ -563,7 +543,7 @@ static inline void ne2000_dma_update(NE2000State *s, int len) } } -static void ne2000_asic_ioport_write(void *opaque, uint32_t addr, uint32_t val) +void ne2000_asic_ioport_write(void *opaque, uint32_t addr, uint32_t val) { NE2000State *s = opaque; @@ -583,7 +563,7 @@ static void ne2000_asic_ioport_write(void *opaque, uint32_t addr, uint32_t val) } } -static uint32_t ne2000_asic_ioport_read(void *opaque, uint32_t addr) +uint32_t ne2000_asic_ioport_read(void *opaque, uint32_t addr) { NE2000State *s = opaque; int ret; @@ -631,142 +611,77 @@ static uint32_t ne2000_asic_ioport_readl(void *opaque, uint32_t addr) return ret; } -static void ne2000_reset_ioport_write(void *opaque, uint32_t addr, uint32_t val) +void ne2000_reset_ioport_write(void *opaque, uint32_t addr, uint32_t val) { /* nothing to do (end of reset pulse) */ } -static uint32_t ne2000_reset_ioport_read(void *opaque, uint32_t addr) +uint32_t ne2000_reset_ioport_read(void *opaque, uint32_t addr) { NE2000State *s = opaque; ne2000_reset(s); return 0; } -static void ne2000_save(QEMUFile* f,void* opaque) -{ - NE2000State* s=(NE2000State*)opaque; - int tmp; - - if (s->pci_dev) - pci_device_save(s->pci_dev, f); - - qemu_put_8s(f, &s->rxcr); - - qemu_put_8s(f, &s->cmd); - qemu_put_be32s(f, &s->start); - qemu_put_be32s(f, &s->stop); - qemu_put_8s(f, &s->boundary); - qemu_put_8s(f, &s->tsr); - qemu_put_8s(f, &s->tpsr); - qemu_put_be16s(f, &s->tcnt); - qemu_put_be16s(f, &s->rcnt); - qemu_put_be32s(f, &s->rsar); - qemu_put_8s(f, &s->rsr); - qemu_put_8s(f, &s->isr); - qemu_put_8s(f, &s->dcfg); - qemu_put_8s(f, &s->imr); - qemu_put_buffer(f, s->phys, 6); - qemu_put_8s(f, &s->curpag); - qemu_put_buffer(f, s->mult, 8); - tmp = 0; - qemu_put_be32s(f, &tmp); /* ignored, was irq */ - qemu_put_buffer(f, s->mem, NE2000_MEM_SIZE); -} - -static int ne2000_load(QEMUFile* f,void* opaque,int version_id) +static int ne2000_post_load(void* opaque, int version_id) { - NE2000State* s=(NE2000State*)opaque; - int ret; - int tmp; - - if (version_id > 3) - return -EINVAL; - - if (s->pci_dev && version_id >= 3) { - ret = pci_device_load(s->pci_dev, f); - if (ret < 0) - return ret; - } - - if (version_id >= 2) { - qemu_get_8s(f, &s->rxcr); - } else { - s->rxcr = 0x0c; - } + NE2000State* s = opaque; - qemu_get_8s(f, &s->cmd); - qemu_get_be32s(f, &s->start); - qemu_get_be32s(f, &s->stop); - qemu_get_8s(f, &s->boundary); - qemu_get_8s(f, &s->tsr); - qemu_get_8s(f, &s->tpsr); - qemu_get_be16s(f, &s->tcnt); - qemu_get_be16s(f, &s->rcnt); - qemu_get_be32s(f, &s->rsar); - qemu_get_8s(f, &s->rsr); - qemu_get_8s(f, &s->isr); - qemu_get_8s(f, &s->dcfg); - qemu_get_8s(f, &s->imr); - qemu_get_buffer(f, s->phys, 6); - qemu_get_8s(f, &s->curpag); - qemu_get_buffer(f, s->mult, 8); - qemu_get_be32s(f, &tmp); /* ignored */ - qemu_get_buffer(f, s->mem, NE2000_MEM_SIZE); - - return 0; + if (version_id < 2) { + s->rxcr = 0x0c; + } + return 0; } -void isa_ne2000_init(int base, qemu_irq irq, NICInfo *nd) -{ - NE2000State *s; - - s = qemu_mallocz(sizeof(NE2000State)); - if (!s) - return; - - register_ioport_write(base, 16, 1, ne2000_ioport_write, s); - register_ioport_read(base, 16, 1, ne2000_ioport_read, s); - - register_ioport_write(base + 0x10, 1, 1, ne2000_asic_ioport_write, s); - register_ioport_read(base + 0x10, 1, 1, ne2000_asic_ioport_read, s); - register_ioport_write(base + 0x10, 2, 2, ne2000_asic_ioport_write, s); - register_ioport_read(base + 0x10, 2, 2, ne2000_asic_ioport_read, s); - - register_ioport_write(base + 0x1f, 1, 1, ne2000_reset_ioport_write, s); - register_ioport_read(base + 0x1f, 1, 1, ne2000_reset_ioport_read, s); - s->irq = irq; - 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 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]); - - register_savevm("ne2000", 0, 2, ne2000_save, ne2000_load, s); -} +const VMStateDescription vmstate_ne2000 = { + .name = "ne2000", + .version_id = 2, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .post_load = ne2000_post_load, + .fields = (VMStateField []) { + VMSTATE_UINT8_V(rxcr, NE2000State, 2), + VMSTATE_UINT8(cmd, NE2000State), + VMSTATE_UINT32(start, NE2000State), + VMSTATE_UINT32(stop, NE2000State), + VMSTATE_UINT8(boundary, NE2000State), + VMSTATE_UINT8(tsr, NE2000State), + VMSTATE_UINT8(tpsr, NE2000State), + VMSTATE_UINT16(tcnt, NE2000State), + VMSTATE_UINT16(rcnt, NE2000State), + VMSTATE_UINT32(rsar, NE2000State), + VMSTATE_UINT8(rsr, NE2000State), + VMSTATE_UINT8(isr, NE2000State), + VMSTATE_UINT8(dcfg, NE2000State), + VMSTATE_UINT8(imr, NE2000State), + VMSTATE_BUFFER(phys, NE2000State), + VMSTATE_UINT8(curpag, NE2000State), + VMSTATE_BUFFER(mult, NE2000State), + VMSTATE_UNUSED(4), /* was irq */ + VMSTATE_BUFFER(mem, NE2000State), + VMSTATE_END_OF_LIST() + } +}; + +static const VMStateDescription vmstate_pci_ne2000 = { + .name = "ne2000", + .version_id = 3, + .minimum_version_id = 3, + .minimum_version_id_old = 3, + .fields = (VMStateField []) { + VMSTATE_PCI_DEVICE(dev, PCINE2000State), + VMSTATE_STRUCT(ne2000, PCINE2000State, 0, vmstate_ne2000, NE2000State), + VMSTATE_END_OF_LIST() + } +}; /***********************************************************/ /* PCI NE2000 definitions */ -typedef struct PCINE2000State { - PCIDevice dev; - NE2000State ne2000; -} PCINE2000State; - static void ne2000_map(PCIDevice *pci_dev, int region_num, - uint32_t addr, uint32_t size, int type) + pcibus_t addr, pcibus_t size, int type) { - PCINE2000State *d = (PCINE2000State *)pci_dev; + PCINE2000State *d = DO_UPCAST(PCINE2000State, dev, pci_dev); NE2000State *s = &d->ne2000; register_ioport_write(addr, 16, 1, ne2000_ioport_write, s); @@ -783,45 +698,82 @@ static void ne2000_map(PCIDevice *pci_dev, int region_num, register_ioport_read(addr + 0x1f, 1, 1, ne2000_reset_ioport_read, s); } -void pci_ne2000_init(PCIBus *bus, NICInfo *nd, int devfn) +static void ne2000_cleanup(VLANClientState *nc) { - PCINE2000State *d; + NE2000State *s = DO_UPCAST(NICState, nc, nc)->opaque; + + s->nic = NULL; +} + +static NetClientInfo net_ne2000_info = { + .type = NET_CLIENT_TYPE_NIC, + .size = sizeof(NICState), + .can_receive = ne2000_can_receive, + .receive = ne2000_receive, + .cleanup = ne2000_cleanup, +}; + +static int pci_ne2000_init(PCIDevice *pci_dev) +{ + PCINE2000State *d = DO_UPCAST(PCINE2000State, dev, pci_dev); NE2000State *s; uint8_t *pci_conf; - d = (PCINE2000State *)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); + pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_REALTEK); + pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_REALTEK_8029); + pci_config_set_class(pci_conf, PCI_CLASS_NETWORK_ETHERNET); + pci_conf[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type + /* TODO: RST# value should be 0. PCI spec 6.2.4 */ + pci_conf[PCI_INTERRUPT_PIN] = 1; // interrupt pin 0 + + pci_register_bar(&d->dev, 0, 0x100, + PCI_BASE_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); + + qemu_macaddr_default_if_unset(&s->c.macaddr); 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); + + s->nic = qemu_new_nic(&net_ne2000_info, &s->c, + pci_dev->qdev.info->name, pci_dev->qdev.id, s); + qemu_format_nic_info_str(&s->nic->nc, s->c.macaddr.a); + + if (!pci_dev->qdev.hotplugged) { + static int loaded = 0; + if (!loaded) { + rom_add_option("pxe-ne2k_pci.bin"); + loaded = 1; + } + } + + return 0; +} + +static int pci_ne2000_exit(PCIDevice *pci_dev) +{ + PCINE2000State *d = DO_UPCAST(PCINE2000State, dev, pci_dev); + NE2000State *s = &d->ne2000; + + qemu_del_vlan_client(&s->nic->nc); + return 0; +} + +static PCIDeviceInfo ne2000_info = { + .qdev.name = "ne2k_pci", + .qdev.size = sizeof(PCINE2000State), + .qdev.vmsd = &vmstate_pci_ne2000, + .init = pci_ne2000_init, + .exit = pci_ne2000_exit, + .qdev.props = (Property[]) { + DEFINE_NIC_PROPERTIES(PCINE2000State, ne2000.c), + DEFINE_PROP_END_OF_LIST(), + } +}; + +static void ne2000_register_devices(void) +{ + pci_qdev_register(&ne2000_info); } + +device_init(ne2000_register_devices)