February 03, 2015

USB bootable NixOS - UEFI version

Previously I wrote how to make USB bootable NixOS.

This time, I’ll cover the UEFI part so that you can boot NixOS with UEFI

Successfully tested on Lenovo ThinkPad T430 and Sony VAIO 13 Touch Ultrabook.

Extract NixOS ISO to a directory

mount -o loop nixos-minimal-14.12.335.676e8d7-x86_64-linux.iso /mnt
mkdir iso
rsync -a /mnt/ iso/
umount /mnt

Copy syslinux files to extracted NixOS

Depending on the version of syslinux, there are special considerations what directory and the config name should be.

mkdir iso/syslinux

cp /nix/store/hash-syslinux-6.03/share/syslinux/isolinux.bin iso/syslinux/syslinux.bin
cp /nix/store/hash-syslinux-6.03/share/syslinux/vesamenu.c32 iso/syslinux/

with syslinux v6.03 you also need to copy these files:

cp /nix/store/hash-syslinux-6.03/share/syslinux/ldlinux.c32 iso/syslinux/
cp /nix/store/hash-syslinux-6.03/share/syslinux/libcom32.c32 iso/syslinux/
cp /nix/store/hash-syslinux-6.03/share/syslinux/libutil.c32 iso/syslinux/

Create new syslinux config based on the original one

[root@nixos:~]# cat iso/loader/entries/nixos-livecd.conf
title NixOS LiveCD
linux /boot/bzImage
initrd /boot/initrd
options init=/nix/store/y606cp5rf75kfz8g36dcyaki2is79kcm-nixos-14.12.335.676e8d7/init root=LABEL=NIXOS_ISO boot.shell_on_fail loglevel=4

[root@nixos:~]# nano -w iso/syslinux/syslinux.cfg

[root@nixos:~]# cat iso/syslinux/syslinux.cfg
  UI vesamenu.c32
  PROMPT 1
  TIMEOUT 50
  DEFAULT nixos
    SAY Now booting the kernel from SYSLINUX...
  LABEL nixos
    KERNEL /boot/bzImage
    APPEND ro initrd=/boot/initrd init=/nix/store/y606cp5rf75kfz8g36dcyaki2is79kcm-nixos-14.12.335.676e8d7/init root=LABEL=NIXOS_ISO boot.shell_on_fail loglevel=4

Set the volume label to efi.img

If you look at nixpkgs/nixos/modules/installer/cd-dvd/iso-image.nix, the efi.img was created without a label. It is crucial to set any label but not equal to NIXOS_ISO as we will generate ISO with this label -V NIXOS_ISO later

[root@nixos:~]# mlabel -s -i iso/boot/efi.img 
 Volume has no label
[root@nixos:~]# mlabel -i iso/boot/efi.img ::EFIBOOT
[root@nixos:~]# mlabel -s -i iso/boot/efi.img 
 Volume label is EFIBOOT    

Without this label, on UEFI boot, stage1 can’t mount the root device which is necessary for stage2 boot process to continue. However it is possible to workaround this by modifying kernel argument manually on boot to root=/dev/sda1 OR root=UUID=2015-02-03-10-11-46-00 OR root=/dev/disk/by-uuid/2015-02-03-10-11-46-00 instead of the default root=LABEL=NIXOS_ISO

Generate new ISO with embedded syslinux and efi.img

genisoimage -o nixos-live-usb-uefi.iso -V NIXOS_ISO -R -b syslinux/syslinux.bin -c .boot.cat -no-emul-boot -boot-load-size 4 -boot-info-table -eltorito-alt-boot -e boot/efi.img -no-emul-boot iso/

Make it USB-bootable now

isohybrid --uefi nixos-live-usb-uefi.iso

Test your ISO image using qemu and UEFI

Download OVMF binary. It enables UEFI firmware for QEMU and KVM so that you can test your ISO before writing it on your USB stick.

CDROM Legacy (BIOS)

qemu-system-x86_64 -enable-kvm -cdrom nixos-live-usb-uefi.iso

CDROM UEFI

qemu-system-x86_64 -enable-kvm -bios ./OVMF.fd -cdrom nixos-live-usb-uefi.iso

USB Legacy (BIOS)

qemu-system-x86_64 -enable-kvm -hda nixos-live-usb-uefi.iso
qemu-system-x86_64 -enable-kvm -usb -usbdevice disk:nixos-live-usb-uefi.iso

USB UEFI

qemu-system-x86_64 -enable-kvm -bios ./OVMF.fd -hda nixos-live-usb-uefi.iso
qemu-system-x86_64 -enable-kvm -bios ./OVMF.fd -usb -usbdevice disk:nixos-live-usb-uefi.iso

As -usb runs very slow, I intentionally specified both -hda and -usb because in most of cases if -hda boots then -usb also boots.

Write your ISO

Now it’s time to write your USB-bootable image onto your USB stick (in my case it was accessible at /dev/sdb)

Be very careful using following commands, do not to overwrite any of your other devices!

[root@nixos:~]# cat nixos-live-usb-uefi.iso > /dev/sdX
[root@nixos:~]# echo 3 > /proc/sys/vm/drop_caches ; sync
[root@nixos:~]# udisksctl power-off -b /dev/sdb

Now you can try booting with UEFI.

Secure Boot

If you will see similar error as this one, then all you have to do is to disable Secure Boot from your BIOS options, but keep UEFI enabled. If you really want to have Secure Boot then see this for an overview.

Secure Boot
Image failed to verify with *ACCESS DENIED*.
Press any key to continue.

additional notes

Create EFI partition

If you wish, you can create/modify EFI partition on your own as follows

dd bs=2048 count=5120 if=/dev/zero of="iso/boot/efi.img"
mkfs.vfat -n "EFIBOOT" "iso/boot/efi.img"
mcopy -svi "iso/boot/efi.img" iso/efi iso/loader ::
mmd -i "iso/boot/efi.img" boot
mcopy -v -i "iso/boot/efi.img" iso/boot/bzImage ::boot/bzImage
mcopy -v -i "iso/boot/efi.img" iso/boot/initrd ::boot/initrd

Checking the lables

[root@nixos:~]# blkid iso/boot/efi.img
iso/boot/efi.img: SEC_TYPE="msdos" LABEL="EFIBOOT" UUID="98D2-735E" TYPE="vfat" 

[root@nixos:~]# blkid nixos-live-usb-uefi.iso
nixos-live-usb-uefi.iso: UUID="2015-02-03-10-11-46-00" LABEL="NIXOS_ISO" TYPE="iso9660" PTUUID="42719253" PTTYPE="dos" 

Xorriso version

Using this method you don’t have to run isohybrid --uefi command

[root@nixos:~]# xorriso -as mkisofs -o nixos-live-usb-uefi.iso -V NIXOS_ISO -R -b syslinux/syslinux.bin -c .boot.cat -no-emul-boot -boot-load-size 4 -boot-info-table -isohybrid-mbr /nix/store/hash-syslinux-6.03/share/syslinux/isohdpfx.bin -eltorito-alt-boot -e boot/efi.img -no-emul-boot -isohybrid-gpt-basdat iso/