2010-08-17

Booting from a btrfs filesystem in a GPT-partitioned USB flash drive attached to a non-EFI system

Previously thought impossible, thanks to syslinux 4 this feat can now be achieved in a few easy steps.

Background

Recently, I had a talk on IRC with the developer of the Arch Linux installer, who wanted to enable Arch Linux installation on legacy BIOS systems with GPT partitioned media.
As I usually carry a bootable USB flash stick with me, containing the netboot installers for various popular Linux distros (don't worry, all of them can be abused to install Gentoo as well), I thought that maybe it is time to get this up to date with the latest and greatest in partitioning and file systems.
  • Why GPT?
    GPT, short form of GUID Partition Table, is the standard for EFI systems and is intended to replace MBR style partition tables. Advantages of GPT include support for up to 128 partitions (no distinction between primary and logical), no limitation to 2³² sector disks (2 TiB for 512 byte sectors), and increased redundancy for easier recovery.
  • Why btrfs?
    No real reason, other than it being the new hotness (in spite of some design flaws).
  • Why syslinux?
    EXTLINUX from the syslinux family of boot loaders can boot both from GPT and btrfs. An alternative would be GRUB 2, which however uses not the standardized method described in T13 EDD-4 Annex 1 and needs special patching for btrfs still.

Prerequisites

  • A USB flash drive of >256 MiB capacity
  • sys-apps/gdisk
  • >=sys-boot/syslinux-4.00
  • sys-fs/btrfs-progs

Partitioning

When first launching gdisk you will be greeted by a message that either the disk was found unpartitioned and a new GPT has been created, or that your existing MBR has been converted to GPT. In this example we use /dev/sdc as the device and /mnt/usb as the mount point.
# gdisk /dev/sdc
GPT fdisk (gdisk) version 0.6.9

Partition table scan:
  MBR: not present
  BSD: not present
  APM: not present
  GPT: not present

Creating new GPT entries.
Now we proceed to create a partition (gdisk syntax follows fdisk closely) and then enter expert mode to mark this partition legacy BIOS bootable.
Command (? for help): n
(answer the questions)
Command (? for help): x
Expert command (? for help): a
Using 1
Attribute value is 0000000000000000. Set fields are:
Known attributes are:
0 - system partition
1 - hide from EFI
2 - legacy BIOS bootable
60 - read-only
62 - hidden
63 - do not automount
Toggle which attribute field (0-63, 64 to exit): 61
Note that due to a bug in gdisk-0.6.9 and earlier, you need to enter 61 instead of 2. This will be fixed in a future release. Verify that you have the correct attribute flags, which are 0000000000000004. Now write the partition table to disk and exit gdisk.

Installing the MBR/GPT boot code and EXTLINUX boot loader

Install the GPT boot code into the MBR
# dd if=/usr/share/syslinux/gptmbr.bin of=/dev/sdc
Create a btrfs filesystem in the partition
# mkfs.btrfs /dev/sdc1
Install the EXTLINUX boot loader into the partition
# mount /dev/sdc1 /mnt/usb
# extlinux -i /mnt/usb
/mnt/usb is device /dev/sdc1
# cp /usr/share/syslinux/menu.c32 /mnt/usb 

Configuring the boot loader

In this example, we put the Debian Squeeze amd64 netboot installer on the USB drive. Same thing works for the netboot (sometimes called PXE) installers of other distros too.
# mkdir /mnt/usb/debian-amd64
# cd /mnt/usb/debian-amd64
# wget http://ftp.debian.org/debian/dists/squeeze/main/installer-amd64/current/images/netboot/debian-installer/amd64/linux
 http://ftp.debian.org/debian/dists/squeeze/main/installer-amd64/current/images/netboot/debian-installer/amd64/initrd.gz
Create /mnt/usb/extlinux.conf with the following content:
DEFAULT menu.c32
PROMPT 0
MENU TITLE Select Installer

LABEL debian-amd64
   MENU LABEL Debian Squeeze amd64
   KERNEL /debian-amd64/linux
   APPEND initrd=/debian-amd64/initrd.gz
Now your USB stick should be bootable and ready to use.

Other Thoughts

While syslinux supports chainloading on GPT disks, you cannot boot Windows this way, because Windows requires an EFI system in order to boot from GPT.
ChromeOS uses a slightly different method of booting from GPT, which resembles the old syslinux 3 and current FreeBSD way (even using the gpt utility from FreeBSD). If you are interested in their way, look at the ChromeOS installer scripts and the gpt utility.
A nice description of the issues surrounding booting from GPT can be found at the gdisk website.