📄 dev_i8254x.c
字号:
else *data = d->fcal; break; /* Flow Control Address High */ case I8254X_REG_FCAH: if (op_type == MTS_WRITE) d->fcah = *data & 0xFFFF; else *data = d->fcah; break; /* Flow Control Type */ case I8254X_REG_FCT: if (op_type == MTS_WRITE) d->fct = *data & 0xFFFF; else *data = d->fct; break; /* RX Delay Timer */ case I8254X_REG_RDTR: case I82542_REG_RDTR: if (op_type == MTS_WRITE) d->rdtr = *data & 0xFFFF; else *data = d->rdtr; break;#if DEBUG_UNKNOWN default: if (op_type == MTS_READ) { cpu_log(cpu,d->name, "read access to unknown offset=0x%x, " "pc=0x%llx (size=%u)\n", offset,cpu_get_pc(cpu),op_size); } else { cpu_log(cpu,d->name, "write access to unknown offset=0x%x, pc=0x%llx, " "val=0x%llx (size=%u)\n", offset,cpu_get_pc(cpu),*data,op_size); }#endif } LVG_UNLOCK(d); return NULL;}/* Read a TX descriptor */static void txdesc_read(struct i8254x_data *d,m_uint64_t txd_addr, struct tx_desc *txd){ /* Get the descriptor from VM physical RAM */ physmem_copy_from_vm(d->vm,txd,txd_addr,sizeof(struct tx_desc)); /* byte-swapping */ txd->tdes[0] = vmtoh32(txd->tdes[0]); txd->tdes[1] = vmtoh32(txd->tdes[1]); txd->tdes[2] = vmtoh32(txd->tdes[2]); txd->tdes[3] = vmtoh32(txd->tdes[3]);}/* Handle the TX ring */static int dev_i8254x_handle_txring(struct i8254x_data *d){ m_uint64_t txd_addr,buf_addr; m_uint32_t buf_len,tot_len; m_uint32_t norm_len,icr; struct tx_desc txd; m_uint8_t *pkt_ptr; /* Transmit Enabled ? */ if (!(d->tctl & I8254X_TCTL_EN)) return(FALSE); /* If Head is at same position than Tail, the ring is empty */ if (d->tdh == d->tdt) return(FALSE); LVG_LOCK(d); /* Empty packet for now */ pkt_ptr = d->tx_buffer; tot_len = 0; icr = 0; while(d->tdh != d->tdt) { txd_addr = d->tx_addr + (d->tdh * sizeof(struct tx_desc)); txdesc_read(d,txd_addr,&txd); /* Copy the packet buffer */ buf_addr = ((m_uint64_t)txd.tdes[1] << 32) | txd.tdes[0]; buf_len = txd.tdes[2] & I8254X_TXDESC_LEN_MASK; //printf("COPYING DATA FROM 0x%8.8llx\n",buf_addr); norm_len = normalize_size(buf_len,4,0); physmem_copy_from_vm(d->vm,pkt_ptr,buf_addr,norm_len); mem_bswap32(pkt_ptr,norm_len); pkt_ptr += buf_len; tot_len += buf_len; /* Write the descriptor done bit if required */ if (txd.tdes[2] & I8254X_TXDESC_RS) { txd.tdes[3] |= I8254X_TXDESC_DD; icr |= I8254X_ICR_TXDW; physmem_copy_u32_to_vm(d->vm,txd_addr+0x0c,txd.tdes[3]); } /* Go to the next descriptor. Wrap ring if we are at end */ if (++d->tdh == (d->tdlen / sizeof(struct tx_desc))) d->tdh = 0; /* End of packet ? */ if (txd.tdes[2] & I8254X_TXDESC_EOP) {#if DEBUG_TRANSMIT LVG_LOG(d,"sending packet of %u bytes\n",tot_len); mem_dump(log_file,d->tx_buffer,tot_len);#endif netio_send(d->nio,d->tx_buffer,tot_len); break; } } if (d->tdh == d->tdt) icr |= I8254X_ICR_TXQE; /* Update the interrupt cause register and trigger IRQ if needed */ d->icr |= icr; dev_i8254x_update_irq_status(d); LVG_UNLOCK(d); return(TRUE);}/* Read a RX descriptor */static void rxdesc_read(struct i8254x_data *d,m_uint64_t rxd_addr, struct rx_desc *rxd){ /* Get the descriptor from VM physical RAM */ physmem_copy_from_vm(d->vm,rxd,rxd_addr,sizeof(struct rx_desc)); /* byte-swapping */ rxd->rdes[0] = vmtoh32(rxd->rdes[0]); rxd->rdes[1] = vmtoh32(rxd->rdes[1]); rxd->rdes[2] = vmtoh32(rxd->rdes[2]); rxd->rdes[3] = vmtoh32(rxd->rdes[3]);}/* * Put a packet in the RX ring. */static int dev_i8254x_receive_pkt(struct i8254x_data *d, u_char *pkt,ssize_t pkt_len){ m_uint64_t rxd_addr,buf_addr; m_uint32_t cur_len,norm_len,tot_len; struct rx_desc rxd; m_uint32_t icr; u_char *pkt_ptr; if (!d->rx_buf_size) return(FALSE); LVG_LOCK(d); pkt_ptr = pkt; tot_len = pkt_len; icr = 0; while(tot_len > 0) { /* No descriptor available: RX overrun condition */ if (d->rdh == d->rdt) { icr |= I8254X_ICR_RXO; break; } rxd_addr = d->rx_addr + (d->rdh * sizeof(struct rx_desc)); rxdesc_read(d,rxd_addr,&rxd); cur_len = (tot_len > d->rx_buf_size) ? d->rx_buf_size : tot_len; /* Copy the packet data into the RX buffer */ buf_addr = ((m_uint64_t)rxd.rdes[1] << 32) | rxd.rdes[0]; norm_len = normalize_size(cur_len,4,0); mem_bswap32(pkt_ptr,norm_len); physmem_copy_to_vm(d->vm,pkt_ptr,buf_addr,norm_len); tot_len -= cur_len; pkt_ptr += cur_len; /* Set length field */ rxd.rdes[2] = cur_len; /* Set the status */ rxd.rdes[3] = I8254X_RXDESC_IXSM|I8254X_RXDESC_DD; if (!tot_len) { rxd.rdes[3] |= I8254X_RXDESC_EOP; icr |= I8254X_ICR_RXT0; d->rx_irq_cnt++; rxd.rdes[2] += 4; /* FCS */ } /* Write back updated descriptor */ physmem_copy_u32_to_vm(d->vm,rxd_addr+0x08,rxd.rdes[2]); physmem_copy_u32_to_vm(d->vm,rxd_addr+0x0c,rxd.rdes[3]); /* Goto to the next descriptor, and wrap if necessary */ if (++d->rdh == (d->rdlen / sizeof(struct rx_desc))) d->rdh = 0; } /* Update the interrupt cause register and trigger IRQ if needed */ d->icr |= icr; dev_i8254x_update_irq_status(d); LVG_UNLOCK(d); return(TRUE);}/* Handle the RX ring */static int dev_i8254x_handle_rxring(netio_desc_t *nio, u_char *pkt,ssize_t pkt_len, struct i8254x_data *d){ /* * Don't start receive if RX has not been enabled in RCTL register. */ if (!(d->rctl & I8254X_RCTL_EN)) return(FALSE);#if DEBUG_RECEIVE LVG_LOG(d,"receiving a packet of %d bytes\n",pkt_len); mem_dump(log_file,pkt,pkt_len);#endif /* * Receive only multicast/broadcast trafic + unicast traffic * for this virtual machine. */ //if (dec21140_handle_mac_addr(d,pkt)) return(dev_i8254x_receive_pkt(d,pkt,pkt_len)); return(FALSE);}/* * pci_i8254x_read() * * Read a PCI register. */static m_uint32_t pci_i8254x_read(cpu_gen_t *cpu,struct pci_device *dev, int reg){ struct i8254x_data *d = dev->priv_data;#if DEBUG_PCI_REGS I8254X_LOG(d,"read PCI register 0x%x\n",reg);#endif switch (reg) { case 0x00: return((I8254X_PCI_PRODUCT_ID << 16) | I8254X_PCI_VENDOR_ID); case 0x08: return(0x02000003); case PCI_REG_BAR0: return(d->dev->phys_addr); default: return(0); }}/* * pci_i8254x_write() * * Write a PCI register. */static void pci_i8254x_write(cpu_gen_t *cpu,struct pci_device *dev, int reg,m_uint32_t value){ struct i8254x_data *d = dev->priv_data;#if DEBUG_PCI_REGS LVG_LOG(d,"write PCI register 0x%x, value 0x%x\n",reg,value);#endif switch(reg) { case PCI_REG_BAR0: vm_map_device(cpu->vm,d->dev,(m_uint64_t)value); LVG_LOG(d,"registers are mapped at 0x%x\n",value); break; }}/* * dev_i8254x_init() */struct i8254x_data *dev_i8254x_init(vm_instance_t *vm,char *name,int interface_type, struct pci_bus *pci_bus,int pci_device,int irq){ struct i8254x_data *d; struct pci_device *pci_dev; struct vdevice *dev; /* Allocate the private data structure for I8254X */ if (!(d = malloc(sizeof(*d)))) { fprintf(stderr,"%s (i8254x): out of memory\n",name); return NULL; } memset(d,0,sizeof(*d)); pthread_mutex_init(&d->lock,NULL); /* Add as PCI device */ pci_dev = pci_dev_add(pci_bus,name, I8254X_PCI_VENDOR_ID,I8254X_PCI_PRODUCT_ID, pci_device,0,irq, d,NULL,pci_i8254x_read,pci_i8254x_write); if (!pci_dev) { fprintf(stderr,"%s (i8254x): unable to create PCI device.\n",name); goto err_pci_dev; } /* Create the device itself */ if (!(dev = dev_create(name))) { fprintf(stderr,"%s (i8254x): unable to create device.\n",name); goto err_dev; } d->name = name; d->vm = vm; d->pci_dev = pci_dev; d->dev = dev; dev->phys_addr = 0; dev->phys_len = 0x10000; dev->handler = dev_i8254x_access; dev->priv_data = d; return(d); err_dev: pci_dev_remove(pci_dev); err_pci_dev: free(d); return NULL;}/* Remove an Intel i8254x device */void dev_i8254x_remove(struct i8254x_data *d){ if (d != NULL) { pci_dev_remove(d->pci_dev); vm_unbind_device(d->vm,d->dev); cpu_group_rebuild_mts(d->vm->cpu_group); free(d->dev); free(d); }}/* Bind a NIO to an Intel i8254x device */int dev_i8254x_set_nio(struct i8254x_data *d,netio_desc_t *nio){ /* check that a NIO is not already bound */ if (d->nio != NULL) return(-1); d->nio = nio; d->tx_tid = ptask_add((ptask_callback)dev_i8254x_handle_txring,d,NULL); netio_rxl_add(nio,(netio_rx_handler_t)dev_i8254x_handle_rxring,d,NULL); return(0);}/* Unbind a NIO from an Intel i8254x device */void dev_i8254x_unset_nio(struct i8254x_data *d){ if (d->nio != NULL) { ptask_remove(d->tx_tid); netio_rxl_remove(d->nio); d->nio = NULL; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -