接前一篇文章:QEMU源码全解析31 —— Machine(1)
本文内容参考:
《趣谈Linux操作系统》 —— 刘超,极客时间
《QEMU/KVM》源码解析与应用 —— 李强,机械工业出版社
特此致谢!
上一篇文章给machine即主板与固件开了个头,并主要介绍了Intel 440FX主板也可以说芯片组。本回讲解QEMU模拟主板架构。
QEMU主板模拟图如下图所示:
可以发现,此图与上一篇文章中的Intel 440FX架构是比较接近的,两者的基本架构一致。为了便于对比和理解,再次贴出Intel 440FX的架构图,如下:
通过以下命令进入QEMU monitor:
qemu-system-x86_64 -vnc :1 -monitor stdio
或
qemu -vnc :1 -monitor stdio
实际命令及结果如下:
$ qemu-system-x86_64 -vnc :1 -monitor stdio
QEMU 7.1.0 monitor - type 'help' for more information
(qemu)
在QEMU monitor中输入“info qtree”,可以看到QEMU虚拟机的设备结构,如下所示:
$ qemu-system-x86_64 -vnc :1 -monitor stdioQEMU 7.1.0 monitor - type 'help' for more information
(qemu) info qtree
bus: main-system-bus
type System
dev: ps2-mouse, id ""
gpio-out "" 1
dev: ps2-kbd, id ""
gpio-out "" 1
dev: hpet, id ""
gpio-in "" 2
gpio-out "" 1
gpio-out "sysbus-irq" 32
timers = 3 (0x3)
msi = false
hpet-intcap = 4 (0x4)
hpet-offset-saved = true
mmio 00000000fed00000/0000000000000400
dev: ioapic, id ""
gpio-in "" 24
version = 32 (0x20)
mmio 00000000fec00000/0000000000001000
dev: i440FX-pcihost, id ""
pci-hole64-size = 2147483648 (2 GiB)
short_root_bus = 0 (0x0)
x-pci-hole64-fix = true
x-config-reg-migration-enabled = true
bypass-iommu = false
bus: pci.0
type PCI
dev: PIIX4_PM, id ""
gpio-out "smi-irq" 1
gpio-out "" 1
smb_io_base = 1792 (0x700)
disable_s3 = 0 (0x0)
disable_s4 = 0 (0x0)
s4_val = 2 (0x2)
acpi-pci-hotplug-with-bridge-support = true
acpi-root-pci-hotplug = true
memory-hotplug-support = true
smm-compat = false
smm-enabled = true
x-not-migrate-acpi-index = false
addr = 01.3
romfile = ""
romsize = 4294967295 (0xffffffff)
rombar = 1 (0x1)
multifunction = false
x-pcie-lnksta-dllla = true
x-pcie-extcap-init = true
failover_pair_id = ""
acpi-index = 0 (0x0)
class Bridge, addr 00:01.3, pci id 8086:7113 (sub 1af4:1100)
bus: i2c
type i2c-bus
dev: smbus-eeprom, id ""
address = 87 (0x57)
dev: smbus-eeprom, id ""
address = 86 (0x56)
dev: smbus-eeprom, id ""
address = 85 (0x55)
dev: smbus-eeprom, id ""
address = 84 (0x54)
dev: smbus-eeprom, id ""
address = 83 (0x53)
dev: smbus-eeprom, id ""
address = 82 (0x52)
dev: smbus-eeprom, id ""
address = 81 (0x51)
dev: smbus-eeprom, id ""
address = 80 (0x50)
dev: piix3-ide, id ""
addr = 01.1
romfile = ""
romsize = 4294967295 (0xffffffff)
rombar = 1 (0x1)
multifunction = false
x-pcie-lnksta-dllla = true
x-pcie-extcap-init = true
failover_pair_id = ""
acpi-index = 0 (0x0)
class IDE controller, addr 00:01.1, pci id 8086:7010 (sub 1af4:1100)
bar 4: i/o at 0xc040 [0xc04f]
bus: ide.1
type IDE
dev: ide-cd, id ""
drive = "ide1-cd0"
backend_defaults = "auto"
logical_block_size = 512 (512 B)
physical_block_size = 512 (512 B)
min_io_size = 0 (0 B)
opt_io_size = 0 (0 B)
discard_granularity = 512 (512 B)
write-cache = "auto"
share-rw = false
rerror = "auto"
werror = "auto"
ver = "2.5+"
wwn = 0 (0x0)
serial = "QM00003"
model = ""
unit = 0 (0x0)
bus: ide.0
type IDE
dev: e1000, id ""
mac = "52:54:00:12:34:56"
netdev = "hub0port0"
autonegotiation = true
mitigation = true
extra_mac_registers = true
migrate_tso_props = true
init-vet = true
addr = 03.0
romfile = "efi-e1000.rom"
romsize = 262144 (0x40000)
rombar = 1 (0x1)
multifunction = false
x-pcie-lnksta-dllla = true
x-pcie-extcap-init = true
failover_pair_id = ""
acpi-index = 0 (0x0)
class Ethernet controller, addr 00:03.0, pci id 8086:100e (sub 1af4:1100)
bar 0: mem at 0xfebc0000 [0xfebdffff]
bar 1: i/o at 0xc000 [0xc03f]
bar 6: mem at 0xffffffffffffffff [0x3fffe]
dev: VGA, id ""
vgamem_mb = 16 (0x10)
mmio = true
qemu-extended-regs = true
edid = true
xres = 1280 (0x500)
yres = 800 (0x320)
xmax = 0 (0x0)
ymax = 0 (0x0)
refresh_rate = 0 (0x0)
global-vmstate = false
addr = 02.0
romfile = "vgabios-stdvga.bin"
romsize = 65536 (0x10000)
rombar = 1 (0x1)
multifunction = false
x-pcie-lnksta-dllla = true
x-pcie-extcap-init = true
failover_pair_id = ""
acpi-index = 0 (0x0)
class VGA controller, addr 00:02.0, pci id 1234:1111 (sub 1af4:1100)
bar 0: mem at 0xfd000000 [0xfdffffff]
bar 2: mem at 0xfebf0000 [0xfebf0fff]
bar 6: mem at 0xffffffffffffffff [0xfffe]
dev: PIIX3, id ""
addr = 01.0
romfile = ""
romsize = 4294967295 (0xffffffff)
rombar = 1 (0x1)
multifunction = true
x-pcie-lnksta-dllla = true
x-pcie-extcap-init = true
failover_pair_id = ""
acpi-index = 0 (0x0)
class ISA bridge, addr 00:01.0, pci id 8086:7000 (sub 1af4:1100)
bus: isa.0
type ISA
dev: port92, id ""
gpio-out "a20" 1
dev: vmmouse, id ""
dev: vmport, id ""
x-read-set-eax = true
x-signal-unsupported-cmd = true
x-report-vmx-type = true
x-cmds-v2 = true
vmware-vmx-version = 6 (0x6)
vmware-vmx-type = 2 (0x2)
dev: i8042, id ""
gpio-in "ps2-mouse-input-irq" 1
gpio-in "ps2-kbd-input-irq" 1
gpio-out "" 2
gpio-out "a20" 1
extended-state = true
kbd-throttle = false
kbd-irq = 1 (0x1)
mouse-irq = 12 (0xc)
dev: isa-fdc, id ""
iobase = 1008 (0x3f0)
irq = 6 (0x6)
dma = 2 (0x2)
fdtypeA = "auto"
fdtypeB = "auto"
fallback = "288"
bus: floppy-bus.0
type floppy-bus
dev: floppy, id ""
unit = 0 (0x0)
drive = "floppy0"
backend_defaults = "auto"
logical_block_size = 512 (512 B)
physical_block_size = 512 (512 B)
min_io_size = 0 (0 B)
opt_io_size = 0 (0 B)
discard_granularity = 4294967295 (4 GiB)
write-cache = "auto"
share-rw = false
drive-type = "288"
dev: isa-parallel, id ""
index = 0 (0x0)
iobase = 888 (0x378)
irq = 7 (0x7)
chardev = "parallel0"
dev: isa-serial, id ""
index = 0 (0x0)
iobase = 1016 (0x3f8)
irq = 4 (0x4)
dev: i8257, id ""
base = 192 (0xc0)
page-base = 136 (0x88)
pageh-base = -1 (0xffffffffffffffff)
dshift = 1 (0x1)
dev: i8257, id ""
base = 0 (0x0)
page-base = 128 (0x80)
pageh-base = -1 (0xffffffffffffffff)
dshift = 0 (0x0)
dev: isa-pcspk, id ""
audiodev = ""
iobase = 97 (0x61)
migrate = true
dev: isa-pit, id ""
gpio-in "" 1
gpio-out "" 1
iobase = 64 (0x40)
dev: mc146818rtc, id ""
gpio-out "" 1
base_year = 0 (0x0)
iobase = 112 (0x70)
irq = 8 (0x8)
lost_tick_policy = "discard"
dev: isa-i8259, id ""
gpio-in "" 8
gpio-out "" 1
iobase = 160 (0xa0)
elcr_addr = 1233 (0x4d1)
elcr_mask = 222 (0xde)
master = false
dev: isa-i8259, id ""
gpio-in "" 8
gpio-out "" 1
iobase = 32 (0x20)
elcr_addr = 1232 (0x4d0)
elcr_mask = 248 (0xf8)
master = true
dev: i440FX, id ""
addr = 00.0
romfile = ""
romsize = 4294967295 (0xffffffff)
rombar = 1 (0x1)
multifunction = false
x-pcie-lnksta-dllla = true
x-pcie-extcap-init = true
failover_pair_id = ""
acpi-index = 0 (0x0)
class Host bridge, addr 00:00.0, pci id 8086:1237 (sub 1af4:1100)
dev: fw_cfg_io, id ""
dma_enabled = true
x-file-slots = 32 (0x20)
acpi-mr-restore = true
dev: kvmvapic, id ""
(qemu)
可以看到,设备的起点是main-system-bus系统总线,其上挂载了hpet和kvm-ioapic等设备,片断如下:
bus: main-system-bus
type System
dev: ps2-mouse, id ""
gpio-out "" 1
dev: ps2-kbd, id ""
gpio-out "" 1
dev: hpet, id ""
gpio-in "" 2
gpio-out "" 1
gpio-out "sysbus-irq" 32
timers = 3 (0x3)
msi = false
hpet-intcap = 4 (0x4)
hpet-offset-saved = true
mmio 00000000fed00000/0000000000000400
dev: ioapic, id ""
gpio-in "" 24
version = 32 (0x20)
mmio 00000000fec00000/0000000000001000
dev: i440FX-pcihost, id ""
pci-hole64-size = 2147483648 (2 GiB)
short_root_bus = 0 (0x0)
x-pci-hole64-fix = true
x-config-reg-migration-enabled = true
bypass-iommu = false
bus: pci.0
当然,最重要的是北桥i440FX-pcihost,其通过main-system-bus系统总线连接到CPU。
北桥的下面连接了一条PCI根总线,就是代码片段的最后一行(笔者是有意为之),大量的设备都挂在了pci.0总线上面。如:PIIX4_PM设备用于电源管理;piix3-ide设备是IDE设备的控制器,其下可以挂IDE总线,IDE总线下面可以挂IDE设备,如硬盘等。片段如下:
bus: pci.0
type PCI
dev: PIIX4_PM, id ""
gpio-out "smi-irq" 1
gpio-out "" 1
smb_io_base = 1792 (0x700)
disable_s3 = 0 (0x0)
disable_s4 = 0 (0x0)
s4_val = 2 (0x2)
acpi-pci-hotplug-with-bridge-support = true
acpi-root-pci-hotplug = true
memory-hotplug-support = true
smm-compat = false
smm-enabled = true
x-not-migrate-acpi-index = false
addr = 01.3
romfile = ""
romsize = 4294967295 (0xffffffff)
rombar = 1 (0x1)
multifunction = false
x-pcie-lnksta-dllla = true
x-pcie-extcap-init = true
failover_pair_id = ""
acpi-index = 0 (0x0)
class Bridge, addr 00:01.3, pci id 8086:7113 (sub 1af4:1100)
bus: i2c
……
dev: piix3-ide, id ""
addr = 01.1
romfile = ""
romsize = 4294967295 (0xffffffff)
rombar = 1 (0x1)
multifunction = false
x-pcie-lnksta-dllla = true
x-pcie-extcap-init = true
failover_pair_id = ""
acpi-index = 0 (0x0)
class IDE controller, addr 00:01.1, pci id 8086:7010 (sub 1af4:1100)
bar 4: i/o at 0xc040 [0xc04f]
bus: ide.1
PCI根总线当然也可以直接挂PCI设备,如e1000、VGA等。片断如下:
dev: piix3-ide, id ""
addr = 01.1
romfile = ""
romsize = 4294967295 (0xffffffff)
rombar = 1 (0x1)
multifunction = false
x-pcie-lnksta-dllla = true
x-pcie-extcap-init = true
failover_pair_id = ""
acpi-index = 0 (0x0)
class IDE controller, addr 00:01.1, pci id 8086:7010 (sub 1af4:1100)
bar 4: i/o at 0xc040 [0xc04f]
bus: ide.1
type IDE
dev: ide-cd, id ""
drive = "ide1-cd0"
backend_defaults = "auto"
logical_block_size = 512 (512 B)
physical_block_size = 512 (512 B)
min_io_size = 0 (0 B)
opt_io_size = 0 (0 B)
discard_granularity = 512 (512 B)
write-cache = "auto"
share-rw = false
rerror = "auto"
werror = "auto"
ver = "2.5+"
wwn = 0 (0x0)
serial = "QM00003"
model = ""
unit = 0 (0x0)
bus: ide.0
type IDE
dev: e1000, id ""
mac = "52:54:00:12:34:56"
netdev = "hub0port0"
autonegotiation = true
mitigation = true
extra_mac_registers = true
migrate_tso_props = true
init-vet = true
addr = 03.0
romfile = "efi-e1000.rom"
romsize = 262144 (0x40000)
rombar = 1 (0x1)
multifunction = false
x-pcie-lnksta-dllla = true
x-pcie-extcap-init = true
failover_pair_id = ""
acpi-index = 0 (0x0)
class Ethernet controller, addr 00:03.0, pci id 8086:100e (sub 1af4:1100)
bar 0: mem at 0xfebc0000 [0xfebdffff]
bar 1: i/o at 0xc000 [0xc03f]
bar 6: mem at 0xffffffffffffffff [0x3fffe]
dev: VGA, id ""
vgamem_mb = 16 (0x10)
mmio = true
qemu-extended-regs = true
edid = true
xres = 1280 (0x500)
yres = 800 (0x320)
xmax = 0 (0x0)
ymax = 0 (0x0)
refresh_rate = 0 (0x0)
global-vmstate = false
addr = 02.0
romfile = "vgabios-stdvga.bin"
romsize = 65536 (0x10000)
rombar = 1 (0x1)
multifunction = false
x-pcie-lnksta-dllla = true
x-pcie-extcap-init = true
failover_pair_id = ""
acpi-index = 0 (0x0)
class VGA controller, addr 00:02.0, pci id 1234:1111 (sub 1af4:1100)
bar 0: mem at 0xfd000000 [0xfdffffff]
bar 2: mem at 0xfebf0000 [0xfebf0fff]
bar 6: mem at 0xffffffffffffffff [0xfffe]
PIIX3是PCI转ISA桥,下面挂了ISA总线,ISA总线下挂了很多ISA设备。片段如下:
dev: PIIX3, id ""
addr = 01.0
romfile = ""
romsize = 4294967295 (0xffffffff)
rombar = 1 (0x1)
multifunction = true
x-pcie-lnksta-dllla = true
x-pcie-extcap-init = true
failover_pair_id = ""
acpi-index = 0 (0x0)
class ISA bridge, addr 00:01.0, pci id 8086:7000 (sub 1af4:1100)
bus: isa.0
type ISA
dev: port92, id ""
gpio-out "a20" 1
dev: vmmouse, id ""
dev: vmport, id ""
x-read-set-eax = true
x-signal-unsupported-cmd = true
x-report-vmx-type = true
x-cmds-v2 = true
vmware-vmx-version = 6 (0x6)
vmware-vmx-type = 2 (0x2)
dev: i8042, id ""
gpio-in "ps2-mouse-input-irq" 1
gpio-in "ps2-kbd-input-irq" 1
gpio-out "" 2
gpio-out "a20" 1
extended-state = true
kbd-throttle = false
kbd-irq = 1 (0x1)
mouse-irq = 12 (0xc)
dev: isa-fdc, id ""
iobase = 1008 (0x3f0)
……
i440FX则表示北桥自身在PCI总线这一侧的抽象。
dev: i440FX, id ""
addr = 00.0
romfile = ""
romsize = 4294967295 (0xffffffff)
rombar = 1 (0x1)
multifunction = false
x-pcie-lnksta-dllla = true
x-pcie-extcap-init = true
failover_pair_id = ""
acpi-index = 0 (0x0)
class Host bridge, addr 00:00.0, pci id 8086:1237 (sub 1af4:1100)
从上边的结构可以看到,总线和设备是交替的。设备只能挂在总线下边,而总线本身也属于一个设备。
上边介绍的是整个PC的系统结构,包括CPU、内存、外存、设备、中断等,后文书都会一一介绍。