C. GRUB 和 LILO

无论是 GNU GRUB 还是 LILO,都能够理解实模式内核头文件格式,并且会将引导扇区(一个扇区)、setup 代码(setup_sects 个扇区)以及压缩的内核镜像(syssize*16 字节)加载到内存中。它们会填充加载器标识符(type_of_loader),并尝试将适当的参数和选项传递给内核。在它们完成工作后,控制权将移交给 setup 代码。

C.1. GNU GRUB

以下 GNU GRUB 程序概要基于 grub-0.93。
stage2/stage2.c:cmain()
`-- run_menu()
    `-- run_script();
        |-- builtin = find_command(heap);
        |-- kernel_func();              // builtin->func() for command "kernel"
        |   `-- load_image();           // search BOOTSEC_SIGNATURE in boot.c
        |   /* memory from 0x100000 is populated by and in the order of
        |    *   (bvmlinux, bbootsect, bsetup) or (vmlinux, bootsect, setup) */
        |-- initrd_func();              // for command "initrd"
        |   `-- load_initrd();
        `-- boot_func();                // for implicit command "boot"
            `-- linux_boot();           // defined in stage2/asm.S
                or big_linux_boot();    //   not in grub/asmstub.c!

// In stage2/asm.S
linux_boot:
        /* copy kernel */
        move system code from 0x100000 to 0x10000 (linux_text_len bytes);
big_linux_boot:
        /* copy the real mode part */
        EBX = linux_data_real_addr;
        move setup code from linux_data_tmp_addr (0x100000+text_len)
            to linux_data_real_addr (0x9100 bytes);
        /* change %ebx to the segment address */
        linux_setup_seg = (EBX >> 4) + 0x20;
        /* XXX new stack pointer in safe area for calling functions */
        ESP = 0x4000;
        stop_floppy();
        /* final setup for linux boot */
        prot_to_real();
        cli;
        SS:ESP = BX:9000;
        DS = ES = FS = GS = BX;
        /* jump to start, i.e. ljmp linux_setup_seg:0
         * Note that linux_setup_seg is just changed to BX. */
        .byte   0xea
        .word   0
linux_setup_seg:
        .word   0

请参考 "info grub" 获取 GRUB 手册。

如果您正在移植 grub-0.93 并修改 bsetup,则应注意 报告的 GNU GRUB 错误

C.2. LILO

与 GRUB 不同,LILO 在启动系统时不会检查配置文件。当从终端调用 lilo 时,会发生一些技巧性的操作。

以下 LILO 程序概要基于 lilo-22.5.8。
lilo.c:main()
|-- cfg_open(config_file);
|-- cfg_parse(cf_options);
|-- bsect_open(boot_dev, map_file, install, delay, timeout);
|   |-- open_bsect(boot_dev);
|   `-- map_create(map_file);
|-- cfg_parse(cf_top)
|   `-- cfg_do_set();
|       `-- do_image();             // walk->action for "image=" section
|           |-- cfg_parse(cf_image) -> cfg_do_set();
|           |-- bsect_common(&descr, 1);
|           |   |-- map_begin_section();
|           |   |-- map_add_sector(fallback_buf);
|           |   `-- map_add_sector(options);
|           |-- boot_image(name, &descr) or boot_device(name, range, &descr);
|           |   |-- int fd = geo_open(&descr, name, O_RDONLY);
|           |   |   read(fd, &buff, SECTOR_SIZE);
|           |   |   map_add(&geo, 0, image_sectors);
|           |   |   map_end_section(&descr->start, setup_sects+2+1);
|           |   |       /* two sectors created in bsect_common(),
|           |   |        *   another one sector for bootsect */
|           |   |   geo_close(&geo);
|           |   `-- fd = geo_open(&descr, initrd, O_RDONLY);
|           |       map_begin_section();
|           |       map_add(&geo, 0, initrd_sectors);
|           |       map_end_section(&descr->initrd,0);
|           |       geo_close(&geo);
|           `-- bsect_done(name, &descr);
`-- bsect_update(backup_file, force_backup, 0); // update boot sector
    |-- make_backup();
    |-- map_begin_section();
    |   map_add_sector(table);
    |   map_write(&param2, keytab, 0, 0);
    |   map_close(&param2, here2);
    |-- // ... perform the relocation of the boot sector
    |-- // ... setup bsect_wr to correct place
    |-- write(fd, bsect_wr, SECTOR_SIZE);
    `-- close(fd);
map_add()、map_add_sector()map_add_zero() 可能会调用 map_register() 来完成它们的工作,而 map_register() 将会维护一个列表,记录所有用于标识已注册扇区的 (CX, DX, AL) 三元组(数据结构 SECTOR_ADDR)。

LILO 运行first.Ssecond.S来启动系统。它调用 second.S:doboot() 来加载映射文件、引导扇区和 setup 代码。然后它调用 lfile() 来加载系统代码,调用 launch2() -> launch() -> cl_wait() -> start_setup() -> start_setup2(),并最终执行 "jmpi 0,SETUPSEG" 指令来运行 setup 代码。

请参考 "man lilo" 和 "man lilo.conf" 获取 LILO 详细信息。

C.3. 参考