GRUB (GRand Unified Bootloader) and is the GNU Project's primary bootloader and the reference implementation of the Multiboot 2 Specification. GRUB can boot any Multiboot-compliant OS (e.g. Hurd, among others), however it can also boot some non-Multiboot-compliant OSes, e.g. Windows, via a chain-loading function, and some others via special support, e.g. Linux. mbchk can be used to determine if a file is Multiboot-compliant. s the GNU project's bootloader.
The current version 2 series have a more complete feature set than GRUB 0.97 (commonly referred to as "GRUB Legacy"), and is now the recommended version. However, GRUB Legacy is somewhat easier to work with, and some pages in the wiki still refer to the earlier version, so the information for it has been retained in a separate page.
GRUB was initially developed by Erich Boleyn as part of work on booting the operating system GNU/Hurd, developed by the Free Software Foundation. In 1999, Gordon Matzigkeit and Yoshinori K. Okuji made GRUB an official software package of the GNU Project and opened the development process to the public
GRUB version 2 started its life as the PUPA (note the pun) research project and was rewritten from the ground up. In 2002, it was integrated into the development branch after GRUB 1.97.
Due to initial stability problems and confusion brought by the move from Multiboot 1 to Multiboot 2, adoption of GRUB 2 by major Linux and FreeBSD distros was slow prior to 2008. GRUB 0.97 remained in wide deployment until 2010, by which time GRUB 2 had improved to the point that it had become the de facto standard for most non-commercial operating systems. Use of GRUB Legacy lingered with hobby OSes out of ease of use, but by 2013, GRUB 2 was the recommended boot loader for most new OS projects.
GRUB takes away all the complexities out of trying to boot your OS by doing it for you. GRUB can handle a variety of File Systems, including Microsoft NTFS, FAT32, and VFAT, Linux Ext2fs/Ext3fs/Ext4fs, ReiserFS, and BSD FFS. It supports loading kernels in a variety of binary Executable Formats, including ELF[32|64], and Unix a.out, as well as a raw binary image; it should be able to load any kernel image file in those formats which has a valid Multiboot header. It can also 'chain-load' non-Multiboot systems such as Microsoft Windows by loading their native boot loader as a raw binary image.
One major advantage of GRUB (or more precisely, a Multiboot-compliant bootloader) is that the kernel will be entered in a known state, which on the x86, includes having the system already in Protected mode when the OS is launched. This takes a lot of the pain out of writing a kernel, rendering GRUB a very useful tool for the amateur, or anyone who wants to spend more time on the intricacies of the kernel rather than worrying about these generic start-up procedures.
Other features available in GRUB 2 include:
- Basic scripting support
- GUI (bootsplash support, custom colors, custom themes, ...)
- Memory management
- Internationalization support
- Rescue mode
Some versions of GRUB 2 like to put Multiboot modules in relatively high physical memory addresses, in contrast to GRUB-legacy which loaded them into low memory. Be careful when making your kernel work with GRUB 2 that it is not making any assumptions about where the Multiboot modules will appear.
When your kernel gets control, the machine state is defined as follows: Multiboot machine state. Your code should have minimal dependency on this initial state; for example, define your own GDT instead of relying on the GDT setup by GRUB.
As the GRUB 2 manual puts it:
The primary requirement for GRUB is that it be compliant with the Multiboot Specification.
But the Multiboot header as used by older versions of GRUB 2 (field is present in GRUB 1.99 and newer) did not include the header_length field that is specified in the Multiboot 1.6 specification.
GRUB 2 also supports the old Multiboot 0.6.96 specification. It is possible to include both headers.
Creating GRUB 2 Disk Images
These instructions cover installing GRUB to a Disk Image under various development hosts.
Older GRUB versions are riddled with nasty bugs. As this probably includes the version from your package management, you should be compiling GRUB from source. As we're compiling for UEFI, you should pass the appropriate flags to configure. An example invocation might look something like this:
../grub-2.02~rc2/configure --prefix="$HOME/opt/grub" --target=x86_64 --with-platform=efi
After completing the build, GRUB refused to do anything as it was missing a font file. To fix this, run
bin/grub-mkfont -o share/grub/unicode.pf2 /usr/share/fonts/truetype/unifont/unifont.ttf
GRUB might warn you about share/locale/ missing. To solution is to create the missing directory.
Building a GRUB UEFI binary (BOOTX64.EFI)
This method builds a standalone GRUB binary you can copy to a FAT partition. However, note that some UEFI implementations assume that it is located at
/EFI/BOOT/BOOTX64.EFI for x86_64 platforms.
Generally, all compiled modules are included in this binary; if you want to cut down on its size, you can specify what modules to include.
This method uses two separate configuration files; this is needed as all GRUB data is located within the binary, but we'll be working around that. The binary contains a memdisk, which also serves as the prefix. As far as I'm aware, there's no way of working around this fact directly. We can, however, use the memdisk grub.cfg to load a configuration file from the disk. This way, we don't have to recreate the binary for every configuration change.
Start off with creating the memdisk grub.cfg. I saved it at build/grub.cfg (we'll need this path later on):
insmod part_msdos configfile (hd0,msdos1)/boot/grub/grub.cfg
All this does is loading the module for reading the disk partitions (line 1) and loading the configuration file from the disk (line 2). Note that it doesn't have to be located at /boot/grub/grub.cfg; you can change this path on the disk to whatever you like, just remember to apply the changes to the memdisk grub.cfg.
The second grub.cfg (the one on the disk) is pretty much up to you, except that you have to load the part_msdos module and set the root (which by default is memdisk):
insmod part_msdos set root=(hd0,msdos1)
Add your regular GRUB2 configuration below the
set root line.
Finally, all that's left is to create the binary. Note that you have to specify what file to include at what path in the memdisk:
bin/grub-mkstandalone -O x86_64-efi -o BOOTX64.EFI "boot/grub/grub.cfg=build/grub.cfg"
Windows (Using Cygwin or MinGW)
Because GRUB is designed as a part of the GNU project, it assumes the use of GCC and the Binutils tool chain. While this does not place an restrictions on the toolchain used by the OS, it does mean that compiling GRUB itself will require a GCC Cross-Compiler and Binutils configured as an OS Specific Toolchain.
Most of the instructions for building GRUB under Linux apply, but there are some notable difference.
It might be useful to create an image file for a HDD; The following instructions help you create a HDD with an MBR partition map. Based on information from <palk> on #osdev, it is slightly more complicated to create a HDD image than you'd expect.
This information might not be applicable to Linux users, who will most probably want to use a loopback device. This is for developers on OS X, which doesn't have a loopback device and has a finicky image mounter.
1. First, create a blank, raw image with DD, with the required size. Here, I'll make a 80MB image -- 163840 sectors of 512 bytes.
dd if=/dev/zero of=disk.img count=163840 bs=512
2. Next, calculate the CHS values for the disk and have them at hand. TODO: Explain this.
Here, it's a 80MB disk, so the CHS values are 78, 32 and 63 respectively.
3. Fire up FDISK (or your tool of choice) -- I'm using the OS X version here, so commands may differ. The concept is essentially identical.
What will show on your screen (in OS X anyway) is on the left, what you enter is on the right.
fdisk -e disk.img The signature for this MBR is invalid. Would you like to initialize the partition table? [y] Yes fdisk:*1> disk Disk: disk.img geometry: 650/4/63 [16340 sectors] Change disk geometry? [n] No fdisk:*1> edit 1 Partition id ('0' to disable) [0 - FF]: [B] (? for help) 0B Do you wish to edit in CHS mode? [n] No Partition offset [0 - 163840]:  2047 Partition size [1 - 161793]:  <Enter> fdisk:*1> write fdisk:*1> quit
4. Now that the MBR Partition Table is initialised, you'll want to make a Filesystem on the disk. But first.
Here, we separate the MBR bit, and the actual FS bit.
dd if=disk.img of=mbr.img bs=512 count=2047 dd if=disk.img of=fs.img bs=512 skip=2047
5. Because we're on OS X, we need to attach the disk image first, without actually mounting it.
hdiutil attach -nomount fs.img
6. Use 'diskutil list' to find out which device your image is, use that below.
7. Now, make a FAT12/16/32 filesystem on the FS.img disk. Remember, use FS.img -- not disk.img
newfs_msdos -F 32 /dev/diskX
8. Now you'll want to unmount it, then recombine the two images, then install GRUB.
hdiutil detach /dev/diskX cat mbr.img fs.img > disk.img hdiutil attach disk.img # note the mount point here (/Volumes/NO NAME, probably) grub-install --modules="part_msdos biosdisk fat multiboot configfile" --root-directory="/Volumes/NO NAME" disk.img Installation finished. No error reported.
And there it is! You know have a disk.img, that will have GRUB 2 installed, ready to go. It should be mountable in OS X simply by double clicking (or with the mount command). Enjoy!
Additional useful options
Whatever device you are using, you may want to have a PC partition table and create a partition you format in one of the filesystems supported by GRUB. If you do, be sure to add the following option the grub-install arguments:
In general, if GRUB 2 happens to fail to do what you want and you suspect that it needs some missing functionality, just try to add a module name you believe has the functionality you need to the --modules argument. The module files generally are in /boot/grub/i386-pc/.
Blessing the binary on macOS
Macs require bootable binaries to be 'blessed' by a utility:
bless --verbose --folder=/Volumes/EFI --file=/Volumes/EFI/EFI/BOOT/BOOTX64.EFI --setBoot