Boot from USB without BIOS support

USB support

Nowadays, virtually every new computer has USB booting capabilities, but it hasn't always been like this. Yesterday I faced the challenge of booting a laptop from USB without native BIOS support. Neither an installation from optical drive nor HDD swapping to another computer were possible.
Note: follow these steps at your own risk and remember to back up every file you modify!

There are clearly two different approaches:

Bootable USB Live/Installer.

Typically copied from a bootable ISO of your preferred Linux distro, prepared using syslinux, Unetbootin or similar. It should be possible to boot other OS but I didn't try.

In this case I used PLOP, a small yet very useful utility that you can boot into. Once it's loaded it can take care of loading USB support and booting from your stick or external HDD. Although it presents a lot of options I provide only the basics for an installation with GRUB2.

You can download Plop here. Extract the archive, then copy file plpbt.bin to /boot

Append the following lines to /etc/grub.d/40_custom

menuentry "Plop Bootmanager" {
insmod ext2
set root='(hd0,msdos1)'
search --no-floppy --fs-uuid --set 90834467-a1a8-94cb-6c6f-0b07e5549083
linux16 /boot/plpbt.bin

Substitute the long hex string with the UUID corresponding your /boot partition, or whatever partition the /boot directory is located. I usually find it out by running df /boot or checking /etc/fstab. Now run:
A new choice will appear next time Grub2 pops up.

USB with GNU/Linux already installed on it

You might also want to boot from a distro installed on your USB stick or HDD. For this method you need a working OS installed in your computer. Here's how I did it.

Please note: all steps are performed on the OS installed in the computer in order to being able to boot from the OS installed on a removable drive (from now on I'll call it guest). It might get tricky at some point, so I suggest to read the full instructions before actually starting. My advice: don't trust everything blindly on the Interweb.

First step: you need to have installed a copy of *exactly* the same kernel that your guest system uses. Our plan is performing ourselves the first stage of the boot process and force it to detect the USB subsystem and carry on from there. Period.
If you happen to run the same OS on both main and guest installations, you may skip this step; otherwise grab a copy and install it yourself. If you compiled your own kernel, simply copy the image itself (vmlinuz-*) and its modules.

Second step: we need to load a few modules into the init ramdisk. Unless support is built in the kernel you definitely need to include this in order to make the computer understand the USB drive. In my case I needed four modules:

uhci_hcd: USB host controller interface.
ehci_hcd: Enhanced host controller interface (USB 2.0)
usb_storage: Mass storage driver.
ext2: EXT2 filesystem. If your guest system isn't on an EXT2 fs, use the appropiate module instead, e.g. jfs, xfs, ext3, ext4.

Append each module in a new line of /etc/initramfs-tools/modules


Third step: regenerate your initrd.
On Debian and derivatives run dpkg-reconfigure initramfs-tools

Fourth step: connect the external drive and identify it.

Running this command will output the identifiers of detected disk drives:
ls /dev/disk/by-id/

You will find out which one you are looking for because it starts with prefix usb- followed by brand and model. It should not end on any -partX suffix, i.e. choose whole disk not partition.
In my case it's named usb-SanDisk_U3_Cruzer_Micro_0000184B8872A303-0:0

Now edit file /boot/grub/ and append a new line with the full path of the chosen drive. I had already one line with disk (hd0), so I added a new entry for (hd1) as follows:

(hd1) /dev/disk/by-id/usb-SanDisk_U3_Cruzer_Micro_0000184B8872A303-0:0

Save changes and exit. This will allow your system to detect your drive at boot.

Fifth step: create a new entry in GRUB.

We want a new option in the bootloader menu. I created new file /etc/grub.d/11_linux_usb as follows:

exec tail -n +3 $0
# Custom entry to boot linux from usb
menuentry 'USB Debian GNU/Linux' --class debian --class gnu-linux --class gnu --class os {
insmod gzio
insmod part_msdos
insmod ext2
# Following line means disk (hd1) from step four, partition number one. Change it to suit your needs.
set root='(hd1,msdos1)'
# Next line states where to look for the kernel image. UUID from INTERNAL drive.
search --no-floppy --fs-uuid --set=root c3851350-db1c-41c5-ab0e-cd69bfe9ff38
# Location of the kernel, passing as argument the UUID from EXTERNAL drive to be booted. This will become the root filesystem.
linux /boot/vmlinuz-3.2.0-4-686-pae root=UUID=336f99cf-0ba1-4ac2-92ba-9827cf29a574 ro quiet
# Location of ramdisk
initrd /boot/initrd.img-3.2.0-4-686-pae

If necessary use blkid to obtain UUIDs.

Sixth step: reinstall GRUB.


Check the output for any errors. If everything went fine you're ready to restart your system. Congratulations! You just added USB software support to your system.