===============================================================
THINGS A BOOTLOADER COULD/SHOULD DO
===============================================================
STAND-ALONE LOADER is a conventional bootloader. This document
also covers loaders which load and start an OS from DOS.

Almost all of these operations are optional. The exact mix
(and the order in which they are executed) is up to you.

1.   (FLOPPY) Get the sectors/track value:
1a.  From BIOS parameter block (BPB) of floppy. The BPB is a
     feature of DOS filesystems, and may not be present for
     other filesystems.
1b.  Assume a value, e.g. 18 sectors/track for 1.44 meg disks.
1c.  Set the BIOS sectors/track value to an inflated value
     ("High doesn't hurt.  Low does." -- Linux BOOTSECT.S),
     then load sectors using INT 13h and a linear search to
     zero in on the actual sectors/track value.

     INT 13h AH=08h does not return accurate geometry
     information for floppies.

2.   (STAND-ALONE LOADER) If the loader is larger than 512 bytes,
     it will have to finish loading itself from the disk. First,
     we have to FIND the "second stage" by one of three methods:
2a.  (disk has no filesystem) Just assume that the second stage
     is adjacent to (and contiguous with) the first stage.
2b.  (disk may or may not have a filesystem) Use a LILO-like
     block list to find the second stage file.
2c.  (disk has a filesystem) Use the filesystem (FAT12, FAT16,
     ext2, FFS, etc). The filesystem code can be read-only
     and root-directory-only, for simplicity.

3.   (STAND-ALONE LOADER) Now we LOAD the second stage:
3a.  Using contiguous disk sectors.
3b.  Using LILO-like block list.
3c.  Using filesystem.

4.   Get system info:
4a.  Get conventional and extended memory sizes using BIOS calls.
4b.  Check for 32-bit CPU.
4c.  Detect drives, and get their geometries.
4d.  (DOS LOADER; 32-BIT CPU; PMODE OS) Check if CPU is in
     Virtual 8086 mode (EMM386 loaded; or Windows DOS box).

5.   (ADVANCED LOADER) FIND config file:
5a.  Using DOS.
5b.  Using contiguous disk sectors.
5c.  Using LILO-like block list.
5d.  Using filesystem.

6.   (ADVANCED LOADER) LOAD config file:
6a.  Using DOS.
6b.  Using contiguous disk sectors.
6c.  Using LILO-like block list.
6d.  Using filesystem.

7.   (ADVANCED LOADER) If no config file, let the user browse
     (kernel) files on the disk.

8.   (ADVANCED LOADER) Present an optional boot menu to the user.
     Have an optional timeout, which loads a default kernel
     unless the user choses another OS. Dim out the names of
     kernels in the menu if they are unbootable (and display an
     error message). Disable the timeout if the default kernel is
     unbootable.

9.   Find the kernel:
9a.  Using DOS.
9b.  Using contiguous disk sectors.
9c.  Using LILO-like block list.
9d.  Using filesystem.

10.  Validate kernel file:
10a. Correct/supported file format (DJGPP COFF, ELF, BSD a.out,
     Win32 PE .EXE, Multiboot, RDSK, etc.)
10b. Ensure kernel is not dynamically-linked, in need of
     relocation, or a .o file
10c. See if enough memory to load it. Note that some kernels
     (like mine :) can be loaded to any 4K boundary.
10d. Need/got 32-bit CPU?
10e. (BLOCK LIST BOOTLOADER ONLY) CRC the first and last sectors
     of kernel, to see if it was deleted/modified/moved since the
     block list installer was last run.

11.  Prepare to copy the kernel:
11a. (286+) Enable the A20 gate.
11b. (286+) Verify A20 is on.
11c. (386+) Enable "unreal" mode. Since this lets you copy data
     without worrying about 64K segment limits or boundaries,
     it's useful even if you don't copy to extended memory.

     It may be better to use INT 15h AH=87h (copy extended
     memory) because it controls the A20 gate automatically.

12.  Load the kernel
12a. Using DOS.
12b. Using contiguous disk sectors.
12c. Using LILO-like block list.
12d. Using filesystem.

13.  Decompress the kernel:
13a. (no compression)
13b. gzip/zlib/lz77 compression.
13c. bzip compression.
13d. LZO, lzop, NRV, or UPX compression
     (http://wildsau.idv.uni-linz.ac.at/mfx)
13e. LZSS compression (http://my.execpc.com/~geezer/software/lzss.zip)

14.  Copy kernel:
14a. (no copy needed)
14b. To alternate location in conventional memory.
14c. To extended memory.

     For a kernel meant to run on an XT (8088 CPU), a "copy_huge"
     function would be nice. It handles segment wrap-around
     when copying more than 64K of data.

15.  (FLOPPY) Done loading, turn off the motor :)

16.  Zero the kernel BSS. This assumes the kernel has some kind
     of header that lets you know where the BSS is, and how big
     it is. Otherwise, let the kernel startup code do this.

17.  Store machine info (e.g. RAM sizes) and boot info (e.g.
     kernel command line):
17a. In a fixed memory location, such as address 90000h (Linux)
17b. In the kernel BSS (Cosmos)
17c. In a variable location, but pass a pointer to the data
     to the kernel (Multiboot)

     Some information being stored here is information (such as
     that obtained with 16-bit BIOS calls) which would be
     difficult to obtain after a 32-bit kernel has started.

18.  Video:
18a. Probe BIOS and/or hardware to see what modes are available.
18b. Prompt user to select a video mode.
18c. Set the video mode (using 16-bit BIOS call).

19.  Make other 16-bit BIOS calls that would be difficult to
     do from a pure 32-bit OS:
19a. Advanced power management (APM)
19b. Plug and play (PnP) (My BIOS has 16-bit PnP but not 32-bit)
19c. BIOS calls to locate text-mode fonts in video ROM.

20.  (DOS LOADER) If booting pmode OS from DOS, and the CPU is
     in V86 pmode because of EMM386, use VCPI to switch out of
     V86 mode

21.  Put some information into registers:
21a. Magic value indicating the bootloader used (Multiboot).
21b. Drive we booted from.
21c. An address that lets the kernel return to the bootloader.
21d. other?

     An earlier version of this document suggesting storing some
     other values:

     Virtual-to-physical conversion value: The kernel itself can
     compute this value, using a code snippet such as:
                call where_am_i
        where_am_i:
                pop ebx
                sub ebx,where_am_i

     Pmode data segment selector: The data segment registers can
     be loaded BEFORE jumping to the kernel.

22.  If booting pmode os, enable pmode.

23.  Jump to loaded kernel.
