Dynamips的PCI模拟

/* PCI device */
struct  pci_device  {
char *name;
u_int vendor_id,product_id;
int device,function,irq;
void *priv_data;

/* Parent bus */
struct pci_bus *pci_bus;

pci_init_t init;
pci_reg_read_t read_register;
pci_reg_write_t write_register;

struct pci_device *next,**pprev;
}
;

/* PCI bus */
struct  pci_bus  {
char *name;
m_uint32_t pci_addr;

/* Bus number */
int bus;

/* PCI device list on this bus */
struct pci_device *dev_list;

/* PCI bridges to access other busses */
struct pci_bridge *bridge_list;
}
;
PCI总线的数据结构

/* PCI bridge */
struct  pci_bridge  {
int pri_bus; /* Primary Bus */
int sec_bus; /* Secondary Bus */
int sub_bus; /* Subordinate Bus */

int skip_bus_check;

/* Bus configuration register */
m_uint32_t cfg_reg_bus;

/* PCI bridge device */
struct pci_device *pci_dev;

/* Secondary PCI bus */
struct pci_bus *pci_bus;

/* Fallback handlers to read/write config registers */
pci_reg_read_t fallback_read;
pci_reg_write_t fallback_write;

struct pci_bridge *next,**pprev;
}
;

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)

pci_bridge_create_dev这个函数的功能是创建PCI桥设备,sec_bus这个入参指向下一级总线.

比如DEC21050桥芯片模拟就调用这个函数,

int  dev_dec21050_init( struct  pci_bus  * pci_bus, int  pci_device,
struct  pci_bus  * sec_bus)
{
struct pci_device *dev;

dev 
= pci_bridge_create_dev(pci_bus,"dec21050",
PCI_VENDOR_DEC,PCI_PRODUCT_DEC_21050,
pci_device,
0,sec_bus,NULL,NULL);
return((dev != NULL) ? 0 : -1);
}



/* 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)

pci_dev_add这个函数创建了PCI设备.
比如
struct  am79c971_data  *
dev_am79c971_init(vm_instance_t 
* vm, char   * name, int  interface_type,
struct  pci_bus  * pci_bus, int  pci_device, int  irq)
{
struct am79c971_data *d;
struct pci_device *pci_dev;
struct vdevice *dev;

/* Allocate the private data structure for AM79C971 */
if (!(d = malloc(sizeof(*d)))) {
fprintf(stderr,
"%s (AM79C971): out of memory ",name);
return NULL;
}


memset(d,
0,sizeof(*d));
memcpy(d
->mii_regs[0],mii_reg_values,sizeof(mii_reg_values));
pthread_mutex_init(
&d->lock,NULL);

/* Add as PCI device */
pci_dev 
= pci_dev_add(pci_bus,name,
AM79C971_PCI_VENDOR_ID,AM79C971_PCI_PRODUCT_ID,
pci_device,
0,irq,
d,NULL,pci_am79c971_read,pci_am79c971_write);

if (!pci_dev) {
fprintf(stderr,
"%s (AM79C971): unable to create PCI device. ",name);
goto err_pci_dev;
}



AM79C971的读写函数被注册为pci_am79c971_read,pci_am79c971_write
实现如下:
static m_uint32_t pci_am79c971_read(cpu_gen_t *cpu,struct pci_device *dev,
int reg)
{
struct am79c971_data *d = dev->priv_data;

#if DEBUG_PCI_REGS
AM79C971_LOG(d,"read PCI register 0x%x/n",reg);
#endif

switch (reg) {
case 0x00:
return((AM79C971_PCI_PRODUCT_ID << 16) | AM79C971_PCI_VENDOR_ID);
case 0x08:
return(0x02000002);
case PCI_REG_BAR1:
return(d->dev->phys_addr);
default:
return(0);
}
}
再比如
/*
* pci_ap1011_read()
*
* Read a PCI register.
*/
static m_uint32_t pci_ap1011_read(cpu_gen_t *cpu,struct pci_device *dev,
int reg)
{
switch (reg) {
case 0x08:
return(0x06040000);
case 0x34:
return(0x00000040);
case 0x40:
return(0x00210008);
case 0x44:
return(0x00000020);
case 0x48:
return(0x000000C0);
default:
return(0);
}
}
这些实现函数就是模拟寄存器响应的实现.
那么什么时候会触发寄存器的访问?

是通过pci_dev_data_handler来处理的,这个函数会调用各个设备挂接在数据结构上的
读写函数来实现访问

/*
* 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_gen_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 = 0x0;

/*
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 ",
cpu_get_pc(cpu), 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 ",
pci_swap(
*data,swap), cpu_get_pc(cpu),
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). ",
cpu_get_pc(cpu), 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). ",
pci_swap(
*data,swap), cpu_get_pc(cpu),
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);
}

}

}

}


dev_c2600_pci_init:
d
-> dev.handler  =  dev_c2600_pci_access;

dev_c2600_pci_access:
switch (offset)  {
case 0x500:
pci_dev_addr_handler(cpu,d
->bus,op_type,FALSE,data);
break;

case 0x504:
pci_dev_data_handler(cpu,d
->bus,op_type,FALSE,data);
break;



PCI的处理最后通过vm_bind_device绑定到VM对象上
也就是说vm->dev_array[i].handler(比如dev_c2600_pci_access)可以访问到PCI处理函数

最后是 dev_access_fast 这个通用访问函数调用了处理函数
/* device access function */
static forced_inline
void *dev_access_fast(cpu_gen_t *cpu,u_int dev_id,m_uint32_t offset,
u_int op_size,u_int op_type,m_uint64_t *data)
{
struct vdevice *dev = cpu->vm->dev_array[dev_id];

if (unlikely(!dev)) {
cpu_log(cpu,"dev_access_fast","null handler (dev_id=%u,offset=0x%x)/n",
dev_id,offset);
return NULL;
}

#if DEBUG_DEV_PERF_CNT
cpu->dev_access_counter++;
#endif

return(dev->handler(cpu,dev,offset,op_size,op_type,data));
}

mips64_mts64_access
mips64_mts32_access
ppc32_mem_access
这三个函数调用了dev_access_fast

以ppc32_mem_access(访问DCACHE时的等效宏定义是PPC32_MEM_DACCESS)为例,看有哪些函数调用了
ppc32_lbz
ppc32_lhz
ppc32_lwz
ppc32_lwbr等内存指令

另外一处调用在ppc32_mem_lookup(虚拟地址查找)
挂接在cpu->mem_op_lookup = ppc32_mem_lookup;

有ppc32_exec_fetch等函数使用了cpu->mem_op_lookup.

还有一些问题:
1.怎么知道哪些地址对应哪个访问函数?



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值