📄 e1000.c
字号:
tp->tso_frames++; } if (tp->sum_needed & E1000_TXD_POPTS_TXSM) putsum(tp->data, tp->size, tp->tucso, tp->tucss, tp->tucse); if (tp->sum_needed & E1000_TXD_POPTS_IXSM) putsum(tp->data, tp->size, tp->ipcso, tp->ipcss, tp->ipcse); qemu_send_packet(s->vc, tp->data, tp->size); s->mac_reg[TPT]++; s->mac_reg[GPTC]++; n = s->mac_reg[TOTL]; if ((s->mac_reg[TOTL] += s->tx.size) < n) s->mac_reg[TOTH]++;}static voidprocess_tx_desc(E1000State *s, struct e1000_tx_desc *dp){ uint32_t txd_lower = le32_to_cpu(dp->lower.data); uint32_t dtype = txd_lower & (E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D); unsigned int split_size = txd_lower & 0xffff, bytes, sz, op; unsigned int msh = 0xfffff, hdr = 0; uint64_t addr; struct e1000_context_desc *xp = (struct e1000_context_desc *)dp; struct e1000_tx *tp = &s->tx; if (dtype == E1000_TXD_CMD_DEXT) { // context descriptor op = le32_to_cpu(xp->cmd_and_length); tp->ipcss = xp->lower_setup.ip_fields.ipcss; tp->ipcso = xp->lower_setup.ip_fields.ipcso; tp->ipcse = le16_to_cpu(xp->lower_setup.ip_fields.ipcse); tp->tucss = xp->upper_setup.tcp_fields.tucss; tp->tucso = xp->upper_setup.tcp_fields.tucso; tp->tucse = le16_to_cpu(xp->upper_setup.tcp_fields.tucse); tp->paylen = op & 0xfffff; tp->hdr_len = xp->tcp_seg_setup.fields.hdr_len; tp->mss = le16_to_cpu(xp->tcp_seg_setup.fields.mss); tp->ip = (op & E1000_TXD_CMD_IP) ? 1 : 0; tp->tcp = (op & E1000_TXD_CMD_TCP) ? 1 : 0; tp->tse = (op & E1000_TXD_CMD_TSE) ? 1 : 0; tp->tso_frames = 0; if (tp->tucso == 0) { // this is probably wrong DBGOUT(TXSUM, "TCP/UDP: cso 0!\n"); tp->tucso = tp->tucss + (tp->tcp ? 16 : 6); } return; } else if (dtype == (E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D)){ // data descriptor tp->sum_needed = le32_to_cpu(dp->upper.data) >> 8; tp->cptse = ( txd_lower & E1000_TXD_CMD_TSE ) ? 1 : 0; } else // legacy descriptor tp->cptse = 0; addr = le64_to_cpu(dp->buffer_addr); if (tp->tse && tp->cptse) { hdr = tp->hdr_len; msh = hdr + tp->mss; do { bytes = split_size; if (tp->size + bytes > msh) bytes = msh - tp->size; cpu_physical_memory_read(addr, tp->data + tp->size, bytes); if ((sz = tp->size + bytes) >= hdr && tp->size < hdr) memmove(tp->header, tp->data, hdr); tp->size = sz; addr += bytes; if (sz == msh) { xmit_seg(s); memmove(tp->data, tp->header, hdr); tp->size = hdr; } } while (split_size -= bytes); } else if (!tp->tse && tp->cptse) { // context descriptor TSE is not set, while data descriptor TSE is set DBGOUT(TXERR, "TCP segmentaion Error\n"); } else { cpu_physical_memory_read(addr, tp->data + tp->size, split_size); tp->size += split_size; } if (!(txd_lower & E1000_TXD_CMD_EOP)) return; if (!(tp->tse && tp->cptse && tp->size < hdr)) xmit_seg(s); tp->tso_frames = 0; tp->sum_needed = 0; tp->size = 0; tp->cptse = 0;}static uint32_ttxdesc_writeback(target_phys_addr_t base, struct e1000_tx_desc *dp){ uint32_t txd_upper, txd_lower = le32_to_cpu(dp->lower.data); if (!(txd_lower & (E1000_TXD_CMD_RS|E1000_TXD_CMD_RPS))) return 0; txd_upper = (le32_to_cpu(dp->upper.data) | E1000_TXD_STAT_DD) & ~(E1000_TXD_STAT_EC | E1000_TXD_STAT_LC | E1000_TXD_STAT_TU); dp->upper.data = cpu_to_le32(txd_upper); cpu_physical_memory_write(base + ((char *)&dp->upper - (char *)dp), (void *)&dp->upper, sizeof(dp->upper)); return E1000_ICR_TXDW;}static voidstart_xmit(E1000State *s){ target_phys_addr_t base; struct e1000_tx_desc desc; uint32_t tdh_start = s->mac_reg[TDH], cause = E1000_ICS_TXQE; if (!(s->mac_reg[TCTL] & E1000_TCTL_EN)) { DBGOUT(TX, "tx disabled\n"); return; } while (s->mac_reg[TDH] != s->mac_reg[TDT]) { base = ((uint64_t)s->mac_reg[TDBAH] << 32) + s->mac_reg[TDBAL] + sizeof(struct e1000_tx_desc) * s->mac_reg[TDH]; cpu_physical_memory_read(base, (void *)&desc, sizeof(desc)); DBGOUT(TX, "index %d: %p : %x %x\n", s->mac_reg[TDH], (void *)desc.buffer_addr, desc.lower.data, desc.upper.data); process_tx_desc(s, &desc); cause |= txdesc_writeback(base, &desc); if (++s->mac_reg[TDH] * sizeof(desc) >= s->mac_reg[TDLEN]) s->mac_reg[TDH] = 0; /* * the following could happen only if guest sw assigns * bogus values to TDT/TDLEN. * there's nothing too intelligent we could do about this. */ if (s->mac_reg[TDH] == tdh_start) { DBGOUT(TXERR, "TDH wraparound @%x, TDT %x, TDLEN %x\n", tdh_start, s->mac_reg[TDT], s->mac_reg[TDLEN]); break; } } set_ics(s, 0, cause);}static intreceive_filter(E1000State *s, const uint8_t *buf, int size){ static uint8_t bcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; static int mta_shift[] = {4, 3, 2, 0}; uint32_t f, rctl = s->mac_reg[RCTL], ra[2], *rp; if (rctl & E1000_RCTL_UPE) // promiscuous return 1; if ((buf[0] & 1) && (rctl & E1000_RCTL_MPE)) // promiscuous mcast return 1; if ((rctl & E1000_RCTL_BAM) && !memcmp(buf, bcast, sizeof bcast)) return 1; for (rp = s->mac_reg + RA; rp < s->mac_reg + RA + 32; rp += 2) { if (!(rp[1] & E1000_RAH_AV)) continue; ra[0] = cpu_to_le32(rp[0]); ra[1] = cpu_to_le32(rp[1]); if (!memcmp(buf, (uint8_t *)ra, 6)) { DBGOUT(RXFILTER, "unicast match[%d]: %02x:%02x:%02x:%02x:%02x:%02x\n", (int)(rp - s->mac_reg - RA)/2, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]); return 1; } } DBGOUT(RXFILTER, "unicast mismatch: %02x:%02x:%02x:%02x:%02x:%02x\n", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]); f = mta_shift[(rctl >> E1000_RCTL_MO_SHIFT) & 3]; f = (((buf[5] << 8) | buf[4]) >> f) & 0xfff; if (s->mac_reg[MTA + (f >> 5)] & (1 << (f & 0x1f))) return 1; DBGOUT(RXFILTER, "dropping, inexact filter mismatch: %02x:%02x:%02x:%02x:%02x:%02x MO %d MTA[%d] %x\n", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], (rctl >> E1000_RCTL_MO_SHIFT) & 3, f >> 5, s->mac_reg[MTA + (f >> 5)]); return 0;}static inte1000_can_receive(void *opaque){ E1000State *s = opaque; return (!(s->mac_reg[RCTL] & E1000_RCTL_EN) || s->mac_reg[RDH] != s->mac_reg[RDT]);}static voide1000_receive(void *opaque, const uint8_t *buf, int size){ E1000State *s = opaque; struct e1000_rx_desc desc; target_phys_addr_t base; unsigned int n, rdt; uint32_t rdh_start; if (!(s->mac_reg[RCTL] & E1000_RCTL_EN)) return; if (size > s->rxbuf_size) { DBGOUT(RX, "packet too large for buffers (%d > %d)\n", size, s->rxbuf_size); return; } if (!receive_filter(s, buf, size)) return; rdh_start = s->mac_reg[RDH]; size += 4; // for the header do { if (s->mac_reg[RDH] == s->mac_reg[RDT] && s->check_rxov) { set_ics(s, 0, E1000_ICS_RXO); return; } base = ((uint64_t)s->mac_reg[RDBAH] << 32) + s->mac_reg[RDBAL] + sizeof(desc) * s->mac_reg[RDH]; cpu_physical_memory_read(base, (void *)&desc, sizeof(desc)); desc.status |= E1000_RXD_STAT_DD; if (desc.buffer_addr) { cpu_physical_memory_write(le64_to_cpu(desc.buffer_addr), (void *)buf, size); desc.length = cpu_to_le16(size); desc.status |= E1000_RXD_STAT_EOP|E1000_RXD_STAT_IXSM; } else // as per intel docs; skip descriptors with null buf addr DBGOUT(RX, "Null RX descriptor!!\n"); cpu_physical_memory_write(base, (void *)&desc, sizeof(desc)); if (++s->mac_reg[RDH] * sizeof(desc) >= s->mac_reg[RDLEN]) s->mac_reg[RDH] = 0; s->check_rxov = 1; /* see comment in start_xmit; same here */ if (s->mac_reg[RDH] == rdh_start) { DBGOUT(RXERR, "RDH wraparound @%x, RDT %x, RDLEN %x\n", rdh_start, s->mac_reg[RDT], s->mac_reg[RDLEN]); set_ics(s, 0, E1000_ICS_RXO); return; } } while (desc.buffer_addr == 0); s->mac_reg[GPRC]++; s->mac_reg[TPR]++; n = s->mac_reg[TORL]; if ((s->mac_reg[TORL] += size) < n) s->mac_reg[TORH]++; n = E1000_ICS_RXT0; if ((rdt = s->mac_reg[RDT]) < s->mac_reg[RDH]) rdt += s->mac_reg[RDLEN] / sizeof(desc); if (((rdt - s->mac_reg[RDH]) * sizeof(desc)) << s->rxbuf_min_shift >= s->mac_reg[RDLEN]) n |= E1000_ICS_RXDMT0; set_ics(s, 0, n);}static uint32_tmac_readreg(E1000State *s, int index){ return s->mac_reg[index];}static uint32_tmac_icr_read(E1000State *s, int index){ uint32_t ret = s->mac_reg[ICR]; DBGOUT(INTERRUPT, "ICR read: %x\n", ret); set_interrupt_cause(s, 0, 0); return ret;}static uint32_tmac_read_clr4(E1000State *s, int index){ uint32_t ret = s->mac_reg[index]; s->mac_reg[index] = 0; return ret;}static uint32_tmac_read_clr8(E1000State *s, int index){ uint32_t ret = s->mac_reg[index]; s->mac_reg[index] = 0; s->mac_reg[index-1] = 0; return ret;}static voidmac_writereg(E1000State *s, int index, uint32_t val){ s->mac_reg[index] = val;}static voidset_rdt(E1000State *s, int index, uint32_t val){ s->check_rxov = 0; s->mac_reg[index] = val & 0xffff;}static voidset_16bit(E1000State *s, int index, uint32_t val){ s->mac_reg[index] = val & 0xffff;}static voidset_dlen(E1000State *s, int index, uint32_t val){ s->mac_reg[index] = val & 0xfff80;}static voidset_tctl(E1000State *s, int index, uint32_t val){ s->mac_reg[index] = val; s->mac_reg[TDT] &= 0xffff; start_xmit(s);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -