Thursday, March 31, 2011

Bootable Arch flash drive with separate data partition

This deceptively simple thing is much more trouble than it seems. Its difficulty can be distilled down to two main reasons:

  • Removable device woes        Windows only being able to read from the first partition on a device that is identified as a removable drive.
    More on the removable media bit from WHDC – FAQ for Driver and Hardware Developer:
    The removable media device setting is a flag contained within the SCSI Inquiry Data response to the SCSI Inquiry command. Bit 7 of byte 1 (indexed from 0) is the Removable Media Bit (RMB). An RMB set to zero indicates that the device is not a removable media device. An RMB of one indicates that the device is a removable media device. Drivers obtain this information by using the StorageDeviceProperty request.
  • BIOS troubles        “Error 18: Selected cylinder exceeds maximum supported by BIOS” when attempting to boot from the second partition with GRUB bootloader.
This second reason is curious indeed, since my 4GB flash drive (on which this was attempted) has a cylinder count within the 1024-cylinder limit commonly prescribed:
# fdisk -l /dev/sdc

Disk /dev/sdc: 4004 MB, 4004511744 bytes
124 heads, 62 sectors/track, 1017 cylinders, total 7821312 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x000bc9f3

Device Boot Start End Blocks Id System
/dev/sdc1 2048 3911679 1954816 b W95 FAT32
/dev/sdc2 * 3911680 7821311 1954816 83 Linux
Can anyone shed some light on this?


In any case, moving on, we find that we need a bootloader that can circumvent this. Here, GRUB exits stage left, and extlinux enters stage right. With much reference to brain0’s comprehensive Arch Linux USB Install and Rescue Media article, I managed to get Arch install media put into the second partition (/dev/sdc2). I quote the relevant section for my future reference here:
The bootable flag needs to be set on sdb2, the boot partition. Now create filesystems on the partitions:
# mkfs.vfat -n SOMELABEL /dev/sdb1
# mkfs.ext2 /dev/sdb2
# tune2fs -i0 -c0 -m0 /dev/sdb2
# e2label /dev/sdb2 ARCH_201005
Notice the label of the Linux partition: While it is arbitrary, it must match the label in the bootloader configuration, which is ARCH_201005 by default. We are finished with the FAT part now: The way we set it up, even Windows will be able to recognize and use it properly. Now, mount the archiso image and the Linux partition:
# mkdir -p /mnt/{archiso,usbboot}
# mount -o loop,ro archlinux-2010.05-netinstall-dual.iso /mnt/archiso
# mount /dev/sdb2 /mnt/usbboot
Copy all the contents of the archiso image onto the USB and umount the ISO:
# cp -a /mnt/archiso/* /mnt/usbboot/
# umount /mnt/archiso
All that is left to do is set up a bootloader. We will use extlinux, as we will be able to reuse all existing configuration from isolinux. First, install the syslinux package, if you don’t have it already:
# pacman -S syslinux
Now, remove the old isolinux bootloader, rename the configuration file, install the extlinux bootloader and umount:
# rm /mnt/usbboot/boot/isolinux/isolinux.bin
# mv /mnt/usbboot/boot/isolinux/isolinux.cfg /mnt/usbboot/boot/isolinux/extlinux.conf
# extlinux --install /mnt/usbboot/boot/isolinux/
# umount /mnt/usbboot
For simplicity, I didn’t rename the isolinux folder here, although the bootloader is technically not isolinux anymore. Feel free to rename it to extlinux if you feel the urge. One last step is setting up a MBR that will recognize the active flag of the second partition and boot its boot sector:
# cat /usr/lib/syslinux/mbr.bin > /dev/sdb

We can do much more than this though. The install media (archiso.img) boots without a root partition on the host, but we can also install a fully functional Arch system alongside the install media, and choose between the two at boot via extlinux. I couldn’t get the booted install media to install to its own partition, so you will need to install from another partition (or try alternative method without rebooting).

Important points to remember during this install:
  1. Do not reformat the partition into which you are installing Arch or you will wipe the existing install media.
  2. Do not set up the GRUB bootloader, since we went to all that effort to use extlinux.
We’re not done yet. The Arch install iso image was compiled with USB boot support, but the new kernel (which we just installed) was not. We will chroot into the new setup (mounted on /bootmnt or /mnt; check!) from the install media setup, and recompile the initramfs with support for USB boot.

# mount -t proc proc /bootmnt/proc
# mount -t sysfs sys /bootmnt/sys
# mount -o bind /dev /bootmnt/dev
# chroot /bootmnt

# nano /etc/mkinitcpio.conf

Edit /etc/mkinitcpio.conf to include USB boot support. Ensure that ‘usb’ is placed before ‘autodetect’ in the hooks list. The HOOKS line should look like:

HOOKS="base udev usb autodetect pata scsi sata filesystems"

Now we remake the initramfs image:

# mkinitcpio -p kernel26
==> Building image "default"
==> Running command: /sbin/mkinitcpio -k 2.6.37-ARCH -c /etc/mkinitcpio.conf -g /boot/kernel26.img
:: Begin build
:: Parsing hook [base]
:: Parsing hook [udev]
:: Parsing hook [usb]
:: Parsing hook [autodetect]
:: Parsing hook [pata]
:: Parsing hook [scsi]
:: Parsing hook [sata]
:: Parsing hook [filesystems]
:: Generating module dependencies
:: Generating image '/boot/kernel26.img'...SUCCESS
==> SUCCESS
==> Building image "fallback"
==> Running command: /sbin/mkinitcpio -k 2.6.37-ARCH -c /etc/mkinitcpio.conf -g /boot/kernel26-fallback.img -S autodetect
:: Begin build
:: Parsing hook [base]
:: Parsing hook [udev]
:: Parsing hook [usb]
:: Parsing hook [pata]
:: Parsing hook [scsi]
:: Parsing hook [sata]
:: Parsing hook [filesystems]
:: Generating module dependencies
:: Generating image '/boot/kernel26-fallback.img'...SUCCESS
==> SUCCESS

Still not done yet. Let’s make some fstab changes.

#nano /etc/fstab

On a flash drive install, we want to minimise writes to the system. Hence, we add the noatime mount option to the root mount, and also put /tmp on tmpfs. It would also be nice to make the data partition (the first partition, the FAT32 one) accessible in our Arch boot, so let’s do it.
# cat /etc/fstab
#
# /etc/fstab: static file system information
#
#file system      dir         type    options        dump pass
devpts            /dev/pts    devpts  defaults       0    0
shm               /dev/shm    tmpfs   nodev,nosuid   0    0
tmpfs             /tmp        tmpfs   defaults       0    0
UUID=964f5668-ddfe-4b6e-b3c8-aa1f1a854310 / ext2 defaults,noatime  0      1
LABEL=CRUSTOR     /crustor    vfat    user,defaults  0    0
Here, I mounted the data partition by label, but you can do it by UUID too.
Once fstab changes are made, on to extlinux.conf changes.

#nano /boot/extlinux/extlinux.conf

We want to add boot options for regular Arch, and optionally the fallback image as well. These look like below in extlinux.conf:

LABEL archboot
TEXT HELP
Boot into the Arch Linux installation.
ENDTEXT
MENU LABEL Arch Linux
LINUX /boot/vmlinuz26
APPEND root=/dev/disk/by-uuid/964f5668-ddfe-4b6e-b3c8-aa1f1a854310 ro
INITRD /boot/kernel26.img

Note the /dev/disk/by-uuid/ line. This ensures that the flash drive will be able to boot properly in various PCs and setups. /dev/sda* format is not used here since it varies depending on the number of disks on the host system.

The final result should look like this (comments and less important lines stripped):
# cat /boot/extlinux/extlinux.conf
DEFAULT archboot
PROMPT 0
TIMEOUT 50
UI vesamenu.c32

MENU WIDTH 78
MENU ROWS 8
MENU TITLE Arch Linux
MENU BACKGROUND /boot/splash.png

LABEL archboot
MENU LABEL Arch Linux
LINUX /boot/vmlinuz26
APPEND root=/dev/disk/by-uuid/964f5668-ddfe-4b6e-b3c8-aa1f1a854310 ro
INITRD /boot/kernel26.img

LABEL archfallback
MENU LABEL Arch Linux Fallback
LINUX /boot/vmlinuz26
APPEND root=/dev/disk/by-uuid/964f5668-ddfe-4b6e-b3c8-aa1f1a854310 ro
INITRD /boot/kernel26-fallback.img

LABEL archiso
MENU LABEL Arch Linux LiveUSB
KERNEL /boot/vmlinuz26_archiso
APPEND initrd=/boot/archiso.img archisolabel=archboot tmpfs_size=75% locale=en_US.UTF-8
IPAPPEND 0

LABEL existing
MENU LABEL Boot existing OS
KERNEL chain.c32
APPEND hd0 0

LABEL reboot
MENU LABEL Reboot
KERNEL reboot.c32

LABEL off
MENU LABEL Power Off
COMBOOT poweroff.com

ONTIMEOUT archboot
Yes, I did change the partition label, which is why archisolabel is different.

And we’re done. Exit from chroot:

# exit
# umount /bootmnt/proc
# umount /bootmnt/sys
# umount /bootmnt/dev

Try booting into it now and hope everything goes well.

0 comments:

Tags

linux (4) software (4) hardware (3) musings (3) osmium (3) projects (3) science (1) typography (1)