1、DEFINE_I440FX_MACHINE函数宏的定义
cpp
#define DEFINE_I440FX_MACHINE(suffix, name, compatfn, optionfn) \
static void pc_init_##suffix(MachineState *machine) \
{ \
void (*compat)(MachineState *m) = (compatfn); \
if (compat) { \
compat(machine); \
} \
pc_init1(machine, TYPE_I440FX_PCI_HOST_BRIDGE, \
TYPE_I440FX_PCI_DEVICE); \
} \
DEFINE_PC_MACHINE(suffix, name, pc_init_##suffix, optionfn)
2、DEFINE_PC_MACHINE函数宏的定义
cpp
#define DEFINE_PC_MACHINE(suffix, namestr, initfn, optsfn) \
static void pc_machine_##suffix##_class_init(ObjectClass *oc, void *data) \
{ \
MachineClass *mc = MACHINE_CLASS(oc); \
optsfn(mc); \
mc->init = initfn; \
mc->kvm_type = pc_machine_kvm_type; \
} \
static const TypeInfo pc_machine_type_##suffix = { \
.name = namestr TYPE_MACHINE_SUFFIX, \
.parent = TYPE_PC_MACHINE, \
.class_init = pc_machine_##suffix##_class_init, \
}; \
static void pc_machine_init_##suffix(void) \
{ \
type_register(&pc_machine_type_##suffix); \
} \
type_init(pc_machine_init_##suffix)
比如:pc-i440fx-8.1
cpp
DEFINE_I440FX_MACHINE(v8_1, "pc-i440fx-8.1", NULL, pc_i440fx_8_1_machine_options);
DEFINE_I440FX_MACHINE(suffix, name, compatfn, optionfn)
DEFINE_PC_MACHINE(suffix, namestr, initfn, optsfn)
DEFINE_PC_MACHINE(v8_1, "pc-i440fx-8.1", pc_init_v8_1, pc_i440fx_8_1_machine_options)
展开来看
static void pc_init_v8_1(MachineState *machine)
{
void (*compat)(MachineState *m) = NULL;
if (compat) {
compat(machine);
}
pc_init1(machine, TYPE_I440FX_PCI_HOST_BRIDGE, TYPE_I440FX_PCI_DEVICE);
}
static void pc_machine_v8_1_class_init(ObjectClass *oc, void *data) \
{
MachineClass *mc = MACHINE_CLASS(oc);
pc_i440fx_8_1_machine_options(mc);
mc->init =pc_init_v8_1;
mc->kvm_type = pc_machine_kvm_type;
}
static const TypeInfo pc_machine_type_v8_1 = {
.name = "pc-i440fx-8.1-machine", // #define TYPE_MACHINE_SUFFIX "-machine"
.parent = "generic-pc-machine", // #define TYPE_PC_MACHINE "generic-pc-machine"
.class_init = pc_machine_v8_1_class_init,
};
static void pc_machine_init_v8_1(void)
{
type_register(&pc_machine_type_v8_1);
}
type_init(pc_machine_init_v8_1)
qemu启动后板级初始化调用
cpp
void machine_run_board_init(MachineState *machine, const char *mem_path, Error **errp)
{
MachineClass *machine_class = MACHINE_GET_CLASS(machine);
ObjectClass *oc = object_class_by_name(machine->cpu_type);
CPUClass *cc;
/* This checkpoint is required by replay to separate prior clock reading from the other reads, because timer polling functions query clock values from the log. */
replay_checkpoint(CHECKPOINT_INIT);
if (!xen_enabled()) {
/* On 32-bit hosts, QEMU is limited by virtual address space */
if (machine->ram_size > (2047 << 20) && HOST_LONG_BITS == 32) {
error_setg(errp, "at most 2047 MB RAM can be simulated");
return;
}
}
if (machine->memdev) {
ram_addr_t backend_size = object_property_get_uint(OBJECT(machine->memdev), "size", &error_abort);
if (backend_size != machine->ram_size) {
error_setg(errp, "Machine memory size does not match the size of the memory backend");
return;
}
} else if (machine_class->default_ram_id && machine->ram_size && numa_uses_legacy_mem()) {
if (object_property_find(object_get_objects_root(), machine_class->default_ram_id)) {
error_setg(errp, "object name '%s' is reserved for the default RAM backend, it can't be used for any other purposes. Change the object's 'id' to something else",
machine_class->default_ram_id);
return;
}
if (!create_default_memdev(current_machine, mem_path, errp)) {
return;
}
}
if (machine->numa_state) {
numa_complete_configuration(machine);
if (machine->numa_state->num_nodes) {
machine_numa_finish_cpu_init(machine);
if (machine_class->cpu_cluster_has_numa_boundary) {
validate_cpu_cluster_to_numa_boundary(machine);
}
}
}
if (!machine->ram && machine->memdev) {
machine->ram = machine_consume_memdev(machine, machine->memdev);
}
/* If the machine supports the valid_cpu_types check and the user specified a CPU with -cpu check here that the user CPU is supported. */
if (machine_class->valid_cpu_types && machine->cpu_type) {
int i;
for (i = 0; machine_class->valid_cpu_types[i]; i++) {
if (object_class_dynamic_cast(oc, machine_class->valid_cpu_types[i])) {
/* The user specificed CPU is in the valid field, we are good to go. */
break;
}
}
if (!machine_class->valid_cpu_types[i]) {
/* The user specified CPU is not valid */
error_report("Invalid CPU type: %s", machine->cpu_type);
error_printf("The valid types are: %s", machine_class->valid_cpu_types[0]);
for (i = 1; machine_class->valid_cpu_types[i]; i++) {
error_printf(", %s", machine_class->valid_cpu_types[i]);
}
error_printf("\n");
exit(1);
}
}
/* Check if CPU type is deprecated and warn if so */
cc = CPU_CLASS(oc);
if (cc && cc->deprecation_note) {
warn_report("CPU model %s is deprecated -- %s", machine->cpu_type, cc->deprecation_note);
}
if (machine->cgs) {
/* With confidential guests, the host can't see the real contents of RAM, so there's no point in it trying to merge areas. */
machine_set_mem_merge(OBJECT(machine), false, &error_abort);
/*
* Virtio devices can't count on directly accessing guest memory, so they need iommu_platform=on to use normal DMA
* mechanisms. That requires also disabling legacy virtio support for those virtio pci devices which allow it.
*/
object_register_sugar_prop(TYPE_VIRTIO_PCI, "disable-legacy", "on", true);
object_register_sugar_prop(TYPE_VIRTIO_DEVICE, "iommu_platform", "on", false);
}
accel_init_interfaces(ACCEL_GET_CLASS(machine->accelerator));
machine_class->init(machine);
phase_advance(PHASE_MACHINE_INITIALIZED);
}
i440fx板级初始化pc_init1():
- 计算 x86 PC 内存布局
- 创建并 realize 所有 CPU
- 建立 PCI 根总线和南桥
- 初始化 BIOS/RAM/ROM 映射
- 建立 PIC/IOAPIC/GSI 中断体系
- 创建 ISA/RTC/VGA/NIC/IDE/USB 等基础设备
- 挂上 ACPI/SMBus/电源管理能力
cpp
/* PC hardware initialisation */
static void pc_init1(MachineState *machine, const char *host_type, const char *pci_type)
{
PCMachineState *pcms = PC_MACHINE(machine);
PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms);
X86MachineState *x86ms = X86_MACHINE(machine);
MemoryRegion *system_memory = get_system_memory();
MemoryRegion *system_io = get_system_io();
PCIBus *pci_bus = NULL;
ISABus *isa_bus;
int piix3_devfn = -1;
qemu_irq smi_irq;
GSIState *gsi_state;
BusState *idebus[MAX_IDE_BUS];
ISADevice *rtc_state;
MemoryRegion *ram_memory;
MemoryRegion *pci_memory = NULL;
MemoryRegion *rom_memory = system_memory;
ram_addr_t lowmem;
uint64_t hole64_size = 0;
// 1. 计算 PC 的物理内存布局
/*
* Calculate ram split, for memory below and above 4G. It's a bit complicated for backward compatibility reasons ...
*
* - Traditional split is 3.5G (lowmem = 0xe0000000). This is the
* default value for max_ram_below_4g now.
*
* - Then, to gigabyte align the memory, we move the split to 3G
* (lowmem = 0xc0000000). But only in case we have to split in
* the first place, i.e. ram_size is larger than (traditional)
* lowmem. And for new machine types (gigabyte_align = true)
* only, for live migration compatibility reasons.
*
* - Next the max-ram-below-4g option was added, which allowed to
* reduce lowmem to a smaller value, to allow a larger PCI I/O
* window below 4G. qemu doesn't enforce gigabyte alignment here,
* but prints a warning.
*
* - Finally max-ram-below-4g got updated to also allow raising lowmem,
* so legacy non-PAE guests can get as much memory as possible in
* the 32bit address space below 4G.
*
* - Note that Xen has its own ram setup code in xen_ram_init(),
* called via xen_hvm_init_pc().
*
* Examples:
* qemu -M pc-1.7 -m 4G (old default) -> 3584M low, 512M high
* qemu -M pc -m 4G (new default) -> 3072M low, 1024M high
* qemu -M pc,max-ram-below-4g=2G -m 4G -> 2048M low, 2048M high
* qemu -M pc,max-ram-below-4g=4G -m 3968M -> 3968M low (=4G-128M)
*/
if (xen_enabled()) {
xen_hvm_init_pc(pcms, &ram_memory);
} else {
ram_memory = machine->ram;
if (!pcms->max_ram_below_4g) {
pcms->max_ram_below_4g = 0xe0000000; /* default: 3.5G */
}
lowmem = pcms->max_ram_below_4g;
if (machine->ram_size >= pcms->max_ram_below_4g) {
if (pcmc->gigabyte_align) {
if (lowmem > 0xc0000000) {
lowmem = 0xc0000000;
}
if (lowmem & (1 * GiB - 1)) {
warn_report("Large machine and max_ram_below_4g (%" PRIu64 ") not a multiple of 1G; possible bad performance.", pcms->max_ram_below_4g);
}
}
}
if (machine->ram_size >= lowmem) {
x86ms->above_4g_mem_size = machine->ram_size - lowmem;
x86ms->below_4g_mem_size = lowmem;
} else {
x86ms->above_4g_mem_size = 0;
x86ms->below_4g_mem_size = machine->ram_size;
}
}
// 2. 初始化 CPU
pc_machine_init_sgx_epc(pcms);
x86_cpus_init(x86ms, pcmc->default_cpu_version);
// 3. 创建 KVM paravirt clock 设备
if (pcmc->kvmclock_enabled) {
kvmclock_create(pcmc->kvmclock_create_always);
}
// 4. 创建 PCI 根总线和 i440FX 主桥
if (pcmc->pci_enabled) {
Object *phb;
pci_memory = g_new(MemoryRegion, 1);
memory_region_init(pci_memory, NULL, "pci", UINT64_MAX);
rom_memory = pci_memory;
phb = OBJECT(qdev_new(host_type));
object_property_add_child(OBJECT(machine), "i440fx", phb);
object_property_set_link(phb, PCI_HOST_PROP_RAM_MEM, OBJECT(ram_memory), &error_fatal);
object_property_set_link(phb, PCI_HOST_PROP_PCI_MEM, OBJECT(pci_memory), &error_fatal);
object_property_set_link(phb, PCI_HOST_PROP_SYSTEM_MEM, OBJECT(system_memory), &error_fatal);
object_property_set_link(phb, PCI_HOST_PROP_IO_MEM, OBJECT(system_io), &error_fatal);
object_property_set_uint(phb, PCI_HOST_BELOW_4G_MEM_SIZE, x86ms->below_4g_mem_size, &error_fatal);
object_property_set_uint(phb, PCI_HOST_ABOVE_4G_MEM_SIZE, x86ms->above_4g_mem_size, &error_fatal);
object_property_set_str(phb, I440FX_HOST_PROP_PCI_TYPE, pci_type, &error_fatal);
sysbus_realize_and_unref(SYS_BUS_DEVICE(phb), &error_fatal);
pci_bus = PCI_BUS(qdev_get_child_bus(DEVICE(phb), "pci.0"));
pci_bus_map_irqs(pci_bus, xen_enabled() ? xen_pci_slot_get_pirq : pc_pci_slot_get_pirq);
pcms->bus = pci_bus;
hole64_size = object_property_get_uint(phb, PCI_HOST_PROP_PCI_HOLE64_SIZE, &error_abort);
}
// 5. 初始化 guest 信息和 BIOS/固件内存
pc_guest_info_init(pcms);
if (pcmc->smbios_defaults) {
MachineClass *mc = MACHINE_GET_CLASS(machine);
/* These values are guest ABI, do not change */
smbios_set_defaults("QEMU", mc->desc, mc->name, pcmc->smbios_legacy_mode, pcmc->smbios_uuid_encoded, pcms->smbios_entry_point_type);
}
/* allocate ram and load rom/bios */
if (!xen_enabled()) {
pc_memory_init(pcms, system_memory, rom_memory, hole64_size);
} else {
assert(machine->ram_size == x86ms->below_4g_mem_size + x86ms->above_4g_mem_size);
pc_system_flash_cleanup_unused(pcms);
if (machine->kernel_filename != NULL) {
/* For xen HVM direct kernel boot, load linux here */
xen_load_linux(pcms);
}
}
// 6. 建立中断体系
gsi_state = pc_gsi_create(&x86ms->gsi, pcmc->pci_enabled);
// 7. 创建南桥PIIX3 southbridge / ISA 总线 / RTC
if (pcmc->pci_enabled) {
PIIX3State *piix3;
PCIDevice *pci_dev;
pci_dev = pci_create_simple_multifunction(pci_bus, -1, TYPE_PIIX3_DEVICE);
if (xen_enabled()) {
pci_device_set_intx_routing_notifier( pci_dev, piix_intx_routing_notifier_xen);
// Xen 支持从 PCI 设备到 IOAPIC 的额外中断路由:总线上每个 PCI 设备的四个引脚也直接连接至 IOAPIC。这些额外路由可通过 ACPI 进行发现。
pci_bus_irqs(pci_bus, xen_intx_set_irq, pci_dev, XEN_IOAPIC_NUM_PIRQS);
}
piix3 = PIIX3_PCI_DEVICE(pci_dev);
piix3->pic = x86ms->gsi;
piix3_devfn = piix3->dev.devfn;
isa_bus = ISA_BUS(qdev_get_child_bus(DEVICE(piix3), "isa.0"));
rtc_state = ISA_DEVICE(object_resolve_path_component(OBJECT(pci_dev), "rtc"));
} else {
isa_bus = isa_bus_new(NULL, system_memory, system_io, &error_abort);
rtc_state = isa_new(TYPE_MC146818_RTC);
qdev_prop_set_int32(DEVICE(rtc_state), "base_year", 2000);
isa_realize_and_unref(rtc_state, isa_bus, &error_fatal);
i8257_dma_init(isa_bus, 0);
pcms->hpet_enabled = false;
}
isa_bus_register_input_irqs(isa_bus, x86ms->gsi);
// 建立中断体系
if (x86ms->pic == ON_OFF_AUTO_ON || x86ms->pic == ON_OFF_AUTO_AUTO) {
pc_i8259_create(isa_bus, gsi_state->i8259_irq);
}
if (pcmc->pci_enabled) {
ioapic_init_gsi(gsi_state, "i440fx");
}
if (tcg_enabled()) {
x86_register_ferr_irq(x86ms->gsi[13]);
}
// 8. 初始化基础外设 VGA,PIT,PS/2 控制器,串口/并口,扬声器,FDC,HPET 等
pc_vga_init(isa_bus, pcmc->pci_enabled ? pci_bus : NULL);
assert(pcms->vmport != ON_OFF_AUTO__MAX);
if (pcms->vmport == ON_OFF_AUTO_AUTO) {
pcms->vmport = xen_enabled() ? ON_OFF_AUTO_OFF : ON_OFF_AUTO_ON;
}
pc_basic_device_init(pcms, isa_bus, x86ms->gsi, rtc_state, true, 0x4);
pc_nic_init(pcmc, isa_bus, pci_bus);
if (pcmc->pci_enabled) {
PCIDevice *dev;
dev = pci_create_simple(pci_bus, piix3_devfn + 1, TYPE_PIIX3_IDE);
pci_ide_create_devs(dev);
idebus[0] = qdev_get_child_bus(&dev->qdev, "ide.0");
idebus[1] = qdev_get_child_bus(&dev->qdev, "ide.1");
pc_cmos_init(pcms, idebus[0], idebus[1], rtc_state);
}
#ifdef CONFIG_IDE_ISA
else {
DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
int i;
ide_drive_get(hd, ARRAY_SIZE(hd));
for (i = 0; i < MAX_IDE_BUS; i++) {
ISADevice *dev;
char busname[] = "ide.0";
dev = isa_ide_init(isa_bus, ide_iobase[i], ide_iobase2[i], ide_irq[i], hd[MAX_IDE_DEVS * i], hd[MAX_IDE_DEVS * i + 1]);
// IDE 总线的名称,第一条为 ide.0,第二条为 ide.1
busname[4] = '0' + i;
idebus[i] = qdev_get_child_bus(DEVICE(dev), busname);
}
pc_cmos_init(pcms, idebus[0], idebus[1], rtc_state);
}
#endif
// 9. 初始化 IDE / CMOS / USB
if (pcmc->pci_enabled && machine_usb(machine)) {
pci_create_simple(pci_bus, piix3_devfn + 2, TYPE_PIIX3_USB_UHCI);
}
if (pcmc->pci_enabled && x86_machine_is_acpi_enabled(X86_MACHINE(pcms))) {
PCIDevice *piix4_pm;
smi_irq = qemu_allocate_irq(pc_acpi_smi_interrupt, first_cpu, 0);
piix4_pm = pci_new(piix3_devfn + 3, TYPE_PIIX4_PM);
qdev_prop_set_uint32(DEVICE(piix4_pm), "smb_io_base", 0xb100);
qdev_prop_set_bit(DEVICE(piix4_pm), "smm-enabled", x86_machine_is_smm_enabled(x86ms));
pci_realize_and_unref(piix4_pm, pci_bus, &error_fatal);
qdev_connect_gpio_out(DEVICE(piix4_pm), 0, x86ms->gsi[9]);
qdev_connect_gpio_out_named(DEVICE(piix4_pm), "smi-irq", 0, smi_irq);
pcms->smbus = I2C_BUS(qdev_get_child_bus(DEVICE(piix4_pm), "i2c"));
/* TODO: Populate SPD eeprom data. */
smbus_eeprom_init(pcms->smbus, 8, NULL, 0);
object_property_add_link(OBJECT(machine), PC_MACHINE_ACPI_DEVICE_PROP, TYPE_HOTPLUG_HANDLER,
(Object **)&x86ms->acpi_dev, object_property_allow_set_link, OBJ_PROP_LINK_STRONG);
object_property_set_link(OBJECT(machine), PC_MACHINE_ACPI_DEVICE_PROP, OBJECT(piix4_pm), &error_abort);
}
// 10. 初始化 ACPI 电源管理
if (machine->nvdimms_state->is_enabled) {
nvdimm_init_acpi_state(machine->nvdimms_state, system_io, x86_nvdimm_acpi_dsmio, x86ms->fw_cfg, OBJECT(pcms));
}
}