C. GRUB and LILO

Both GNU GRUB and LILO understand the real-mode kernel header format and will load the bootsect (one sector), setup code (setup_sects sectors) and compressed kernel image (syssize*16 bytes) into memory. They fill out the loader identifier (type_of_loader) and try to pass appropriate parameters and options to the kernel. After they finish their jobs, control is passed to setup code.

C.1. GNU GRUB

The following GNU GRUB program outline is based on 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

Refer to "info grub" for GRUB manual.

One reported GNU GRUB bug should be noted if you are porting grub-0.93 and making changes to bsetup.

C.2. LILO

Unlike GRUB, LILO does not check the configuration file when booting system. Tricks happen when lilo is invoked from terminal.

The following LILO program outline is based on 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() and map_add_zero() may call map_register() to complete their jobs, while map_register() will keep a list for all (CX, DX, AL) triplets (data structure SECTOR_ADDR) used to identify all registered sectors.

LILO runs first.S and second.S to boot a system. It calls second.S:doboot() to load map file, bootsect and setup code. Then it calls lfile() to load the system code, calls launch2() -> launch() -> cl_wait() -> start_setup() -> start_setup2() and finnaly executes "jmpi 0,SETUPSEG" instruction to run setup code.

Refer to "man lilo" and "man lilo.conf" for LILO details.

C.3. Reference