跳转指令
#define SWITCH_TO(rsp, to) \
{ \
asm volatile ("movq %0, %%rsp\n" \
"pushq %1\n" \
"jmpq *%2\n" \
: \
: "r"(rsp), "rm"(SP_BOTTOM_MAGIC), "a"(to)); \
}
后面主要谈谈vpci_init流程:
pcie中:系统将IO Space中从0CF8h-0CFBh这32bit划分为Configuration Address Port,将0CFCh-0CFFh这32bit划分为Configuration Data Port。
Configuration Address Port有一下定义:
- Bit0-1是硬编码进芯片的。
- Bit2-7定义Target dword,表明要写的comfiguration space的位置Configuration Space总计有64个Dword。
- Bit8-23为目标的ID。
- Bit31为使能位,为一时使能工作。
当CPU想要进行一个Configuration Write时,它只需在Configuration Address Port写进它的地址,和Target dwor。在Configuration Data Port写入数据,使能就完成一个配置写操作了。当CPU从Configuration Data Port进行读操作就完成配置读操作了
void init_vpci(struct acrn_vm *vm)
{
struct vm_io_range pci_cfgaddr_range = {
.base = PCI_CONFIG_ADDR,
.len = 1U
};
struct vm_io_range pci_cfgdata_range = {
.base = PCI_CONFIG_DATA,
.len = 4U
};
vm->vpci.pci_mmcfg.address = UOS_VIRT_PCI_MMCFG_BASE;
vm->vpci.pci_mmcfg.start_bus = UOS_VIRT_PCI_MMCFG_START_BUS;
vm->vpci.pci_mmcfg.end_bus = UOS_VIRT_PCI_MMCFG_END_BUS;
vm->vpci.res32.start = UOS_VIRT_PCI_MEMBASE32;
vm->vpci.res32.end = UOS_VIRT_PCI_MEMLIMIT32;
vm->vpci.res64.start = UOS_VIRT_PCI_MEMBASE64;
vm->vpci.res64.end = UOS_VIRT_PCI_MEMLIMIT64;
/* Build up vdev list for vm */
vpci_init_vdevs(vm);
register_mmio_emulation_handler(vm, vpci_mmio_cfg_access, vm->vpci.pci_mmcfg.address,
vm->vpci.pci_mmcfg.address + get_pci_mmcfg_size(&vm->vpci.pci_mmcfg), &vm->vpci, false);
/* Intercept and handle I/O ports CF8h */
register_pio_emulation_handler(vm, PCI_CFGADDR_PIO_IDX, &pci_cfgaddr_range,
vpci_pio_cfgaddr_read, vpci_pio_cfgaddr_write);
/* Intercept and handle I/O ports CFCh -- CFFh */
register_pio_emulation_handler(vm, PCI_CFGDATA_PIO_IDX, &pci_cfgdata_range,
vpci_pio_cfgdata_read, vpci_pio_cfgdata_write);
spinlock_init(&vm->vpci.lock);
}