无论是 GNU GRUB 还是 LILO,都能够理解实模式内核头文件格式,并且会将引导扇区(一个扇区)、setup 代码(setup_sects 个扇区)以及压缩的内核镜像(syssize*16 字节)加载到内存中。它们会填充加载器标识符(type_of_loader),并尝试将适当的参数和选项传递给内核。在它们完成工作后,控制权将移交给 setup 代码。
以下 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 错误。
与 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(¶m2, keytab, 0, 0); | map_close(¶m2, here2); |-- // ... perform the relocation of the boot sector |-- // ... setup bsect_wr to correct place |-- write(fd, bsect_wr, SECTOR_SIZE); `-- close(fd); |
LILO 运行first.S和second.S来启动系统。它调用 second.S:doboot() 来加载映射文件、引导扇区和 setup 代码。然后它调用 lfile() 来加载系统代码,调用 launch2() -> launch() -> cl_wait() -> start_setup() -> start_setup2(),并最终执行 "jmpi 0,SETUPSEG" 指令来运行 setup 代码。
请参考 "man lilo" 和 "man lilo.conf" 获取 LILO 详细信息。