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橋芯片模擬就調用這個函數,
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.怎麼知道哪些地址對應哪個訪問函數?