Hierarchical Boot-entry Organization w/o GRUB

With many specializations, my boot menu is getting very cluttered. I’d like to be able to hierarchically organize the boot-entries to solve this.

If NixOS doesn’t explicitly have config options to set this up, I’m fine configuring it at a lower level.

I believe something like this is possible in GRUB, but GRUB is too unreliable for me.

I’m using Systemd-boot currently, and I’m willing to switch to Limine.

Is it possible to organize specializations & generations hierarchically without GRUB?

For example:

⏷ Generation 100
├ ⏵ Boot-entry Group 1
└ ⏷ Boot-entry Group 2
  ├ Specialization 1
  └ Specialization 2
⏵ Generation 99

EDIT:

For others coming across this thread:

Quick solutions/setup:

  • Submenus to group specialisations of generations: Switch your bootloader to one that supports submenus. This feature is implemented in Nix bootloader modules where possible. Options:
  • Submenus to group arbitrary specialisations together, within one generation: NixOS currently doesn’t have options for this.

Opportunities for contribution:

  • There’s a (currently open) PR for systemd-boot that implements automatic submenus. It may allow Nix-generation submenus in the future, but not necessarily grouped specialisations.
    Credit to @ElvishJerricco for linking this.
  • The best-supported non-GRUB bootloader in Nixpkgs that supports customizable submenus seems to be Limine, though customizing the submenus is not implemented in the Nix options (yet).
    If you want to contribute, look further in this thread.

Unless there’s a better place for discussing NixOS module development, I’m going to leave this discussion open for now.

systemd-boot unfortunately cannot do this currently, but there is a PR for systemd to add something like this: https://github.com/systemd/systemd/pull/28084

I don’t think we’ll be able to get arbitrary nesting hierarchies with that PR, but we could at least get it down to something like:

⏵ Gen 100
⏷ Gen 99
├ Specialisation A
└ Specialisation B
⏵ Gen 98
⏵ Gen 97
3 Likes

Does any of the option you are willing to consider have the ability to reinitialise or chainload itself with an alternative configuration file?

How do you imagine that working?

Each submenu is a config; entering a submenu is loading or chainloading this config (you can also use the same to go up); and there are also normal entries.

Sure, I meant moreso how would that actually be implemented? systemd-boot, for instance, just displays all $ESP/loader/entries/*.conf entries, so there’s no way to chainload another systemd-boot and tell it to show a different set of entries.

Since you mentioned limine, it does support multi-level nesting.
I’m not sure whether NixOS itself handles it that way with the limine module… but some changes can be made there if not.

1 Like

Thanks!

I don’t see any explicit NixOS configuration options for that under boot.loader.limine, but I’ll try switching to Limine to see if it groups generations by default.

Yeah there’s no option for it, I meant if it doesn’t work it’d have to be changed in nixpkgs (or via disabledModules and co.) Curious to know if it works since I’d use it too.

1 Like

I tried booting with Limine, and NixOS does use Limine’s submenu feature by default for generations. However, none of the configuration options can be used to manually bring in custom submenus.

Limine’s configuration is generated in this Python script.

Looking through it, the feature would need to be implemented in its generate_config_entry function, which can be found on line 314.

I’ll try making a PR later.

There are a lot of other Limine config options that currently can’t be adjusted by the Nix module, so I might try implementing a few of those as well.

1 Like

It is possible that you want to look at RFC42 (in the sense that a PR adding all the options one by one explicitly might get more scrutiny than «let’s switch to a more overridable style and then the end user can add all the options»)

2 Likes

Thanks! I’ll take that into account.

1 Like

For custom-defined specialisation ‘categories’, or submenus, I imagine we’d have to add the relevant data to bootspec and add general (not bootloader-specific) options for it (maybe under system or boot?)

please report back if you don’t mind - lately i am reviewing that python script and am interested in any changes you make

I’m not going to try modifying the bootspec (for categories) yet, but I’ve opened a PR with some smaller tweaks. If you’d like, let me know what you think.

That PR is currently in draft. I’ll work on it maybe Friday/Sunday this week.

EDIT: I closed the PR as the changes it suggests can be better solved another way, that also allows the specialisation grouping. More on that in my reply below.

2 Likes

Perhaps something like this would be the best option:

boot.submenus = [ "${profile_name}" "Generation ${generation_num}" ];

Overriding this on specific specialisations would only affect where those specialisations end up on the menu.

For example:

boot.submenus = [ "Boot-entry Group 2" ]

Assuming specialisation.<name>.inheritParentConfig = true, this would append "Boot-entry Group 2" to the list, putting that specialisation in its own submenu.

If another specialisation does the same, and the name of the submenu is identical, they are both grouped into the same one.