2026-08-05 18:57:23 +01:00
|
|
|
{...}: {
|
|
|
|
|
flake.nixosModules.bootloader = {
|
|
|
|
|
pkgs,
|
|
|
|
|
lib,
|
|
|
|
|
...
|
|
|
|
|
}: {
|
|
|
|
|
boot = {
|
|
|
|
|
loader = {
|
|
|
|
|
timeout = 2;
|
|
|
|
|
efi = {
|
|
|
|
|
canTouchEfiVariables = true;
|
|
|
|
|
};
|
2026-08-06 17:08:15 +01:00
|
|
|
# Pinned explicitly. grub.enable defaults to true, so this host silently
|
|
|
|
|
# switched from systemd-boot (used at install time) to GRUB when this
|
|
|
|
|
# block was added. NixOS never removes the previous bootloader's files
|
|
|
|
|
# or its NVRAM entry, so both lived on the ESP and the firmware kept
|
|
|
|
|
# booting the frozen systemd-boot menu. Keep this explicit, and never
|
|
|
|
|
# set systemd-boot.enable alongside it.
|
|
|
|
|
#
|
|
|
|
|
# Note what this does and does not do. Both of these lines are no-ops
|
|
|
|
|
# against nixpkgs' defaults (grub.enable is already true,
|
|
|
|
|
# systemd-boot.enable already false); their value is that a conflicting
|
|
|
|
|
# definition elsewhere now fails loudly instead of silently winning. They
|
|
|
|
|
# delete nothing — stale EFI/systemd/, loader/ and the leftover NVRAM
|
|
|
|
|
# entry have to be removed by hand on any host installed with
|
|
|
|
|
# systemd-boot. Done on shadow; NOT yet verified on t480.
|
|
|
|
|
#
|
|
|
|
|
# This is stock UEFI GRUB: NixOS installs EFI/<distro><esp>/grubx64.efi
|
|
|
|
|
# (here EFI/NixOS-boot/grubx64.efi) and registers a matching NVRAM entry
|
|
|
|
|
# via efibootmgr, because canTouchEfiVariables is true. That NVRAM entry
|
|
|
|
|
# is what makes GRUB the default; NixOS does not manage the removable
|
|
|
|
|
# fallback path EFI/BOOT/BOOTX64.EFI and we deliberately do not ask it to
|
|
|
|
|
# (grub.efiInstallAsRemovable, which would need canTouchEfiVariables=false,
|
|
|
|
|
# is only for firmware that ignores NVRAM entries — neither host needs it).
|
|
|
|
|
#
|
|
|
|
|
# On shadow that fallback path is NOT empty, though: bcdboot left a copy of
|
|
|
|
|
# the *Windows* boot manager at EFI/BOOT/bootx64.efi (byte-identical to
|
|
|
|
|
# EFI/Microsoft/Boot/bootmgfw.efi). Normal boots are unaffected because the
|
|
|
|
|
# firmware follows its NVRAM entry to GRUB. But it does mean that if NVRAM
|
|
|
|
|
# is ever cleared — CMOS reset, battery, firmware update — the fallback
|
|
|
|
|
# lands on Windows rather than GRUB. Left as-is by choice; recover by
|
|
|
|
|
# rerunning `nixos-rebuild boot` to reinstate the NVRAM entry.
|
|
|
|
|
systemd-boot.enable = false;
|
2026-08-05 18:57:23 +01:00
|
|
|
grub = {
|
2026-08-06 17:08:15 +01:00
|
|
|
enable = true;
|
2026-08-05 18:57:23 +01:00
|
|
|
efiSupport = true;
|
|
|
|
|
device = "nodev";
|
|
|
|
|
theme = pkgs.catppuccin-grub;
|
2026-08-06 17:08:15 +01:00
|
|
|
# Bound the menu so the ESP cannot fill up with old kernels.
|
|
|
|
|
# install-grub.pl unlinks any $boot/kernels/* not referenced by a kept
|
|
|
|
|
# generation, so this genuinely caps ESP usage rather than just
|
|
|
|
|
# trimming the menu.
|
|
|
|
|
#
|
|
|
|
|
# Sizing, measured on shadow rather than assumed. Generations share
|
|
|
|
|
# aggressively in practice: 10 kept generations referenced 1 bzImage
|
|
|
|
|
# (13.3MiB) and 3 initrds (~33.4MiB each) for 114MiB total, i.e. ~11MiB
|
|
|
|
|
# per generation, not ~47MiB. Only a kernel or initrd change mints a new
|
|
|
|
|
# file — and the initrd does change more often than you'd expect, since
|
|
|
|
|
# nixpkgs embeds /etc/modprobe.d/nixos.conf inside it, so every kernel
|
|
|
|
|
# module parameter edit produces a fresh one.
|
|
|
|
|
#
|
|
|
|
|
# So the real bound is between ~11MiB and ~47MiB per generation
|
|
|
|
|
# depending on churn: 10 generations costs ~115MiB typically and ~470MiB
|
|
|
|
|
# worst case, against a 1GiB ESP that also carries grub/x86_64-efi, the
|
|
|
|
|
# catppuccin theme, and Windows' own boot files (bootmgfw.efi + BCD,
|
|
|
|
|
# ~30-60MiB) since Windows was bcdboot'd onto this same ESP. 10 keeps
|
|
|
|
|
# the worst case under half the partition.
|
|
|
|
|
#
|
|
|
|
|
# Keep this conservative: overflow fails as `copy ... or die` in
|
|
|
|
|
# install-grub.pl, which runs *after* the system profile has already
|
|
|
|
|
# been switched, so the result is an activated but unbootable
|
|
|
|
|
# generation. t480 reaches this module too and its ESP may be smaller.
|
|
|
|
|
configurationLimit = 10;
|
2026-08-05 18:57:23 +01:00
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
plymouth = {
|
|
|
|
|
enable = true;
|
|
|
|
|
theme = "catppuccin-mocha";
|
|
|
|
|
themePackages = with pkgs; [
|
|
|
|
|
(catppuccin-plymouth.override {
|
|
|
|
|
variant = "mocha";
|
|
|
|
|
})
|
|
|
|
|
];
|
|
|
|
|
};
|
|
|
|
|
kernelPackages = pkgs.linuxPackages_latest;
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
}
|