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

📄 dev_dec21140.c

📁 思科路由器仿真器,用来仿7200系列得,可以在电脑上模拟路由器-Cisco router simulator, used to fake a 7200 series can be simulated
💻 C
📖 第 1 页 / 共 2 页
字号:
/*   * Cisco C7200 (Predator) DEC21140 Module. * Copyright (C) 2005,2006 Christophe Fillot.  All rights reserved. * * DEC21140 FastEthernet chip emulation. * * It allows to emulate a C7200-IO-FE card with 1 port and PA-FE-TX cards. * * Many many thanks to mtve (aka "Mtv Europe") for his great work on  * this stuff. * * Manuals: * * DECchip 21140 PCI fast Ethernet LAN controller Hardware reference manual * http://ftp.nluug.nl/NetBSD/misc/dec-docs/ec-qc0cb-te.ps.gz * * National DP83840 PHY * http://www.rezrov.net/docs/DP83840A.pdf * * Remark: only Big-endian mode is supported. */#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 "crc.h"#include "utils.h"#include "mips64.h"#include "dynamips.h"#include "memory.h"#include "device.h"#include "net.h"#include "net_io.h"#include "ptask.h"#include "dev_dec21140.h"/* Debugging flags */#define DEBUG_MII_REGS   0#define DEBUG_CSR_REGS   0#define DEBUG_PCI_REGS   0#define DEBUG_TRANSMIT   0#define DEBUG_RECEIVE    0/* DEC21140 PCI vendor/product codes */#define DEC21140_PCI_VENDOR_ID    0x1011#define DEC21140_PCI_PRODUCT_ID   0x0009/* DEC21140 PCI registers */#define DEC21140_PCI_CFID_REG_OFFSET   0x00#define DEC21140_PCI_CFCS_REG_OFFSET   0x04#define DEC21140_PCI_CFRV_REG_OFFSET   0x08#define DEC21140_PCI_CFLT_REG_OFFSET   0x0C#define DEC21140_PCI_CBIO_REG_OFFSET   0x10#define DEC21140_PCI_CBMA_REG_OFFSET   0x14#define DEC21140_PCI_CFIT_REG_OFFSET   0x3C#define DEC21140_PCI_CFDA_REG_OFFSET   0x40/* Number of CSR registers */#define DEC21140_CSR_NR  16/* CSR5: Status Register */#define DEC21140_CSR5_TI          0x00000001#define DEC21140_CSR5_RI          0x00000040#define DEC21140_CSR5_RS_SHIFT    17#define DEC21140_CSR5_TS_SHIFT    20/* CSR6: Operating Mode Register */#define DEC21140_CSR6_START_RX    0x00000002#define DEC21140_CSR6_START_TX    0x00002000#define DEC21140_CSR6_PROMISC     0x00000040/* CSR9: Serial EEPROM and MII */#define DEC21140_CSR9_RX_BIT      0x00080000#define DEC21140_CSR9_MII_READ    0x00040000#define DEC21140_CSR9_TX_BIT      0x00020000#define DEC21140_CSR9_MDC_CLOCK   0x00010000#define DEC21140_CSR9_READ        0x00004000#define DEC21140_CSR9_WRITE       0x00002000/* Maximum packet size */#define DEC21140_MAX_PKT_SIZE     2048/* Send up to 32 packets in a TX ring scan pass */#define DEC21140_TXRING_PASS_COUNT  32/* Setup frame size */#define DEC21140_SETUP_FRAME_SIZE 192/* RX descriptors */#define DEC21140_RXDESC_OWN       0x80000000  /* Ownership */#define DEC21140_RXDESC_LS        0x00000100  /* Last Segment */#define DEC21140_RXDESC_FS        0x00000200  /* First Segment */#define DEC21140_RXDESC_MF        0x00000400  /* Multicast Frame */#define DEC21140_RXDESC_DE        0x00004000  /* Descriptor Error */#define DEC21140_RXDESC_RCH       0x01000000  /* Sec. Addr. Chained */#define DEC21140_RXDESC_RER       0x02000000  /* Receive End of Ring */#define DEC21140_RXDESC_FL_SHIFT  16#define DEC21140_RXDESC_LEN_MASK  0x7ff/* TX descriptors */#define DEC21140_TXDESC_OWN       0x80000000  /* Ownership */#define DEC21140_TXDESC_TCH       0x01000000  /* Sec. Addr. Chained */#define DEC21140_TXDESC_TER       0x02000000  /* Transmit End of Ring */#define DEC21140_TXDESC_SET       0x08000000  /* Setup frame */#define DEC21140_TXDESC_FS        0x20000000  /* First Segment */#define DEC21140_TXDESC_LS        0x40000000  /* Last Segment */#define DEC21140_TXDESC_IC        0x80000000  /* IRQ on completion */#define DEC21140_TXDESC_LEN_MASK  0x7ff/* RX Descriptor */struct rx_desc {   m_uint32_t rdes[4];};/* TX Descriptor */struct tx_desc {   m_uint32_t tdes[4];};/* DEC21140 Data */struct dec21140_data {   char *name;      /* Physical addresses of current RX and TX descriptors */   m_uint32_t rx_current;   m_uint32_t tx_current;   /* CSR registers */   m_uint32_t csr[DEC21140_CSR_NR];   /* MII registers */   m_uint32_t mii_state;   m_uint32_t mii_phy;   m_uint32_t mii_reg;   m_uint32_t mii_data;   m_uint32_t mii_outbits;   m_uint16_t mii_regs[32][32];   /* Ethernet unicast addresses */   n_eth_addr_t mac_addr[16];   u_int mac_addr_count;   /* 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;   /* TX ring scanner task id */   ptask_id_t tx_tid;};/* Log a dec21140 message */#define DEC21140_LOG(d,msg...) vm_log((d)->vm,(d)->name,msg)/*  * ISL rewrite. * * See: http://www.cisco.com/en/US/tech/tk389/tk390/technologies_tech_note09186a0080094665.shtml */static void dec21140_isl_rewrite(m_uint8_t *pkt,m_uint32_t tot_len){   static m_uint8_t isl_xaddr[N_ETH_ALEN] = { 0x01,0x00,0x0c,0x00,0x10,0x00 };   u_int real_offset,real_len;   n_eth_hdr_t *hdr;   m_uint32_t ifcs;   hdr = (n_eth_hdr_t *)pkt;   if (!memcmp(&hdr->daddr,isl_xaddr,N_ETH_ALEN)) {      real_offset = N_ETH_HLEN + N_ISL_HDR_SIZE;      real_len    = ntohs(hdr->type);      real_len    -= (N_ISL_HDR_SIZE + 4);         if ((real_offset+real_len) > tot_len)         return;         /* Rewrite the destination MAC address */      hdr->daddr.eth_addr_byte[4] = 0x00;      /* Compute the internal FCS on the encapsulated packet */      ifcs = crc32_compute(0xFFFFFFFF,pkt+real_offset,real_len);      pkt[tot_len-4] = ifcs & 0xff;      pkt[tot_len-3] = (ifcs >> 8) & 0xff;      pkt[tot_len-2] = (ifcs >> 16) & 0xff;      pkt[tot_len-1] = ifcs >> 24;   }}/* Check if a packet must be delivered to the emulated chip */static inline int dec21140_handle_mac_addr(struct dec21140_data *d,                                           m_uint8_t *pkt){   n_eth_hdr_t *hdr = (n_eth_hdr_t *)pkt;   int i;   /* Accept systematically frames if we are running is promiscuous mode */   if (d->csr[6] & DEC21140_CSR6_PROMISC)      return(TRUE);   /* Accept systematically all multicast frames */   if (eth_addr_is_mcast(&hdr->daddr))      return(TRUE);   /* Accept frames directly for us, discard others */   for(i=0;i<d->mac_addr_count;i++)      if (!memcmp(&d->mac_addr[i],&hdr->daddr,N_ETH_ALEN))         return(TRUE);         return(FALSE);}/* Update MAC addresses */static void dec21140_update_mac_addr(struct dec21140_data *d,                                     u_char *setup_frame){   n_eth_addr_t addr;   int i,nb_addr,addr_size;   d->mac_addr_count = 0;   addr_size = N_ETH_ALEN * 2;   nb_addr = DEC21140_SETUP_FRAME_SIZE / addr_size;   for(i=0;i<nb_addr;i++) {      addr.eth_addr_byte[0] = setup_frame[(i * addr_size) + 0];      addr.eth_addr_byte[1] = setup_frame[(i * addr_size) + 1];      addr.eth_addr_byte[2] = setup_frame[(i * addr_size) + 4];      addr.eth_addr_byte[3] = setup_frame[(i * addr_size) + 5];      addr.eth_addr_byte[4] = setup_frame[(i * addr_size) + 8];      addr.eth_addr_byte[5] = setup_frame[(i * addr_size) + 9];      if (!eth_addr_is_mcast(&addr)) {         memcpy(&d->mac_addr[d->mac_addr_count],&addr,N_ETH_ALEN);         DEC21140_LOG(d,"unicast MAC address: "                      "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",                      addr.eth_addr_byte[0],addr.eth_addr_byte[1],                      addr.eth_addr_byte[2],addr.eth_addr_byte[3],                      addr.eth_addr_byte[4],addr.eth_addr_byte[5]);         d->mac_addr_count++;      }   }}/* Get a PCI register name */static char *pci_cfgreg_name(int reg){   static char *name[] = {      "FID", "FCS", "FRV", "FLT", "BIO", "BMA", "?", "?",      "?", "?", "?", "?", "?", "?", "?", "FIT", "FDA"   };   return((reg>=0) && (reg<=DEC21140_CSR_NR*4) && ((reg&3)==0) ?          name[reg>>2] : "?");}/* * read from register of DP83840A PHY */ static m_uint16_t mii_reg_read(struct dec21140_data *d){#if DEBUG_MII_REGS   DEC21140_LOG(d,"MII PHY read %d reg %d\n",d->mii_phy,d->mii_reg);#endif   /*    * if it's BASIC MODE STATUS REGISTER (BMSR) at address 0x1    * then tell them that "Link Status" is up and no troubles.    */   if (d->mii_reg == 1) {      if (d->nio != NULL)         return(0x04);      else         return(0x00);   }   return(d->mii_regs[d->mii_phy][d->mii_reg]);}/* * write to register of DP83840A PHY */ static void mii_reg_write(struct dec21140_data *d){#if DEBUG_MII_REGS   DEC21140_LOG(d,"MII PHY write %d reg %d value %04x\n",                d->mii_phy,d->mii_reg,d->mii_data);#endif   assert(d->mii_phy < 32);   assert(d->mii_reg < 32);   d->mii_regs[d->mii_phy][d->mii_reg] = d->mii_data;}/* * process new bit sent by IOS to PHY. */static void mii_newbit(struct dec21140_data *d,int newbit){#if DEBUG_MII_REGS   DEC21140_LOG(d,"MII state was %d\n",d->mii_state);#endif   switch (d->mii_state) {      case 0: /* init */         d->mii_state = newbit ? 0 : 1;         d->mii_phy = 0;         d->mii_reg = 0;         d->mii_data = 0;         break;      case 1: /* already got 0 */         d->mii_state = newbit ? 2 : 0;         break;      case 2: /* already got attention */         d->mii_state = newbit ? 3 : 4;         break;      case 3: /* probably it's read */         d->mii_state = newbit ? 0 : 10;         break;      case 4: /* probably it's write */         d->mii_state = newbit ? 20 : 0;         break;      case 10: case 11: case 12: case 13: case 14:      case 20: case 21: case 22: case 23: case 24:         /* read or write state, read 5 bits of phy */         d->mii_phy <<= 1;         d->mii_phy |= newbit;         d->mii_state++;         break;      case 15: case 16: case 17: case 18: case 19:      case 25: case 26: case 27: case 28: case 29:         /* read or write state, read 5 bits of reg */         d->mii_reg <<= 1;         d->mii_reg |= newbit;         d->mii_state++;         if (d->mii_state == 20) {            /* read state, got everything */            d->mii_outbits = mii_reg_read (d) << 15; /* first bit will                                                      * be thrown away!                                                      */            d->mii_state = 0;         }         break;      case 30: /* write state, read first waiting bit */         d->mii_state = newbit ? 31 : 0;         break;      case 31: /* write state, read second waiting bit */         d->mii_state = newbit ? 0 : 32;         break;      case 32: case 33: case 34: case 35: case 36: case 37: case 38: case 39:      case 40: case 41: case 42: case 43: case 44: case 45: case 46: case 47:         /* write state, read 16 bits of data */         d->mii_data <<= 1;         d->mii_data |= newbit;         d->mii_state++;         if (d->mii_state == 48) {            /* write state, got everything */            mii_reg_write (d);            d->mii_state = 0;         }         break;      default:         DEC21140_LOG(d,"MII impossible state\n");   }#if DEBUG_MII_REGS   DEC21140_LOG(d,"MII state now %d\n",d->mii_state);#endif}/* * dev_dec21140_access() */void *dev_dec21140_access(cpu_mips_t *cpu,struct vdevice *dev,                          m_uint32_t offset,u_int op_size,u_int op_type,                          m_uint64_t *data){   struct dec21140_data *d = dev->priv_data;   u_int reg;      /* which CSR register ? */   reg = offset / 8;   if ((reg >= DEC21140_CSR_NR) || (offset % 8) != 0) {      cpu_log(cpu,d->name,"invalid access to offset 0x%x\n",offset);      return NULL;   }   if (op_type == MTS_READ) {#if DEBUG_CSR_REGS      cpu_log(cpu,d->name,"read CSR%u value 0x%x\n",reg,d->csr[reg]);#endif      switch(reg) {         case 5:            /* Dynamically construct CSR5 */            *data = 0;            if (d->csr[6] & DEC21140_CSR6_START_RX)               *data |= 0x03 << DEC21140_CSR5_RS_SHIFT;                           if (d->csr[6] & DEC21140_CSR6_START_TX)               *data |= 0x03 << DEC21140_CSR5_TS_SHIFT;                     *data |= d->csr[5] & (DEC21140_CSR5_TI|DEC21140_CSR5_RI);            break;         case 8:            /* CSR8 is cleared when read (missed frame counter) */            d->csr[reg] = 0;            *data = 0;            break;                     default:            *data = d->csr[reg];      }   } else {#if DEBUG_CSR_REGS      cpu_log(cpu,d->name,"write CSR%u value 0x%x\n",reg,(m_uint32_t)*data);#endif      d->csr[reg] = *data;      switch(reg) {         case 3:            d->rx_current = d->csr[reg];            break;         case 4:            d->tx_current = d->csr[reg];            break;         case 9:            /*             * CSR9, probably they want to mess with MII PHY             * The protocol to PHY is like serial over one bit.             * We will ignore clock 0 of read or write.             *             * This whole code is needed only to tell IOS that "Link Status"             * bit in BMSR register of DP83840A PHY is set.             *             * Also it makes "sh contr f0/0" happy.             */            if ((*data&~DEC21140_CSR9_TX_BIT) == (DEC21140_CSR9_MII_READ|                 DEC21140_CSR9_READ|DEC21140_CSR9_MDC_CLOCK)) {               /*                * read, pop one bit from mii_outbits                */               if (d->mii_outbits & (1<<31))                  d->csr[9] |= DEC21140_CSR9_RX_BIT;               else                  d->csr[9] &= ~DEC21140_CSR9_RX_BIT;               d->mii_outbits <<= 1;            } else if((*data&~DEC21140_CSR9_TX_BIT) ==                       (DEC21140_CSR9_WRITE|DEC21140_CSR9_MDC_CLOCK)) {               /*                * write, we've got input, do state machine                */               mii_newbit(d,(*data&DEC21140_CSR9_TX_BIT) ? 1 : 0);                        }            break;      }   }   return NULL;}/* * Get the address of the next RX descriptor. */static m_uint32_t rxdesc_get_next(struct dec21140_data *d,m_uint32_t rxd_addr,                                  struct rx_desc *rxd){   m_uint32_t nrxd_addr;   /* go to the next descriptor */

⌨️ 快捷键说明

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