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

📄 dev_i8255x.c

📁 思科路由器仿真器,用来仿7200系列得,可以在电脑上模拟路由器
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Cisco router simulation platform. * Copyright (c) 2007 Christophe Fillot. * * Intel i8255x (eepro100) Ethernet chip emulation. */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <stdarg.h>#include <unistd.h>#include <time.h>#include <errno.h>#include <assert.h>#include "utils.h"#include "cpu.h"#include "vm.h"#include "dynamips.h"#include "memory.h"#include "device.h"#include "net.h"#include "net_io.h"#include "ptask.h"#include "dev_i8255x.h"/* Debugging flags */#define DEBUG_MII_REGS   0#define DEBUG_PCI_REGS   0#define DEBUG_ACCESS     0#define DEBUG_TRANSMIT   0#define DEBUG_RECEIVE    0#define DEBUG_UNKNOWN    1/* Intel i8255x PCI vendor/product codes */#define I8255X_PCI_VENDOR_ID    0x8086#define I8255X_PCI_PRODUCT_ID   0x1229/* Maximum packet size */#define I8255X_MAX_PKT_SIZE  4096/* MDI Control Register */#define I8255X_MDI_IE          0x20000000#define I8255X_MDI_R           0x10000000#define I8255X_MDI_OP_MASK     0x0C000000#define I8255X_MDI_OP_SHIFT    26#define I8255X_MDI_PHY_MASK    0x03E00000#define I8255X_MDI_PHY_SHIFT   21#define I8255X_MDI_REG_MASK    0x001F0000#define I8255X_MDI_REG_SHIFT   16#define I8255X_MDI_DATA_MASK   0x0000FFFF/* Microcode size (in dwords) */#define I8255X_UCODE_SIZE  64/* Size of configuration block (in dwords) */#define I8255X_CONFIG_SIZE  6/* Size of statistical counters (in dwords) */#define I8255X_STAT_CNT_SIZE  20/* SCB Command Register (Command byte) */#define SCB_CMD_RUC_MASK   0x07  /* RU Command */#define SCB_CMD_RUC_SHIFT  0#define SCB_CMD_CUC_MASK   0xF0  /* CU Command */#define SCB_CMD_CUC_SHIFT  4/* SCB Command Register (Interrupt Control Byte) */#define SCB_CMD_CX    0x80  /* CX Mask */#define SCB_CMD_FR    0x40  /* FR Mask */#define SCB_CMD_CNA   0x20  /* CNA Mask */#define SCB_CMD_RNR   0x10  /* RNR Mask */#define SCB_CMD_ER    0x08  /* ER Mask */#define SCB_CMD_FCP   0x04  /* FCP Mask */#define SCB_CMD_SI    0x02  /* Software generated interrupt */#define SCB_CMD_M     0x01  /* Mask Interrupt *//* SCB Interrupt Mask */#define SCB_INT_MASK  0xF0/* SCB Status Word (Stat/ACK byte) */#define SCB_STAT_CX   0x80  /* CU finished command execution */#define SCB_STAT_FR   0x40  /* RU finished Frame Reception */#define SCB_STAT_CNA  0x20  /* CU left active state or entered idle state */#define SCB_STAT_RNR  0x10  /* RU left ready state */#define SCB_STAT_MDI  0x08  /* MDI read/write cycle completed */#define SCB_STAT_SWI  0x04  /* Software generated interrupt */#define SCB_STAT_FCP  0x01  /* Flow Control Pause interrupt *//* CU states */#define CU_STATE_IDLE     0x00  /* Idle */#define CU_STATE_SUSPEND  0x01  /* Suspended */#define CU_STATE_LPQ_ACT  0x02  /* LPQ Active */#define CU_STATE_HQP_ACT  0x03  /* HQP Active *//* RU states */#define RU_STATE_IDLE     0x00  /* Idle */#define RU_STATE_SUSPEND  0x01  /* Suspended */#define RU_STATE_NO_RES   0x02  /* No RX ressources available */#define RU_STATE_READY    0x04  /* Ready *//* CU (Command Unit) commands */#define CU_CMD_NOP                0x00  /* No Operation */#define CU_CMD_START              0x01  /* Start */#define CU_CMD_RESUME             0x02  /* Resume */#define CU_CMD_LOAD_DUMP_CNT      0x04  /* Load Dump Counters Address */#define CU_CMD_DUMP_STAT_CNT      0x05  /* Dump Statistical Counters */#define CU_CMD_LOAD_CU_BASE       0x06  /* Load CU Base */#define CU_CMD_DUMP_RST_STAT_CNT  0x07  /* Dump & Reset Stat Counters */#define CU_CMD_STAT_RESUME        0x0a  /* Static Resume *//* RU (Receive Unit) commands */#define RU_CMD_NOP                0x00  /* No Operation */#define RU_CMD_START              0x01  /* Start */#define RU_CMD_RESUME             0x02  /* Resume */#define RU_CMD_RX_DMA_REDIRECT    0x03  /* Receive DMA redirect */#define RU_CMD_ABORT              0x04  /* Abort */#define RU_CMD_LOAD_HDS           0x05  /* Load Header Data Size */#define RU_CMD_LOAD_RU_BASE       0x06  /* Load RU Base *//* CB (Command Block) commands */#define CB_CMD_NOP            0x00  /* No Operation */#define CB_CMD_IADDR_SETUP    0x01  /* Individual Address Setup */#define CB_CMD_CONFIGURE      0x02  /* Configure Device Parameters */#define CB_CMD_XCAST_SETUP    0x03  /* Multicast Address Setup */#define CB_CMD_TRANSMIT       0x04  /* Transmit a single frame */#define CB_CMD_LOAD_UCODE     0x05  /* Load Microcode */#define CB_CMD_DUMP           0x06  /* Dump Internal Registers */#define CB_CMD_DIAGNOSE       0x07  /* Diagnostics *//* CB (Command Block) control/status word */#define CB_CTRL_EL          0x80000000   /* Last command in CBL */#define CB_CTRL_S           0x40000000   /* Suspend CU after completion */#define CB_CTRL_I           0x20000000   /* Interrupt at end of exec (CX) */#define CB_CTRL_SF          0x00080000   /* Mode: 0=simplified,1=flexible */#define CB_CTRL_CMD_MASK    0x00070000   /* Command */#define CB_CTRL_CMD_SHIFT   16#define CB_CTRL_C           0x00008000   /* Execution status (1=completed) */#define CB_CTRL_OK          0x00002000   /* Command success *//* CB Transmit Command */#define TXCB_NUM_MASK    0xFF000000   /* TBD Number */#define TXCB_NUM_SHIFT   24#define TXCB_EOF         0x00008000   /* Whole frame in TxCB */#define TXCB_BLK_SIZE    0x00003FFF   /* TxCB Byte count *//* Receive Frame Descriptor (RxFD) control status/word */#define RXFD_CTRL_EL        0x80000000   /* Last RXFD in RFA */#define RXFD_CTRL_S         0x40000000   /* Suspend RU after completion */#define RXFD_CTRL_H         0x00100000   /* Header RXFD */#define RXFD_CTRL_SF        0x00080000   /* Mode: 0=simplified,1=flexible */#define RXFD_CTRL_C         0x00008000   /* Execution status (1=completed) */#define RXFD_CTRL_OK        0x00002000   /* Packet OK */#define RXFD_CTRL_CRC_ERR   0x00000800   /* CRC Error */#define RXFD_CTRL_CRC_AL    0x00000400   /* Alignment Error */#define RXFD_CTRL_NO_RES    0x00000200   /* No Ressources */#define RXFD_CTRL_DMA_OV    0x00000100   /* DMA Overrun */#define RXFD_CTRL_FTS       0x00000080   /* Frame Too Short */#define RXFD_CTRL_TL        0x00000020   /* Type/Length */#define RXFD_CTRL_ERR       0x00000010   /* RX Error */#define RXFD_CTRL_NAM       0x00000004   /* No Address Match */#define RXFD_CTRL_IAM       0x00000002   /* Individual Address Match */#define RXFD_CTRL_COLL      0x00000001   /* RX Collision */#define RXFD_EOF            0x00008000   /* End Of Frame */#define RXFD_SIZE_MASK      0x00003FFF   /* Size mask */#define RXBD_CTRL_EOF       0x00008000   /* End Of Frame */#define RXBD_CTRL_F         0x00004000   /* Buffer used  *//* Tx Buffer Descriptor */struct i8255x_txbd {   m_uint32_t buf_addr;   m_uint32_t buf_size;};/* CU (Command Unit) Action */struct i8255x_cu_action {   m_uint32_t ctrl;   m_uint32_t link_offset;   m_uint32_t txbd_addr;   m_uint32_t txbd_count;};/* RX Buffer Descriptor */struct i8255x_rxbd {   m_uint32_t ctrl;   m_uint32_t rxbd_next;   m_uint32_t buf_addr;   m_uint32_t buf_size;};/* RX Frame Descriptor */struct i8255x_rxfd {   m_uint32_t ctrl;   m_uint32_t link_offset;   m_uint32_t rxbd_addr;   m_uint32_t rxbd_size;};/* Statistical counters indexes */#define STAT_CNT_TX_GOOD     0   /* Transmit good frames */#define STAT_CNT_RX_GOOD     9   /* Receive good frames */#define STAT_CNT_RX_RES_ERR  12  /* Receive resource errors *//* Intel i8255x private data */struct i8255x_data {   char *name;   /* Lock test */   pthread_mutex_t lock;   /* Physical (MAC) address */   n_eth_addr_t mac_addr;   /* Device information */   struct vdevice *dev;   /* PCI device information */   struct pci_device *pci_dev;   /* Virtual machine */   vm_instance_t *vm;   /* NetIO descriptor */   netio_desc_t *nio;   /* CU and RU current states */   u_int cu_state,ru_state;   /* CU/RU bases + current offsets */   m_uint32_t cu_base,ru_base;   m_uint32_t cu_offset,ru_offset;   /* SCB general pointer */   m_uint32_t scb_gptr;   /* SCB Interrupt Control */   m_uint8_t scb_ic;   /* SCB Status Acknowledge (for interrupts) */   m_uint8_t scb_stat_ack;   /* Statistical counters address */   m_uint32_t stat_cnt_addr;   /* MII registers */   m_uint32_t mii_ctrl;   u_int mii_regs[32][32];   /* MAC Individual Address */   n_eth_addr_t iaddr;   /* Configuration data */   m_uint32_t config_data[I8255X_CONFIG_SIZE];   /* Microcode */   m_uint32_t microcode[I8255X_UCODE_SIZE];   /* Statistical counters */   m_uint32_t stat_counters[I8255X_STAT_CNT_SIZE];   /* TX packet buffer */   m_uint8_t tx_buffer[I8255X_MAX_PKT_SIZE];};#define EEPRO_LOCK(d)   pthread_mutex_lock(&(d)->lock)#define EEPRO_UNLOCK(d) pthread_mutex_unlock(&(d)->lock)/* Log an message */#define EEPRO_LOG(d,msg...) vm_log((d)->vm,(d)->name,msg)enum {   MII_OPCODE_WRITE = 1,   MII_OPCODE_READ,};/* Read a MII register */static m_uint16_t mii_reg_read(struct i8255x_data *d){   u_int mii_phy,mii_reg;   mii_phy = (d->mii_ctrl & I8255X_MDI_PHY_MASK) >> I8255X_MDI_PHY_SHIFT;   mii_reg = (d->mii_ctrl & I8255X_MDI_REG_MASK) >> I8255X_MDI_REG_SHIFT;#if DEBUG_MII_REGS   EEPRO_LOG(d,"MII PHY read %d reg %d\n",mii_phy,mii_reg);#endif   switch(mii_reg) {      case 0x00:         return((d->mii_regs[mii_phy][mii_reg] & ~0x8200) | 0x2000);      case 0x01:         return(0x782c);      case 0x02:         return(0x0013);      case 0x03:         return(0x61d4);      case 0x05:         return(0x41e1);      case 0x06:         return(0x0001);      case 0x11:         return(0x4700);      default:         return(d->mii_regs[mii_phy][mii_reg]);   }}/* Write a MII register */static void mii_reg_write(struct i8255x_data *d){   u_int mii_phy,mii_reg,mii_data;      mii_phy = (d->mii_ctrl & I8255X_MDI_PHY_MASK) >> I8255X_MDI_PHY_SHIFT;   mii_reg = (d->mii_ctrl & I8255X_MDI_REG_MASK) >> I8255X_MDI_REG_SHIFT;   mii_data = d->mii_ctrl & I8255X_MDI_DATA_MASK;#if DEBUG_MII_REGS   EEPRO_LOG(d,"MII PHY write %d reg %d value %04x\n",             mii_phy,mii_reg,mii_data);#endif   d->mii_regs[mii_phy][mii_reg] = mii_data;}/* Update interrupt status */static void dev_i8255x_update_irq_status(struct i8255x_data *d){   /* If interrupts are masked, clear IRQ */   if (d->scb_ic & SCB_CMD_M) {      pci_dev_clear_irq(d->vm,d->pci_dev);      return;   }   /* Software generated interrupt ? */   if (d->scb_ic & SCB_CMD_SI) {      pci_dev_trigger_irq(d->vm,d->pci_dev);      return;   }   /* Hardware interrupt ? */   if (d->scb_stat_ack & (~d->scb_ic & SCB_INT_MASK))      pci_dev_trigger_irq(d->vm,d->pci_dev);   else      pci_dev_clear_irq(d->vm,d->pci_dev);}/* Fetch a CB (Command Block) */static void dev_i8255x_fetch_cb(struct i8255x_data *d,m_uint32_t addr,                                struct i8255x_cu_action *action){   physmem_copy_from_vm(d->vm,action,addr,sizeof(*action));   action->ctrl        = vmtoh32(action->ctrl);   action->link_offset = vmtoh32(action->link_offset);   action->txbd_addr   = vmtoh32(action->txbd_addr);   action->txbd_count  = vmtoh32(action->txbd_count);}/* Fetch a TX buffer descriptor */static void dev_i8255x_fetch_txbd(struct i8255x_data *d,m_uint32_t addr,                                  struct i8255x_txbd *bd){   physmem_copy_from_vm(d->vm,bd,addr,sizeof(*bd));   bd->buf_addr = vmtoh32(bd->buf_addr);   bd->buf_size = vmtoh32(bd->buf_size);}/* Transmit a frame */static int dev_i8255x_send_tx_pkt(struct i8255x_data *d,m_uint32_t cb_addr,                                  struct i8255x_cu_action *action){   m_uint32_t i,blk_size,tx_size,txbd_addr,txbd_cnt;   struct i8255x_txbd txbd;   m_uint8_t *tx_ptr;   m_uint32_t norm_len;   /* === Simplified mode: copy the data directly from the TxCB === */   if (!(action->ctrl & CB_CTRL_SF)) {      tx_size = action->txbd_count & TXCB_BLK_SIZE;      norm_len = normalize_size(tx_size,4,0);      physmem_copy_from_vm(d->vm,d->tx_buffer,cb_addr+0x10,norm_len);      mem_bswap32(d->tx_buffer,norm_len);      goto do_transmit;   }      /* === Flexible mode === */   tx_ptr  = d->tx_buffer;   tx_size = 0;   if (action->txbd_addr == 0xFFFFFFFF) {      txbd_addr = cb_addr + 0x10;   } else {      /* copy the data directly from the TxCB if present */      blk_size = action->txbd_count & TXCB_BLK_SIZE;      if (blk_size > 0) {         tx_size = action->txbd_count & TXCB_BLK_SIZE;         norm_len = normalize_size(tx_size,4,0);         physmem_copy_from_vm(d->vm,tx_ptr,cb_addr+0x10,norm_len);         mem_bswap32(tx_ptr,norm_len);         tx_ptr += tx_size;      }      txbd_addr = action->txbd_addr;   }      txbd_cnt = (action->txbd_count & TXCB_NUM_MASK) >> TXCB_NUM_SHIFT;   /*     * Fetch all Tx buffer descriptors and copy data from each separate buffer.    */   for(i=0;i<txbd_cnt;i++) {      dev_i8255x_fetch_txbd(d,txbd_addr,&txbd);      norm_len = normalize_size(txbd.buf_size,4,0);      physmem_copy_from_vm(d->vm,tx_ptr,txbd.buf_addr,norm_len);      mem_bswap32(tx_ptr,norm_len);      tx_ptr  += txbd.buf_size;      tx_size += txbd.buf_size;      txbd_addr += sizeof(txbd);   } do_transmit:   d->stat_counters[STAT_CNT_TX_GOOD]++;#if DEBUG_TRANSMIT   EEPRO_LOG(d,"sending packet of %u bytes\n",tx_size);   mem_dump(log_file,d->tx_buffer,tx_size);#endif   netio_send(d->nio,d->tx_buffer,tx_size);   return(TRUE);}/* Process an indidual CB (Command Block) */static void dev_i8255x_process_cb(struct i8255x_data *d,m_uint32_t cb_addr,                                  struct i8255x_cu_action *action){   m_uint32_t tmp[2];   u_int cmd,res;   cmd = (action->ctrl & CB_CTRL_CMD_MASK) >> CB_CTRL_CMD_SHIFT;   switch(cmd) {      /* No Operation */      case CB_CMD_NOP:         res = TRUE;         break;          /* Transmit a frame */      case CB_CMD_TRANSMIT:         res = dev_i8255x_send_tx_pkt(d,cb_addr,action);         break;      /* Configure */      case CB_CMD_CONFIGURE:         physmem_copy_from_vm(d->vm,d->config_data,cb_addr+0x08,                              I8255X_CONFIG_SIZE * sizeof(m_uint32_t));         mem_bswap32(d->config_data,I8255X_CONFIG_SIZE * sizeof(m_uint32_t));         res = TRUE;         break;      /* Individual address setup */      case CB_CMD_IADDR_SETUP:         tmp[0] = physmem_copy_u32_from_vm(d->vm,cb_addr+0x08);         tmp[1] = physmem_copy_u32_from_vm(d->vm,cb_addr+0x0c);         d->iaddr.eth_addr_byte[0] = tmp[0];         d->iaddr.eth_addr_byte[1] = tmp[0] >> 8;         d->iaddr.eth_addr_byte[2] = tmp[0] >> 16;         d->iaddr.eth_addr_byte[3] = tmp[0] >> 24;         d->iaddr.eth_addr_byte[4] = tmp[1];         d->iaddr.eth_addr_byte[5] = tmp[1] >> 8;         EEPRO_LOG(d,"iaddr set to: %2.2x%2.2x.%2.2x%2.2x.%2.2x%2.2x\n",                   d->iaddr.eth_addr_byte[0],d->iaddr.eth_addr_byte[1],                   d->iaddr.eth_addr_byte[2],d->iaddr.eth_addr_byte[3],                   d->iaddr.eth_addr_byte[4],d->iaddr.eth_addr_byte[5]);                           res = TRUE;         break;      /* Load Microcode */      case CB_CMD_LOAD_UCODE:         physmem_copy_from_vm(d->vm,d->microcode,cb_addr+0x08,                              I8255X_UCODE_SIZE * sizeof(m_uint32_t));         mem_bswap32(d->microcode,I8255X_UCODE_SIZE * sizeof(m_uint32_t));         EEPRO_LOG(d,"microcode loaded\n");         res = TRUE;         break;      /* Unsupported command */      default:         EEPRO_LOG(d,"unsupported CB command 0x%2.2x (cb_addr=0x%8.8x)\n",                   cmd,cb_addr);         res = TRUE;   }   /* Set the completed bit with the result */   action->ctrl |= CB_CTRL_C;   if (res) action->ctrl |= CB_CTRL_OK;   /* Update control word */   physmem_copy_u32_to_vm(d->vm,cb_addr,action->ctrl);}/* Process a CBL (Command Block List) */static void dev_i8255x_process_cbl(struct i8255x_data *d){   struct i8255x_cu_action action;   m_uint32_t cb_addr;   for(;;) {      cb_addr = d->cu_base + d->cu_offset;      dev_i8255x_fetch_cb(d,cb_addr,&action);      /* Execute command */      dev_i8255x_process_cb(d,cb_addr,&action);      /* Interrupt at end of execution ? */

⌨️ 快捷键说明

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