Operating System Development: Writing your own bootloader

When you’re writing your own toy operating system, the first thing you’ll need is a boot sector. It’s a piece of code (the boot loader) that lives in the first sector of a (floppy) disk. This code gets called by the BIOS as soon as the computer starts up, and is responsible for setting everything […]

This article was posted by Independent Software, a website and database application development company based in Maputo, Mozambique. Our website offers regular write-ups on technical and design issues, ranging from details at code level to 3D Studio Max rendering. Read more about Independent Software's philosophy, or get in touch with Independent Software.

When you’re writing your own toy operating system, the first thing you’ll need is a boot sector. It’s a piece of code (the boot loader) that lives in the first sector of a (floppy) disk. This code gets called by the BIOS as soon as the computer starts up, and is responsible for setting everything up for your operating system’s kernel to be loaded and executed.

This article is part of a series on toy operating system development.

Note that you can actually start developing other components of your toy operating system before writing boot code, since you can use GRUB (GNU Grand Unified Boot Loader) or LILO to start your kernel. Using one of these tools brings advantages, since they’ll switch the processor to protected mode for you, and allow you to load kernels that are placed beyond cylinder 1024 of a hard disk.

However, writing your own boot code can be a very interesting exercise in assembly programming, and you’ll have full control over what your boot loader actually does. Plus, you get to try and do it better than the people who wrote the DOS/Win95 boot loaders (which isn’t saying a lot as you’ll see below).

Boot loader requirements

The boot code lives in the first sector of a floppy disk, which typically has a size of 512 bytes. However, 61 of those bytes are occupied by data, placed on the disk when it is formatted. This data includes the size of a disk sector, number of FAT tables, number of tracks per sector, volume ID, and more. This yields 451 bytes available for code, which is not a whole lot. That’s one reason we’ll use assembler to write our code.

The DOS/Windows bootloader and its limitations

Let’s consider the boot loader that most of us have used many times: the boot loader that comes with DOS or Windows (up to Windows 95). What does it do?

  • Reset the floppy disk system
  • Read the first sector of the root directory from the disk
  • Verify that the first file found there is IO.SYS (the kernel)
  • Load IO.SYS into memory
  • Transfer control to IO.SYS

Since the space available for actual code in the boot sector is limited, the author of the DOS boot loader introduced an important requirement: the file IO.SYS must be the first file in the root directory. The DOS code does not scan the entire root directory looking for the required file. If IO.SYS is not the first file found, then the boot code fails.

This is why DOS/Windows comes with the SYS.COM program, which is used to make a disk bootable. This program actually cleans the root directory of a floppy disk and copies IO.SYS into it as the first entry, effectively removing all the other files. It would have been much nicer if it had been possible to copy IO.SYS to the root directory of a disk, at any position. Then any disk could be make bootable without sacrificing the files on it. This can actually be done, but it requires more assembly code, something the DOS developers apparently did not find any space for – but we can do better.

At any rate, modern operating systems will switch the processor to protected mode, which allows us to address up to 4 GB of memory in a flat model (not segmented), and switch on paging to protect processes from one another. This wasn’t part of the DOS/Windows 95 boot loader, but we’ll need to do it.

How a boot loader gets called

When the computer starts up, it executes a power-on self test (POST). It then performs the following actions:

  • Determine which device (drive) to use for booting, using preferences stored in the CMOS.
  • Try to load the first sector (and only the first sector) from the boot drive into memory at address 0:0x7C00 .
  • Verify that the the first sector is in fact bootable by checking for the presence of a magic number (see below).
  • Store the number of the drive used in register DL.
  • Point the CPU’s instruction pointer to 0:0x7C00 , and start execution from there.

The computer knows how to do these things, and does them automatically, because the code for this is in its BIOS ROM. In other words, these procedures we get for free with any computer.

What a boot loader should do

Here’s a list of things that a modern boot loader should do in order to load and start your operating system’s kernel (we’ll cover concepts like the A20-line, IDT and GDT tables later):

  • Reset the floppy disk system
  • Write a “loading” message to the screen
  • Find the kernel in the root directory of the disk (at any position)
  • Read the kernel from disk into memory
  • Enable the A20-line
  • Setup the IDT and GDT tables
  • Switch to protected mode
  • Clear the processor prefetch queue
  • Run the kernel

Boot Sector Layout

The boot sector of a floppy disk has a very specific layout, because the BIOS requires access to certain data which it needs to find in the place it expects it to be. Also, an operating system will need to access this data to determine how large the disk is, what file system it uses, what its volume label is and so on. For this article, we’ll assume a floppy disk formatted with a FAT16 file system. The layout of the boot sector is then:

OffsetSize ContentsTypical value
00003CodeJump to rest of code
00038BPBOEM nameGreat-OS
00112Bytes per sector512
00131Number of sectors per cluster1
00142Number of reserved sectors1
00161Number of FAT tables2
00172Number of root directory entries (usually 224)224
00192Total number of sectors2880
00211Media descriptor0xf0
00222Number of sectors per FAT9
00242Number of sectors/track9
00262Number of heads2
00282Number of hidden sectors0
00302EBPBNumber of hidden sectors (high word)0
00324Total number of sectors in filesystem
00361Logical drive number0
00371Reserved
00381Extended signature0x29
00394Serial number
004311Volume labelMYVOLUME
00548Filesystem typeFAT16
0062448CodeBoot code
05102RequiredBoot signature0xaa55

A required element of the boot sector is the boot parameter block (BPB) and the extended boot parameter block (EBPB, for FAT16). This block must be placed at offset 3, size 59 bytes. Also, the boot sector must end with the magic number 0xaa55 : (some) BIOSes will check whether this value is present at offset 510. If not, the BIOS will refuse to boot from the disk. All other bytes are available for us to fill in. We can calculate that that adds in fact up to 451 bytes. Also, the first three bytes are separated from the rest and should only be used to jump to the rest of the code, so that’s less 3 bytes for interesting code…

Here is a typical hex dump of a boot sector without any code. Colored in red are the parts in the BPB and EBPB as decribed above, and the magic number at the end. Everything else is available for code:

0x0000 00 00 00 47 72 65 61 74 2d 4f 53 00 02 01 01 00 ...Great-OS.....
0x0010 02 e0 00 40 0b f0 09 00 09 00 02 00 00 00 00 00 .à.@............
0x0020 00 00 00 00 00 00 29 73 65 72 69 00 00 00 00 00 ......)seri.....
0x0030 00 00 00 00 00 00 46 41 54 31 36 20 20 20 fa 88 ......FAT16   ú^
0x0040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0080 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0090 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x00a0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x00b0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x00c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x00d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x00e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x00f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0100 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0110 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0120 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0130 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0140 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0150 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0160 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0170 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0180 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0190 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x01a0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x01b0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x01c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x01d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x01e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x01f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 aa ..............

Summary

This article described how a computer bootstraps. The Power-On Self Test (POST) causes the first sector of a (floppy) disk to be read into memory. This boot sector contains information about the disk and (at most) 451 bytes of code. In the next part of this guide, we’ll see how we can write assembly code to roll our own boot loader.

Series index Next tutorial: Writing your first bootloader code

Save

Save

Save

Save

Save

Save

Save

Did this article help you out? Please help us find more time to write useful guides & articles like this by donating a buck or two. It'll keep us coffee-fueled. Thanks!

Trackbacks

  1. Writing your own toy operating system: First bootloader code | Independent Software
  2. Writing your own toy operating system: File Allocation Table (FAT) and reading from disk | Independent Software

Comments

9 9 Responses to “Writing your own boot loader for a toy operating system”
  1. larrat says:

    Hi,
    thanks for this article.

    what about if i have a NTFS’s formated disk (Pendrive)?

    how would be the layout boot sector?

    i am looking for “google” references, but no success..

    thanks, and i am wating for your next article 🙂

  2. alex says:

    Hello and thanks for your feedback!

    The layout of the NTFS partition boot sector can be found here. Since we’re writing a toy operating system, the file system structure is something we’ll be tackling at some point and it doesn’t necessarily have to be FAT or NTFS. However, FAT is a simple system and used in these articles as a starting point (since we don’t have an OS yet, we can profit from DOS/Windows’s FAT support to be able to put files on a disk that we’ll boot from).

    Here’s the next article in this series about bootstrapping.

  3. wipe3out says:

    Thank you for very helpful article!
    but size of “Filesystem type” field might be incorrect.
    http://wiki.osdev.org/FAT
    It says it’s 11 bytes.

  4. alex says:

    Hello wipe3out,

    You’re correct – there is an error in the table. However, it’s not filesystem type but rather volume label. I had marked that with a size of 8 bytes while it’s actually 11, like OSDev’s FAT information says. Thanks for spotting that!

    Just an observation though: when you’re writing your own OS, there is no need to follow the “official” FAT boot sector structure. If you don’t want to include a volume label, or want to allow a different size for it, then go ahead and do that – your code will be the only code using the data.

  5. marisa says:

    I downloaded the first version of akernelloader in google code I tested with Desiros operating system. I think it’s good to start

  6. BillKoul says:

    When i run the Makefile it says “Warning: boot sector file (532 bytes) is larger than one sector (512 bytes).
    – skipping excess bytes.” and when i load the img in VW Player it keeps rebooting after printing the first line. Can you please help?

  7. BillKoul says:

    nevermind i kept reading and i answered my own question

Leave a Reply

Your email address will not be published. Required fields are marked *