OSD Home

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: 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:

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:

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:

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 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:

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