Skip to the content.

QEMU 如何加载 Linux kernel image

QEMU 提供了 -kernel 参数,让 guest 运行的内核可以随意指定,这对于调试内核非常的方便,现在说明一下 -kernel 选项是如何实现的:

阅读本文需要大致了解 fw_cfg 的知识

QEMU’s preparation

  1. 通过 QEMU 的参数解析 机制,将参数保存到 MachineState::kernel_filename 中
    static void machine_set_kernel(Object *obj, const char *value, Error **errp)
    {
     MachineState *ms = MACHINE(obj);
    
     g_free(ms->kernel_filename);
     ms->kernel_filename = g_strdup(value);
    }
    
  2. x86_load_linux 中添加 linuxboot_dma.bin 到 option_rom 数组中
    f = fopen(kernel_filename, "rb");

    if (fread(kernel, 1, kernel_size, f) != kernel_size) { // 读去文件内容
        fprintf(stderr, "fread() failed\n");
        exit(1);
    }

    fw_cfg_add_bytes(fw_cfg, FW_CFG_KERNEL_DATA, kernel, kernel_size); // 通过 FW_CFG_KERNEL_DATA 告知 seabios

    option_rom[nb_option_roms].bootindex = 0;
    option_rom[nb_option_roms].name = "linuxboot.bin";
    if (linuxboot_dma_enabled && fw_cfg_dma_enabled(fw_cfg)) {
        option_rom[nb_option_roms].name = "linuxboot_dma.bin";
    }
  1. 在 pc_memory_init 中调用 rom_add_option 添加到 fw_cfg 中,之后 seabios 就可以通过 fw_cfg 读取 linuxboot_dma.bin
     for (i = 0; i < nb_option_roms; i++) {
         rom_add_option(option_rom[i].name, option_rom[i].bootindex);
     }
    
  2. rom_add_option 会进一步调用 add_boot_device_path 中,记录到 fw_boot_order,从而让 get_boot_devices_list 可以返回 “/rom@genroms/linuxboot_dma.bin”

  3. fw_cfg_machine_reset 中修改 “bootorder”
     buf = get_boot_devices_list(&len); // 返回内容 /rom@genroms/linuxboot_dma.bin
     ptr = fw_cfg_modify_file(s, "bootorder", (uint8_t *)buf, len);
    

到此,QEMU 的准备完成,实际上就是修改 “bootorder”,让 seabios 通过执行 linuxboot_dma.bin 来启动

Seabios 的基本执行流程

其实,总体来说,seabios 做了两个事情:

linuxboot_dma.bin 源代码解析

linuxboot_dma.bin 是通过 pc-bios/optionrom/linuxboot_dma.c 编译出来的,通过前面的分析,其实我们已经可以大致的猜测出来到底

第一个部分是 pnp optionrom 规范的内容,第二个就是通过 fw_cfg 获取到 kernel image 的地址,然后跳转过去了

本站所有文章转发 CSDN 将按侵权追究法律责任,其它情况随意。

本站所有文章转发 CSDN 将按侵权追究法律责任,其它情况随意。