📄 pcnet.c
字号:
/* * QEMU AMD PC-Net II (Am79C970A) emulation * * 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. */ /* This software was written to be compatible with the specification: * AMD Am79C970A PCnet-PCI II Ethernet Controller Data-Sheet * AMD Publication# 19436 Rev:E Amendment/0 Issue Date: June 2000 */ /* * On Sparc32, this is the Lance (Am7990) part of chip STP2000 (Master I/O), also * produced as NCR89C100. See * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C100.txt * and * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR92C990.txt *//* TODO: remove little endian host assumptions */ #include "vl.h"//#define PCNET_DEBUG//#define PCNET_DEBUG_IO//#define PCNET_DEBUG_BCR//#define PCNET_DEBUG_CSR//#define PCNET_DEBUG_RMD//#define PCNET_DEBUG_TMD//#define PCNET_DEBUG_MATCH#define PCNET_IOPORT_SIZE 0x20#define PCNET_PNPMMIO_SIZE 0x20typedef struct PCNetState_st PCNetState;struct PCNetState_st { PCIDevice dev; PCIDevice *pci_dev; VLANClientState *vc; NICInfo *nd; QEMUTimer *poll_timer; int mmio_index, rap, isr, lnkst; uint32_t rdra, tdra; uint8_t prom[16]; uint16_t csr[128]; uint16_t bcr[32]; uint64_t timer; int xmit_pos, recv_pos; uint8_t buffer[4096]; int tx_busy; void (*set_irq_cb)(void *s, int isr); void (*phys_mem_read)(void *dma_opaque, target_phys_addr_t addr, uint8_t *buf, int len, int do_bswap); void (*phys_mem_write)(void *dma_opaque, target_phys_addr_t addr, uint8_t *buf, int len, int do_bswap); void *dma_opaque;};/* XXX: using bitfields for target memory structures is almost surely not portable, so it should be suppressed ASAP */#ifdef __GNUC__#define PACKED_FIELD(A) A __attribute__ ((packed))#else#error FixMe#endifstruct qemu_ether_header { uint8_t ether_dhost[6]; uint8_t ether_shost[6]; uint16_t ether_type;};/* BUS CONFIGURATION REGISTERS */#define BCR_MSRDA 0#define BCR_MSWRA 1#define BCR_MC 2#define BCR_LNKST 4#define BCR_LED1 5#define BCR_LED2 6#define BCR_LED3 7#define BCR_FDC 9#define BCR_BSBC 18#define BCR_EECAS 19#define BCR_SWS 20#define BCR_PLAT 22#define BCR_DWIO(S) !!((S)->bcr[BCR_BSBC] & 0x0080)#define BCR_SSIZE32(S) !!((S)->bcr[BCR_SWS ] & 0x0100)#define BCR_SWSTYLE(S) ((S)->bcr[BCR_SWS ] & 0x00FF)#define CSR_INIT(S) !!(((S)->csr[0])&0x0001)#define CSR_STRT(S) !!(((S)->csr[0])&0x0002)#define CSR_STOP(S) !!(((S)->csr[0])&0x0004)#define CSR_TDMD(S) !!(((S)->csr[0])&0x0008)#define CSR_TXON(S) !!(((S)->csr[0])&0x0010)#define CSR_RXON(S) !!(((S)->csr[0])&0x0020)#define CSR_INEA(S) !!(((S)->csr[0])&0x0040)#define CSR_BSWP(S) !!(((S)->csr[3])&0x0004)#define CSR_LAPPEN(S) !!(((S)->csr[3])&0x0020)#define CSR_DXSUFLO(S) !!(((S)->csr[3])&0x0040)#define CSR_ASTRP_RCV(S) !!(((S)->csr[4])&0x0800)#define CSR_DPOLL(S) !!(((S)->csr[4])&0x1000)#define CSR_SPND(S) !!(((S)->csr[5])&0x0001)#define CSR_LTINTEN(S) !!(((S)->csr[5])&0x4000)#define CSR_TOKINTD(S) !!(((S)->csr[5])&0x8000)#define CSR_DRX(S) !!(((S)->csr[15])&0x0001)#define CSR_DTX(S) !!(((S)->csr[15])&0x0002)#define CSR_LOOP(S) !!(((S)->csr[15])&0x0004)#define CSR_DRCVPA(S) !!(((S)->csr[15])&0x2000)#define CSR_DRCVBC(S) !!(((S)->csr[15])&0x4000)#define CSR_PROM(S) !!(((S)->csr[15])&0x8000)#define CSR_CRBC(S) ((S)->csr[40])#define CSR_CRST(S) ((S)->csr[41])#define CSR_CXBC(S) ((S)->csr[42])#define CSR_CXST(S) ((S)->csr[43])#define CSR_NRBC(S) ((S)->csr[44])#define CSR_NRST(S) ((S)->csr[45])#define CSR_POLL(S) ((S)->csr[46])#define CSR_PINT(S) ((S)->csr[47])#define CSR_RCVRC(S) ((S)->csr[72])#define CSR_XMTRC(S) ((S)->csr[74])#define CSR_RCVRL(S) ((S)->csr[76])#define CSR_XMTRL(S) ((S)->csr[78])#define CSR_MISSC(S) ((S)->csr[112])#define CSR_IADR(S) ((S)->csr[ 1] | ((S)->csr[ 2] << 16))#define CSR_CRBA(S) ((S)->csr[18] | ((S)->csr[19] << 16))#define CSR_CXBA(S) ((S)->csr[20] | ((S)->csr[21] << 16))#define CSR_NRBA(S) ((S)->csr[22] | ((S)->csr[23] << 16))#define CSR_BADR(S) ((S)->csr[24] | ((S)->csr[25] << 16))#define CSR_NRDA(S) ((S)->csr[26] | ((S)->csr[27] << 16))#define CSR_CRDA(S) ((S)->csr[28] | ((S)->csr[29] << 16))#define CSR_BADX(S) ((S)->csr[30] | ((S)->csr[31] << 16))#define CSR_NXDA(S) ((S)->csr[32] | ((S)->csr[33] << 16))#define CSR_CXDA(S) ((S)->csr[34] | ((S)->csr[35] << 16))#define CSR_NNRD(S) ((S)->csr[36] | ((S)->csr[37] << 16))#define CSR_NNXD(S) ((S)->csr[38] | ((S)->csr[39] << 16))#define CSR_PXDA(S) ((S)->csr[60] | ((S)->csr[61] << 16))#define CSR_NXBA(S) ((S)->csr[64] | ((S)->csr[65] << 16))#define PHYSADDR(S,A) \ (BCR_SSIZE32(S) ? (A) : (A) | ((0xff00 & (uint32_t)(s)->csr[2])<<16))struct pcnet_initblk16 { uint16_t mode; uint16_t padr[3]; uint16_t ladrf[4]; uint32_t rdra; uint32_t tdra;};struct pcnet_initblk32 { uint16_t mode; uint8_t rlen; uint8_t tlen; uint16_t padr[3]; uint16_t _res; uint16_t ladrf[4]; uint32_t rdra; uint32_t tdra;};struct pcnet_TMD { struct { unsigned tbadr:32; } tmd0; struct { unsigned PACKED_FIELD(bcnt:12), PACKED_FIELD(ones:4), PACKED_FIELD(res:7), PACKED_FIELD(bpe:1); unsigned PACKED_FIELD(enp:1), PACKED_FIELD(stp:1), PACKED_FIELD(def:1), PACKED_FIELD(one:1); unsigned PACKED_FIELD(ltint:1), PACKED_FIELD(nofcs:1), PACKED_FIELD(err:1), PACKED_FIELD(own:1); } tmd1; struct { unsigned PACKED_FIELD(trc:4), PACKED_FIELD(res:12); unsigned PACKED_FIELD(tdr:10), PACKED_FIELD(rtry:1), PACKED_FIELD(lcar:1); unsigned PACKED_FIELD(lcol:1), PACKED_FIELD(exdef:1), PACKED_FIELD(uflo:1), PACKED_FIELD(buff:1); } tmd2; struct { unsigned res:32; } tmd3; };struct pcnet_RMD { struct { unsigned rbadr:32; } rmd0; struct { unsigned PACKED_FIELD(bcnt:12), PACKED_FIELD(ones:4), PACKED_FIELD(res:4); unsigned PACKED_FIELD(bam:1), PACKED_FIELD(lafm:1), PACKED_FIELD(pam:1), PACKED_FIELD(bpe:1); unsigned PACKED_FIELD(enp:1), PACKED_FIELD(stp:1), PACKED_FIELD(buff:1), PACKED_FIELD(crc:1); unsigned PACKED_FIELD(oflo:1), PACKED_FIELD(fram:1), PACKED_FIELD(err:1), PACKED_FIELD(own:1); } rmd1; struct { unsigned PACKED_FIELD(mcnt:12), PACKED_FIELD(zeros:4); unsigned PACKED_FIELD(rpc:8), PACKED_FIELD(rcc:8); } rmd2; struct { unsigned res:32; } rmd3; };#define PRINT_TMD(T) printf( \ "TMD0 : TBADR=0x%08x\n" \ "TMD1 : OWN=%d, ERR=%d, FCS=%d, LTI=%d, " \ "ONE=%d, DEF=%d, STP=%d, ENP=%d,\n" \ " BPE=%d, BCNT=%d\n" \ "TMD2 : BUF=%d, UFL=%d, EXD=%d, LCO=%d, " \ "LCA=%d, RTR=%d,\n" \ " TDR=%d, TRC=%d\n", \ (T)->tmd0.tbadr, \ (T)->tmd1.own, (T)->tmd1.err, (T)->tmd1.nofcs, \ (T)->tmd1.ltint, (T)->tmd1.one, (T)->tmd1.def, \ (T)->tmd1.stp, (T)->tmd1.enp, (T)->tmd1.bpe, \ 4096-(T)->tmd1.bcnt, \ (T)->tmd2.buff, (T)->tmd2.uflo, (T)->tmd2.exdef,\ (T)->tmd2.lcol, (T)->tmd2.lcar, (T)->tmd2.rtry, \ (T)->tmd2.tdr, (T)->tmd2.trc)#define PRINT_RMD(R) printf( \ "RMD0 : RBADR=0x%08x\n" \ "RMD1 : OWN=%d, ERR=%d, FRAM=%d, OFLO=%d, " \ "CRC=%d, BUFF=%d, STP=%d, ENP=%d,\n " \ "BPE=%d, PAM=%d, LAFM=%d, BAM=%d, ONES=%d, BCNT=%d\n" \ "RMD2 : RCC=%d, RPC=%d, MCNT=%d, ZEROS=%d\n", \ (R)->rmd0.rbadr, \ (R)->rmd1.own, (R)->rmd1.err, (R)->rmd1.fram, \ (R)->rmd1.oflo, (R)->rmd1.crc, (R)->rmd1.buff, \ (R)->rmd1.stp, (R)->rmd1.enp, (R)->rmd1.bpe, \ (R)->rmd1.pam, (R)->rmd1.lafm, (R)->rmd1.bam, \ (R)->rmd1.ones, 4096-(R)->rmd1.bcnt, \ (R)->rmd2.rcc, (R)->rmd2.rpc, (R)->rmd2.mcnt, \ (R)->rmd2.zeros)static inline void pcnet_tmd_load(PCNetState *s, struct pcnet_TMD *tmd1, target_phys_addr_t addr){ uint32_t *tmd = (uint32_t *)tmd1; if (!BCR_SWSTYLE(s)) { uint16_t xda[4]; s->phys_mem_read(s->dma_opaque, addr, (void *)&xda[0], sizeof(xda), 0); le16_to_cpus(&xda[0]); le16_to_cpus(&xda[1]); le16_to_cpus(&xda[2]); le16_to_cpus(&xda[3]); tmd[0] = (xda[0]&0xffff) | ((xda[1]&0x00ff) << 16); tmd[1] = (xda[2]&0xffff)| ((xda[1] & 0xff00) << 16); tmd[2] = (xda[3] & 0xffff) << 16; tmd[3] = 0; } else { uint32_t xda[4]; s->phys_mem_read(s->dma_opaque, addr, (void *)&xda[0], sizeof(xda), 0); le32_to_cpus(&xda[0]); le32_to_cpus(&xda[1]); le32_to_cpus(&xda[2]); le32_to_cpus(&xda[3]); if (BCR_SWSTYLE(s) != 3) { memcpy(tmd, xda, sizeof(xda)); } else { tmd[0] = xda[2]; tmd[1] = xda[1]; tmd[2] = xda[0]; tmd[3] = xda[3]; } }}static inline void pcnet_tmd_store(PCNetState *s, const struct pcnet_TMD *tmd1, target_phys_addr_t addr){ const uint32_t *tmd = (const uint32_t *)tmd1; if (!BCR_SWSTYLE(s)) { uint16_t xda[4]; xda[0] = tmd[0] & 0xffff; xda[1] = ((tmd[0]>>16)&0x00ff) | ((tmd[1]>>16)&0xff00); xda[2] = tmd[1] & 0xffff; xda[3] = tmd[2] >> 16; cpu_to_le16s(&xda[0]); cpu_to_le16s(&xda[1]); cpu_to_le16s(&xda[2]); cpu_to_le16s(&xda[3]); s->phys_mem_write(s->dma_opaque, addr, (void *)&xda[0], sizeof(xda), 0); } else { uint32_t xda[4]; if (BCR_SWSTYLE(s) != 3) { memcpy(xda, tmd, sizeof(xda)); } else { xda[0] = tmd[2]; xda[1] = tmd[1]; xda[2] = tmd[0]; xda[3] = tmd[3]; } cpu_to_le32s(&xda[0]); cpu_to_le32s(&xda[1]); cpu_to_le32s(&xda[2]); cpu_to_le32s(&xda[3]); s->phys_mem_write(s->dma_opaque, addr, (void *)&xda[0], sizeof(xda), 0); }}static inline void pcnet_rmd_load(PCNetState *s, struct pcnet_RMD *rmd1, target_phys_addr_t addr){ uint32_t *rmd = (uint32_t *)rmd1; if (!BCR_SWSTYLE(s)) { uint16_t rda[4]; s->phys_mem_read(s->dma_opaque, addr, (void *)&rda[0], sizeof(rda), 0); le16_to_cpus(&rda[0]); le16_to_cpus(&rda[1]); le16_to_cpus(&rda[2]); le16_to_cpus(&rda[3]); rmd[0] = (rda[0]&0xffff)| ((rda[1] & 0x00ff) << 16); rmd[1] = (rda[2]&0xffff)| ((rda[1] & 0xff00) << 16); rmd[2] = rda[3] & 0xffff; rmd[3] = 0; } else { uint32_t rda[4]; s->phys_mem_read(s->dma_opaque, addr, (void *)&rda[0], sizeof(rda), 0); le32_to_cpus(&rda[0]); le32_to_cpus(&rda[1]); le32_to_cpus(&rda[2]); le32_to_cpus(&rda[3]); if (BCR_SWSTYLE(s) != 3) { memcpy(rmd, rda, sizeof(rda)); } else { rmd[0] = rda[2]; rmd[1] = rda[1]; rmd[2] = rda[0]; rmd[3] = rda[3]; } }}static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd1, target_phys_addr_t addr){ const uint32_t *rmd = (const uint32_t *)rmd1; if (!BCR_SWSTYLE(s)) { uint16_t rda[4]; rda[0] = rmd[0] & 0xffff; rda[1] = ((rmd[0]>>16)&0xff)| ((rmd[1]>>16)&0xff00); rda[2] = rmd[1] & 0xffff; rda[3] = rmd[2] & 0xffff; cpu_to_le16s(&rda[0]); cpu_to_le16s(&rda[1]); cpu_to_le16s(&rda[2]); cpu_to_le16s(&rda[3]); s->phys_mem_write(s->dma_opaque, addr, (void *)&rda[0], sizeof(rda), 0); } else { uint32_t rda[4]; if (BCR_SWSTYLE(s) != 3) { memcpy(rda, rmd, sizeof(rda)); } else { rda[0] = rmd[2]; rda[1] = rmd[1]; rda[2] = rmd[0]; rda[3] = rmd[3]; } cpu_to_le32s(&rda[0]); cpu_to_le32s(&rda[1]); cpu_to_le32s(&rda[2]); cpu_to_le32s(&rda[3]); s->phys_mem_write(s->dma_opaque, addr, (void *)&rda[0], sizeof(rda), 0); }}#define TMDLOAD(TMD,ADDR) pcnet_tmd_load(s,TMD,ADDR)#define TMDSTORE(TMD,ADDR) pcnet_tmd_store(s,TMD,ADDR)#define RMDLOAD(RMD,ADDR) pcnet_rmd_load(s,RMD,ADDR)#define RMDSTORE(RMD,ADDR) pcnet_rmd_store(s,RMD,ADDR)#if 1#define CHECK_RMD(ADDR,RES) do { \ struct pcnet_RMD rmd; \ RMDLOAD(&rmd,(ADDR)); \ (RES) |= (rmd.rmd1.ones != 15) \ || (rmd.rmd2.zeros != 0); \} while (0)#define CHECK_TMD(ADDR,RES) do { \ struct pcnet_TMD tmd; \ TMDLOAD(&tmd,(ADDR)); \ (RES) |= (tmd.tmd1.ones != 15); \} while (0)#else#define CHECK_RMD(ADDR,RES) do { \ switch (BCR_SWSTYLE(s)) { \ case 0x00: \ do { \ uint16_t rda[4]; \ s->phys_mem_read(s->dma_opaque, (ADDR), \ (void *)&rda[0], sizeof(rda), 0); \ (RES) |= (rda[2] & 0xf000)!=0xf000; \ (RES) |= (rda[3] & 0xf000)!=0x0000; \ } while (0); \ break; \ case 0x01: \ case 0x02: \ do { \ uint32_t rda[4]; \ s->phys_mem_read(s->dma_opaque, (ADDR), \ (void *)&rda[0], sizeof(rda), 0); \ (RES) |= (rda[1] & 0x0000f000L)!=0x0000f000L; \ (RES) |= (rda[2] & 0x0000f000L)!=0x00000000L; \ } while (0); \ break; \ case 0x03: \ do { \ uint32_t rda[4]; \ s->phys_mem_read(s->dma_opaque, (ADDR), \ (void *)&rda[0], sizeof(rda), 0); \ (RES) |= (rda[0] & 0x0000f000L)!=0x00000000L; \ (RES) |= (rda[1] & 0x0000f000L)!=0x0000f000L; \ } while (0); \ break; \ } \} while (0)#define CHECK_TMD(ADDR,RES) do { \ switch (BCR_SWSTYLE(s)) { \ case 0x00: \ do { \ uint16_t xda[4]; \ s->phys_mem_read(s->dma_opaque, (ADDR), \ (void *)&xda[0], sizeof(xda), 0); \ (RES) |= (xda[2] & 0xf000)!=0xf000;\ } while (0); \ break; \ case 0x01: \ case 0x02: \ case 0x03: \ do { \ uint32_t xda[4]; \ s->phys_mem_read(s->dma_opaque, (ADDR), \ (void *)&xda[0], sizeof(xda), 0); \ (RES) |= (xda[1] & 0x0000f000L)!=0x0000f000L; \ } while (0); \ break; \ } \} while (0)#endif#define PRINT_PKTHDR(BUF) do { \ struct qemu_ether_header *hdr = (void *)(BUF); \ printf("packet dhost=%02x:%02x:%02x:%02x:%02x:%02x, " \ "shost=%02x:%02x:%02x:%02x:%02x:%02x, " \ "type=0x%04x\n", \ hdr->ether_dhost[0],hdr->ether_dhost[1],hdr->ether_dhost[2], \ hdr->ether_dhost[3],hdr->ether_dhost[4],hdr->ether_dhost[5], \ hdr->ether_shost[0],hdr->ether_shost[1],hdr->ether_shost[2], \ hdr->ether_shost[3],hdr->ether_shost[4],hdr->ether_shost[5], \ be16_to_cpu(hdr->ether_type)); \
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -