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

📄 dev_plx.c

📁 思科路由器仿真器,用来仿7200系列得,可以在电脑上模拟路由器
💻 C
字号:
/* * Cisco router simulation platform. * Copyright (C) 2005,2006 Christophe Fillot.  All rights reserved. * * PLX PCI9060/PCI9054 - PCI bus master interface chip. * * This is very basic, it has been designed to allow the C7200 PA-POS-OC3 * to work, and for the upcoming PA-MC-8TE1. */#include <stdio.h>#include <stdlib.h>#include <string.h>#include "cpu.h"#include "vm.h"#include "dynamips.h"#include "memory.h"#include "device.h"#include "pci_dev.h"#include "dev_plx.h"#define DEBUG_ACCESS  1/* PLX vendor/product codes */#define PLX_PCI_VENDOR_ID        0x10b5#define PLX9060_PCI_PRODUCT_ID   0x9060#define PLX9054_PCI_PRODUCT_ID   0x9054/* Number of Local Spaces (1 on 9060, 2 on 9054) */#define PLX_LOCSPC_MAX  2/* Local Space ranges */#define PLX_LOCSPC_RANGE_DEFAULT      0xFFF00000#define PLX_LOCSPC_RANGE_DECODE_MASK  0xFFFFFFF0/* Local space definition */struct plx_locspace {   m_uint32_t lbaddr;   m_uint32_t range;   struct vdevice *dev;};/* PLX data */struct plx_data {   /* Device name */   char *name;   /* Variant (9060, 9054) */   u_int variant;   /* Virtual machine and object info */   vm_instance_t *vm;   vm_obj_t vm_obj;   /* Virtual PLX device */   struct vdevice plx_dev;   struct pci_device *pci_plx_dev;   /* Local spaces */   struct plx_locspace lspc[PLX_LOCSPC_MAX];   /* Doorbell registers */   m_uint32_t pci2loc_doorbell_reg,loc2pci_doorbell_reg;   dev_plx_doorbell_cbk pci2loc_doorbell_cbk;   void *pci2loc_doorbell_cbk_arg;};/* Log a PLX message */#define PLX_LOG(d,msg...) vm_log((d)->vm,(d)->name,msg)/* Map a local space device */static void plx_map_space(struct plx_data *d,u_int id){   struct plx_locspace *lspc;   lspc = &d->lspc[id];   if (!lspc->dev)      return;   lspc->dev->phys_len = 1+(~(lspc->range & PLX_LOCSPC_RANGE_DECODE_MASK));   vm_map_device(d->vm,lspc->dev,lspc->lbaddr);   PLX_LOG(d,"device %u mapped at 0x%llx, size=0x%x\n",           id,lspc->dev->phys_addr,lspc->dev->phys_len);}/* PLX device common access routine */void *dev_plx_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 plx_data *d = dev->priv_data;   if (op_type == MTS_READ)      *data = 0;   switch(offset) {      /* Local Address Space 0 Range Register */      case 0x00:         if (op_type == MTS_WRITE) {            d->lspc[0].range = *data;            plx_map_space(d,0);         } else {            *data = d->lspc[0].range;         }         break;      /* PCI-to-Local Doorbell Register */      case 0x60:         if (op_type == MTS_WRITE) {            d->pci2loc_doorbell_reg = *data;            if (d->pci2loc_doorbell_cbk != NULL) {               d->pci2loc_doorbell_cbk(d,d->pci2loc_doorbell_cbk_arg,                                       d->pci2loc_doorbell_reg);            }         }         break;      /* Local-to-PCI Doorbell Register */      case 0x64:         if (op_type == MTS_READ)            *data = d->loc2pci_doorbell_reg;         else            d->loc2pci_doorbell_reg &= ~(*data);         break;      default:         if (op_type == MTS_READ) {            cpu_log(cpu,d->name,                    "read from unhandled addr 0x%x, pc=0x%llx (size=%u)\n",                    offset,cpu_get_pc(cpu),op_size);         } else {            cpu_log(cpu,d->name,                    "write to handled addr 0x%x, value=0x%llx, "                    "pc=0x%llx (size=%u)\n",                    offset,*data,cpu_get_pc(cpu),op_size);         }   }   return NULL;}/* PLX9054 access routine */void *dev_plx9054_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 plx_data *d = dev->priv_data;   if (op_type == MTS_READ)      *data = 0;   switch(offset) {      /* Local Address Space 1 Range Register */      case 0xF0:         if (op_type == MTS_WRITE) {            d->lspc[1].range = *data;            plx_map_space(d,1);         } else {            *data = d->lspc[1].range;         }         break;      default:         return(dev_plx_access(cpu,dev,offset,op_size,op_type,data));   }   return NULL;}/* * pci_plx_read() - Common PCI read. */static m_uint32_t pci_plx_read(cpu_gen_t *cpu,struct pci_device *dev,int reg){      struct plx_data *d = dev->priv_data;#if DEBUG_ACCESS   PLX_LOG(d,"read PLX PCI register 0x%x\n",reg);#endif   switch(reg) {      /* PLX registers */      case PCI_REG_BAR0:         return(d->plx_dev.phys_addr);      /* Local space 0 */      case PCI_REG_BAR2:         return(d->lspc[0].lbaddr);      default:         return(0);   }}/* * pci_plx_write() - Common PCI write. */static void pci_plx_write(cpu_gen_t *cpu,struct pci_device *dev,                          int reg,m_uint32_t value){   struct plx_data *d = dev->priv_data;#if DEBUG_ACCESS   PLX_LOG(d,"write 0x%x to PLX PCI register 0x%x\n",value,reg);#endif   switch(reg) {      /* PLX registers */      case PCI_REG_BAR0:         vm_map_device(cpu->vm,&d->plx_dev,(m_uint64_t)value);         PLX_LOG(d,"PLX registers are mapped at 0x%x\n",value);         break;      /* Local space 0 */      case PCI_REG_BAR2:         d->lspc[0].lbaddr = value;         plx_map_space(d,0);         break;   }}/* * pci_plx9054_read() */static m_uint32_t pci_plx9054_read(cpu_gen_t *cpu,struct pci_device *dev,                                   int reg){      struct plx_data *d = dev->priv_data;#if DEBUG_ACCESS   PLX_LOG(d,"read PLX PCI register 0x%x\n",reg);#endif   switch(reg) {      /* Local space 1 */      case PCI_REG_BAR3:         return(d->lspc[1].lbaddr);      default:         return(pci_plx_read(cpu,dev,reg));   }}/* * pci_plx9054_write() */static void pci_plx9054_write(cpu_gen_t *cpu,struct pci_device *dev,                              int reg,m_uint32_t value){   struct plx_data *d = dev->priv_data;#if DEBUG_ACCESS   PLX_LOG(d,"write 0x%x to PLX PCI register 0x%x\n",value,reg);#endif   switch(reg) {      /* Local space 1 */      case PCI_REG_BAR3:         d->lspc[1].lbaddr = value;         plx_map_space(d,1);         break;      default:         pci_plx_write(cpu,dev,reg,value);   }}/* Shutdown a PLX device */void dev_plx_shutdown(vm_instance_t *vm,struct plx_data *d){   int i;   if (d != NULL) {      /* Unbind the managed devices */      for(i=0;i<PLX_LOCSPC_MAX;i++) {         if (d->lspc[i].dev)            vm_unbind_device(vm,d->lspc[i].dev);      }      /* Remove the PLX device */      dev_remove(vm,&d->plx_dev);      /* Remove the PCI PLX device */      pci_dev_remove(d->pci_plx_dev);      /* Free the structure itself */      free(d);   }}/* Create a generic PLX device */struct plx_data *dev_plx_init(vm_instance_t *vm,char *name){   struct plx_data *d;   int i;   /* Allocate the private data structure */   if (!(d = malloc(sizeof(*d)))) {      fprintf(stderr,"PLX: unable to create device.\n");      return NULL;   }   memset(d,0,sizeof(*d));   vm_object_init(&d->vm_obj);   d->vm_obj.name = name;   d->vm_obj.data = d;   d->vm_obj.shutdown = (vm_shutdown_t)dev_plx_shutdown;   d->vm   = vm;   d->name = name;   for(i=0;i<PLX_LOCSPC_MAX;i++)      d->lspc[i].range = PLX_LOCSPC_RANGE_DEFAULT;   dev_init(&d->plx_dev);   d->plx_dev.name      = name;   d->plx_dev.priv_data = d;   d->plx_dev.phys_addr = 0;   d->plx_dev.phys_len  = 0x1000;   d->plx_dev.handler   = dev_plx_access;   return(d);}/* Create a PLX9060 device */vm_obj_t *dev_plx9060_init(vm_instance_t *vm,char *name,                           struct pci_bus *pci_bus,int pci_device,                           struct vdevice *dev0){   struct plx_data *d;   /* Create the PLX data */   if (!(d = dev_plx_init(vm,name))) {      fprintf(stderr,"PLX: unable to create device.\n");      return NULL;   }   /* Set the PLX variant */   d->variant = 9060;   /* Set device for Local Space 0 */   d->lspc[0].dev = dev0;   /* Add PLX as a PCI device */   d->pci_plx_dev = pci_dev_add(pci_bus,name,                                PLX_PCI_VENDOR_ID,PLX9060_PCI_PRODUCT_ID,                                pci_device,0,-1,d,                                NULL,pci_plx_read,pci_plx_write);   if (!d->pci_plx_dev) {      fprintf(stderr,"%s (PLX9060): unable to create PCI device.\n",name);      goto err_pci_dev;   }   vm_object_add(vm,&d->vm_obj);   return(&d->vm_obj); err_pci_dev:   free(d);   return NULL;}/* Create a PLX9054 device */vm_obj_t *dev_plx9054_init(vm_instance_t *vm,char *name,                           struct pci_bus *pci_bus,int pci_device,                           struct vdevice *dev0,struct vdevice *dev1){   struct plx_data *d;   /* Create the PLX data */   if (!(d = dev_plx_init(vm,name))) {      fprintf(stderr,"PLX: unable to create device.\n");      return NULL;   }   /* Set the PLX variant */   d->variant = 9054;   d->plx_dev.handler = dev_plx9054_access;   /* Set device for Local Space 0 and 1 */   d->lspc[0].dev = dev0;   d->lspc[1].dev = dev1;   /* Add PLX as a PCI device */   d->pci_plx_dev = pci_dev_add(pci_bus,name,                                PLX_PCI_VENDOR_ID,PLX9054_PCI_PRODUCT_ID,                                pci_device,0,-1,d,                                NULL,pci_plx9054_read,pci_plx9054_write);   if (!d->pci_plx_dev) {      fprintf(stderr,"%s (PLX9054): unable to create PCI device.\n",name);      goto err_pci_dev;   }   vm_object_add(vm,&d->vm_obj);   return(&d->vm_obj); err_pci_dev:   free(d);   return NULL;}/* Set callback function for PCI-to-Local doorbell register */void dev_plx_set_pci2loc_doorbell_cbk(struct plx_data *d,                                      dev_plx_doorbell_cbk cbk,                                      void *arg){   if (d != NULL) {      d->pci2loc_doorbell_cbk = cbk;      d->pci2loc_doorbell_cbk_arg = arg;   }}/* Set the Local-to-PCI doorbell register (for Local device use) */void dev_plx_set_loc2pci_doorbell_reg(struct plx_data *d,m_uint32_t value){   if (d != NULL)      d->loc2pci_doorbell_reg = value;}

⌨️ 快捷键说明

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