SystemD-boot keeps starting even if GRUB is installed

Good morning.

I’m writing this post as I’m encountering a strange issue that I’m unable to reproduce in the other two devices on which I installed NixOS and that I’m having some difficulties to troubleshoot.

As you can guess from the title, I originally installed NixOS with SystemD-boot enabled, and now it keeps firing off even if I replaced it in favor of GRUB, rebuilt my configuration without any error and made sure that the ESP actually contains the correct EFI files.

Here you can find my current NixOS configuration (with the lines that enable GRUB commented out just to apply to SystemD-boot the various generations that I create over time, since leaving them on updates the GRUB menu that I’m unable to open); here you can find the content of my /boot directory while here it is a screenshot of my boot order settings.

Since I’m still learning how to properly use Nix I probably forgot to set some option in my configuration but, since setting systemd-boot.enable = false; and uncommenting the GRUB-related lines is sufficient to successfully replace SystemD-boot on my other devices, I don’t know where to start looking.

The device that is having this problem, for reference, is an Acer Aspire ES1-523-887J.

Many thanks in advance to anyone who can point me in the right direction.

You need to manually clean up systemd-boot’s files. NixOS does not know systemd-boot was installed previously and just removing any NixOS systemd-boot installation would be dangerous since you might dual boot two NixOS systems with two separate boot loaders for some odd reason.

If you have no other OSs in this boot/EFI partition, easiest is to delete all files from /boot and then nixos-rebuild boot since /boot is semi-stateless in NixOS.

Well, I think that I can try that.

Just to be sure, though, on my other laptop (a Lenovo IdeaPad Flex 10) rebuilding NixOS after disabling SystemD-boot and enabling GRUB with the parameters that you can find commented out in the attachments of the original post was sufficient to switch from one bootloader to the other. Why isn’t this the case?

It might be due to differences in EFI implementations.

Bootloaders actually set the EFI firmware’s persistent variables to register themself. Whether the EFI sets them as the default boot option.

Check whether your other device still has the files in /boot and also check whether this device has both bootloaders as an option in the firmware’s boot menu.

I suspect the issue is that you have boot.loader.efi.canTouchEfiVariables rather than boot.loader.grub.efiInstallAsRemovable. Some systems just don’t respect EFI boot variables, and efiInstallAsRemovable tells grub to write BOOTX64.EFI (which is UEFI’s fallback). I imagine that right now, the BOOTX64.EFI on your system is still systemd-boot because Grub hasn’t replaced it, and your system is preferring BOOTX64.EFI and ignoring the EFI variables that Grub set altogether.

If you just delete all the systemd files without fixing this, there’s a good chance your system won’t boot at all, either because you deleted the only boot loader it respects (the BOOTX64.EFI that is currently systemd-boot), or because you didn’t and systemd-boot can’t find its entries.

EDIT: Actually, according to man configuration.nix, BOOTX64.EFI is required to be tried first? I did not know that. Regardless, the fact that you likely have systemd-boot at that file is probably the reason for the problem.

1 Like

So, should I just set boot.loader.grub.efiInstallAsRemovable to true and boot.loader.efi.canTouchEfiVariables to false or should I leave both to true?

I’m asking because I once read that SystemD expects EFI vars to be writable, and I’m afraid to fix the bootloader just to break something else…

Setting boot.loader.efi.canTouchEfiVariables to false won’t have any effect on any components other than the boot loader. But I think that once I discovered the thing I put in the edit (that BOOTX64.EFI is always preferred, which is the opposite of what I had thought), the suggestion to just remove systemd-boot files rather than changing those options should work (in particular BOOTX64.EFI, though the others may as well be deleted too). Grub will set EFI variables rather than creating BOOTX64.EFI and it should work, unless your system doesn’t implement EFI variables (VirtualBox does this but I’ve never seen it on a physical system).

TL;DR: I was confused and wrong about a UEFI detail; ignore me and delete BOOTX64.EFI :stuck_out_tongue:

I don’t know if this can be related, but among the various test that I made to fix this problem, I once tried to manually invoke efibootmgr, which shows the following boot order

BootCurrent: 0000
Timeout: 0 seconds
BootOrder: 0000,2001,2002,2003
Boot0000* HDD: CT500MX500SSD1
Boot0001* Unknown Device: 
Boot0004* NixOS-boot-efi
Boot2001* EFI USB Device
Boot2002* EFI DVD/CDROM
Boot2003* EFI Network

and I tried to manually change it to move 0004 (which, as you can see, is not shown in the Insyde utility) on top, but rebooting seems to reset the preference.

Is it possible that this is a symptom of a bug in the firmware that ignores/resets the EFI variables?

No, as I said, the detail I missed is that UEFI is required to try BOOTX64.EFI first, no matter what your EFI variables say the boot order is.

OK, so I’ll just follow @Atemu suggestion.

For safety reasons, can backing up /boot content to another partition before wiping it and rebuilding NixOS be considered sufficient to do a rollback in case the system refuses to boot after the change?

I’d just get a recovery USB because NixOS is trivial to re-install at next to no cost.

Though you wouldn’t even need to do that; just nixos-enter and activate your previous generation with GRUB for booting.

So, I tried to follow the advice of wiping the content of /boot and rebuilding the system, but the following was the only result:

For reference, here you can find the /boot directory produced by GRUB for this unbootable derivation.

At this point, since the only way to recover the system was to plug in my NixOS USB and rebuild the system with the other bootloader, I first tried to wipe /boot again, set boot.loader.efi.canTouchEfiVariables=false; and boot.loader.grub.efiInstallAsRemovable = true; and rebuild the system, which worked instantly (here it is the working /boot content).

Clearly, it seems that GRUB does not produce BOOTX64.EFI without the option boot.loader.grub.efiInstallAsRemovable set to true and that my laptop’s UEFI implementation completely ignores all other executables (who knows whether due to a bug or a specific architectural choice).

In any case, thank you very much for all your advices!

1 Like

Thanks a lot!
My GRUB menu wasn’t showing with UEFI and your solution fixed it:

# configuration.nix
{
  boot.loader = {
    timeout = 5;

    efi = {
      efiSysMountPoint = "/boot";
    };

    grub = {
      enable = true;
      version = 2;
      
      efiSupport = true;
      efiInstallAsRemovable = true; # Otherwise /boot/EFI/BOOT/BOOTX64.EFI isn't generated
      devices = [ "nodev" ];
      extraEntriesBeforeNixOS = true;
      extraEntries = ''
        menuentry "Reboot" {
          reboot
        }
        menuentry "Poweroff" {
          halt
        }
      '';
    };
  };
}

Then

$ rm -rv /boot/*
$ nixos-rebuild switch

3 Likes

Thank you guys! this helped me fixed the same issue

1 Like

Thank you! I was facing the same issue with my setup. Now finally I can see the grub menu and can boot into my nixos and arch Linux machines. Though I can’t still figure out why it’s not showing my windows partition (/dev/sda1) but I’ll fix that too.
Any suggestions might help :slight_smile:

2 Likes