The many ways PCs can dual boot multiple OSes
In response to yesterday's entry, a commentator asked a question related to dual booting. That means it's time to open the can of complexity that is dual booting on PCs. One of the reasons that dual booting is much more complex than how PCs boot the main OS is that there are at least three different ways that you can boot an alternate OS:
- you can load the other OS's boot sector and jump to it, just as if
it was the real MBR being loaded by the BIOS. This is simple and
basically guaranteed to work, but it requires that you capture and
maintain the boot sector (and the primary partition table that
is embedded into it), and the rest of the OS's bootloader has to
be on disk where it expects it to be (which may be where your
bootloader also wants to go).
(For obvious reasons this is a favorite technique of boot sector viruses.)
I believe that GRUB chainloading usually does this. There seems to be more or less a standard where many OSes stick a properly set up copy of their boot sector in the first sector of their BIOS partition.
- you can load and jump to the other OS's bootloader itself (what's
often called the second stage bootloader), loading it either from
where it normally lives or from a copy that's located in a place
more convenient for you. The drawback of this approach is that
loading a bootloader second stage and transferring control to it
is somewhat more complicated and more bootloader specific.
(Although since the second stage is loaded by the boot sector and the boot sector code is very small, this is generally not going to be that complex. Still, second stage bootloaders can live in all sorts of places depending on the OS.)
- you can directly load and start the other OS's kernel and any
additional bits that it needs. The drawback is that loading a
kernel, setting it properly, and passing boot parameters to it
is complex and OS dependent (and changes every so often, which
means that your bootloader has to keep up). Also, generally you
need to understand the OS's filesystem (whatever it is), since
kernels are usually in the filesystem (unlike live bootloaders).
However, if everything works this is the most direct way of booting another OS plus you can do everything in a single step; you do not have the user experience of telling the computer to boot another OS twice (once for the real bootloader and once again to the other OS's bootloader).
Every so often people in the open source world have tried to create a common generic boot protocol for loading OS kernels and passing arguments to them; one example is the GRUB Multiboot protocol. These have the goal of eliminating most of the complexity of the last approach, which is especially important for people who are trying to create a generic open source bootloader since they would rather not maintain special kernel setup code for each different free Unix. My impression is that none of these protocols have really caught on and the major open source OSes like Linux have preferred to stick to their existing kernel setup protocols.
Some of dual booting interacts with partitioning. If you use chainloading from the first sector of an OS's partition, well, your bootloader has to be able to find that; generally this only requires knowing the global partitioning scheme in effect (eg, BIOS primary and extended partitions). If your bootloader is directly loading the OS's kernel it needs to understand enough of the OS's own partitioning scheme (if any) to let it find the filesystem with the kernel. If the OS nests its own partitioning scheme inside BIOS partitioning, your bootloader will need to understand both in addition to being able to read the OS's filesystem.
(Here we can see a subtle win from the Linux decision not to have its own disk partitioning scheme. Since Linux partitioning is BIOS partitioning, Linux bootloaders only have to know one sort of partitioning. Or zero sorts of partitioning in the case of LILO.)
Sidebar: the extremely minimal bootloader
All of this description has assumed a relatively sophisticated bootloader. Bootloaders don't have to be sophisticated; they can be extremely minimal instead. A minimal bootloader does not try to understand and parse anything; not partitioning, not filesystems. Instead it loads things through a hardcoded set of mappings of disk blocks (probably encoded as extents) and the mapping information is maintained outside of the bootloader itself. Such a minimal bootloader is completely agnostic about partitioning and filesystems, although the tool to maintain the mapping data needs to be able to generate the block map for files on the disk.
As you might guess from what I said above, LILO is an example of such a bootloader.