at master 15 kB view raw
1{ 2 config, 3 lib, 4 pkgs, 5 ... 6}: 7let 8 cfg = config.boot.loader.limine; 9 efi = config.boot.loader.efi; 10 limineInstallConfig = pkgs.writeText "limine-install.json" ( 11 builtins.toJSON { 12 nixPath = config.nix.package; 13 efiBootMgrPath = pkgs.efibootmgr; 14 liminePath = cfg.package; 15 efiMountPoint = efi.efiSysMountPoint; 16 fileSystems = config.fileSystems; 17 luksDevices = builtins.attrNames config.boot.initrd.luks.devices; 18 canTouchEfiVariables = efi.canTouchEfiVariables; 19 efiSupport = cfg.efiSupport; 20 efiRemovable = cfg.efiInstallAsRemovable; 21 secureBoot = cfg.secureBoot; 22 biosSupport = cfg.biosSupport; 23 biosDevice = cfg.biosDevice; 24 partitionIndex = cfg.partitionIndex; 25 forceMbr = cfg.forceMbr; 26 enrollConfig = cfg.enrollConfig; 27 style = cfg.style; 28 maxGenerations = if cfg.maxGenerations == null then 0 else cfg.maxGenerations; 29 hostArchitecture = pkgs.stdenv.hostPlatform.parsed.cpu; 30 timeout = if config.boot.loader.timeout != null then config.boot.loader.timeout else 10; 31 enableEditor = cfg.enableEditor; 32 extraConfig = cfg.extraConfig; 33 extraEntries = cfg.extraEntries; 34 additionalFiles = cfg.additionalFiles; 35 validateChecksums = cfg.validateChecksums; 36 panicOnChecksumMismatch = cfg.panicOnChecksumMismatch; 37 } 38 ); 39 defaultWallpaper = pkgs.nixos-artwork.wallpapers.simple-dark-gray-bootloader.gnomeFilePath; 40in 41{ 42 meta = { 43 inherit (pkgs.limine.meta) maintainers; 44 }; 45 46 options.boot.loader.limine = { 47 enable = lib.mkEnableOption "the Limine Bootloader"; 48 package = lib.mkPackageOption pkgs "limine" { }; 49 50 enableEditor = lib.mkEnableOption null // { 51 description = '' 52 Whether to allow editing the boot entries before booting them. 53 It is recommended to set this to false, as it allows gaining root 54 access by passing `init=/bin/sh` as a kernel parameter. 55 ''; 56 }; 57 58 maxGenerations = lib.mkOption { 59 default = null; 60 example = 50; 61 type = lib.types.nullOr lib.types.int; 62 description = '' 63 Maximum number of latest generations in the boot menu. 64 Useful to prevent boot partition of running out of disk space. 65 `null` means no limit i.e. all generations that were not 66 garbage collected yet. 67 ''; 68 }; 69 70 extraConfig = lib.mkOption { 71 default = ""; 72 type = lib.types.lines; 73 example = lib.literalExpression '' 74 serial: yes 75 ''; 76 description = '' 77 A string which is prepended to limine.conf. The config format can be found [here](https://github.com/limine-bootloader/limine/blob/trunk/CONFIG.md). 78 ''; 79 }; 80 81 extraEntries = lib.mkOption { 82 default = ""; 83 type = lib.types.lines; 84 example = lib.literalExpression '' 85 /memtest86 86 protocol: chainload 87 path: boot():///efi/memtest86/memtest86.efi 88 ''; 89 description = '' 90 A string which is appended to the end of limine.conf. The config format can be found [here](https://github.com/limine-bootloader/limine/blob/trunk/CONFIG.md). 91 ''; 92 }; 93 94 additionalFiles = lib.mkOption { 95 default = { }; 96 type = lib.types.attrsOf lib.types.path; 97 example = lib.literalExpression '' 98 { "efi/memtest86/memtest86.efi" = "''${pkgs.memtest86-efi}/BOOTX64.efi"; } 99 ''; 100 description = '' 101 A set of files to be copied to {file}`/boot`. Each attribute name denotes the 102 destination file name in {file}`/boot`, while the corresponding attribute value 103 specifies the source file. 104 ''; 105 }; 106 107 validateChecksums = lib.mkEnableOption null // { 108 default = true; 109 description = '' 110 Whether to validate file checksums before booting. 111 ''; 112 }; 113 114 panicOnChecksumMismatch = lib.mkEnableOption null // { 115 description = '' 116 Whether or not checksum validation failure should be a fatal 117 error at boot time. 118 ''; 119 }; 120 121 efiSupport = lib.mkEnableOption null // { 122 default = pkgs.stdenv.hostPlatform.isEfi; 123 defaultText = lib.literalExpression "pkgs.stdenv.hostPlatform.isEfi"; 124 description = '' 125 Whether or not to install the limine EFI files. 126 ''; 127 }; 128 129 efiInstallAsRemovable = lib.mkEnableOption null // { 130 default = !efi.canTouchEfiVariables; 131 defaultText = lib.literalExpression "!config.boot.loader.efi.canTouchEfiVariables"; 132 description = '' 133 Whether or not to install the limine EFI files as removable. 134 135 See {option}`boot.loader.grub.efiInstallAsRemovable` 136 ''; 137 }; 138 139 biosSupport = lib.mkEnableOption null // { 140 default = !cfg.efiSupport && pkgs.stdenv.hostPlatform.isx86; 141 defaultText = lib.literalExpression "!config.boot.loader.limine.efiSupport && pkgs.stdenv.hostPlatform.isx86"; 142 description = '' 143 Whether or not to install limine for BIOS. 144 ''; 145 }; 146 147 biosDevice = lib.mkOption { 148 default = "nodev"; 149 type = lib.types.str; 150 description = '' 151 Device to install the BIOS version of limine on. 152 ''; 153 }; 154 155 partitionIndex = lib.mkOption { 156 default = null; 157 type = lib.types.nullOr lib.types.int; 158 description = '' 159 The 1-based index of the dedicated partition for limine's second stage. 160 ''; 161 }; 162 163 enrollConfig = lib.mkEnableOption null // { 164 default = cfg.panicOnChecksumMismatch; 165 defaultText = lib.literalExpression "boot.loader.limine.panicOnChecksumMismatch"; 166 description = '' 167 Whether or not to enroll the config. 168 Only works on EFI! 169 ''; 170 }; 171 172 forceMbr = lib.mkEnableOption null // { 173 description = '' 174 Force MBR detection to work even if the safety checks fail, use absolutely only if necessary! 175 ''; 176 }; 177 178 secureBoot = { 179 enable = lib.mkEnableOption null // { 180 description = '' 181 Whether to use sign the limine binary with sbctl. 182 183 ::: {.note} 184 This requires you to already have generated the keys and enrolled them with {command}`sbctl`. 185 186 To create keys use {command}`sbctl create-keys`. 187 188 To enroll them first reset secure boot to "Setup Mode". This is device specific. 189 Then enroll them using {command}`sbctl enroll-keys -m -f`. 190 191 You can now rebuild your system with this option enabled. 192 193 Afterwards turn setup mode off and enable secure boot. 194 ::: 195 ''; 196 }; 197 198 createAndEnrollKeys = lib.mkEnableOption null // { 199 internal = true; 200 description = '' 201 Creates secure boot signing keys and enrolls them during bootloader installation. 202 203 ::: {.note} 204 This is used for automated nixos tests. 205 NOT INTENDED to be used on a real system. 206 ::: 207 ''; 208 }; 209 210 sbctl = lib.mkPackageOption pkgs "sbctl" { }; 211 }; 212 213 style = { 214 wallpapers = lib.mkOption { 215 default = [ ]; 216 example = lib.literalExpression "[ pkgs.nixos-artwork.wallpapers.simple-dark-gray-bootloader.gnomeFilePath ]"; 217 type = lib.types.listOf lib.types.path; 218 description = '' 219 A list of wallpapers. 220 If more than one is specified, a random one will be selected at boot. 221 ''; 222 }; 223 224 wallpaperStyle = lib.mkOption { 225 default = "streched"; 226 type = lib.types.enum [ 227 "centered" 228 "streched" 229 "tiled" 230 ]; 231 description = '' 232 How the wallpaper should be fit to the screen. 233 ''; 234 }; 235 236 backdrop = lib.mkOption { 237 default = null; 238 example = "7EBAE4"; 239 type = lib.types.nullOr lib.types.str; 240 description = '' 241 Color to fill the rest of the screen with when wallpaper_style is centered in RRGGBB format. 242 ''; 243 }; 244 245 interface = { 246 resolution = lib.mkOption { 247 default = null; 248 type = lib.types.nullOr lib.types.str; 249 description = '' 250 The resolution of the interface. 251 ''; 252 }; 253 254 branding = lib.mkOption { 255 default = null; 256 type = lib.types.nullOr lib.types.str; 257 description = '' 258 The title at the top of the screen. 259 ''; 260 }; 261 262 brandingColor = lib.mkOption { 263 default = null; 264 type = lib.types.nullOr lib.types.int; 265 description = '' 266 Color index of the title at the top of the screen in the range of 0-7 (Limine defaults to 6 (cyan)). 267 ''; 268 }; 269 270 helpHidden = lib.mkEnableOption null // { 271 description = '' 272 Whether or not to hide the keybinds at the top of the screen. 273 ''; 274 }; 275 }; 276 graphicalTerminal = { 277 font = { 278 scale = lib.mkOption { 279 default = null; 280 example = lib.literalExpression "2x2"; 281 type = lib.types.nullOr lib.types.str; 282 description = '' 283 The scale of the font in the format <width>x<height>. 284 ''; 285 }; 286 287 spacing = lib.mkOption { 288 default = null; 289 type = lib.types.nullOr lib.types.int; 290 description = '' 291 The horizontal spacing between characters in pixels. 292 ''; 293 }; 294 }; 295 296 palette = lib.mkOption { 297 default = null; 298 type = lib.types.nullOr lib.types.str; 299 description = '' 300 A ; seperated array of 8 colors in the format RRGGBB: 301 black, red, green, brown, blue, magenta, cyan, and gray. 302 ''; 303 }; 304 305 brightPalette = lib.mkOption { 306 default = null; 307 type = lib.types.nullOr lib.types.str; 308 description = '' 309 A ; seperated array of 8 colors in the format RRGGBB: 310 dark gray, bright red, bright green, yellow, bright blue, bright magenta, bright cyan, and white. 311 ''; 312 }; 313 314 foreground = lib.mkOption { 315 default = null; 316 type = lib.types.nullOr lib.types.str; 317 description = '' 318 Text foreground color (RRGGBB). 319 ''; 320 }; 321 322 background = lib.mkOption { 323 default = null; 324 type = lib.types.nullOr lib.types.str; 325 description = '' 326 Text background color (TTRRGGBB). TT is transparency. 327 ''; 328 }; 329 330 brightForeground = lib.mkOption { 331 default = null; 332 type = lib.types.nullOr lib.types.str; 333 description = '' 334 Text foreground bright color (RRGGBB). 335 ''; 336 }; 337 338 brightBackground = lib.mkOption { 339 default = null; 340 type = lib.types.nullOr lib.types.str; 341 description = '' 342 Text background bright color (RRGGBB). 343 ''; 344 }; 345 346 margin = lib.mkOption { 347 default = null; 348 type = lib.types.nullOr lib.types.int; 349 description = '' 350 The amount of margin around the terminal. 351 ''; 352 }; 353 354 marginGradient = lib.mkOption { 355 default = null; 356 type = lib.types.nullOr lib.types.int; 357 description = '' 358 The thickness in pixels for the margin around the terminal. 359 ''; 360 }; 361 }; 362 }; 363 }; 364 365 config = lib.mkMerge [ 366 { 367 boot.loader.limine.style.wallpapers = lib.mkDefault [ defaultWallpaper ]; 368 } 369 (lib.mkIf (cfg.style.wallpapers == [ defaultWallpaper ]) { 370 boot.loader.limine.style.backdrop = lib.mkDefault "2F302F"; 371 boot.loader.limine.style.wallpaperStyle = lib.mkDefault "streched"; 372 }) 373 (lib.mkIf cfg.enable { 374 assertions = [ 375 { 376 assertion = 377 pkgs.stdenv.hostPlatform.isx86_64 378 || pkgs.stdenv.hostPlatform.isi686 379 || pkgs.stdenv.hostPlatform.isAarch64; 380 message = "Limine can only be installed on aarch64 & x86 platforms"; 381 } 382 { 383 assertion = cfg.efiSupport || cfg.biosSupport; 384 message = "Both UEFI support and BIOS support for Limine are disabled, this will result in an unbootable system"; 385 } 386 ]; 387 388 boot.loader.grub.enable = lib.mkDefault false; 389 390 boot.loader.supportsInitrdSecrets = true; 391 392 system = { 393 boot.loader.id = "limine"; 394 build.installBootLoader = pkgs.replaceVarsWith { 395 src = ./limine-install.py; 396 isExecutable = true; 397 replacements = { 398 python3 = pkgs.python3.withPackages (python-packages: [ python-packages.psutil ]); 399 configPath = limineInstallConfig; 400 }; 401 }; 402 }; 403 }) 404 (lib.mkIf (cfg.enable && cfg.secureBoot.enable) { 405 assertions = [ 406 { 407 assertion = cfg.enrollConfig; 408 message = "Disabling enrollConfig allows bypassing secure boot."; 409 } 410 { 411 assertion = cfg.validateChecksums; 412 message = "Disabling validateChecksums allows bypassing secure boot."; 413 } 414 { 415 assertion = cfg.panicOnChecksumMismatch; 416 message = "Disabling panicOnChecksumMismatch allows bypassing secure boot."; 417 } 418 { 419 assertion = cfg.efiSupport; 420 message = "Secure boot is only supported on EFI systems."; 421 } 422 ]; 423 424 boot.loader.limine.enrollConfig = true; 425 boot.loader.limine.validateChecksums = true; 426 boot.loader.limine.panicOnChecksumMismatch = true; 427 }) 428 429 # Fwupd binary needs to be signed in secure boot mode 430 (lib.mkIf (cfg.enable && cfg.secureBoot.enable && config.services.fwupd.enable) { 431 systemd.services.fwupd = { 432 environment.FWUPD_EFIAPPDIR = "/run/fwupd-efi"; 433 }; 434 435 systemd.services.fwupd-efi = { 436 description = "Sign fwupd EFI app for secure boot"; 437 wantedBy = [ "fwupd.service" ]; 438 partOf = [ "fwupd.service" ]; 439 before = [ "fwupd.service" ]; 440 441 unitConfig.ConditionPathIsDirectory = "/var/lib/sbctl"; 442 serviceConfig = { 443 Type = "oneshot"; 444 RemainAfterExit = true; 445 RuntimeDirectory = "fwupd-efi"; 446 }; 447 448 script = '' 449 cp ${config.services.fwupd.package.fwupd-efi}/libexec/fwupd/efi/fwupd*.efi /run/fwupd-efi/ 450 chmod +w /run/fwupd-efi/fwupd*.efi 451 ${lib.getExe cfg.secureBoot.sbctl} sign /run/fwupd-efi/fwupd*.efi 452 ''; 453 }; 454 455 services.fwupd.uefiCapsuleSettings = { 456 DisableShimForSecureBoot = true; 457 }; 458 }) 459 ]; 460}