系列文章目录

第二十九章 QEMU系统仿真的机器创建分析实例



前言

本文以 QEMU 8.2.2 为例,分析其作为系统仿真工具的工作过程,并为读者展示各种 QEMU 系统仿真的启动配置实例。
本文读者需要具备一定的 QEMU 系统仿真使用经验,并对 C 语言编程有一定了解。


一、QEMU是什么?

QEMU 是一个通用且开源的机器模拟器和虚拟机。
其官方主页是:https://www.qemu.org/


二、QEMU系统仿真的机器创建分析实例

1.系统仿真的命令行参数

QEMU 作为系统仿真工具,其入口代码在 system/main.c 文件中,初始化函数 qemu_init() 的实现在 system/vl.c 文件中。
前文完成创建目标机器的过程分析,本文将继续后续运行过程的分析,读者需要对 QEMU 系统启动过程的程序代码有所了解,相关内容可以参考《QEMU系统分析之启动篇》系列文章。

..\qemu\8.2.2-qkd\qemu-system-x86_64.exe -cpu "Penryn,vendor=GenuineIntel,+ssse3,+sse4.2" -M  "q35,accel=whpx,smm=off" -object "memory-backend-ram,id=ram0,size=4G,prealloc=on,share=on,merge=off,dump=off"  -object "memory-backend-ram,id=ram1,size=2G,prealloc=on,share=on,merge=off,dump=off" -numa "node,memdev=ram0,cpus=0,nodeid=0" -numa "node,memdev=ram1,cpus=1,nodeid=1" -smp "cpus=2" -m "6G" -audio "sdl,model=hda" -vga "std" -netdev "user,id=mynet0" -device "e1000,id=nic1,netdev=mynet0" -L "data" -qtest "unix:qtest-sock,server,nowait"

2. 将当前机器配置导出到文件

这部分代码在 system/vl.c 文件中,实现如下:

int qemu_init(int argc, char **argv)
{
...
    if (!preconfig_requested) {
        qmp_x_exit_preconfig(&error_fatal);
    }
...
}

前文分析了解析机器的存储设备设置的过程,本文将分析解析 NUMA 结点配置项的过程。


qmp_x_exit_preconfig()

函数 qmp_x_exit_preconfig() 代码如下:

void qmp_x_exit_preconfig(Error **errp)
{
    if (phase_check(PHASE_MACHINE_INITIALIZED)) {
        error_setg(errp, "The command is permitted only before machine initialization");
        return;
    }

    qemu_init_board();
    qemu_create_cli_devices();
    qemu_machine_creation_done();

    if (loadvm) {
        load_snapshot(loadvm, NULL, false, NULL, &error_fatal);
    }
    if (replay_mode != REPLAY_MODE_NONE) {
        replay_vmstate_init();
    }

    if (incoming) {
        Error *local_err = NULL;
        if (strcmp(incoming, "defer") != 0) {
            qmp_migrate_incoming(incoming, false, NULL, &local_err);
            if (local_err) {
                error_reportf_err(local_err, "-incoming %s: ", incoming);
                exit(1);
            }
        }
    } else if (autostart) {
        qmp_cont(NULL);
    }
}

首先,调用函数 qemu_init_board() 初始化机器主板,代码如下:

    qemu_init_board();

qemu_init_board()

代码如下:

static void qemu_init_board(void)
{
    /* process plugin before CPUs are created, but once -smp has been parsed */
    qemu_plugin_load_list(&plugin_list, &error_fatal);

    /* From here on we enter MACHINE_PHASE_INITIALIZED.  */
    machine_run_board_init(current_machine, mem_path, &error_fatal);

    drive_check_orphaned();

    realtime_init();
}

在函数 qemu_init_board() 中,首先运行机器主板的初始化,代码如下:

void machine_run_board_init(MachineState *machine, const char *mem_path, Error **errp)
{
    ERRP_GUARD();
    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's id '%s' is reserved for the default"
                " RAM backend, it can't be used for any other purposes",
                machine_class->default_ram_id);
            error_append_hint(errp,
                "Change the object's 'id' to something else or disable"
                " automatic creation of the default RAM backend by setting"
                " 'memory-backend=%s' with '-machine'.\n",
                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 specified 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);
}

跟踪调式进入函数 machine_class->init(machine),代码如下:

void machine_run_board_init(MachineState *machine, const char *mem_path, Error **errp)
{
...
    machine_class->init(machine);
...
}

在本例中,machine_class->init() 实际调用函数 pc_q35_init(),代码如下:

/* PC hardware initialisation */
static void pc_q35_init(MachineState *machine)
{
    PCMachineState *pcms = PC_MACHINE(machine);
    PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms);
    X86MachineState *x86ms = X86_MACHINE(machine);
    Object *phb;
    PCIBus *host_bus;
    PCIDevice *lpc;
    DeviceState *lpc_dev;
    BusState *idebus[MAX_SATA_PORTS];
    ISADevice *rtc_state;
    MemoryRegion *system_memory = get_system_memory();
    MemoryRegion *system_io = get_system_io();
    MemoryRegion *pci_memory;
    MemoryRegion *rom_memory;
    GSIState *gsi_state;
    ISABus *isa_bus;
    int i;
    PCIDevice *ahci;
    ram_addr_t lowmem;
    DriveInfo *hd[MAX_SATA_PORTS];
    MachineClass *mc = MACHINE_GET_CLASS(machine);
    bool acpi_pcihp;
    bool keep_pci_slot_hpc;
    uint64_t pci_hole64_size = 0;

    HUEDBG("enter\n");

    /* Check whether RAM fits below 4G (leaving 1/2 GByte for IO memory
     * and 256 Mbytes for PCI Express Enhanced Configuration Access Mapping
     * also known as MMCFG).
     * If it doesn't, we need to split it in chunks below and above 4G.
     * In any case, try to make sure that guest addresses aligned at
     * 1G boundaries get mapped to host addresses aligned at 1G boundaries.
     */
    if (machine->ram_size >= 0xb0000000) {
        lowmem = 0x80000000;
    } else {
        lowmem = 0xb0000000;
    }

    /* Handle the machine opt max-ram-below-4g.  It is basically doing
     * min(qemu limit, user limit).
     */
    if (!pcms->max_ram_below_4g) {
        pcms->max_ram_below_4g = 4 * GiB;
    }
    if (lowmem > pcms->max_ram_below_4g) {
        lowmem = pcms->max_ram_below_4g;
        if (machine->ram_size - lowmem > lowmem &&
            lowmem & (1 * GiB - 1)) {
            warn_report("There is possibly poor performance as the ram size "
                        " (0x%" PRIx64 ") is more then twice the size of"
                        " max-ram-below-4g (%"PRIu64") and"
                        " max-ram-below-4g is not a multiple of 1G.",
                        (uint64_t)machine->ram_size, 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;
    }

    HUEDBG("\n");
    pc_machine_init_sgx_epc(pcms);
    HUEDBG("\n");
    x86_cpus_init(x86ms, pcmc->default_cpu_version);
    HUEDBG("\n");

    if (kvm_enabled()) {
        kvmclock_create(pcmc->kvmclock_create_always);
    }

    HUEDBG("\n");
    /* pci enabled */
    if (pcmc->pci_enabled) {
        huedbg_flag = 1;
        HUEDBG("\n");
        pci_memory = g_new(MemoryRegion, 1);
        memory_region_init(pci_memory, NULL, "pci", UINT64_MAX);
        rom_memory = pci_memory;
        HUEDBG("\n");
        huedbg_flag = 0;
    } else {
        pci_memory = NULL;
        rom_memory = system_memory;
    }

    HUEDBG("\n");
    pc_guest_info_init(pcms);

    if (pcmc->smbios_defaults) {
        /* 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);
    }

    HUEDBG("\n");
    /* create pci host bus */
    phb = OBJECT(qdev_new(TYPE_Q35_HOST_DEVICE));

    if (pcmc->pci_enabled) {
        pci_hole64_size = object_property_get_uint(phb,
                                                   PCI_HOST_PROP_PCI_HOLE64_SIZE,
                                                   &error_abort);
    }

    HUEDBG("\n");
    /* allocate ram and load rom/bios */
    pc_memory_init(pcms, system_memory, rom_memory, pci_hole64_size);

    object_property_add_child(OBJECT(machine), "q35", phb);
    object_property_set_link(phb, PCI_HOST_PROP_RAM_MEM,
                             OBJECT(machine->ram), NULL);
    object_property_set_link(phb, PCI_HOST_PROP_PCI_MEM,
                             OBJECT(pci_memory), NULL);
    object_property_set_link(phb, PCI_HOST_PROP_SYSTEM_MEM,
                             OBJECT(system_memory), NULL);
    object_property_set_link(phb, PCI_HOST_PROP_IO_MEM,
                             OBJECT(system_io), NULL);
    object_property_set_int(phb, PCI_HOST_BELOW_4G_MEM_SIZE,
                            x86ms->below_4g_mem_size, NULL);
    object_property_set_int(phb, PCI_HOST_ABOVE_4G_MEM_SIZE,
                            x86ms->above_4g_mem_size, NULL);
    object_property_set_bool(phb, PCI_HOST_BYPASS_IOMMU,
                             pcms->default_bus_bypass_iommu, NULL);
    sysbus_realize_and_unref(SYS_BUS_DEVICE(phb), &error_fatal);

    HUEDBG("\n");
    /* pci */
    host_bus = PCI_BUS(qdev_get_child_bus(DEVICE(phb), "pcie.0"));
    pcms->bus = host_bus;

    HUEDBG("\n");
    /* irq lines */
    gsi_state = pc_gsi_create(&x86ms->gsi, pcmc->pci_enabled);

    HUEDBG("\n");
    /* create ISA bus */
    lpc = pci_new_multifunction(PCI_DEVFN(ICH9_LPC_DEV, ICH9_LPC_FUNC),
                                TYPE_ICH9_LPC_DEVICE);
    HUEDBG("\n");
    qdev_prop_set_bit(DEVICE(lpc), "smm-enabled",
                      x86_machine_is_smm_enabled(x86ms));
    HUEDBG("\n");
    lpc_dev = DEVICE(lpc);
    HUEDBG("\n");
    for (i = 0; i < IOAPIC_NUM_PINS; i++) {
        qdev_connect_gpio_out_named(lpc_dev, ICH9_GPIO_GSI, i, x86ms->gsi[i]);
    }
    HUEDBG("\n");
    pci_realize_and_unref(lpc, host_bus, &error_fatal);

    rtc_state = ISA_DEVICE(object_resolve_path_component(OBJECT(lpc), "rtc"));

    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(lpc), &error_abort);

    HUEDBG("\n");
    acpi_pcihp = object_property_get_bool(OBJECT(lpc),
                                          ACPI_PM_PROP_ACPI_PCIHP_BRIDGE,
                                          NULL);

    HUEDBG("\n");
    keep_pci_slot_hpc = object_property_get_bool(OBJECT(lpc),
                                                 "x-keep-pci-slot-hpc",
                                                 NULL);

    if (!keep_pci_slot_hpc && acpi_pcihp) {
        object_register_sugar_prop(TYPE_PCIE_SLOT,
                                   "x-do-not-expose-native-hotplug-cap",
                                   "true", true);
    }

    HUEDBG("\n");
    isa_bus = ISA_BUS(qdev_get_child_bus(lpc_dev, "isa.0"));

    HUEDBG("\n");
    if (x86ms->pic == ON_OFF_AUTO_ON || x86ms->pic == ON_OFF_AUTO_AUTO) {
        pc_i8259_create(isa_bus, gsi_state->i8259_irq);
    }

    HUEDBG("\n");
    if (pcmc->pci_enabled) {
        ioapic_init_gsi(gsi_state, "q35");
    }

    HUEDBG("\n");
    if (tcg_enabled()) {
        x86_register_ferr_irq(x86ms->gsi[13]);
    }

    assert(pcms->vmport != ON_OFF_AUTO__MAX);
    if (pcms->vmport == ON_OFF_AUTO_AUTO) {
        pcms->vmport = ON_OFF_AUTO_ON;
    }

    HUEDBG("\n");
    /* init basic PC hardware */
    pc_basic_device_init(pcms, isa_bus, x86ms->gsi, rtc_state, !mc->no_floppy,
                         0xff0104);

    HUEDBG("\n");
    if (pcms->sata_enabled) {
        /* ahci and SATA device, for q35 1 ahci controller is built-in */
        ahci = pci_create_simple_multifunction(host_bus,
                                               PCI_DEVFN(ICH9_SATA1_DEV,
                                                         ICH9_SATA1_FUNC),
                                               "ich9-ahci");
        idebus[0] = qdev_get_child_bus(&ahci->qdev, "ide.0");
        idebus[1] = qdev_get_child_bus(&ahci->qdev, "ide.1");
        g_assert(MAX_SATA_PORTS == ahci_get_num_ports(ahci));
        ide_drive_get(hd, ahci_get_num_ports(ahci));
        ahci_ide_create_devs(ahci, hd);
    } else {
        idebus[0] = idebus[1] = NULL;
    }

    HUEDBG("\n");
    if (machine_usb(machine)) {
        /* Should we create 6 UHCI according to ich9 spec? */
        ehci_create_ich9_with_companions(host_bus, 0x1d);
    }

    HUEDBG("\n");
    if (pcms->smbus_enabled) {
        PCIDevice *smb;

        /* TODO: Populate SPD eeprom data.  */
        smb = pci_create_simple_multifunction(host_bus,
                                              PCI_DEVFN(ICH9_SMB_DEV,
                                                        ICH9_SMB_FUNC),
                                              TYPE_ICH9_SMB_DEVICE);
        pcms->smbus = I2C_BUS(qdev_get_child_bus(DEVICE(smb), "i2c"));

        smbus_eeprom_init(pcms->smbus, 8, NULL, 0);
    }

    HUEDBG("\n");
    pc_cmos_init(pcms, idebus[0], idebus[1], rtc_state);

    HUEDBG("\n");
    /* the rest devices to which pci devfn is automatically assigned */
    pc_vga_init(isa_bus, host_bus);
    pc_nic_init(pcmc, isa_bus, host_bus, pcms->xenbus);

    HUEDBG("\n");
    if (machine->nvdimms_state->is_enabled) {
        nvdimm_init_acpi_state(machine->nvdimms_state, system_io,
                               x86_nvdimm_acpi_dsmio,
                               x86ms->fw_cfg, OBJECT(pcms));
    }
    HUEDBG("exit\n");
}

跟踪进入函数 pc_memory_init(),代码如下:


pc_memory_init(pcms, system_memory, rom_memory, pci_hole64_size)
void pc_memory_init(PCMachineState *pcms,
                    MemoryRegion *system_memory,
                    MemoryRegion *rom_memory,
                    uint64_t pci_hole64_size)
{
    int linux_boot, i;
    MemoryRegion *option_rom_mr;
    MemoryRegion *ram_below_4g, *ram_above_4g;
    FWCfgState *fw_cfg;
    MachineState *machine = MACHINE(pcms);
    MachineClass *mc = MACHINE_GET_CLASS(machine);
    PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms);
    X86MachineState *x86ms = X86_MACHINE(pcms);
    hwaddr maxphysaddr, maxusedaddr;
    hwaddr cxl_base, cxl_resv_end = 0;
    X86CPU *cpu = X86_CPU(first_cpu);

    assert(machine->ram_size == x86ms->below_4g_mem_size +
                                x86ms->above_4g_mem_size);

    linux_boot = (machine->kernel_filename != NULL);

    /*
     * The HyperTransport range close to the 1T boundary is unique to AMD
     * hosts with IOMMUs enabled. Restrict the ram-above-4g relocation
     * to above 1T to AMD vCPUs only. @enforce_amd_1tb_hole is only false in
     * older machine types (<= 7.0) for compatibility purposes.
     */
    if (IS_AMD_CPU(&cpu->env) && pcmc->enforce_amd_1tb_hole) {
        /* Bail out if max possible address does not cross HT range */
        if (pc_max_used_gpa(pcms, pci_hole64_size) >= AMD_HT_START) {
            x86ms->above_4g_mem_start = AMD_ABOVE_1TB_START;
        }

        /*
         * Advertise the HT region if address space covers the reserved
         * region or if we relocate.
         */
        if (cpu->phys_bits >= 40) {
            e820_add_entry(AMD_HT_START, AMD_HT_SIZE, E820_RESERVED);
        }
    }

    /*
     * phys-bits is required to be appropriately configured
     * to make sure max used GPA is reachable.
     */
    maxusedaddr = pc_max_used_gpa(pcms, pci_hole64_size);
    maxphysaddr = ((hwaddr)1 << cpu->phys_bits) - 1;
    if (maxphysaddr < maxusedaddr) {
        error_report("Address space limit 0x%"PRIx64" < 0x%"PRIx64
                     " phys-bits too low (%u)",
                     maxphysaddr, maxusedaddr, cpu->phys_bits);
        exit(EXIT_FAILURE);
    }

    /*
     * Split single memory region and use aliases to address portions of it,
     * done for backwards compatibility with older qemus.
     */
    ram_below_4g = g_malloc(sizeof(*ram_below_4g));
    memory_region_init_alias(ram_below_4g, NULL, "ram-below-4g", machine->ram,
                             0, x86ms->below_4g_mem_size);
    memory_region_add_subregion(system_memory, 0, ram_below_4g);
    e820_add_entry(0, x86ms->below_4g_mem_size, E820_RAM);
    if (x86ms->above_4g_mem_size > 0) {
        ram_above_4g = g_malloc(sizeof(*ram_above_4g));
        memory_region_init_alias(ram_above_4g, NULL, "ram-above-4g",
                                 machine->ram,
                                 x86ms->below_4g_mem_size,
                                 x86ms->above_4g_mem_size);
        memory_region_add_subregion(system_memory, x86ms->above_4g_mem_start,
                                    ram_above_4g);
        e820_add_entry(x86ms->above_4g_mem_start, x86ms->above_4g_mem_size,
                       E820_RAM);
    }

    if (pcms->sgx_epc.size != 0) {
        e820_add_entry(pcms->sgx_epc.base, pcms->sgx_epc.size, E820_RESERVED);
    }

    if (!pcmc->has_reserved_memory &&
        (machine->ram_slots ||
         (machine->maxram_size > machine->ram_size))) {

        error_report("\"-memory 'slots|maxmem'\" is not supported by: %s",
                     mc->name);
        exit(EXIT_FAILURE);
    }

    /* initialize device memory address space */
    if (pcmc->has_reserved_memory &&
        (machine->ram_size < machine->maxram_size)) {
        ram_addr_t device_mem_size;
        hwaddr device_mem_base;

        if (machine->ram_slots > ACPI_MAX_RAM_SLOTS) {
            error_report("unsupported amount of memory slots: %"PRIu64,
                         machine->ram_slots);
            exit(EXIT_FAILURE);
        }

        if (QEMU_ALIGN_UP(machine->maxram_size,
                          TARGET_PAGE_SIZE) != machine->maxram_size) {
            error_report("maximum memory size must by aligned to multiple of "
                         "%d bytes", TARGET_PAGE_SIZE);
            exit(EXIT_FAILURE);
        }

        pc_get_device_memory_range(pcms, &device_mem_base, &device_mem_size);

        if (device_mem_base + device_mem_size < device_mem_size) {
            error_report("unsupported amount of maximum memory: " RAM_ADDR_FMT,
                         machine->maxram_size);
            exit(EXIT_FAILURE);
        }
        machine_memory_devices_init(machine, device_mem_base, device_mem_size);
    }

    if (pcms->cxl_devices_state.is_enabled) {
        MemoryRegion *mr = &pcms->cxl_devices_state.host_mr;
        hwaddr cxl_size = MiB;

        cxl_base = pc_get_cxl_range_start(pcms);
        memory_region_init(mr, OBJECT(machine), "cxl_host_reg", cxl_size);
        memory_region_add_subregion(system_memory, cxl_base, mr);
        cxl_resv_end = cxl_base + cxl_size;
        if (pcms->cxl_devices_state.fixed_windows) {
            hwaddr cxl_fmw_base;
            GList *it;

            cxl_fmw_base = ROUND_UP(cxl_base + cxl_size, 256 * MiB);
            for (it = pcms->cxl_devices_state.fixed_windows; it; it = it->next) {
                CXLFixedWindow *fw = it->data;

                fw->base = cxl_fmw_base;
                memory_region_init_io(&fw->mr, OBJECT(machine), &cfmws_ops, fw,
                                      "cxl-fixed-memory-region", fw->size);
                memory_region_add_subregion(system_memory, fw->base, &fw->mr);
                cxl_fmw_base += fw->size;
                cxl_resv_end = cxl_fmw_base;
            }
        }
    }

    /* Initialize PC system firmware */
    pc_system_firmware_init(pcms, rom_memory);

    option_rom_mr = g_malloc(sizeof(*option_rom_mr));
    memory_region_init_ram(option_rom_mr, NULL, "pc.rom", PC_ROM_SIZE,
                           &error_fatal);
    if (pcmc->pci_enabled) {
        memory_region_set_readonly(option_rom_mr, true);
    }
    memory_region_add_subregion_overlap(rom_memory,
                                        PC_ROM_MIN_VGA,
                                        option_rom_mr,
                                        1);

    fw_cfg = fw_cfg_arch_create(machine,
                                x86ms->boot_cpus, x86ms->apic_id_limit);

    rom_set_fw(fw_cfg);

    if (machine->device_memory) {
        uint64_t *val = g_malloc(sizeof(*val));
        uint64_t res_mem_end = machine->device_memory->base;

        if (!pcmc->broken_reserved_end) {
            res_mem_end += memory_region_size(&machine->device_memory->mr);
        }

        if (pcms->cxl_devices_state.is_enabled) {
            res_mem_end = cxl_resv_end;
        }
        *val = cpu_to_le64(ROUND_UP(res_mem_end, 1 * GiB));
        fw_cfg_add_file(fw_cfg, "etc/reserved-memory-end", val, sizeof(*val));
    }

    if (linux_boot) {
        x86_load_linux(x86ms, fw_cfg, pcmc->acpi_data_size,
                       pcmc->pvh_enabled);
    }

    for (i = 0; i < nb_option_roms; i++) {
        rom_add_option(option_rom[i].name, option_rom[i].bootindex);
    }
    x86ms->fw_cfg = fw_cfg;

    /* Init default IOAPIC address space */
    x86ms->ioapic_as = &address_space_memory;

    /* Init ACPI memory hotplug IO base address */
    pcms->memhp_io_base = ACPI_MEMORY_HOTPLUG_BASE;
}

在函数 pc_memory_init() 中,创建完 ram_below_4g 和 ram_above_4g 两块存储区域后,调用函数 pc_system_firmware_init() 完成 BIOS 初始化。


3.调试输出

首先,添加跟踪调试信息,修改后的代码如下:

void pc_memory_init(PCMachineState *pcms,
                    MemoryRegion *system_memory,
                    MemoryRegion *rom_memory,
                    uint64_t pci_hole64_size)
{
...
    huedbg_flag = 1;
    HUEDBG("run\n");
    option_rom_mr = g_malloc(sizeof(*option_rom_mr));
    memory_region_init_ram(option_rom_mr, NULL, "pc.rom", PC_ROM_SIZE,
                           &error_fatal);
    if (pcmc->pci_enabled) {
        memory_region_set_readonly(option_rom_mr, true);
    }
    memory_region_add_subregion_overlap(rom_memory,
                                        PC_ROM_MIN_VGA,
                                        option_rom_mr,
                                        1);
    HUEDBG("run\n");
    huedbg_flag = 0;
...
}




运行后,输出信息如下:

[19684]../hw/i386/pc.c/pc_memory_init(1055):run
[19684]../system/memory.c/memory_region_init_ram(3602):name=pc.rom mr=0x00000210240cbff0
[19684]../system/memory.c/memory_region_init_ram_nomigrate(1566):name=pc.rom mr=0x00000210240cbff0
[19684]../system/memory.c/memory_region_init_ram_flags_nomigrate(1577):name=pc.rom mr=0x00000210240cbff0
[19684]../system/memory.c/memory_region_init(1230):tid=[19684] mr=[0x00000210240cbff0] name=[pc.rom] size=0x0000000000020000
[19684]../qom/object.c/type_table_lookup(103):lookup type(memory-region) in hash table
[19684]../qom/object.c/object_initialize_with_type(573):obj with type(memory-region) enter
[19684]../qom/object.c/object_initialize_with_type(581):mapping obj(memory-region).class with type(memory-region).class
[19684]../qom/object.c/object_initialize_with_type(584):try object_class_property_init_all(memory-region)
[19684]../qom/object.c/object_class_property_init_all(554):obj(memory-region) enter
[19684]../qom/object.c/object_class_property_iter_init(1517):objclass{memory-region} enter
[19684]../qom/object.c/object_class_get_parent(1157):enter
[19684]../qom/object.c/type_get_parent(194):parent_type(object)
[19684]../qom/object.c/object_class_get_parent(1168):objclass(memory-region) has parent(object)
[19684]../qom/object.c/object_class_get_parent(1171):objclass(memory-region) return
[19684]../qom/object.c/object_class_property_iter_init(1520):objclass{memory-region} return
[19684]../qom/object.c/object_class_get_parent(1157):enter
[19684]../qom/object.c/type_get_parent(196):no parent_type
[19684]../qom/object.c/object_class_get_parent(1161):objclass(object) has no parent return
[19684]../qom/object.c/object_class_property_init_all(557):prop name=[type] type=[string] desc=[(null)] init=[0000000000000000]
[19684]../qom/object.c/object_class_property_init_all(565):obj(memory-region) return
[19684]../qom/object.c/object_initialize_with_type(588):try object_init_with_type(memory-region)
[19684]../qom/object.c/object_init_with_type(416):obj->class->type->name=[memory-region] ti->name=[memory-region] enter
[19684]../qom/object.c/type_get_parent(194):parent_type(object)
[19684]../qom/object.c/object_init_with_type(416):obj->class->type->name=[memory-region] ti->name=[object] enter
[19684]../qom/object.c/object_init_with_type(427):obj->class->type->name=[memory-region] ti->name=[object] return
[19684]../qom/object.c/object_init_with_type(423):name=[memory-region] ti->instance_init() before
[19684]../qom/object.c/object_property_try_add(1373):name=[container] enter!
[19684]../qom/object.c/object_class_get_parent(1157):enter
[19684]../qom/object.c/type_get_parent(194):parent_type(object)
[19684]../qom/object.c/object_class_get_parent(1168):objclass(memory-region) has parent(object)
[19684]../qom/object.c/object_class_get_parent(1171):objclass(memory-region) return
[19684]../qom/object.c/object_class_get_parent(1157):enter
[19684]../qom/object.c/type_get_parent(196):no parent_type
[19684]../qom/object.c/object_class_get_parent(1161):objclass(object) has no parent return
[19684]../qom/object.c/object_property_try_add(1420):name=[container] return-3!
[19684]../qom/object.c/object_property_try_add(1373):name=[addr] enter!
[19684]../qom/object.c/object_class_get_parent(1157):enter
[19684]../qom/object.c/type_get_parent(194):parent_type(object)
[19684]../qom/object.c/object_class_get_parent(1168):objclass(memory-region) has parent(object)
[19684]../qom/object.c/object_class_get_parent(1171):objclass(memory-region) return
[19684]../qom/object.c/object_class_get_parent(1157):enter
[19684]../qom/object.c/type_get_parent(196):no parent_type
[19684]../qom/object.c/object_class_get_parent(1161):objclass(object) has no parent return
[19684]../qom/object.c/object_property_try_add(1420):name=[addr] return-3!
[19684]../qom/object.c/object_property_try_add(1373):name=[priority] enter!
[19684]../qom/object.c/object_class_get_parent(1157):enter
[19684]../qom/object.c/type_get_parent(194):parent_type(object)
[19684]../qom/object.c/object_class_get_parent(1168):objclass(memory-region) has parent(object)
[19684]../qom/object.c/object_class_get_parent(1171):objclass(memory-region) return
[19684]../qom/object.c/object_class_get_parent(1157):enter
[19684]../qom/object.c/type_get_parent(196):no parent_type
[19684]../qom/object.c/object_class_get_parent(1161):objclass(object) has no parent return
[19684]../qom/object.c/object_property_try_add(1420):name=[priority] return-3!
[19684]../qom/object.c/object_property_try_add(1373):name=[size] enter!
[19684]../qom/object.c/object_class_get_parent(1157):enter
[19684]../qom/object.c/type_get_parent(194):parent_type(object)
[19684]../qom/object.c/object_class_get_parent(1168):objclass(memory-region) has parent(object)
[19684]../qom/object.c/object_class_get_parent(1171):objclass(memory-region) return
[19684]../qom/object.c/object_class_get_parent(1157):enter
[19684]../qom/object.c/type_get_parent(196):no parent_type
[19684]../qom/object.c/object_class_get_parent(1161):objclass(object) has no parent return
[19684]../qom/object.c/object_property_try_add(1420):name=[size] return-3!
[19684]../qom/object.c/object_init_with_type(425):name=[memory-region] ti->instance_init() after
[19684]../qom/object.c/object_init_with_type(427):obj->class->type->name=[memory-region] ti->name=[memory-region] return
[19684]../qom/object.c/object_initialize_with_type(590):try object_post_init_with_type(memory-region)
[19684]../qom/object.c/object_post_init_with_type(433):obj->class->type->name=[memory-region] ti->name=[memory-region] enter
[19684]../qom/object.c/type_get_parent(194):parent_type(object)
[19684]../qom/object.c/object_post_init_with_type(433):obj->class->type->name=[memory-region] ti->name=[object] enter
[19684]../qom/object.c/object_post_init_with_type(444):return
[19684]../qom/object.c/object_post_init_with_type(444):return
[19684]../qom/object.c/object_initialize_with_type(592):obj(memory-region) return
[19684]../qom/object.c/object_class_get_parent(1157):enter
[19684]../qom/object.c/type_get_parent(194):parent_type(generic-pc-machine)
[19684]../qom/object.c/object_class_get_parent(1168):objclass(pc-q35-8.2-machine) has parent(generic-pc-machine)
[19684]../qom/object.c/object_class_get_parent(1171):objclass(pc-q35-8.2-machine) return
[19684]../qom/object.c/object_class_get_parent(1157):enter
[19684]../qom/object.c/type_get_parent(194):parent_type(x86-machine)
[19684]../qom/object.c/object_class_get_parent(1168):objclass(generic-pc-machine) has parent(x86-machine)
[19684]../qom/object.c/object_class_get_parent(1171):objclass(generic-pc-machine) return
[19684]../qom/object.c/object_class_get_parent(1157):enter
[19684]../qom/object.c/type_get_parent(194):parent_type(machine)
[19684]../qom/object.c/object_class_get_parent(1168):objclass(x86-machine) has parent(machine)
[19684]../qom/object.c/object_class_get_parent(1171):objclass(x86-machine) return
[19684]../qom/object.c/object_class_get_parent(1157):enter
[19684]../qom/object.c/type_get_parent(194):parent_type(object)
[19684]../qom/object.c/object_class_get_parent(1168):objclass(machine) has parent(object)
[19684]../qom/object.c/object_class_get_parent(1171):objclass(machine) return
[19684]../qom/object.c/object_class_get_parent(1157):enter
[19684]../qom/object.c/type_get_parent(196):no parent_type
[19684]../qom/object.c/object_class_get_parent(1161):objclass(object) has no parent return
[19684]../qom/object.c/object_property_try_add(1373):name=[pc.rom[*]] enter!
[19684]../qom/object.c/object_property_try_add(1373):name=[pc.rom[0]] enter!
[19684]../qom/object.c/object_class_get_parent(1157):enter
[19684]../qom/object.c/type_get_parent(194):parent_type(object)
[19684]../qom/object.c/object_class_get_parent(1168):objclass(container) has parent(object)
[19684]../qom/object.c/object_class_get_parent(1171):objclass(container) return
[19684]../qom/object.c/object_class_get_parent(1157):enter
[19684]../qom/object.c/type_get_parent(196):no parent_type
[19684]../qom/object.c/object_class_get_parent(1161):objclass(object) has no parent return
[19684]../qom/object.c/object_property_try_add(1420):name=[pc.rom[0]] return-3!
[19684]../qom/object.c/object_property_try_add(1392):name=[pc.rom[*]] return-1!
[19684]../system/memory.c/memory_region_init_io(1552):tid=[19684] name=(null) mr=0x00000211a46f5ec0 enter!
[19684]../system/memory.c/memory_region_init(1230):tid=[19684] mr=[0x00000211a46f5ec0] name=[(null)] size=0x0000000000001000
[19684]../qom/object.c/type_table_lookup(103):lookup type(memory-region) in hash table
[19684]../qom/object.c/object_initialize_with_type(573):obj with type(memory-region) enter
[19684]../qom/object.c/object_initialize_with_type(581):mapping obj(memory-region).class with type(memory-region).class
[19684]../qom/object.c/object_initialize_with_type(584):try object_class_property_init_all(memory-region)
[19684]../qom/object.c/object_class_property_init_all(554):obj(memory-region) enter
[19684]../qom/object.c/object_class_property_iter_init(1517):objclass{memory-region} enter
[19684]../qom/object.c/object_class_get_parent(1157):enter
[19684]../qom/object.c/type_get_parent(194):parent_type(object)
[19684]../qom/object.c/object_class_get_parent(1168):objclass(memory-region) has parent(object)
[19684]../qom/object.c/object_class_get_parent(1171):objclass(memory-region) return
[19684]../qom/object.c/object_class_property_iter_init(1520):objclass{memory-region} return
[19684]../qom/object.c/object_class_get_parent(1157):enter
[19684]../qom/object.c/type_get_parent(196):no parent_type
[19684]../qom/object.c/object_class_get_parent(1161):objclass(object) has no parent return
[19684]../qom/object.c/object_class_property_init_all(557):prop name=[type] type=[string] desc=[(null)] init=[0000000000000000]
[19684]../qom/object.c/object_class_property_init_all(565):obj(memory-region) return
[19684]../qom/object.c/object_initialize_with_type(588):try object_init_with_type(memory-region)
[19684]../qom/object.c/object_init_with_type(416):obj->class->type->name=[memory-region] ti->name=[memory-region] enter
[19684]../qom/object.c/type_get_parent(194):parent_type(object)
[19684]../qom/object.c/object_init_with_type(416):obj->class->type->name=[memory-region] ti->name=[object] enter
[19684]../qom/object.c/object_init_with_type(427):obj->class->type->name=[memory-region] ti->name=[object] return
[19684]../qom/object.c/object_init_with_type(423):name=[memory-region] ti->instance_init() before
[19684]../qom/object.c/object_property_try_add(1373):name=[container] enter!
[19684]../qom/object.c/object_class_get_parent(1157):enter
[19684]../qom/object.c/type_get_parent(194):parent_type(object)
[19684]../qom/object.c/object_class_get_parent(1168):objclass(memory-region) has parent(object)
[19684]../qom/object.c/object_class_get_parent(1171):objclass(memory-region) return
[19684]../qom/object.c/object_class_get_parent(1157):enter
[19684]../qom/object.c/type_get_parent(196):no parent_type
[19684]../qom/object.c/object_class_get_parent(1161):objclass(object) has no parent return
[19684]../qom/object.c/object_property_try_add(1420):name=[container] return-3!
[19684]../qom/object.c/object_property_try_add(1373):name=[addr] enter!
[19684]../qom/object.c/object_class_get_parent(1157):enter
[19684]../qom/object.c/type_get_parent(194):parent_type(object)
[19684]../qom/object.c/object_class_get_parent(1168):objclass(memory-region) has parent(object)
[19684]../qom/object.c/object_class_get_parent(1171):objclass(memory-region) return
[19684]../qom/object.c/object_class_get_parent(1157):enter
[19684]../qom/object.c/type_get_parent(196):no parent_type
[19684]../qom/object.c/object_class_get_parent(1161):objclass(object) has no parent return
[19684]../qom/object.c/object_property_try_add(1420):name=[addr] return-3!
[19684]../qom/object.c/object_property_try_add(1373):name=[priority] enter!
[19684]../qom/object.c/object_class_get_parent(1157):enter
[19684]../qom/object.c/type_get_parent(194):parent_type(object)
[19684]../qom/object.c/object_class_get_parent(1168):objclass(memory-region) has parent(object)
[19684]../qom/object.c/object_class_get_parent(1171):objclass(memory-region) return
[19684]../qom/object.c/object_class_get_parent(1157):enter
[19684]../qom/object.c/type_get_parent(196):no parent_type
[19684]../qom/object.c/object_class_get_parent(1161):objclass(object) has no parent return
[19684]../qom/object.c/object_property_try_add(1420):name=[priority] return-3!
[19684]../qom/object.c/object_property_try_add(1373):name=[size] enter!
[19684]../qom/object.c/object_class_get_parent(1157):enter
[19684]../qom/object.c/type_get_parent(194):parent_type(object)
[19684]../qom/object.c/object_class_get_parent(1168):objclass(memory-region) has parent(object)
[19684]../qom/object.c/object_class_get_parent(1171):objclass(memory-region) return
[19684]../qom/object.c/object_class_get_parent(1157):enter
[19684]../qom/object.c/type_get_parent(196):no parent_type
[19684]../qom/object.c/object_class_get_parent(1161):objclass(object) has no parent return
[19684]../qom/object.c/object_property_try_add(1420):name=[size] return-3!
[19684]../qom/object.c/object_init_with_type(425):name=[memory-region] ti->instance_init() after
[19684]../qom/object.c/object_init_with_type(427):obj->class->type->name=[memory-region] ti->name=[memory-region] return
[19684]../qom/object.c/object_initialize_with_type(590):try object_post_init_with_type(memory-region)
[19684]../qom/object.c/object_post_init_with_type(433):obj->class->type->name=[memory-region] ti->name=[memory-region] enter
[19684]../qom/object.c/type_get_parent(194):parent_type(object)
[19684]../qom/object.c/object_post_init_with_type(433):obj->class->type->name=[memory-region] ti->name=[object] enter
[19684]../qom/object.c/object_post_init_with_type(444):return
[19684]../qom/object.c/object_post_init_with_type(444):return
[19684]../qom/object.c/object_initialize_with_type(592):obj(memory-region) return
[19684]../system/memory.c/memory_region_init_io(1552):tid=[19684] name=(null) mr=0x00000211a4710010 enter!
[19684]../system/memory.c/memory_region_init(1230):tid=[19684] mr=[0x00000211a4710010] name=[(null)] size=0x0000000000001000
[19684]../qom/object.c/type_table_lookup(103):lookup type(memory-region) in hash table
[19684]../qom/object.c/object_initialize_with_type(573):obj with type(memory-region) enter
[19684]../qom/object.c/object_initialize_with_type(581):mapping obj(memory-region).class with type(memory-region).class
[19684]../qom/object.c/object_initialize_with_type(584):try object_class_property_init_all(memory-region)
[19684]../qom/object.c/object_class_property_init_all(554):obj(memory-region) enter
[19684]../qom/object.c/object_class_property_iter_init(1517):objclass{memory-region} enter
[19684]../qom/object.c/object_class_get_parent(1157):enter
[19684]../qom/object.c/type_get_parent(194):parent_type(object)
[19684]../qom/object.c/object_class_get_parent(1168):objclass(memory-region) has parent(object)
[19684]../qom/object.c/object_class_get_parent(1171):objclass(memory-region) return
[19684]../qom/object.c/object_class_property_iter_init(1520):objclass{memory-region} return
[19684]../qom/object.c/object_class_get_parent(1157):enter
[19684]../qom/object.c/type_get_parent(196):no parent_type
[19684]../qom/object.c/object_class_get_parent(1161):objclass(object) has no parent return
[19684]../qom/object.c/object_class_property_init_all(557):prop name=[type] type=[string] desc=[(null)] init=[0000000000000000]
[19684]../qom/object.c/object_class_property_init_all(565):obj(memory-region) return
[19684]../qom/object.c/object_initialize_with_type(588):try object_init_with_type(memory-region)
[19684]../qom/object.c/object_init_with_type(416):obj->class->type->name=[memory-region] ti->name=[memory-region] enter
[19684]../qom/object.c/type_get_parent(194):parent_type(object)
[19684]../qom/object.c/object_init_with_type(416):obj->class->type->name=[memory-region] ti->name=[object] enter
[19684]../qom/object.c/object_init_with_type(427):obj->class->type->name=[memory-region] ti->name=[object] return
[19684]../qom/object.c/object_init_with_type(423):name=[memory-region] ti->instance_init() before
[19684]../qom/object.c/object_property_try_add(1373):name=[container] enter!
[19684]../qom/object.c/object_class_get_parent(1157):enter
[19684]../qom/object.c/type_get_parent(194):parent_type(object)
[19684]../qom/object.c/object_class_get_parent(1168):objclass(memory-region) has parent(object)
[19684]../qom/object.c/object_class_get_parent(1171):objclass(memory-region) return
[19684]../qom/object.c/object_class_get_parent(1157):enter
[19684]../qom/object.c/type_get_parent(196):no parent_type
[19684]../qom/object.c/object_class_get_parent(1161):objclass(object) has no parent return
[19684]../qom/object.c/object_property_try_add(1420):name=[container] return-3!
[19684]../qom/object.c/object_property_try_add(1373):name=[addr] enter!
[19684]../qom/object.c/object_class_get_parent(1157):enter
[19684]../qom/object.c/type_get_parent(194):parent_type(object)
[19684]../qom/object.c/object_class_get_parent(1168):objclass(memory-region) has parent(object)
[19684]../qom/object.c/object_class_get_parent(1171):objclass(memory-region) return
[19684]../qom/object.c/object_class_get_parent(1157):enter
[19684]../qom/object.c/type_get_parent(196):no parent_type
[19684]../qom/object.c/object_class_get_parent(1161):objclass(object) has no parent return
[19684]../qom/object.c/object_property_try_add(1420):name=[addr] return-3!
[19684]../qom/object.c/object_property_try_add(1373):name=[priority] enter!
[19684]../qom/object.c/object_class_get_parent(1157):enter
[19684]../qom/object.c/type_get_parent(194):parent_type(object)
[19684]../qom/object.c/object_class_get_parent(1168):objclass(memory-region) has parent(object)
[19684]../qom/object.c/object_class_get_parent(1171):objclass(memory-region) return
[19684]../qom/object.c/object_class_get_parent(1157):enter
[19684]../qom/object.c/type_get_parent(196):no parent_type
[19684]../qom/object.c/object_class_get_parent(1161):objclass(object) has no parent return
[19684]../qom/object.c/object_property_try_add(1420):name=[priority] return-3!
[19684]../qom/object.c/object_property_try_add(1373):name=[size] enter!
[19684]../qom/object.c/object_class_get_parent(1157):enter
[19684]../qom/object.c/type_get_parent(194):parent_type(object)
[19684]../qom/object.c/object_class_get_parent(1168):objclass(memory-region) has parent(object)
[19684]../qom/object.c/object_class_get_parent(1171):objclass(memory-region) return
[19684]../qom/object.c/object_class_get_parent(1157):enter
[19684]../qom/object.c/type_get_parent(196):no parent_type
[19684]../qom/object.c/object_class_get_parent(1161):objclass(object) has no parent return
[19684]../qom/object.c/object_property_try_add(1420):name=[size] return-3!
[19684]../qom/object.c/object_init_with_type(425):name=[memory-region] ti->instance_init() after
[19684]../qom/object.c/object_init_with_type(427):obj->class->type->name=[memory-region] ti->name=[memory-region] return
[19684]../qom/object.c/object_initialize_with_type(590):try object_post_init_with_type(memory-region)
[19684]../qom/object.c/object_post_init_with_type(433):obj->class->type->name=[memory-region] ti->name=[memory-region] enter
[19684]../qom/object.c/type_get_parent(194):parent_type(object)
[19684]../qom/object.c/object_post_init_with_type(433):obj->class->type->name=[memory-region] ti->name=[object] enter
[19684]../qom/object.c/object_post_init_with_type(444):return
[19684]../qom/object.c/object_post_init_with_type(444):return
[19684]../qom/object.c/object_initialize_with_type(592):obj(memory-region) return
[19684]../hw/i386/pc.c/pc_memory_init(1066):run

从跟踪信息可知,option_rom_mr 大小为 128k,起始地址从 0x000c0000 起。

[19684]../system/memory.c/memory_region_init(1230):tid=[19684] mr=[0x00000210240cbff0] name=[pc.rom] size=0x0000000000020000
...


总结

以上分析了系统初始化过程中对目标机器存储空间的初始化配置。

05-13 07:58