追踪QEMU中PCI设备的初始化过程


首先需要知道的一些背景知识:PCI是总线的名称,同时也可以是一个PCI bridge,这个bridge就是一个设备了。在这个bridge上可以挂多种PCI设备,例如virtio-block,virtio-net等设备,这些block或者net设备逻辑上挂载到PCI总线上,物理上连接到PCI bridge上。

pci_qdev_realize这个函数位置设置断点。
bt栈如下:

Thread 1 "qemu-system-x86" hit Breakpoint 1, pci_qdev_realize (qdev=0x555556cb67f0, errp=0x7fffffffda40) at hw/pci/pci.c:2070
2070	{
(gdb) bt
#0  pci_qdev_realize (qdev=0x555556cb67f0, errp=0x7fffffffda40) at hw/pci/pci.c:2070
#1  0x0000555555a68aae in device_set_realized (obj=0x555556cb67f0, value=true, errp=0x7fffffffdc00) at hw/core/qdev.c:834
#2  0x0000555555c4ba4f in property_set_bool (obj=0x555556cb67f0, v=0x555556cbb020, name=0x555555f6aa11 "realized", opaque=0x555556c7fdb0,
    errp=0x7fffffffdc00) at qom/object.c:2079
#3  0x0000555555c49cb9 in object_property_set (obj=0x555556cb67f0, v=0x555556cbb020, name=0x555555f6aa11 "realized", errp=0x7fffffffdc00)
    at qom/object.c:1271
#4  0x0000555555c4cdc4 in object_property_set_qobject (obj=0x555556cb67f0, value=0x555556cbaf70, name=0x555555f6aa11 "realized", errp=0x7fffffffdc00)
    at qom/qom-qobject.c:26
#5  0x0000555555c49f97 in object_property_set_bool (obj=0x555556cb67f0, value=true, name=0x555555f6aa11 "realized", errp=0x7fffffffdc00)
    at qom/object.c:1337
#6  0x0000555555a67790 in qdev_init_nofail (dev=0x555556cb67f0) at hw/core/qdev.c:321
#7  0x0000555555b224c2 in pci_create_simple_multifunction (bus=0x555556c7f270, devfn=0, multifunction=false, name=0x555555f35b65 "i440FX")
    at hw/pci/pci.c:2131
#8  0x0000555555b22526 in pci_create_simple (bus=0x555556c7f270, devfn=0, name=0x555555f35b65 "i440FX") at hw/pci/pci.c:2142
#9  0x0000555555b199fe in i440fx_init (host_type=0x555555f35b6c "i440FX-pcihost", pci_type=0x555555f35b65 "i440FX", pi440fx_state=0x7fffffffdda8,
    piix3_devfn=0x7fffffffdd98, isa_bus=0x7fffffffdda0, pic=0x555556c7b5a0, address_space_mem=0x5555569b1a90, address_space_io=0x5555569b2510,
    ram_size=4294967296, below_4g_mem_size=3221225472, above_4g_mem_size=1073741824, pci_address_space=0x555556a60be0, ram_memory=0x555556a612d0)
    at hw/pci-host/piix.c:384
#10 0x0000555555937e59 in pc_init1 (machine=0x5555569ad800, host_type=0x555555f35b6c "i440FX-pcihost", pci_type=0x555555f35b65 "i440FX")
    at /root/code/qemu-4.1.0/hw/i386/pc_piix.c:201
#11 0x00005555559387e3 in pc_init_v4_1 (machine=0x5555569ad800) at /root/code/qemu-4.1.0/hw/i386/pc_piix.c:445
#12 0x0000555555a71a49 in machine_run_board_init (machine=0x5555569ad800) at hw/core/machine.c:1132
#13 0x00005555559fe083 in main (argc=25, argv=0x7fffffffe208, envp=0x7fffffffe2d8) at vl.c:4348

其中需要注意的是相关的realized函数是在xxx_xxx_class_init()函数中设定的。例如,

static void pci_device_class_init(ObjectClass *klass, void *data)
{
    DeviceClass *k = DEVICE_CLASS(klass);

    k->realize = pci_qdev_realize;
    k->unrealize = pci_qdev_unrealize;
    k->bus_type = TYPE_PCI_BUS;
    k->props = pci_props;
}
1. 初始化i440FX
Thread 1 "qemu-system-x86" hit Breakpoint 1, pci_create_simple (bus=0x555556c7f270, devfn=0, name=0x555555f35b65 "i440FX") at hw/pci/pci.c:2142
#0  pci_create_simple (bus=0x555556c7f270, devfn=0, name=0x555555f35b65 "i440FX") at hw/pci/pci.c:2142
#1  0x0000555555b199fe in i440fx_init (host_type=0x555555f35b6c "i440FX-pcihost", pci_type=0x555555f35b65 "i440FX", pi440fx_state=0x7fffffffdda8,
    piix3_devfn=0x7fffffffdd98, isa_bus=0x7fffffffdda0, pic=0x555556c7b5a0, address_space_mem=0x5555569b1a90, address_space_io=0x5555569b2510,
    ram_size=4294967296, below_4g_mem_size=3221225472, above_4g_mem_size=1073741824, pci_address_space=0x555556a60be0, ram_memory=0x555556a612d0)
    at hw/pci-host/piix.c:384
#2  0x0000555555937e59 in pc_init1 (machine=0x5555569ad800, host_type=0x555555f35b6c "i440FX-pcihost", pci_type=0x555555f35b65 "i440FX")
    at /root/code/qemu-4.1.0/hw/i386/pc_piix.c:201
#3  0x00005555559387e3 in pc_init_v4_1 (machine=0x5555569ad800) at /root/code/qemu-4.1.0/hw/i386/pc_piix.c:445
#4  0x0000555555a71a49 in machine_run_board_init (machine=0x5555569ad800) at hw/core/machine.c:1132
#5  0x00005555559fe083 in main (argc=25, argv=0x7fffffffe208, envp=0x7fffffffe2d8) at vl.c:4348

2. 初始化VGA PCI设备
Thread 1 "qemu-system-x86" hit Breakpoint 1, pci_create_simple (bus=0x555556c7f270, devfn=-1, name=0x555555fab6df "VGA") at hw/pci/pci.c:2142
2142        return pci_create_simple_multifunction(bus, devfn, false, name);
(gdb) bt
#0  pci_create_simple (bus=0x555556c7f270, devfn=-1, name=0x555555fab6df "VGA") at hw/pci/pci.c:2142
#1  0x0000555555b21e97 in pci_vga_init (bus=0x555556c7f270) at hw/pci/pci.c:1951
#2  0x0000555555934085 in pc_vga_init (isa_bus=0x555556ffea70, pci_bus=0x555556c7f270) at /root/code/qemu-4.1.0/hw/i386/pc.c:1975
#3  0x000055555593801a in pc_init1 (machine=0x5555569ad800, host_type=0x555555f35b6c "i440FX-pcihost", pci_type=0x555555f35b65 "i440FX")
    at /root/code/qemu-4.1.0/hw/i386/pc_piix.c:236
#4  0x00005555559387e3 in pc_init_v4_1 (machine=0x5555569ad800) at /root/code/qemu-4.1.0/hw/i386/pc_piix.c:445
#5  0x0000555555a71a49 in machine_run_board_init (machine=0x5555569ad800) at hw/core/machine.c:1132
#6  0x00005555559fe083 in main (argc=25, argv=0x7fffffffe208, envp=0x7fffffffe2d8) at vl.c:4348

3. 初始化芯片组PIIX3(控制IO)
Thread 1 "qemu-system-x86" hit Breakpoint 1, pci_create_simple (bus=0x555556c7f270, devfn=9, name=0x555555f7240c "piix3-ide") at hw/pci/pci.c:2142
2142        return pci_create_simple_multifunction(bus, devfn, false, name);
(gdb) bt
#0  pci_create_simple (bus=0x555556c7f270, devfn=9, name=0x555555f7240c "piix3-ide") at hw/pci/pci.c:2142
#1  0x0000555555ab8dc3 in pci_piix3_ide_init (bus=0x555556c7f270, hd_table=0x7fffffffde50, devfn=9) at hw/ide/piix.c:229
#2  0x0000555555938172 in pc_init1 (machine=0x5555569ad800, host_type=0x555555f35b6c "i440FX-pcihost", pci_type=0x555555f35b65 "i440FX")
    at /root/code/qemu-4.1.0/hw/i386/pc_piix.c:256
#3  0x00005555559387e3 in pc_init_v4_1 (machine=0x5555569ad800) at /root/code/qemu-4.1.0/hw/i386/pc_piix.c:445
#4  0x0000555555a71a49 in machine_run_board_init (machine=0x5555569ad800) at hw/core/machine.c:1132
#5  0x00005555559fe083 in main (argc=25, argv=0x7fffffffe208, envp=0x7fffffffe2d8) at vl.c:4348

 命令行参数:
-device virtio-blk-pci,iothread=iothreadxxx1,scsi=off,bus=pci.0,addr=0x6,drive=drive-virtio-disk1,id=virtio-disk0,disable-modern=off,disable-legacy=on 
-drive format=raw,if=none,id=drive-virtio-disk1,cache=directsync,file=/data/rootfs.img,aio=native 

对应的流程如下:

1. 初始化virtio-pci的流程

#0  pci_qdev_realize (qdev=0x55555789a4c0, errp=0x7fffffffdc30) at hw/pci/pci.c:2073
#1  0x0000555555bae9e5 in virtio_pci_dc_realize (qdev=0x55555789a4c0, errp=0x7fffffffdc30) at hw/virtio/virtio-pci.c:1859
#2  0x0000555555a68aae in device_set_realized (obj=0x55555789a4c0, value=true, errp=0x7fffffffde10) at hw/core/qdev.c:834
#3  0x0000555555c4ba4f in property_set_bool (obj=0x55555789a4c0, v=0x5555578a7be0, name=0x555555f500f2 "realized", opaque=0x55555789a030,
    errp=0x7fffffffde10) at qom/object.c:2079
#4  0x0000555555c49cb9 in object_property_set (obj=0x55555789a4c0, v=0x5555578a7be0, name=0x555555f500f2 "realized", errp=0x7fffffffde10)
    at qom/object.c:1271
#5  0x0000555555c4cdc4 in object_property_set_qobject (obj=0x55555789a4c0, value=0x5555578a7840, name=0x555555f500f2 "realized", errp=0x7fffffffde10)
    at qom/qom-qobject.c:26
#6  0x0000555555c49f97 in object_property_set_bool (obj=0x55555789a4c0, value=true, name=0x555555f500f2 "realized", errp=0x7fffffffde10)
    at qom/object.c:1337
#7  0x00005555559f146b in qdev_device_add (opts=0x5555568fae30, errp=0x555556859010 <error_fatal>) at qdev-monitor.c:634
#8  0x00005555559f916b in device_init_func (opaque=0x0, opts=0x5555568fae30, errp=0x555556859010 <error_fatal>) at vl.c:2191
#9  0x0000555555d9b5bb in qemu_opts_foreach (list=0x555556676040 <qemu_device_opts>, func=0x5555559f9144 <device_init_func>, opaque=0x0,
    errp=0x555556859010 <error_fatal>) at util/qemu-option.c:1170
#10 0x00005555559fe128 in main (argc=25, argv=0x7fffffffe208, envp=0x7fffffffe2d8) at vl.c:4372

继续追踪到virtio-blk设备的realize,如下:

Thread 1 "qemu-system-x86" hit Breakpoint 1, virtio_blk_pci_realize (vpci_dev=0x55555789a4c0, errp=0x7fffffffdb78)
    at /root/code/qemu-4.1.0/hw/virtio/virtio-blk-pci.c:50
50          VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(vpci_dev);
(gdb) bt
#0  virtio_blk_pci_realize (vpci_dev=0x55555789a4c0, errp=0x7fffffffdb78) at /root/code/qemu-4.1.0/hw/virtio/virtio-blk-pci.c:50
#1  0x0000555555bae634 in virtio_pci_realize (pci_dev=0x55555789a4c0, errp=0x7fffffffdb78) at hw/virtio/virtio-pci.c:1788
#2  0x0000555555b22308 in pci_qdev_realize (qdev=0x55555789a4c0, errp=0x7fffffffdc30) at hw/pci/pci.c:2092
#3  0x0000555555bae9e5 in virtio_pci_dc_realize (qdev=0x55555789a4c0, errp=0x7fffffffdc30) at hw/virtio/virtio-pci.c:1859
#4  0x0000555555a68aae in device_set_realized (obj=0x55555789a4c0, value=true, errp=0x7fffffffde10) at hw/core/qdev.c:834
#5  0x0000555555c4ba4f in property_set_bool (obj=0x55555789a4c0, v=0x5555578a7be0, name=0x555555f500f2 "realized", opaque=0x55555789a030,
    errp=0x7fffffffde10) at qom/object.c:2079
#6  0x0000555555c49cb9 in object_property_set (obj=0x55555789a4c0, v=0x5555578a7be0, name=0x555555f500f2 "realized", errp=0x7fffffffde10)
    at qom/object.c:1271
#7  0x0000555555c4cdc4 in object_property_set_qobject (obj=0x55555789a4c0, value=0x5555578a7840, name=0x555555f500f2 "realized", errp=0x7fffffffde10)
    at qom/qom-qobject.c:26
#8  0x0000555555c49f97 in object_property_set_bool (obj=0x55555789a4c0, value=true, name=0x555555f500f2 "realized", errp=0x7fffffffde10)
    at qom/object.c:1337
#9  0x00005555559f146b in qdev_device_add (opts=0x5555568fae30, errp=0x555556859010 <error_fatal>) at qdev-monitor.c:634
#10 0x00005555559f916b in device_init_func (opaque=0x0, opts=0x5555568fae30, errp=0x555556859010 <error_fatal>) at vl.c:2191
--Type <RET> for more, q to quit, c to continue without paging--
#11 0x0000555555d9b5bb in qemu_opts_foreach (list=0x555556676040 <qemu_device_opts>, func=0x5555559f9144 <device_init_func>, opaque=0x0,
    errp=0x555556859010 <error_fatal>) at util/qemu-option.c:1170
#12 0x00005555559fe128 in main (argc=25, argv=0x7fffffffe208, envp=0x7fffffffe2d8) at vl.c:4372


--------------------------------------------

Thread 1 "qemu-system-x86" hit Breakpoint 1, virtio_blk_device_realize (dev=0x5555578a2630, errp=0x7fffffffd8e0)
    at /root/code/qemu-4.1.0/hw/block/virtio-blk.c:1097
1097    {
(gdb) bt
#0  virtio_blk_device_realize (dev=0x5555578a2630, errp=0x7fffffffd8e0) at /root/code/qemu-4.1.0/hw/block/virtio-blk.c:1097
#1  0x000055555591a452 in virtio_device_realize (dev=0x5555578a2630, errp=0x7fffffffd940) at /root/code/qemu-4.1.0/hw/virtio/virtio.c:2613
#2  0x0000555555a68aae in device_set_realized (obj=0x5555578a2630, value=true, errp=0x7fffffffdb78) at hw/core/qdev.c:834
#3  0x0000555555c4ba4f in property_set_bool (obj=0x5555578a2630, v=0x5555578a5fc0, name=0x555555f32f98 "realized", opaque=0x5555578a3cf0,
    errp=0x7fffffffdb78) at qom/object.c:2079
#4  0x0000555555c49cb9 in object_property_set (obj=0x5555578a2630, v=0x5555578a5fc0, name=0x555555f32f98 "realized", errp=0x7fffffffdb78)
    at qom/object.c:1271
#5  0x0000555555c4cdc4 in object_property_set_qobject (obj=0x5555578a2630, value=0x5555578a5f10, name=0x555555f32f98 "realized", errp=0x7fffffffdb78)
    at qom/qom-qobject.c:26
#6  0x0000555555c49f97 in object_property_set_bool (obj=0x5555578a2630, value=true, name=0x555555f32f98 "realized", errp=0x7fffffffdb78)
    at qom/object.c:1337
#7  0x000055555592dbc4 in virtio_blk_pci_realize (vpci_dev=0x55555789a4c0, errp=0x7fffffffdb78) at /root/code/qemu-4.1.0/hw/virtio/virtio-blk-pci.c:58
#8  0x0000555555bae634 in virtio_pci_realize (pci_dev=0x55555789a4c0, errp=0x7fffffffdb78) at hw/virtio/virtio-pci.c:1788
#9  0x0000555555b22308 in pci_qdev_realize (qdev=0x55555789a4c0, errp=0x7fffffffdc30) at hw/pci/pci.c:2092
#10 0x0000555555bae9e5 in virtio_pci_dc_realize (qdev=0x55555789a4c0, errp=0x7fffffffdc30) at hw/virtio/virtio-pci.c:1859
#11 0x0000555555a68aae in device_set_realized (obj=0x55555789a4c0, value=true, errp=0x7fffffffde10) at hw/core/qdev.c:834
#12 0x0000555555c4ba4f in property_set_bool (obj=0x55555789a4c0, v=0x5555578a7be0, name=0x555555f500f2 "realized", opaque=0x55555789a030,
    errp=0x7fffffffde10) at qom/object.c:2079
--Type <RET> for more, q to quit, c to continue without paging--
#13 0x0000555555c49cb9 in object_property_set (obj=0x55555789a4c0, v=0x5555578a7be0, name=0x555555f500f2 "realized", errp=0x7fffffffde10)
    at qom/object.c:1271
#14 0x0000555555c4cdc4 in object_property_set_qobject (obj=0x55555789a4c0, value=0x5555578a7840, name=0x555555f500f2 "realized", errp=0x7fffffffde10)
    at qom/qom-qobject.c:26
#15 0x0000555555c49f97 in object_property_set_bool (obj=0x55555789a4c0, value=true, name=0x555555f500f2 "realized", errp=0x7fffffffde10)
    at qom/object.c:1337
#16 0x00005555559f146b in qdev_device_add (opts=0x5555568fae30, errp=0x555556859010 <error_fatal>) at qdev-monitor.c:634
#17 0x00005555559f916b in device_init_func (opaque=0x0, opts=0x5555568fae30, errp=0x555556859010 <error_fatal>) at vl.c:2191
#18 0x0000555555d9b5bb in qemu_opts_foreach (list=0x555556676040 <qemu_device_opts>, func=0x5555559f9144 <device_init_func>, opaque=0x0,
    errp=0x555556859010 <error_fatal>) at util/qemu-option.c:1170
#19 0x00005555559fe128 in main (argc=25, argv=0x7fffffffe208, envp=0x7fffffffe2d8) at vl.c:4372
(gdb)

参考文献:
https://github.com/GiantVM/doc/blob/master/pci.md
https://dangokyo.me/2018/03/28/qemu-internal-pci-device/

原文地址:https://www.cnblogs.com/powerrailgun/p/12653864.html