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

📄 pci_dev.c

📁 思科路由器仿真器,用来仿7200系列得,可以在电脑上模拟路由器-Cisco router simulator, used to fake a 7200 series can be simulated
💻 C
字号:
/* * Cisco 7200 (Predator) simulation platform. * Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr) * * PCI devices. * * Very interesting docs: *   http://www.science.unitn.it/~fiorella/guidelinux/tlk/node72.html *   http://www.science.unitn.it/~fiorella/guidelinux/tlk/node76.html */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <sys/types.h>#include "mips64.h"#include "dynamips.h"#include "memory.h"#include "device.h"#include "vm.h"#define DEBUG_PCI 1#define GET_PCI_ADDR(offset,mask) ((pci_bus->pci_addr >> offset) & mask)/* Trigger a PCI device IRQ */void pci_dev_trigger_irq(vm_instance_t *vm,struct pci_device *dev){   if (dev->irq != -1)      vm_set_irq(vm,dev->irq);}/* Clear a PCI device IRQ */void pci_dev_clear_irq(vm_instance_t *vm,struct pci_device *dev){   if (dev->irq != -1)      vm_clear_irq(vm,dev->irq);}/* Swapping function */static inline m_uint32_t pci_swap(m_uint32_t val,int swap){   return((swap) ? swap32(val) : val);}/* PCI bus lookup */struct pci_bus *pci_bus_lookup(struct pci_bus *pci_bus_root,int bus){   struct pci_bus *next_bus,*cur_bus = pci_bus_root;   struct pci_bridge *bridge;   while(cur_bus != NULL) {      if (cur_bus->bus == bus)         return cur_bus;            /* Try busses behind PCI bridges */      next_bus = NULL;      for(bridge=cur_bus->bridge_list;bridge;bridge=bridge->next) {         /*           * Specific case: final bridge with no checking of secondary          * bus number. Dynamically programming.          */         if (bridge->skip_bus_check) {            pci_bridge_set_bus_info(bridge,cur_bus->bus,bus,bus);            bridge->skip_bus_check = FALSE;            return bridge->pci_bus;         }         if ((bus >= bridge->sec_bus) && (bus <= bridge->sub_bus)) {            next_bus = bridge->pci_bus;            break;         }      }      cur_bus = next_bus;   }   return NULL;}/* PCI device local lookup */struct pci_device *pci_dev_lookup_local(struct pci_bus *pci_bus,                                        int device,int function){   struct pci_device *dev;   for(dev=pci_bus->dev_list;dev;dev=dev->next)      if ((dev->device == device) && (dev->function == function))         return dev;   return NULL;}/* PCI Device lookup */struct pci_device *pci_dev_lookup(struct pci_bus *pci_bus_root,                                  int bus,int device,int function){   struct pci_bus *req_bus;   /* Find, try to find the request bus */   if (!(req_bus = pci_bus_lookup(pci_bus_root,bus)))      return NULL;   /* Walk through devices present on this bus */   return pci_dev_lookup_local(req_bus,device,function);}/* Handle the address register access */void pci_dev_addr_handler(cpu_mips_t *cpu,struct pci_bus *pci_bus,                          u_int op_type,int swap,m_uint64_t *data){   if (op_type == MTS_WRITE)      pci_bus->pci_addr = pci_swap(*data,swap);   else      *data = pci_swap(pci_bus->pci_addr,swap);}/* * Handle the data register access. * * The address of requested register is first written at address 0xcf8 * (with pci_dev_addr_handler). * * The data is read/written at address 0xcfc. */void pci_dev_data_handler(cpu_mips_t *cpu,struct pci_bus *pci_bus,                          u_int op_type,int swap,m_uint64_t *data){      struct pci_device *dev;   int bus,device,function,reg;   if (op_type == MTS_READ)      *data = 0;   /*    * http://www.mega-tokyo.com/osfaq2/index.php/PciSectionOfPentiumVme    *    * 31      : Enable Bit     * 30 - 24 : Reserved    * 23 - 16 : Bus Number    * 15 - 11 : Device Number    * 10 -  8 : Function Number    *  7 -  2 : Register Number    *  1 -  0 : always 00    */   bus      = GET_PCI_ADDR(16,0xff);   device   = GET_PCI_ADDR(11,0x1f);   function = GET_PCI_ADDR(8,0x7);   reg      = GET_PCI_ADDR(0,0xff);   /* Find the corresponding PCI device */   dev = pci_dev_lookup(pci_bus,bus,device,function);#if DEBUG_PCI   if (op_type == MTS_READ) {      cpu_log(cpu,"PCI","read request at pc=0x%llx: "              "bus=%d,device=%d,function=%d,reg=0x%2.2x\n",              cpu->pc, bus, device, function, reg);   } else {      cpu_log(cpu,"PCI","write request (data=0x%8.8x) at pc=0x%llx: "              "bus=%d,device=%d,function=%d,reg=0x%2.2x\n",              pci_swap(*data,swap), cpu->pc, bus, device, function, reg);   }#endif   if (!dev) {      if (op_type == MTS_READ) {         cpu_log(cpu,"PCI","read request for unknown device at pc=0x%llx "                 "(bus=%d,device=%d,function=%d,reg=0x%2.2x).\n",                 cpu->pc, bus, device, function, reg);      } else {         cpu_log(cpu,"PCI","write request (data=0x%8.8x) for unknown device "                 "at pc=0x%llx (bus=%d,device=%d,function=%d,reg=0x%2.2x).\n",                 pci_swap(*data,swap), cpu->pc, bus, device, function, reg);      }      /* Returns an invalid device ID */      if ((op_type == MTS_READ) && (reg == PCI_REG_ID))         *data = 0xffffffff;   } else {      if (op_type == MTS_WRITE) {         if (dev->write_register != NULL)            dev->write_register(cpu,dev,reg,pci_swap(*data,swap));      } else {         if (reg == PCI_REG_ID)            *data = pci_swap((dev->product_id << 16) | dev->vendor_id,swap);         else {            if (dev->read_register != NULL)               *data = pci_swap(dev->read_register(cpu,dev,reg),swap);         }      }   }}/* Add a PCI bridge */struct pci_bridge *pci_bridge_add(struct pci_bus *pci_bus){   struct pci_bridge *bridge;   if (!pci_bus)      return NULL;   if (!(bridge = malloc(sizeof(*bridge)))) {      fprintf(stderr,"pci_bridge_add: unable to create new PCI bridge.\n");      return NULL;   }   memset(bridge,0,sizeof(*bridge));   bridge->pri_bus = pci_bus->bus;   bridge->sec_bus = -1;   bridge->sub_bus = -1;   bridge->pci_bus = NULL;   /* Insert the bridge in the double-linked list */   bridge->next = pci_bus->bridge_list;   bridge->pprev = &pci_bus->bridge_list;   if (pci_bus->bridge_list != NULL)      pci_bus->bridge_list->pprev = &bridge->next;   pci_bus->bridge_list = bridge;   return bridge;}/* Remove a PCI bridge from the double-linked list */static inline void pci_bridge_remove_from_list(struct pci_bridge *bridge){   if (bridge->next)      bridge->next->pprev = bridge->pprev;   if (bridge->pprev)      *(bridge->pprev) = bridge->next;}/* Remove a PCI bridge */void pci_bridge_remove(struct pci_bridge *bridge){   if (bridge != NULL) {      pci_bridge_remove_from_list(bridge);      free(bridge);   }}/* Map secondary bus to a PCI bridge */void pci_bridge_map_bus(struct pci_bridge *bridge,struct pci_bus *pci_bus){   if (bridge != NULL) {      bridge->pci_bus = pci_bus;      if (bridge->pci_bus != NULL)         bridge->pci_bus->bus = bridge->sec_bus;   }}/* Set PCI bridge bus info */void pci_bridge_set_bus_info(struct pci_bridge *bridge,                             int pri_bus,int sec_bus,int sub_bus){   if (bridge != NULL) {      bridge->pri_bus = pri_bus;      bridge->sec_bus = sec_bus;      bridge->sub_bus = sub_bus;      if (bridge->pci_bus != NULL)         bridge->pci_bus->bus = bridge->sec_bus;   }}/* Add a PCI device */struct pci_device *pci_dev_add(struct pci_bus *pci_bus,char *name,            u_int vendor_id,u_int product_id,            int device,int function,int irq,            void *priv_data,pci_init_t init,            pci_reg_read_t read_register,            pci_reg_write_t write_register){   struct pci_device *dev;   if (!pci_bus)      return NULL;   if ((dev = pci_dev_lookup_local(pci_bus,device,function)) != NULL) {      fprintf(stderr,"pci_dev_add: bus %s, device %d, function %d already "              "registered (device '%s').\n",              pci_bus->name,device,function,dev->name);      return NULL;   }   /* we can create safely the new device */   if (!(dev = malloc(sizeof(*dev)))) {      fprintf(stderr,"pci_dev_add: unable to create new PCI device.\n");      return NULL;   }   memset(dev,0,sizeof(*dev));   dev->name = name;   dev->vendor_id = vendor_id;   dev->product_id = product_id;   dev->pci_bus = pci_bus;   dev->device = device;   dev->function = function;   dev->irq = irq;   dev->priv_data = priv_data;   dev->init = init;   dev->read_register = read_register;   dev->write_register = write_register;   /* Insert the device in the double-linked list */   dev->next = pci_bus->dev_list;   dev->pprev = &pci_bus->dev_list;   if (pci_bus->dev_list != NULL)      pci_bus->dev_list->pprev = &dev->next;   pci_bus->dev_list = dev;   if (init) init(dev);   return dev;}/* Add a basic PCI device that just returns a Vendor/Product ID */struct pci_device *pci_dev_add_basic(struct pci_bus *pci_bus,                  char *name,u_int vendor_id,u_int product_id,                  int device,int function){   return(pci_dev_add(pci_bus,name,vendor_id,product_id,                      device,function,-1,NULL,                      NULL,NULL,NULL));}/* Remove a device from the double-linked list */static inline void pci_dev_remove_from_list(struct pci_device *dev){   if (dev->next)      dev->next->pprev = dev->pprev;   if (dev->pprev)      *(dev->pprev) = dev->next;}/* Remove a PCI device */void pci_dev_remove(struct pci_device *dev){   if (dev != NULL) {      pci_dev_remove_from_list(dev);      free(dev);   }}/* Remove a PCI device given its ID (bus,device,function) */int pci_dev_remove_by_id(struct pci_bus *pci_bus,                         int bus,int device,int function){   struct pci_device *dev;   if (!(dev = pci_dev_lookup(pci_bus,bus,device,function)))      return(-1);   pci_dev_remove(dev);   return(0);}/* Remove a PCI device given its name */int pci_dev_remove_by_name(struct pci_bus *pci_bus,char *name){   struct pci_device *dev,*next;   int count = 0;   for(dev=pci_bus->dev_list;dev;dev=next) {      next = dev->next;      if (!strcmp(dev->name,name)) {         pci_dev_remove(dev);         count++;      }   }   return(count);}/* Create a PCI bus */struct pci_bus *pci_bus_create(char *name,int bus){   struct pci_bus *d;   if (!(d = malloc(sizeof(*d)))) {      fprintf(stderr,"pci_bus_create: unable to create PCI info.\n");      return NULL;   }   memset(d,0,sizeof(*d));   d->name = strdup(name);   d->bus  = bus;   return d;}/* Delete a PCI bus */void pci_bus_remove(struct pci_bus *pci_bus){   struct pci_device *dev,*next;   struct pci_bridge *bridge,*next_bridge;   if (pci_bus) {      /* Remove all devices */      for(dev=pci_bus->dev_list;dev;dev=next) {         next = dev->next;         free(dev);      }      /* Remove all bridges */      for(bridge=pci_bus->bridge_list;bridge;bridge=next_bridge) {         next_bridge = bridge->next;         free(bridge);      }      /* Free the structure itself */      free(pci_bus->name);      free(pci_bus);   }}/* Read a configuration register of a PCI bridge */static m_uint32_t pci_bridge_read_reg(cpu_mips_t *cpu,struct pci_device *dev,                                      int reg){   struct pci_bridge *bridge = dev->priv_data;   m_uint32_t val = 0;   switch(reg) {      case 0x18:         return(bridge->cfg_reg_bus);      default:         if (bridge->fallback_read != NULL)            val = bridge->fallback_read(cpu,dev,reg);            /* Returns appropriate PCI bridge class code if nothing defined */         if ((reg == 0x08) && !val)            val = 0x06040000;         return(val);   }}/* Write a configuration register of a PCI bridge */static void pci_bridge_write_reg(cpu_mips_t *cpu,struct pci_device *dev,                                 int reg,m_uint32_t value){   struct pci_bridge *bridge = dev->priv_data;   u_int pri_bus,sec_bus,sub_bus;   switch(reg) {      case 0x18:         bridge->cfg_reg_bus = value;         sub_bus = (value >> 16) & 0xFF;         sec_bus = (value >>  8) & 0xFF;         pri_bus = value & 0xFF;         /* Modify the PCI bridge settings */         vm_log(cpu->vm,"PCI",                "PCI bridge %d,%d,%d -> pri: %2.2u, sec: %2.2u, sub: %2.2u\n",                dev->pci_bus->bus,dev->device,dev->function,                pri_bus,sec_bus,sub_bus);         pci_bridge_set_bus_info(bridge,pri_bus,sec_bus,sub_bus);         break;               default:         if (bridge->fallback_write != NULL)            bridge->fallback_write(cpu,dev,reg,value);   }}/* Create a PCI bridge device */struct pci_device *pci_bridge_create_dev(struct pci_bus *pci_bus,char *name,                                         u_int vendor_id,u_int product_id,                                         int device,int function,                                         struct pci_bus *sec_bus,                                         pci_reg_read_t fallback_read,                                         pci_reg_write_t fallback_write){   struct pci_bridge *bridge;   struct pci_device *dev;   /* Create the PCI bridge structure */   if (!(bridge = pci_bridge_add(pci_bus)))      return NULL;   /* Create the PCI device corresponding to the bridge */   dev = pci_dev_add(pci_bus,name,vendor_id,product_id,device,function,-1,                     bridge,NULL,pci_bridge_read_reg,pci_bridge_write_reg);      if (!dev)      goto err_pci_dev;      /* Keep the associated PCI device for this bridge */   bridge->pci_dev = dev;   /* Set the fallback functions */   bridge->fallback_read  = fallback_read;   bridge->fallback_write = fallback_write;   /* Map the secondary bus (disabled at startup) */   pci_bridge_map_bus(bridge,sec_bus);   return dev; err_pci_dev:   pci_bridge_remove(bridge);   return NULL;}/* Show PCI device list of the specified bus */static void pci_bus_show_dev_list(struct pci_bus *pci_bus){   struct pci_device *dev;   struct pci_bridge *bridge;   char bus_id[32];   if (!pci_bus)      return;   if (pci_bus->bus != -1) {      snprintf(bus_id,sizeof(bus_id),"%2d",pci_bus->bus);   } else {      strcpy(bus_id,"XX");   }   for(dev=pci_bus->dev_list;dev;dev=dev->next) {      printf("   %-18s: ID %4.4x:%4.4x, Bus %s, Dev. %2d, Func. %2d",             dev->name,dev->vendor_id,dev->product_id,             bus_id,dev->device,dev->function);      if (dev->irq != -1)         printf(", IRQ: %d\n",dev->irq);      else         printf("\n");   }   for(bridge=pci_bus->bridge_list;bridge;bridge=bridge->next)      pci_bus_show_dev_list(bridge->pci_bus);}/* Show PCI device list */void pci_dev_show_list(struct pci_bus *pci_bus){   if (!pci_bus)      return;   printf("PCI Bus \"%s\" Device list:\n",pci_bus->name);   pci_bus_show_dev_list(pci_bus);   printf("\n");}

⌨️ 快捷键说明

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