1 QEMU函数执行流程

  machine_init(pc_machine_init) –> pc_machine_init(void) –> 注册QEMUMachine结构体变量pc_i440fx_machine_v2_3 –> pc_init_pci –> pc_init1 –> pc_memory_init –> pc_system_firmware_init –> old_pc_system_rom_init –> 检查bios文件不为空并且大小是65536的整数倍 –> memory_region_init_ram初始化一定大小的虚拟机物理内存 –> vmstate_register_ram_global –> memory_region_set_readonly –> rom_add_file_fixed将bios文件加载到虚拟机物理内存(uint32_t)(-bios_size)(物理内存最高的地方)处 –> memory_region_init_alias创建isa_bios作为bios的别名使用,但是最多映射bios的最后128Kb –> memory_region_add_subregion_overlap将isa_bios映射到ISA空间 –> memory_region_set_readonly设置ISA空间为只读 –> memory_region_add_subregion将bios映射到ROM内存的最高处。

2 seaBIOS背景知识

  SeaBIOS也像正常的BIOS一样,在虚拟机上电的时候,会被加载到地址空间0xFFFFFFF0处,并且该处是一条跳转指令,虚拟机的虚拟CPU会去执行SeaBIOS的代码,完成虚拟硬件的初始化,中断服务函数的设置,ACPI表、SMBIOS表、E820表等的创建,最后引导启动OS。
  SeaBIOS程序的各种入口点都在src/romlayout.S这个文件中定义了,启动包括了vCPU上电后开始执行的起点src/romlayout.S:reset_vector,该位置会被QEMU加载到vCPU物理空间的0xFFFFFFF0位置。该处的指令是一个跳转指令,该指令会跳转到src/romlayout.S:entry_post位置,然后判断是否是系统resume,如果不是则跳转到post.c:handle_post()函数处,开始POST(Power On Self Test)阶段。

3 Seabios启动流程分析

这里写图片描述

4 maininit函数功能

  对各种系统资源进行初始化,然后寻找可启动的设备,其中比较重要的是对fw_cfg设备进行初始化,该设备是QEMU传递Firmware信息给SeaBIOS的一个模拟设备,SeaBIOS通过fw_cfg设备可以获取到SMBIOS、ACPI、E820表等信息。
  详细过程如下:
  1. 对系统的各种接口进行初始化,主要是软件上的接口,没怎么动到其他硬件
    1.1 对fw_cfg设备进行初始化,该设备是QEMU传递Firmware信息给SeaBIOS的一个模拟设备,SeaBIOS通过fw_cfg设备可以获取到SMBIOS、ACPI、E820表等信息。
    1.2 初始化中断向量表
    1.3 初始化BDA(BIOS Data Area)、EBDA(Extended BIOS Data Area)数据区,这两个区域是BIOS标准中定义的,用于存放一些BIOS相关的信息,并且有一些指定的用途。
  2. 配置平台硬件
    1.1 配置平台DMA控制器
    1.2 配置中断控制器
    1.3 配置PCI设备,搜索系统中的PCI设备,并为各个PCI设备分配I/O和Memory地址空间,让系统能够正确地访问PCI设备,并配置相应的中断。
    1.4 配置好SMRAM的内存入口点,并将其隐藏起来
    1.5 配置好MTRR(Memory Type Range Register)寄存器,即配置不同内存区间的内存属性(从CPU的角度看)
    1.6 给其他非BSP(Bootstrap Processor)CPU,即AP(Application Processor)发送IPI中断,让AP对其自身进行初始化。并等待其他AP执行完毕。
    1.7 建立MP表,SMBIOS表和ACPI表
    1.8 配置时钟和定时器
  3. 选取系统的显卡,并执行其PCI Option ROM对显卡进行初始化,这步完成后,显示器就被点亮了,并且可以开始显示启动过程
  4. 对各种外设进行初始化,如USB控制器,磁盘控制器,键鼠控制器等等,由于外设比较多,并且速度慢,所以在对这些设备进行初始化的时候,SeaBIOS引入了Thread的概念(其实更应该叫做协程),让多个设备的初始化同时执行,并不是严格的并行执行,此时只有一个CPU在执行,它在多个设备的初始化程序中来回切换,确保不会在一个设备的初始化中卡住很长时间
  5. 执行其他PCI设备的Option ROM,初始化相应的PCI设备
  6. 收集可启动选项,并且调用0x19中断,开始OS的启动。