Failsafe Pi Dual-boot with GPIO

tl;dr

Add this to /boot/config.txt:

# Set GPIO 26 to pull-up
gpio=26=pu

# If GPIO 26 is high, the kernel, dtb and cmdline will be taken from /boot/other/
[gpio26=1]
# Note the trailing slash is important
os_prefix=other/

The background

I’ve been keen for quite some time on using Arm powered machines for as much as I can. Back in 2012 I bought the first Samsung Chromebook which used a dual-core Cortex-A15 Samsung Exynos chip. I used that as my main laptop until I eventually bought an Intel Inside Thinkpad at the end of 2016.

My main machine at my day job is an Arm powered HP Envy x2 with a Snapdragon 835, but at home I’ve been using an i5 2500k desktop for the past 10 years.

I’ve been itching to try and replace at least some of that machine’s time with something Arm based, but appropriate devices just haven’t been available. They’re all too underpowered (Cortex A53 cores), too low on RAM (less than 8 GB), or too pricey (the $4000 Ampere eMAG desktop). I came very close to picking up a Honeycomb LX2K, but before I actually did, the 8 GB Pi 4 was announced (somewhat out of nowhere) - so that was a no-brainer: A usable amount of horsepower (4 x A72), with an excellent software ecosystem, for less than £100. I bought one on release day.

So, since then I’ve been trying to leave the i5 desktop turned off and using the Pi 4 almost exclusively - including to write this post of course. I’ve installed tuptime to track how much time I use each machine for, and I expect I’ll do some more blogging about my experiences here as time goes on.

The “Problem”

I think we all probably know the problem of fiddling with our computers, and messing something up to the point where it won’t boot any more. Usually, I find it’s possible to interrupt the bootloader (GRUB or UEFI), boot into some kind of recovery mode, and fix whatever I screwed up.

On the Pi, the bootloader doesn’t give an interactive prompt, and while you can install extra boot stages and add GRUB and whatever, the built-in bootloader is actually really capable, and there’s a wealth of options available in config.txt which can help.

Of course, you can just take the SD card out and put it into another machine, but I think it’s much nicer to have a recovery option without having to mess around with that.

The Solution

One of the more interesting set of directives in config.txt are the Conditional Filters, which let you set boot parameters based on GPIO state, the name of the plugged-in monitor, the serial number, hardware version…

So, using this, I’m setting up my Pi to boot a “failsafe” OS on the SD card if a particular GPIO is pulled high, and otherwise it will boot to my “main” partition on an external USB SSD.

I tell the bootloader to enable the pull-up on a pin, and then have a jumper between the GPIO and GND, which will normally keep the pin pulled low. If something goes wrong and I need to boot to the “failsafe” OS, I just need to take the jumper off and reboot.

It’s really very very simple, I added these few lines in /boot/config.txt:

# Set the GPIO to pull-up
gpio=26=pu

# If the GPIO is high, load boot files from "/boot/failsafe/"
[gpio26=1]
# Note the trailing slash is important
os_prefix=failsafe/

Then made a set of boot files for the failsafe OS:

$ sudo mkdir /boot/failsafe
# I'm on a Pi 4 with 64-bit OS, so I only need these three files
$ sudo cp /boot/kernel8.img /boot/failsafe/
$ sudo cp /boot/bcm2711-rpi-4-b.dtb /boot/failsafe/
$ sudo cp /boot/cmdline.txt /boot/failsafe/
# Then change  /boot/failsafe/cmdline.txt to set root= to point at the "failsafe" root filesystem

And that’s it. I can now pick which OS I boot based on whether the little blue jumper in the picture below is fitted or not, and it fits nicely under the GPIO cover on my Argon One case (which I’ll happily recommend if you’re looking for a desktop-style case for your Pi).

Argon One Pi 4 case