
/**//* 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.怎么知道哪些地址对应哪个访问函数?