OSD Home

- # - Some advice on writing your own bootloader
- # - Reviews of some open source bootloaders
  - # - GRUB
  - # - Alexei Frounze's bootloader
  - # - LILO
  - # - The built-in loader of Linux
- # - BIOS role in bootstrap
- # - MBR role in bootstrap
- # - The bootsector proper
- # - Boosector code snippets
- # - Links
- REPORT BUGS OR ERRORS IN THIS DOCUMENT

## Some advice on writing your own bootloader

Don't do it. At least, don't make the bootloader the first thing you work on. Reasons:

- A bootloader is not an OS.
- A bootloader is a VERY SMALL part of an OS.
- Writing a GOOD bootloader is as much work as writing a small OS (e.g. GRUB).
- Writing a robust and flexible bootloader is difficult. (Writing a crappy and inflexible bootloader is distressingly easy.)
- Writing a bootloader requires a lot of arcane knowledge (e.g. unreal mode, A20 gate, BIOS bugs and subtleties) that is otherwise useless.
- Bootloaders are very difficult to test and debug.
- Because of the hybrid 16- and 32-bit nature of x86 CPUs, x86 boot code is ugly.
- If booting your kernel fails, you won't know if the error is in your kernel or in your bootloader.

If you are developing under DOS or Windows 9x, you can use DOS (or FreeDOS) as your bootloader. Otherwise, use GRUB. It's not perfect, but it's still better than writing your own, and it's the closest thing to a 'standard' bootloader there is.

## Reviews of some open source bootloaders

#### GRUB

http://www.gnu.org/software/grub/

GRUB HOW-TOs:

- http://www.washingdishes.freeuk.com/grubtut.html
- grub-how.txt

GRUB understands the FAT (DOS/Win) filesystems, ext2 and Reiserfs filesystems (Linux), and FFS (BSD). GRUB will use a configuration file if it can find one. The config file can specify automatic loading or display a boot menu. GRUB also has a command-line shell, which lets you configure and install it, or load a kernel 'by hand'. It supports loading a kernel as a group of modules, e.g. monolithic kernel plus compressed RAM disk image, or microkernel plus vital servers.

#### Alexei Frounze's bootloader

http://alexfru.chat.ru/epm.html#bootprog

This loader starts up with a command-line shell similar to DOS, which lets you navigate a FAT12 or FAT16 filesystem, list directories, and chose a kernel file to be loaded. It can load DOS .COM and .EXE files, and DJGPP COFF files, and it builds with the freely-available Turbo C. If memory below 1 meg + 64K is left untouched, you can return to the loader to chose a new kernel to boot.

#### LILO

This loader no longer appears to have a home page.
Technical overview of LILO (gzip'ed PostScript): http://metalab.unc.edu/pub/Linux/system/boot/lilo/lilo-t-21.ps.gz. This 8-page document was written by Werner Almesberger, the author of LILO.

#### The built-in loader of Linux

bootsect.s is the built-in bootloader of Linux.
Operation and memory usage of this loader. More information can be found here: http://www.moses.uklinux.net/patches/lki-1.html

This boot code is no longer present in kernel version 2.6.

## BIOS role in bootstrap

1. The BIOS loads sector zero (CHS=0:0:1) of the boot drive to linear address 7C00h
2. The BIOS checks the loaded sector for the magic bootstrap signature bytes: 55h at offset 510 and 0AAh at offset 511. Many BIOSes will load and execute sector zero, regardless of the value of these bytes. MBRs, however, will check for the presence of these bytes.
3. CPU register DL is set to the boot drive number: 0 for floppy drive A, or 80h for hard drive C.
4. BIOS jumps to sector 0 code it just loaded.

Your boot code should initialize the following registers:

- DS. Some BIOSes set this register to 0, some set it to 40h. It should be set to (7C00h - BOOT_ORG) / 16. BOOT_ORG is the ORG value of your boot code, usually 7C00h.
- SS and SP (the stack). The initial values in these registers depend on the BIOS
- CS and IP (re-initialize these with a far JMP). Most BIOSes enter the boot code at address 0000:7C00h, but some (like the Compaq Presario 4328) jump to 07C0:0000h. Because short and conditional jumps are IP-relative, there is no need to reload CS and IP if your boot code does not use far or absolute JMPs. DS must still contain the correct value, however.

The most common disk sector size is 512 bytes. The code loaded by the BIOS must be smaller than this, so you will probably need to write this code in asm. If you can't do everything you want in 512 bytes, you need a two-stage bootloader.

## MBR role in bootstrap

Sector 0 of a hard disk typically contains a Master Boot Record (MBR). It has three parts:

1. Code to load a bootsector from one of four primary partitions
2. Top level partition table for the hard drive, at offset 446. This contains four partition table records; 16 bytes each.
3. Magic values: 55h at offset 510, 0AAh at offset 511.

16-byte partition table record:

offset | size | description
--- | --- | ---
0 | 1 byte | partition flag byte (0=not bootable, 80h=bootable, or 'active')
1 | 1 | partition start head (H)
2 | 1 | b7:6 = b9:8 of partition start cylinder (C) b5:0 = partition start sector (S)
3 | 1 | b7:0 of partition start C
4 | 1 | OS/filesystem type indicator byte
5 | 1 | partition end H
6 | 1 | b7:6 = b9:8 of partition end C b5:0 = partition end S
7 | 1 | b7:0 of partition end C
8 | 4 bytes | 32-bit LBA first sector of partition
12 | 4 | 32-bit LBA number of sectors in partition

Under both DOS and Linux, the utility that creates or modifies the partition table is called `fdisk`. Under DOS, the undocumented command `FDISK /MBR` will (re-)install the DOS MBR code, leaving the partition table untouched. This is useful is you mess up, or if you want to un-install a non-DOS bootloader such as LILO. If your BIOS has 'boot sector virus protection', it may interfere with attempts to install or modify the MBR using DOS FDISK.

No MBR is involved if the system boots from a floppy disk. Floppies do not have partitions or MBRs; only a boot sector. It is also possible to have a hard drive without an MBR, but this is uncommon.

Commented dis-assembly of DOS 7.0 (Win95a) MBR. This MBR uses CHS disk functions only.

## The bootsector proper

Sector 0 of a hard disk partition or floppy disk contains the actual bootsector. It's primary purpose is to find and load the kernel or second-stage loader. Both of these operations can be done in one of three ways:

1. Load kernel or second stage from contiguous sectors (disk has no filesystem)
2. Load kernel or second stage from non-contiguous sectors (disk may or may not have a filesystem). The install program for the bootloader must create a map of the non-contiguous sectors and write this map into the first-stage code.
3. Load kernel or second stage using the filesystem present on the disk

An exhaustive list of things a bootloader could do.

## Bootsector code snippets

Turn off floppy drive motors:

            mov dx,3F2h
            mov al,0
            out dx,al

Get memory size with BIOS calls. Because of problems with CMOS and direct probing, this should be the preferred method of getting memory sizes on the PC.

Get memory size from CMOS:

            ; read extended memory size to AX
    	; won't report more than 63.999 meg (65535/1024) of extended memory
                    mov al,18h
    		out 70h,al
    		in al,71h
    		mov ah,al
    		mov al,17h
    		out 70h,al
    		in al,71h
                    mov [_ext_mem],ax ; in K
            ; read conventional memory size to AX
    		mov al,16h
    		out 70h,al
    		in al,71h
    		mov ah,al
    		mov al,15h
    		out 70h,al
    		in al,71h
                    mov [_conv_mem],ax ; in K

INT 13h AH=08h gives unreliable sectors-per-track values for floppy disks. The FAT filesystems store the sectors-per-track value in the BIOS parameter block (BPB). For other filesystems, either assume a value (e.g. 18 sectors per track for 1.44 meg floppies), or use direct probing:

- C code
- NASM code

Real mode code to check for 32-bit CPU:

    	pushf
    		pushf
    		pop bx		; old FLAGS -> BX
    		mov ax,bx
    		xor ah,70h	; try changing b14 (NT)...
    		push ax		; ... or b13:b12 (IOPL)
    		popf
    		pushf
    		pop ax		; new FLAGS -> AX
    	popf
    	xor ah,bh		; 32-bit CPU if we changed NT...
    	and ah,70h		; ...or IOPL
            jne is_32bit_cpu

Check for Virtual 8086 mode (Windows DOS box or EMM386 loaded):

            smsw ax         ; smsw is a 286+ instruction; V86 mode is a 386+ feature
            test al,1       ; look at PE bit of MSW (CR0)
            jne in_v86_mode

You can't switch directly to pmode from V86 mode, because the `LGDT` and `LIDT` instructions, and writing the CR0 register (MSW) are privileged operations. If the system is in V86 mode because of a memory manager like EMM386, VCPI can be used to switch to paged protected mode:

- NASM code that uses VCPI to kick out EMM386
- LOADLIN (loads Linux from the DOS command prompt): http://www.ibiblio.org/pub/Linux/system/boot/dualboot
- John Fine's VLOAD: http://my.execpc.com/~geezer/johnfine/#sample
- Chris Giese's simulated linear framebuffer uses VCPI to switch from V86 mode to pmode and back again: http://my.execpc.com/~geezer/os/slfb.asm

NASM code to enable A20 and verify it's on. Your boot code should use INT 15h AH=89h (enter pmode) and INT 15h AH=87h (copy to extended memory) to control A20. Use code such as this only if these BIOS calls fail.

A FAT 12 bootsector. Finds, loads, and runs a 16-bit binary file that is stored in the root directory. Includes graphical test program.

## Links

The A20 gate in gory detail: http://www.win.tue.nl/~aeb/linux/kbd/A20.html

Other bootloaders with source code:

- http://www.openbg.net/sto/os/implement/v2osboot.asm
- XOSL: http://home.wanadoo.nl/geurt/home.html. This is a very elaborate bootloader with a GUI (!)
- http://my.execpc.com/~geezer/johnfine/#sample
- http://www.cix.co.uk/~mayday

Detailed Explanation of FAT Boot Sector http://support.microsoft.com/support/kb/articles/Q140/4/18.asp

http://www.nondot.org/sabre/os/articles/TheBootProcess/

Hale Landis' site: http://www.ata-atapi.com

## TO DO

    Floppy and IDE sectors are almost always 512 bytes, but SCSI
    devices may have larger sectors. I don't know how (or if) DOS
    can boot from a device with larger sectors.)

    - can you have multiple MBRs? to boot from an extended partition?

    - Network booting with BOOTP, TFTP, and/or Intel PXE
    - El Torito CD-ROM boot

    - Microsoft's new MBR format?

## REPORT BUGS OR ERRORS IN THIS DOCUMENT