无论是 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 详细信息。