系列文章目录
第二十九章 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
...
总结
以上分析了系统初始化过程中对目标机器存储空间的初始化配置。