Generic boot code
The expression “generic boot code” simply refers to boot code that is not specific to a particular operating system.
Newer computers are moving toward UEFI booting, but there are still many computers that use BIOS based MBR booting. And I still have some of those computers. Booting of such a computer starts with boot code in the MBR (or main boot record). And typically, that is generic boot code.
First a quick rundown on how MBR booting typically works.
The MBR is the first physical sector on the hard drive. When you power on the computer, the BIOS loads that sector into memory at a standard location, and then jumps to that memory location (starts running instructions from there). Normally a properly initialized MBR will have 0xaa55 as the last 16 bits (that’s hexadecimal). This is a boot flag and indicates that the disk is bootable. The BIOS usually checks for this flag before it jumps to the boot code that it has loaded from the MBR.
The generic boot code first copies itself to a different location in memory, and then jumps to that copy. The generic boot code next examines the partition table, which is part of the MBR that has been loaded into memory. From the partition table, it identifies the active partition (if there is one). It then loads the first sector of the active partition into the memory location where it was initially loaded. That first sector of the active partition is usually called the PBR or “partition boot record”. The generic boot code then jumps to the loaded copy of the PBR, which is supposed to then load the operating system.
If you are running linux, and you installed grub into the MBR, then you are not using generic boot code. Instead, the MBR contains part of your operating system loader.
It is typical for a Windows install to insert the Windows version of generic boot code into the MBR. An opensuse install will also offer to put generic boot code in the MBR if you are installing grub elsewhere. I usually install grub (actually grub2) in “/boot” which is a separate small partition. I need a separate “/boot” because I use an encrypted LVM.
It turns out that the “syslinux” software includes several versions of generic boot code. So I have been testing those. And that’s mainly what this post is about.
Recent versions of opensuse seem to automatically install “syslinux”, and the generic code can be found in files in “/usr/share/syslinux”.
There are three major versions of the generic boot code, with names “mbr.bin”, “altmbr.bin” and “gptmbr.bin”. I’ll be describing what each of those does.
There are also some other variants. For example, there’s “mbr_f.bin” and “mbr_c.bin”. I won’t say much about those because I have not tested them. According to the documentation, if using “mbr_f.bin” then it forces the hard drive to be hd0 (the first hard drive). This only makes sense if you have more than one hard drive. I occasionally boot from a USB. When I tell the BIOS to boot from a USB, the BIOS forces that to be hd0. So the “mbr_f.bin” is doing something similar. This is done so that boot code can just assume it is booting the first hard drive and need not know the actual drive designation.
I’ll start with “mbr.bin”. This is pretty much standard generic boot code. That is, it does about what I described earlier.
But not quite. It turns out that this is a bit more flexible. What I described earlier can only boot a primary partition. That is, it can only boot partitions 1,2,3 or 4. It turns out that if you use “mbr.bin” instead of the Windows provided generic boot code, you can also boot a logical partition such as partition 5. I tried this on my laptop. I turned off the active flag for all of partitions “/dev/sda1”, “/dev/sda2″, /dev/sda3” and “/dev/sda4”. Then I turned on the active flag for “/dev/sda5”. I did have the syslinux “mbr.bin” generic boot code installed at the time. And note that “/dev/sda5” is actually the “/boot” partition for an alternative linux (actually Tumbleweed) that I have installed.
I then rebooted the computer. And it went straight to the boot menu for that Tumbleweed installation booting from “/dev/sda5”. I used “fdisk” (from linux) for those active flag changes.
I later restored the original Windows provided generic boot code, and attempted to boot. The system gave me an error message that no partition was bootable. I expected that. The Windows provided generic boot code cannot boot a logical partition (a partition numbered 5 or above).
I should add a warning here. Using “mbr.bin” to boot a logical partition, I was able to boot linux. However, that probably would not work to boot Windows from a logical partition.
I am testing this one at present. It is intended for booting a disk with GPT partitioning. When a disk is partitioned using the GPT partitioning scheme, there is still an MBR, but it is a fake. It is called a “protective MBR”. The partition table typically has the whole disk on one partition, as a protection against accidentally partitioning with a tool that does not understand GPT partition tables.
With “gptmbr.bin” in the MBR on a legacy BIOS based computer, when the BIOS loads the boot code, that boot code is smart enough to read the actual GPT partition table, and find the active partition there and boot it.
My most recent Tumbleweed test install was to an external drive with GPT partitioning. It is set to boot from “/boot” which is one of the GPT partitions. The Tumbleweed installer put generic boot code into the protective MBR. So this serves as a good test. When I plug in the external drive, and tell the BIOS to boot from USB, it loads that boot code which does indeed manage to read the GPT partition table and find the partition with the legacy_boot flag (the equivalent of the “active” flag). So this is working well.
Again, do not try to boot Windows this way. If Windows is installed with GPT partitioning, then it wants to use UEFI booting. As far as I know, the only way to use legacy booting with Windows and a GPT partition table, is to use a hybrid MBR. The Windows partition has to be in both the GPT partition table and the hybrid MBR. I have not tested this.
I am currently testing this on two computers. It works similarly to “mbr.bin” but with a subtle difference. It ignores the active partition flag in the partition table. Instead, you put the active partition number at the end of the boot code.
Normally, boot code is 440 bytes in length. The file “altmbr.bin” is 439 bytes in length.
Normally, I have the active bit set on partition 3 of my laptop. That’s a Windows partition. I use the Windows boot manager to boot linux.
My main linux install on that laptop uses partition 1 as “/boot”. So here’s what I did
echo -e -n '\01' > x cat /usr/share/syslinux/altmbr.bin x > bootcode.bin
The first line created a one-byte file containing a binary 1. The next line concatenated that onto the end of “altmbr.bin” to create a 440 byte file “bootcode.bin”. I later renamed that file to “altmbr-01.bin” so that I could better remember what it contained.
When run as boot code, “altmbr.bin” reads that one byte containing 1, and then boots partition 1. It ignores the active flag. So it boots me straight into the linux grub menu. There, I can choose to boot Windows if I prefer. And windows will see that its partition is the active partition. So Windows will think that all is hunky dory about booting.
Note that to install that bootcode.bin into the MBR, I simply used
# cat bootcode.bin > /dev/sda
This works because “bootcode.bin” is exactly the right length. To reinstall the Windows generic boot code, I will need to find a copy (saved as “/boot/backup_mbr” by opensuse install), and then use
# dd if=backup_mbr of=/dev/sda bs=440 count=1
Here, I need to carefully limit the amount copied to 440 bytes, since “backup_mbr” is 512 bytes in length.
I’ll note that I also tested “altmbr.bin” for booting a logical partition. This time it was partition 6 on a different computer where “/dev/sda6” is “/boot” for an alternative linux install.
Those “syslinux” provided versions of boot code seem to do pretty well for the purposes for which they were designed. And, strictly speaking, only “mbr.bin” should be called “generic boot code” as the others differ from what generic code should do.