Sunday, December 13, 2009

Grub

Haven't posted for a while, so thought I'd go a bit geeky and give some information on the usage of various technologies (since I get asked these types of questions a lot on various IRC / IM channels). My first post will be on the architecture and usage of GRUB (note, the latest versions of Ubuntu etc using GRUB2 which is a complete rewrite of GRUB. I'll try and highlight some of the differences as I'm going along, but I'm still getting my head around GRUB2. For a complete breakdown of the differences between GRUB and GRUB2, then look here), then (at some point in the future) I'll blog about Xorg. These are the two most common queries and, in my opinion, the two most unappreciated pieces of software in existence.

So, what is GRUB? Well, simply put, it's a bootloader. However, that really is simplifying it rather too far. For one, it's the reference implementation of the Multiboot specification on the GNU OS. What this means is that it pretty much defines the de-facto standard for bootloaders. Without GRUB, you wouldn't have UNIX, Linux or even Solaris (since v10).

So, what's a bootloader? Well, generally speaking, when a computer is powered on, the BIOS reads the first 512 bytes of the hard disk (known as the Master Boot Record (MBR)). The MBR contains code known as the "bootstrap" program. Control is then passed to the bootstrap program. This is known as "Stage 1".

Stage 1 generally does little more than just load and execute code located at some other point in some partition on the hard disk, known as "Stage 2". (Actually, there is a situation where the GRUB MBR, for example, reads code from the 30K immediately following the MBR. This is generally termed "Stage 1.5". GRUB2, however, has eliminated this stage completely.).

Stage 2 generally presents an interface to the user (dependent on settings) to decide which OS to load. GRUB2 doesn't do this if there's only one OS installed, although you can get to the menu if you press the shift key. In situations where the OS installs a completely different bootloader into the MBR (such as Microsoft Windows), GRUB handles this by "chainloading", which creates a copy of the alternative MBR, and then executes that as though is was execute by the BIOS. It is this which allows GRUB to boot Windows (and even allow multiple versions of Windows).

So, how do I install GRUB? Well, it's obviously the default on most Linux distributions, but if the question really is "how do I install GRUB when it's not already installed?", the answer is to use a Linux distribution (any really small one will generally do) and use the "grub-install" routine. This will then install stage1 into the MBR, and the stage2 code into a usable partition, for example :

# grub-install /dev/hda

Installs GRUB stage1 onto the MBR of /dev/hda which is, typically, the first IDE disk. See below for typical device mappings.

# grub-install --root-directory=/boot /dev/hda

Installs GRUB stage1 onto the first disk, with the boot manager code in /boot.

So, how do I configure GRUB stage 2? Well, this is the power of GRUB really. It's all done by a single config file on the "usable" partition defined when using grub-install. In Debian, the file is /boot/grub/menu.lst, whereas in Fedora (and Gentoo) it's in /boot/grub/grub.conf. In GRUB2, it's been replaced by /boot/grub/grub.cfg (although, this is not meant to be edited, not even by root, GRUB2 provides /etc/default/grub which is merged into /boot/grub/grub.cfg when the update-grub command is used).

In terms of GRUB terminology of how your hard drive partition(s) are denoted, they follow the layout of "hd" followed by a number, a comma followed by the partition number (starting at 0 in GRUB, 1 in GRUB2), i.e. :

Primary Master=hd0,0
Primary slave=hd1,0
Secondary Master=hd2,0
Secondary slave=hd3,0

Therefore, in GRUB, hd0,0 denotes the first partition on the primary master, hd0,1 the second, and so on. In GRUB2, these would be hd0,1 and hd0,2 respectively.

A typical GRUB menu.lst looks something like this :

#
# GRUB's menu.lst config file, with examples for various OSes
#

# Default: boot the first entry. Problems? boot the second entry.
default 0
fallback 1

title Ubuntu hardy (development branch), kernel 2.6.24-12-386
root (hd0,0)
kernel /boot/vmlinuz-2.6.24-12-386 root=UUID=d1562435-e820-4486-99b8-eaad92e502cd ro clock=pit acpi=off noapic nolapic
initrd /boot/initrd.img-2.6.24-12-386
quiet

title Ubuntu hardy (development branch), kernel 2.6.24-12-386 (recovery mode)
root (hd0,0)
kernel /boot/vmlinuz-2.6.24-12-386 root=UUID=d1562435-e820-4486-99b8-eaad92e502cd ro clock=pit single
initrd /boot/initrd.img-2.6.24-12-386

title Microsoft Windows XP
root (hd0,1)
rootnoverify (hd0,1)
makeactive
chainloader +1

title Linux from second HDD
kernel (hd1,0)/vmlinuz root=/dev/hdb1

Here showing the first partition containing an installation of Ubuntu (Hardy Heron = 8.04) on the first partition (hd0,0) and an installation of Microsoft Windows XP on the second partition (hd0,1), as well as others. The "chainloader +1" command, specifies that (as I mentioned above) GRUB should pass control over to the subsequent boot manager specified in the first sector of the relevant partition.

The version of GRUB installed can be found easily (here on my Ubuntu 9.10 installation, which uses GRUB2 by default when newly installed)

chadders-desktop:/boot/grub$ grub-install -v
grub-install (GNU GRUB 1.97~beta4)

GRUB (now termed "GRUB legacy") would have a version of 0.97 or similar.

Obviously, GRUB (and certainly GRUB2) is an extremely complex beast. A full breakdown of all commands etc is explained at https://help.ubuntu.com/community/Grub2.