QEMU code analysis: BIOS loading process
QEMU is a widely used open-source computer simulator and virtual machine. It provides virtual machine hardware virtualization functions, and some firmware of specific hardware is provided by some open-source projects. This article will introduce the bios used in the qemu code. By analyzing the QEMU code, we will explain how the BIOS loads into the physical memory of the virtual machine.
Introduction to using BIOS in QEMU
The BIOS provides firmware information and basic input/output functions for the motherboard or video card. QEMU uses open-source projects such as Bochs and openBIOS. The BIOS and firmware used in QEMU are saved as binary files in the pc-bios directory of the source code tree. The pc-bios directory contains the firmware used by QEMU, and some BIOS are saved in the QEMU source code repository as git source code submodules. When the QEMU program is compiled, these BIOS or firmware binary files are also compiled. QEMU supports multiple startup modes, such as efi and pxe, which are included in this directory and all of which require the support of specific BIOS.
Listing 1. BIOS files in the QEMU source code tree
$ ls pc-bios/acpi-dsdt.aml efi-rtl8139.rom openbios-ppc pxe-e1000.rom qemu_logo_no_text.svg slof.bin bamboo.dtb efi-virtio.rom openbios-sparc32 pxe-eepro100.rom qemu-nsis.bmp spapr-rtas bamboo.dts keymaps openbios-sparc64 pxe-ne2k_pci.rom qemu-nsis.ico spapr-rtas.bin bios.bin kvmvapic.bin optionrom pxe-pcnet.rom vgabios.bin efi-e1000.rom linuxboot.bin palcode-clipper pxe-rtl8139.rom s390-ccwvgabios-cirrus.bin efi-eepro100.rom petalogix-ml605.dtb pxe-virtio.rom s390-ccw.img vgabios-qxl.bin efi-ne2k_pci.rom multiboot.bin petalogix-s3adsp1800.dtb q35-acpi-dsdt.aml s390-zipl.rom vgabios-stdvga.bin efi-pcnet.rom ohw.diff ppc_rom.bin qemu-icon.bmp sgabios.bin vgabios-vmware.bin
Listing 2. BIOS code stored in the QEMU source code tree as a sub-module
-Bash-4.1 $ cat. gitmodules [submodule "roms/vgabios"] path = roms/vgabios url = git: // git.qemu.org/vgabios.git/#submodule "roms/seabios"] path = roms/seabios url = git: // configure "roms/SLOF"] path = roms/SLOF url = git: // git.qemu.org/slof.git?submodule "roms/ipxe"] path = roms/ipxe url = git: // git.qemu.org/ipxe.git?submodule "roms/openbios"] path = roms/openbios url = git: // Git.qemu.org/openbios.git?submodule "roms/qemu-palcode"] path = roms/qemu-palcode url = git: // route "roms/sgabios"] path = roms/sgabios url = git: // git.qemu.org/sgabios.git?submodule "pixman"] path = pixman url = git: // anongit.free?top.orpixg/man=submodule "dtc"] path = dtc url = git: // QEMU, QEMU Makefile copies These binary files to Q EMU data file directory.
Listing 3. BIOS copy operations in QEMU Makefile:
ifneq ($(BLOBS),) set -e; for x in $(BLOBS); do \ $(INSTALL_DATA) $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(qemu_datadir)"; \ done
Analysis of qemu bios loading process
When the QEMU user space process starts, the QEMU process automatically loads the appropriate BIOS firmware based on the passed parameters and the current host platform type. In the initial phase of QEMU process startup, qemu_register_machine is called through the module_call_init function to register all machine types supported by the platform. Then, find_default_machine is called to select a default model for initialization. Take the x86_64 platform of the latest QEMU code (1.7.0) as an example. The supported machine types include:
Listing 4. types supported in QEMU 1.7.0 x86_64
pc-q35-1.7 pc-q35-1.6 pc-q35-1.5 pc-q35-1.4 pc-i440fx-1.7 pc-i440fx-1.6 pc-i440fx-1.5pc-i440fx-1.4 pc-1.3 pc-1.2 pc-1.1 pc-1.0 pc-0.15 pc-0.14pc-0.13 pc-0.12 pc-0.11 pc-0.10 isapc
The default model used in the latest code is pc-i440fx-1.7 and the BIOS file used is:
pc-bios/bios.binDefault machine name : pc-i440fx-1.7bios_name = bios.bin
The pc-i440fx-1.7 explains that QEMU is simulating INTEL's iphonfx hardware chipset, and 1.7 is the version number of QEMU. After finding the default machine, initialize the physical memory for it. QEMU first applies for a piece of memory space to simulate the physical memory space of the Virtual Machine. After applying for good memory, based on the parameters of different platforms or starting the QEMU process, initialize the physical memory of the VM. The specific function call process is shown in Figure 1.
Figure 1. QEMU hardware initialization function call flowchart:
In QEMU, the entire physical memory is represented by a struct MemoryRegion. For specific definitions, see Figure 5.
Listing 5. MemoryRegion struct in QEMU
struct MemoryRegion { /* All fields are private - violators will be prosecuted */ const MemoryRegionOps *ops; const MemoryRegionIOMMUOps *iommu_ops; void *opaque; struct Object *owner; MemoryRegion *parent; Int128 size; hwaddr addr; void (*destructor)(MemoryRegion *mr); ram_addr_t ram_addr; bool subpage; bool terminates; bool romd_mode; bool ram; bool readonly; /* For RAM regions */ bool enabled; bool rom_device; bool warning_printed; /* For reservations */ bool flush_coalesced_mmio; MemoryRegion *alias; hwaddr alias_offset; unsigned priority; bool may_overlap; QTAILQ_HEAD(subregions, MemoryRegion) subregions; QTAILQ_ENTRY(MemoryRegion) subregions_link; QTAILQ_HEAD(coalesced_ranges, CoalescedMemoryRange) subregions_link; const char *name; uint8_t dirty_log_mask; unsigned ioeventfd_nb; MemoryRegionIoeventfd *ioeventfds; NotifierList iommu_notify;};
Each MemoryRegion represents a memory area. Take a closer look at the MemoryRegion member function. It contains an Object member function that points to its owner, and a MemoryRegion member that points to its parent node (similar to a linked list ). There are also three end queues (QTAILQ) subregions, subregions_link, and subregions_link. That is to say, a MemoryRegion can contain multiple memory zones and distinguish the functions of this memory region based on different parameters. Before using MemoryRegion, allocate memory space for it and call memory_region_init for necessary initialization. BIOS is also indicated by a MemoryRegion structure. Its MemoryRegion. name is set to "pc. bios", and the size is set to the size of the BIOS file (an integer multiple of 65536 ). Then, use rom_add_file_fixed to load the BIOS file to a global rom queue.
Finally, return to the old_pc_system_rom_init function and map the BIOS to the top address space of the memory.
Listing 6. Code for ing BIOS to physical memory space in the old_pc_system_rom_init function:
hw/i386/pc_sysfw.c : memory_region_add_subregion(rom_memory, (uint32_t)(-bios_size) bios);
(Uint32_t) (-bios_size) is a 32-bit unsigned number, so the address corresponding to-bios_size is the size of FFFFFFFF to remove bios_size. The bios size is. /pc-bios/bios. bin = 131072 (20000 KB) bytes. The hexadecimal format is 0 x. Therefore, the bios position in the memory is bios position = fffe0000, And the bios position in the memory is 0xfffdffff ~ 0 xffffffff the BIOS has been added to the physical memory address space of the VM.
Finally, QEMU calls the CPU reset function to reset the VCPU register value IP = 0x0000fff0, CS = 0xf000, CS. BASE = 0xffff0000, CS. LIMIT = 0xffff. the command starts from 0xfffffff0, which is exactly the starting position of the ROM program. The Virtual Machine finds the BIOS entry.
Summary
By reading the source code of the QEMU program, the author gives a detailed introduction to the BIOS files used in QEMU and the representation of physical memory in QEMU, and how QEMU loads the binary BIOS to the memory of the virtual machine created through QEMU step by step.
For more information, see http://wiki.qemu.org/main_page.
Refer to the source code of QEMU in git: // git.qemu.org/qemu.git.
Ubuntu 12.04 cannot find the Qemu command
Install QEMU + efi bios on Arch Linux
QEMU translation framework and debugging tools
QEMU details: click here
QEMU: click here
This article permanently updates the link address: