Hardware boot selection switch

A physical switch for my computer to choose between Linux and Windows

Similar projects worth following
After a decade of dual-booting Linux, I got tired of waiting around to change the GRUB boot selection any time I wanted to boot Windows. With a little tinkering, here's a physical switch that determines the OS to boot each time the computer is turned on.

This uses an STM32 microcontroller to act as a USB mass-storage device, serving up a dynamic file. This file can be loaded by the system's boot config to change its boot behaviour based on the physical input:

A full write-up of the process to arrive at this solution is in the project log.

Source code is available on GitHub.

  • Hardware OS selection switch

    Stephen Holdaway2 days ago 0 comments

    Dual-booting Linux and Windows is a great way to get the best of both worlds, but there's one thing that's always bothered me. To boot into Linux, I simply press the power button and walk away. To boot into Windows on the other hand requires a tactical, precision-timed strike on the keyboard to change the selection when GRUB briefly reveals itself:

    Now I could just increase the GRUB selection timeout, or remove it entirely, but I'd still need to wait around to make an operating system selection. I could use the mode in GRUB that remembers the last OS selection, but I'd still need to be around to change it half the time. I could make a "reboot into Windows" action in Linux, but I'm just as often booting from a powered-off state as I am rebooting from Linux.

    Since I always know which operating system I want ahead of time, why not make a physical switch to select between Linux and Windows?

    Scripting in the boot loader

    GNU GRUB is a popular Linux boot loader - a program that runs before any operating system is loaded to decide what to boot and how to boot it. You'll normally interact with a menu like the one pictured above, but under the hood GRUB is configured by a simplified scripting language. Underneath that it's a system of modules written in C.

    My only hands-on experience with GRUB script to date has been those occasional times where a system fails to boot and you find yourself plunged into a shell with the prompt "grub>". You fairly quickly discover that while this looks like typical Linux shell with ls, cat and tab completion, it is very much not. Running outside of an operating system, GRUB has to supply all of its own tools, so the functionality available is fairly bare-bones.

    Arbitrary USB device access in GRUB?

    My first thought was creating a USB device with a custom ("vendor-specific") interface to read out the switch position, which in non-USB terms is kind of like a bare serial connection. This is straight forward enough to access from an operating system, but I wasn't sure if GRUB could handle it.

    GRUB does implement native USB support in its ehci, uhci and ohci modules, but there's a catch - loading any of these disables the normal mechanism used to access disks through the BIOS to avoid conflicts, leaving you with no disk access. There is a nativedisk module for accessing disks independently of the BIOS, but slowness aside, using this module critically means that GRUB can't chain-load Windows (explanation), making this approach a write-off.

    In short, native access to arbitrary USB devices from GRUB isn't practical for this project, but USB isn't off the table entirely...

    Pretending to be a USB mass-storage device

    Instead of making a custom USB interface, we can leverage the fact that the BIOS already provides GRUB with access to all attached storage devices. All we would need to do is present our device as storage, containing a file whose contents indicate the switch position.

    This is conceptually simple, but there are a few layers to it:

    1. Provide the mass-storage class descriptor, indicating one of several storage protocols to use (SCSI, ATA).
    2. Implement the chosen storage protocol. This is a set of commands to interrogate the storage device's capabilities, capacity, layout and other metadata in addition to standard requests to read and write sectors.
    3. Emulate a valid filesystem when read from, without actually having any storage medium.

    Using the USB-capable STM32 boards and code I already have from USB Status Light, changing a vendor class device to a mass-storage class device was a matter of changing a few bytes in the existing USB descriptors.

    For the storage protocol layer, I was happy to find that libopencm3 has a built-in SCSI mass-storage implementation with simple read_block(address) and write_block(address) callbacks, hiding the complexity of the storage protocol:

    Thanks to this, I was up and running fairly quickly with a recognisable storage device, even...

    Read more »

View project log

Enjoy this project?



Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates