This article may be unbalanced towards certain viewpoints. Please improve the article by adding information on neglected viewpoints.
GRUB or custom bootloader?
This is one of the never-ending arguments of the OSDev community. No one can give you a definitive answer, so it's up to you to weight the available options and make up your mind.
Arguments in favour of using GRUB as your bootloader are:
- You can avoid almost all legacy things that make booting complicated (e.g. real mode segmentation, A20, the large list of BIOS interrupts, etc) so you can get to writing the kernel and the userspace faster.
- If you are willing to implement Multiboot, most arguments in favour of writing a custom bootloader are voided anyway.
Apart from the "Not Invented Here" syndrome and the "enjoying doing fun things" argument, there are technical arguments in favour of doing a custom bootloader:
- Better control over the booting process. See also What should my bootloader support? for things a bootloader should do. Hint: GRUB probably doesn't do half of them.
- Less external dependencies, which may be desirable as internal components can be patched at any time whenever the need arises. This also allows to easily add features to your bootloader at your own pace.
- If your OS is not UNIX-like, a custom bootloader may make it easier to integrate it as part of the OS installation process, as GRUB's installer requires some level of "UNIX-ness" to work.
- Less bloat. Let's admit it, GRUB is not only a bootloader, but also a boot manager. A bootloader is (should be) OS-dependent, while a boot manager is (should be) able to chainload any bootloader the user selects. In other words, it's two separate concerns.
BIOS or UEFI?
How do I load the kernel (BIOS)?
You probably followed a tutorial that shows how to write a "bootloader" that prints "Hello, World!" using the BIOS. Now you naturally ask how to load the kernel, which is indeed the intended purpose of a bootloader.
Unfortunately, loading the kernel isn't quite a simple thing, as seen from What should my bootloader support? Of course, these things won't fit in the 512 bytes you got in your stage-1, so you need to load more sectors before even initialising the environment for the kernel.
Depending on the media, the boot process is differentiated enough to make sense to have different bootloaders for each supported media. Initially, however, it's probably a good idea to start with a single media (e.g. CDs), go up to the point where an initial kernel can be started and then support more media.
Assuming a MBR-partitioned hard disk, the BIOS loads and executes the Master Boot Record (MBR), which is responsible for loading and executing the Volume Boot Record (VBR) of the active partition. Normally, the VBR should simply do some initial checks and load stage-2 from either the filesystem or some reserved sectors right after the VBR (not the MBR, see "Footnote 1"). I suggest doing the latter, in order not to bother with filesystems yet. If you, however, decide to implement a filesystem already, be warned that common filesystems don't reserve much space for stage-1. FAT is probably the worst in this regard, reserving only one single sector (the VBR) for doing initial checks, parsing the filesystem tables and loading stage-2. Ext2 is somewhat better, reserving another sector right after the VBR, but then again Ext2 needs more parsing than FAT. Or, if you want, design your own filesystem (don't do it before designing and implementing the VFS), where the VBR says how many sectors at the start of the partition are reserved so you can put the whole bootloader there.
Footnote 1: The space after the MBR and before the first partition is not supposed to be used by any OS.
Footnote 2: For a GPT-partitioned hard disk, the boot process is slightly differentiated, as the Protective Master Boot Record (PMBR) needs to be aware of the existence of the GPT.
When booting from a floppy, the BIOS loads and executes its first sector, which should do some initial checks and load stage-2 from either the filesystem or some reserved sectors right after sector 0.
Note however that floppies have small capacities (usually 1.44 MB) and are slow and generally unreliable. Not to mention that most machines less than a decade old don't support them anyway.
For CDs, there is the El-Torito specification. The CD has an ISO-9660 filesystem and the BIOS reads a file from the filesystem and executes the code from it. Compliant BIOSes will load the full file if requested appropriately. However, some older BIOSes may still only load the first sector (2048 bytes), so you might want to split it into two stages; either as two files, or as two parts of the same file where the second part of the file starting at offset 2048 contains a magic number that's checked by the first part.
Note that the CDs you buy in bulk may usually be burned only once. Please look for CD-RWs which, while a bit more expensive than CD-Rs, allow to be rewritten multiple times, making them acceptable for testing your OS.
The last time you installed a Linux distro, chances are you wrote the live CD to the USB drive and booted from it. The problem, however, is that BIOSes treat USB drives as hard disks, so the CD image needs to additionally contain a valid MBR that is then loaded by the BIOS. Now, in contrast to hard drives, the space available between the MBR and the first interesting ISO-9660 sector may be used for stage-2.
What should my bootloader support?
Apart from loading the kernel, the bootloader also has to prepare the environment appropriately before handing off control to the kernel. This includes:
- Detecting CPU/BIOS features. You need to make sure that the CPU or the BIOS supports any features that you use (e.g. INT 0x13 extensions).
- Getting the memory map. Where will you even load the kernel if you don't know what memory areas actually are memory?
- Enabling A20 and protected mode with paging (or long mode if running on a x86_64). GRUB doesn't enable paging or long mode, but that doesn't mean other bootloaders shouldn't do better. Not enabling paging or long mode in the bootloader means that you need to decide a priori in which physical memory area the kernel will reside, which may lead to two potential consequences:
- There might not be actually any memory at that address;
- It makes it a bit harder and more messy to do a higher half kernel.
When you are more advanced, you may also want/need to do these things in the bootloader:
- Set a suitable video mode;
- Get the ACPI info;
- Load the needed kernel modules or the ramdisk;
- Feel free to add anything you deem important.
It's probably a good idea to start from the bare minimum in order to load the kernel, then implement whatever you see the kernel needs. Don't try to match an existing specification (e.g. Multiboot), otherwise it would be probably better to use an existing bootloader (e.g. GRUB).