Installing a 64 bit system with a 32 bit bootloader


I’m currently trying to install NixOS on a T100TAF, it has a 64 bit CPU but only supports 32 bit bootloaders.

I would use (and managed to install) an i686 image but Hydra doesn’t build i686 packages anymore, meaning that installing anything would take ages.

  • I tried using nixos-rebuild --build-host with my fast x86_64 machine but it sent me back 64-bit binaries, even though I forced nixpkgs.system = 'i686-linux';
  • I tried installing an x86_64 image but the USB refuses to boot altogether, following this guide’s step 4 also led to failures during stage 1 (however it booted).
  • I’m currently tring to migrate from my i686 installation to x86_64 using this guide. I managed to build a generation with an x86_64 kernel but it will refuse to boot (Failed to execute NixOS (\efi\nixos\$HASH-linux-4.14-bzImage.efi): Unsupported)
  • I installed NixOS with UEFI support, I think this means systemd-boot will match my installed architecture and this may cause issues if I manage to migrate to x86_64.

I think multiple choices are available to me:

  • Keep my i686 install and figure out a way to build from my main x86_64 PC. This is most likely the easiest solution but I could not find any relevant help in manuals.
  • Attempt to install from an x86_64 USB again using a bootia32.efi from an i686 USB rather than a random one from the internet
  • Keep attempting to migrate to x86_64
  • Last two options probably still mean incompatibilities in bootloader architecture

What do you think ? What glaring issues can you notice?


Completely untested, but maybe you could try something like this within your configuration.nix for systemd-boot:

{ pkgs, lib, config, ... }:

{ = let
    cfg = config.boot.loader.systemd-boot;
    inherit (config.boot.loader) efi;
  in pkgs.substituteAll {
    src = <nixpkgs/nixos/modules/system/boot/loader/systemd-boot/>;
    isExecutable = true;
    inherit (pkgs) python3;
    systemd = pkgs.pkgsi686Linux.systemd.package;
    nix = config.nix.package.out;
    timeout = lib.optionalString (config.boot.loader.timeout != null) config.boot.loader.timeout;
    editor = if cfg.editor then "True" else "False";
    inherit (cfg) consoleMode;
    inherit (efi) efiSysMountPoint canTouchEfiVariables;

Eg. you can add this to systemd-boot32.nix or something like that and use imports = [ /path/to/systemd-boot32.nix ]; in your configuration.nix.

This should in theory get you a i686 bootloader while the rest of your system stays at whatever builtins.currentSystem is (or what you specified explicitly).

Wow, thanks for taking the time to write that, I’ll attempt to make it work shortly

It seems like that worked out fine but it turns out that systemd-boot in i686 just can’t load the 64 bit kernel “botoload stub”(?), giving me the error message I had previously (Failed to execute NixOS (\efi\nixos\$HASH-linux-4.14-bzImage.efi): Unsupported)
EDIT 2: Yup, just found a random reddit thread mentioning systemd-boot only supports booting stubs from its own architecture. Thanks for helping me pinpoint the issue!

The weird and wonderful systems you find nowadays… GRUB might be worth a try as well, since it aims to support a lot more things than systemd-boot. Using a 32-bit grub ought to be a bit simpler as well, since it’s its own package (not tested though):

  nixpkgs.overlays = [(self: super: { inherit (super.pkgsi686Linux) grub2_efi; })]
  boot.loader.grub = {
    enable = true;
    efiSupport = true;
    device = "nodev";
1 Like

That’s exactly where I’m headed, haha
Is the grub.device mean to be nodev?
I still have my 512mb /boot partition, should I keep that ? It doesn’t exactly seem like grub is using it but I’ve booted with EFI support :man_shrugging:
I booted with an x86_64 kernel, woo!
EDIT: And I migrated to a complete x86_64 system, thanks to you two for helping me.

Ah, yeah forgot about that, systemd-boot actually is quite minimal and just starts EFI executables, so mixing 32/64 bit doesn’t work here.

For EFI boot, yes. It should only be set to something else for legacy (MBR) boot.

Yes, do keep it! That’s where GRUB and its config live.

Yay, congratulations! Glad I could help.

This doesn’t work for me sadly on a similar machine with 64 bit Atom CPU and 32 bit UEFI bootloader. If I do as recommended by @lheckemann nixpkgs.overlays = [(self: super: { inherit (super.pkgsi686Linux) grub2_efi; })], it hangs the machine for a bit after “building the system configuration” message, then runs out of memory. I tried to do --build-host root@build-machine.lan, but then it runs out of 16 gigs of memory + 16 gigs of swap on the build machine. --verbose doesn’t give any hints, as all the messages stop after evaluating NixOS. strace just gives neverending amount of reads (if I do strace nix-build <nixpkgs/nixos> -A system). I guess it might cause infinite recursion or just evaluate whole pkgsi686Linux for some reason. BTW, I can totally do nix-shell -p pkgsi686Linux.grub2 on the same machine, and it works.
If I instead do nixpkgs.overlays = [(self: super: { inherit (import <nixpkgs> {system = "i686-linux";}) grub2_efi; })] it builds, but then it fails on GRUB installation, saying that blkid for /boot failed. When I took a closer look on exact perl script, it seems that util-linux that is used doesn’t work (ELF headers of libblkid are incorrect). Yet just doing $ blkid on the system works. How can I force usage of system blkid as opposed to the broken one?
EDIT: actually, it seems that no matter what I try to do, the new util-linux is always broken (invalid ELF header is the error message). (I am on x86_64 kernel but i686 nixpkgs).