⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dev_i8255x.c

📁 思科路由器仿真器,用来仿7200系列得,可以在电脑上模拟路由器
💻 C
📖 第 1 页 / 共 2 页
字号:
      if (action.ctrl & CB_CTRL_I)         d->scb_stat_ack |= SCB_STAT_CX;      /* Return to idle state ? */      if (action.ctrl & CB_CTRL_EL) {         d->cu_state = CU_STATE_IDLE;         d->scb_stat_ack |= SCB_STAT_CNA;         break;      } else {         /* Enter suspended state ? */         if (action.ctrl & CB_CTRL_S) {            d->cu_state = CU_STATE_SUSPEND;            d->scb_stat_ack |= SCB_STAT_CNA;            break;         }      }      /* Go to next descriptor */      d->cu_offset = action.link_offset;   }      /* Update interrupt status */   dev_i8255x_update_irq_status(d);}/* Resume a Command Block List */static int dev_i8255x_cu_resume(struct i8255x_data *d){   struct i8255x_cu_action action;   m_uint32_t cu_addr;   /* If we are in idle state, ignore the command */   if (d->cu_state == CU_STATE_IDLE)      return(FALSE);   cu_addr = d->cu_base + d->cu_offset;   /* Check if the previous block has still the S bit set */   dev_i8255x_fetch_cb(d,cu_addr,&action);      if (action.ctrl & CB_CTRL_S)      return(FALSE);      d->cu_offset = action.link_offset;   d->cu_state  = CU_STATE_LPQ_ACT;   dev_i8255x_process_cbl(d);   return(TRUE);}/* Dump Statistical counters */static void dev_i8255x_dump_stat_cnt(struct i8255x_data *d){   m_uint32_t counters[I8255X_STAT_CNT_SIZE];   memcpy(counters,d->stat_counters,sizeof(counters));   mem_bswap32(counters,sizeof(counters));   physmem_copy_to_vm(d->vm,counters,d->stat_cnt_addr,sizeof(counters));}/* Process a CU command */static void dev_i8255x_process_cu_cmd(struct i8255x_data *d,u_int cuc){   switch(cuc) {      /* No Operation */      case CU_CMD_NOP:         break;      /* Start */      case CU_CMD_START:         d->cu_offset = d->scb_gptr;         d->cu_state  = CU_STATE_LPQ_ACT;         dev_i8255x_process_cbl(d);         break;      /* Resume */      case CU_CMD_RESUME:         dev_i8255x_cu_resume(d);         break;      /* Load CU base */      case CU_CMD_LOAD_CU_BASE:         d->cu_base = d->scb_gptr;         break;      /* Load Dump Counters Address */      case CU_CMD_LOAD_DUMP_CNT:         d->stat_cnt_addr = d->scb_gptr;         break;      /* Dump Statistical Counters */      case CU_CMD_DUMP_STAT_CNT:         dev_i8255x_dump_stat_cnt(d);         break;      /* Dump Statistical Counters and reset them */      case CU_CMD_DUMP_RST_STAT_CNT:         dev_i8255x_dump_stat_cnt(d);         memset(d->stat_counters,0,sizeof(d->stat_counters));         break;      default:         EEPRO_LOG(d,"unsupported CU command 0x%2.2x\n",cuc);   }}/* Fetch an RxFD (RX Frame Descriptor) */static void dev_i8255x_fetch_rxfd(struct i8255x_data *d,m_uint32_t addr,                                  struct i8255x_rxfd *rxfd){   physmem_copy_from_vm(d->vm,rxfd,addr,sizeof(*rxfd));   rxfd->ctrl        = vmtoh32(rxfd->ctrl);   rxfd->link_offset = vmtoh32(rxfd->link_offset);   rxfd->rxbd_addr   = vmtoh32(rxfd->rxbd_addr);   rxfd->rxbd_size   = vmtoh32(rxfd->rxbd_size);}/* Fetch an RxBD (Rx Buffer Descriptor) */static void dev_i8255x_fetch_rxbd(struct i8255x_data *d,m_uint32_t addr,                                  struct i8255x_rxbd *rxbd){   physmem_copy_from_vm(d->vm,rxbd,addr,sizeof(*rxbd));   rxbd->ctrl        = vmtoh32(rxbd->ctrl);   rxbd->rxbd_next   = vmtoh32(rxbd->rxbd_next);   rxbd->buf_addr    = vmtoh32(rxbd->buf_addr);   rxbd->buf_size    = vmtoh32(rxbd->buf_size);}/* Store a packet */static int dev_i8255x_store_rx_pkt(struct i8255x_data *d,                                   m_uint8_t *pkt,ssize_t pkt_len){   m_uint32_t rxfd_addr,rxbd_addr;   m_uint32_t rxfd_next,rxbd_next;   m_uint32_t clen,buf_size,norm_len;   struct i8255x_rxfd rxfd;   struct i8255x_rxbd rxbd;   m_uint8_t *pkt_ptr;   ssize_t tot_len;   /* Fetch the RX Frame descriptor */   rxfd_addr = d->ru_base + d->ru_offset;   dev_i8255x_fetch_rxfd(d,rxfd_addr,&rxfd);   /* === Simplified mode === */   if (!(rxfd.ctrl & RXFD_CTRL_SF)) {      /* Copy the packet data directly into the frame descriptor */      norm_len = normalize_size(pkt_len,4,0);      mem_bswap32(pkt,norm_len);      physmem_copy_to_vm(d->vm,pkt,rxfd_addr+0x10,norm_len);      /* Update the RxFD and generate the appropriate interrupt */      goto update_rxfd;   }   /* === Flexible mode === */   rxbd_addr = d->ru_base + rxfd.rxbd_addr;   pkt_ptr = pkt;   tot_len = pkt_len;   do {      /* Fetch the RX buffer */      dev_i8255x_fetch_rxbd(d,rxbd_addr,&rxbd);      rxbd_next = rxbd.rxbd_next;      /* Get the current buffer size */      buf_size = rxbd.buf_size & RXFD_SIZE_MASK;      clen = m_min(tot_len,buf_size);            /* Copy the data into the buffer */      norm_len = normalize_size(clen,4,0);      mem_bswap32(pkt_ptr,norm_len);      physmem_copy_to_vm(d->vm,pkt_ptr,rxbd.buf_addr,norm_len);      pkt_ptr += clen;      tot_len -= clen;      /* Update RX buffer info */      if (!tot_len) {         rxbd.ctrl |= RXBD_CTRL_EOF;         clen += 4;  /* Add CRC */      }            rxbd.ctrl |= RXBD_CTRL_F | clen;      physmem_copy_u32_to_vm(d->vm,rxbd_addr+0x00,rxbd.ctrl);   }while(tot_len > 0);   /* Set the next available RxBD in next RxFD */   rxbd_next = d->ru_base + rxbd.rxbd_next;   rxfd_next = d->ru_base + rxfd.link_offset;   physmem_copy_u32_to_vm(d->vm,rxfd_next+0x08,rxbd_next);   /* Update the RxFD */ update_rxfd:   rxfd.ctrl |= RXFD_CTRL_C | RXFD_CTRL_OK;   rxfd.rxbd_size &= ~0xFFFF;   rxfd.rxbd_size |= RXFD_EOF | (pkt_len + 4);      physmem_copy_u32_to_vm(d->vm,rxfd_addr+0x00,rxfd.ctrl);   physmem_copy_u32_to_vm(d->vm,rxfd_addr+0x0c,rxfd.rxbd_size);   d->stat_counters[STAT_CNT_RX_GOOD]++;   /* A frame has been received: generate an IRQ */   d->scb_stat_ack |= SCB_STAT_FR;   if (rxfd.ctrl & RXFD_CTRL_EL) {      d->ru_state = RU_STATE_NO_RES;      d->scb_stat_ack |= SCB_STAT_RNR;   } else {      if (rxfd.ctrl & RXFD_CTRL_S) {         d->ru_state = RU_STATE_SUSPEND;         d->scb_stat_ack |= SCB_STAT_RNR;      } else {         d->ru_offset = rxfd.link_offset;      }   }   dev_i8255x_update_irq_status(d);   return(TRUE);}/* Resume reception */static int dev_i8255x_ru_resume(struct i8255x_data *d){   struct i8255x_rxfd rxfd;   m_uint32_t rxfd_addr;   /* If we are not in ready state, ignore the command */   if (d->ru_state != RU_STATE_READY)      return(FALSE);   /* Fetch the RX Frame descriptor */   rxfd_addr = d->ru_base + d->ru_offset;   dev_i8255x_fetch_rxfd(d,rxfd_addr,&rxfd);   /* Check if the previous frame descriptor has still the S bit set */   if (rxfd.ctrl & RXFD_CTRL_S)      return(FALSE);      d->ru_offset = rxfd.link_offset;   d->ru_state  = RU_STATE_READY;   return(TRUE);}/* Process a RU command */static void dev_i8255x_process_ru_cmd(struct i8255x_data *d,u_int ruc){   switch(ruc) {      /* No Operation */      case RU_CMD_NOP:         break;      /* Start */      case RU_CMD_START:         d->ru_offset = d->scb_gptr;         d->ru_state  = RU_STATE_READY;         break;      /* Resume */      case RU_CMD_RESUME:         dev_i8255x_ru_resume(d);         break;      /* Load RU base */      case RU_CMD_LOAD_RU_BASE:                  d->ru_base = d->scb_gptr;         break;               default:         EEPRO_LOG(d,"unsupported RU command 0x%2.2x\n",ruc);   }}/* * dev_i8255x_access() */void *dev_i8255x_access(cpu_gen_t *cpu,struct vdevice *dev,                        m_uint32_t offset,u_int op_size,u_int op_type,                        m_uint64_t *data){   struct i8255x_data *d = dev->priv_data;   u_int cuc,ruc,mii_op;   if (op_type == MTS_READ)      *data = 0x0;#if DEBUG_ACCESS   if (op_type == MTS_READ) {      cpu_log(cpu,d->name,"read  access to 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 offset=0x%x, pc=0x%llx, "              "val=0x%llx, size=%u\n",offset,cpu_get_pc(cpu),*data,op_size);   }#endif   EEPRO_LOCK(d);   switch(offset) {      /* SCB Command Word (interrupt control byte) */      case 0x00:         if (op_type == MTS_WRITE)            d->scb_ic = *data;         break;      /* SCB Command Word (command byte) */      case 0x01:         if (op_type == MTS_WRITE) {            cuc = (*data & SCB_CMD_CUC_MASK) >> SCB_CMD_CUC_SHIFT;            ruc = (*data & SCB_CMD_RUC_MASK) >> SCB_CMD_RUC_SHIFT;            /* Process CU and RU commands */            dev_i8255x_process_cu_cmd(d,cuc);            dev_i8255x_process_ru_cmd(d,ruc);         }         break;      /* SCB Status Word */      case 0x02:         if (op_type == MTS_READ) {            *data  = d->scb_stat_ack << 8;         } else {            d->scb_stat_ack &= ~(*data >> 8);            dev_i8255x_update_irq_status(d);         }         break;      /* SCB General Pointer */      case 0x04:         if (op_type == MTS_WRITE)            d->scb_gptr = *data;         else            *data = d->scb_gptr;         break;      /* MDI control register */      case 0x10:         if (op_type == MTS_READ) {            mii_op = (d->mii_ctrl & I8255X_MDI_OP_MASK) >> I8255X_MDI_OP_SHIFT;                        if (mii_op == MII_OPCODE_READ) {               d->mii_ctrl &= ~I8255X_MDI_DATA_MASK;               d->mii_ctrl |= mii_reg_read(d);            }            *data = d->mii_ctrl | I8255X_MDI_R;         } else {            d->mii_ctrl = *data;            mii_op = (d->mii_ctrl & I8255X_MDI_OP_MASK) >> I8255X_MDI_OP_SHIFT;            if (mii_op == MII_OPCODE_WRITE)               mii_reg_write(d);         }         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   }   EEPRO_UNLOCK(d);   return NULL;}/* Handle the RX ring */static int dev_i8255x_handle_rxring(netio_desc_t *nio,                                    u_char *pkt,ssize_t pkt_len,                                    struct i8255x_data *d){     int res = FALSE;    EEPRO_LOCK(d);   if (d->ru_state == RU_STATE_READY)      res = dev_i8255x_store_rx_pkt(d,pkt,pkt_len);      EEPRO_UNLOCK(d);   return(res);}/* * pci_i8255x_read() * * Read a PCI register. */static m_uint32_t pci_i8255x_read(cpu_gen_t *cpu,struct pci_device *dev,                                  int reg){   struct i8255x_data *d = dev->priv_data;#if DEBUG_PCI_REGS   EEPRO_LOG(d,"read PCI register 0x%x\n",reg);#endif   switch (reg) {      case 0x00:         return((I8255X_PCI_PRODUCT_ID << 16) | I8255X_PCI_VENDOR_ID);      case PCI_REG_BAR0:         return(d->dev->phys_addr);      case 0x0c:         return(0x4000);      default:         return(0);   }}/* * pci_i8255x_write() * * Write a PCI register. */static void pci_i8255x_write(cpu_gen_t *cpu,struct pci_device *dev,                             int reg,m_uint32_t value){   struct i8255x_data *d = dev->priv_data;#if DEBUG_PCI_REGS   EEPRO_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);         EEPRO_LOG(d,"registers are mapped at 0x%x\n",value);         break;   }}/* * dev_i8255x_init() */struct i8255x_data *dev_i8255x_init(vm_instance_t *vm,char *name,int interface_type,                struct pci_bus *pci_bus,int pci_device,int irq){   struct i8255x_data *d;   struct pci_device *pci_dev;   struct vdevice *dev;   /* Allocate the private data structure for I8255X */   if (!(d = malloc(sizeof(*d)))) {      fprintf(stderr,"%s (i8255x): 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,                         I8255X_PCI_VENDOR_ID,I8255X_PCI_PRODUCT_ID,                         pci_device,0,irq,                         d,NULL,pci_i8255x_read,pci_i8255x_write);   if (!pci_dev) {      fprintf(stderr,"%s (i8255x): unable to create PCI device.\n",name);      goto err_pci_dev;   }   /* Create the device itself */   if (!(dev = dev_create(name))) {      fprintf(stderr,"%s (i8255x): 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_i8255x_access;   dev->priv_data = d;   return(d); err_dev:   pci_dev_remove(pci_dev); err_pci_dev:   free(d);   return NULL;}/* Remove an Intel i8255x device */void dev_i8255x_remove(struct i8255x_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 i8255x device */int dev_i8255x_set_nio(struct i8255x_data *d,netio_desc_t *nio){   /* check that a NIO is not already bound */   if (d->nio != NULL)      return(-1);   d->nio = nio;   netio_rxl_add(nio,(netio_rx_handler_t)dev_i8255x_handle_rxring,d,NULL);   return(0);}/* Unbind a NIO from an Intel i8255x device */void dev_i8255x_unset_nio(struct i8255x_data *d){   if (d->nio != NULL) {      netio_rxl_remove(d->nio);      d->nio = NULL;   }}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -