mirror of
https://github.com/NixOS/nixpkgs.git
synced 2025-06-13 05:05:29 +03:00
nixos/systemd-boot: Simpler windows dual booting (#344327)
This commit is contained in:
commit
12ef18d2e3
3 changed files with 593 additions and 272 deletions
|
@ -631,6 +631,8 @@
|
||||||
The derivation now installs "impl" headers selectively instead of by a wildcard.
|
The derivation now installs "impl" headers selectively instead of by a wildcard.
|
||||||
Use `imgui.src` if you just want to access the unpacked sources.
|
Use `imgui.src` if you just want to access the unpacked sources.
|
||||||
|
|
||||||
|
- The new `boot.loader.systemd-boot.windows` option makes setting up dual-booting with Windows on a different drive easier
|
||||||
|
|
||||||
- Linux 4.19 has been removed because it will reach its end of life within the lifespan of 24.11
|
- Linux 4.19 has been removed because it will reach its end of life within the lifespan of 24.11
|
||||||
|
|
||||||
- Unprivileged access to the kernel syslog via `dmesg` is now restricted by default. Users wanting to keep an
|
- Unprivileged access to the kernel syslog via `dmesg` is now restricted by default. Users wanting to keep an
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
with lib;
|
with lib;
|
||||||
|
|
||||||
|
@ -10,16 +15,21 @@ let
|
||||||
# We check the source code in a derivation that does not depend on the
|
# We check the source code in a derivation that does not depend on the
|
||||||
# system configuration so that most users don't have to redo the check and require
|
# system configuration so that most users don't have to redo the check and require
|
||||||
# the necessary dependencies.
|
# the necessary dependencies.
|
||||||
checkedSource = pkgs.runCommand "systemd-boot" {
|
checkedSource =
|
||||||
preferLocalBuild = true;
|
pkgs.runCommand "systemd-boot"
|
||||||
} ''
|
{
|
||||||
install -m755 -D ${./systemd-boot-builder.py} $out
|
preferLocalBuild = true;
|
||||||
${lib.getExe pkgs.buildPackages.mypy} \
|
}
|
||||||
--no-implicit-optional \
|
''
|
||||||
--disallow-untyped-calls \
|
install -m755 -D ${./systemd-boot-builder.py} $out
|
||||||
--disallow-untyped-defs \
|
${lib.getExe pkgs.buildPackages.mypy} \
|
||||||
$out
|
--no-implicit-optional \
|
||||||
'';
|
--disallow-untyped-calls \
|
||||||
|
--disallow-untyped-defs \
|
||||||
|
$out
|
||||||
|
'';
|
||||||
|
|
||||||
|
edk2ShellEspPath = "efi/edk2-uefi-shell/shell.efi";
|
||||||
|
|
||||||
systemdBootBuilder = pkgs.substituteAll rec {
|
systemdBootBuilder = pkgs.substituteAll rec {
|
||||||
name = "systemd-boot";
|
name = "systemd-boot";
|
||||||
|
@ -44,13 +54,17 @@ let
|
||||||
|
|
||||||
configurationLimit = if cfg.configurationLimit == null then 0 else cfg.configurationLimit;
|
configurationLimit = if cfg.configurationLimit == null then 0 else cfg.configurationLimit;
|
||||||
|
|
||||||
inherit (cfg) consoleMode graceful editor rebootForBitlocker;
|
inherit (cfg)
|
||||||
|
consoleMode
|
||||||
|
graceful
|
||||||
|
editor
|
||||||
|
rebootForBitlocker
|
||||||
|
;
|
||||||
|
|
||||||
inherit (efi) efiSysMountPoint canTouchEfiVariables;
|
inherit (efi) efiSysMountPoint canTouchEfiVariables;
|
||||||
|
|
||||||
bootMountPoint = if cfg.xbootldrMountPoint != null
|
bootMountPoint =
|
||||||
then cfg.xbootldrMountPoint
|
if cfg.xbootldrMountPoint != null then cfg.xbootldrMountPoint else efi.efiSysMountPoint;
|
||||||
else efi.efiSysMountPoint;
|
|
||||||
|
|
||||||
nixosDir = "/EFI/nixos";
|
nixosDir = "/EFI/nixos";
|
||||||
|
|
||||||
|
@ -60,29 +74,35 @@ let
|
||||||
|
|
||||||
netbootxyz = optionalString cfg.netbootxyz.enable pkgs.netbootxyz-efi;
|
netbootxyz = optionalString cfg.netbootxyz.enable pkgs.netbootxyz-efi;
|
||||||
|
|
||||||
|
edk2-uefi-shell = optionalString cfg.edk2-uefi-shell.enable pkgs.edk2-uefi-shell;
|
||||||
|
|
||||||
checkMountpoints = pkgs.writeShellScript "check-mountpoints" ''
|
checkMountpoints = pkgs.writeShellScript "check-mountpoints" ''
|
||||||
fail() {
|
fail() {
|
||||||
echo "$1 = '$2' is not a mounted partition. Is the path configured correctly?" >&2
|
echo "$1 = '$2' is not a mounted partition. Is the path configured correctly?" >&2
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
${pkgs.util-linuxMinimal}/bin/findmnt ${efiSysMountPoint} > /dev/null || fail efiSysMountPoint ${efiSysMountPoint}
|
${pkgs.util-linuxMinimal}/bin/findmnt ${efiSysMountPoint} > /dev/null || fail efiSysMountPoint ${efiSysMountPoint}
|
||||||
${lib.optionalString
|
${lib.optionalString (cfg.xbootldrMountPoint != null)
|
||||||
(cfg.xbootldrMountPoint != null)
|
"${pkgs.util-linuxMinimal}/bin/findmnt ${cfg.xbootldrMountPoint} > /dev/null || fail xbootldrMountPoint ${cfg.xbootldrMountPoint}"
|
||||||
"${pkgs.util-linuxMinimal}/bin/findmnt ${cfg.xbootldrMountPoint} > /dev/null || fail xbootldrMountPoint ${cfg.xbootldrMountPoint}"}
|
}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
copyExtraFiles = pkgs.writeShellScript "copy-extra-files" ''
|
copyExtraFiles = pkgs.writeShellScript "copy-extra-files" ''
|
||||||
empty_file=$(${pkgs.coreutils}/bin/mktemp)
|
empty_file=$(${pkgs.coreutils}/bin/mktemp)
|
||||||
|
|
||||||
${concatStrings (mapAttrsToList (n: v: ''
|
${concatStrings (
|
||||||
${pkgs.coreutils}/bin/install -Dp "${v}" "${bootMountPoint}/"${escapeShellArg n}
|
mapAttrsToList (n: v: ''
|
||||||
${pkgs.coreutils}/bin/install -D $empty_file "${bootMountPoint}/${nixosDir}/.extra-files/"${escapeShellArg n}
|
${pkgs.coreutils}/bin/install -Dp "${v}" "${bootMountPoint}/"${escapeShellArg n}
|
||||||
'') cfg.extraFiles)}
|
${pkgs.coreutils}/bin/install -D $empty_file "${bootMountPoint}/${nixosDir}/.extra-files/"${escapeShellArg n}
|
||||||
|
'') cfg.extraFiles
|
||||||
|
)}
|
||||||
|
|
||||||
${concatStrings (mapAttrsToList (n: v: ''
|
${concatStrings (
|
||||||
${pkgs.coreutils}/bin/install -Dp "${pkgs.writeText n v}" "${bootMountPoint}/loader/entries/"${escapeShellArg n}
|
mapAttrsToList (n: v: ''
|
||||||
${pkgs.coreutils}/bin/install -D $empty_file "${bootMountPoint}/${nixosDir}/.extra-files/loader/entries/"${escapeShellArg n}
|
${pkgs.coreutils}/bin/install -Dp "${pkgs.writeText n v}" "${bootMountPoint}/loader/entries/"${escapeShellArg n}
|
||||||
'') cfg.extraEntries)}
|
${pkgs.coreutils}/bin/install -D $empty_file "${bootMountPoint}/${nixosDir}/.extra-files/loader/entries/"${escapeShellArg n}
|
||||||
|
'') cfg.extraEntries
|
||||||
|
)}
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -91,23 +111,61 @@ let
|
||||||
${systemdBootBuilder}/bin/systemd-boot "$@"
|
${systemdBootBuilder}/bin/systemd-boot "$@"
|
||||||
${cfg.extraInstallCommands}
|
${cfg.extraInstallCommands}
|
||||||
'';
|
'';
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
|
|
||||||
meta.maintainers = with lib.maintainers; [ julienmalka ];
|
meta.maintainers = with lib.maintainers; [ julienmalka ];
|
||||||
|
|
||||||
imports =
|
imports = [
|
||||||
[ (mkRenamedOptionModule [ "boot" "loader" "gummiboot" "enable" ] [ "boot" "loader" "systemd-boot" "enable" ])
|
(mkRenamedOptionModule
|
||||||
(lib.mkChangedOptionModule
|
[
|
||||||
[ "boot" "loader" "systemd-boot" "memtest86" "entryFilename" ]
|
"boot"
|
||||||
[ "boot" "loader" "systemd-boot" "memtest86" "sortKey" ]
|
"loader"
|
||||||
(config: lib.strings.removeSuffix ".conf" config.boot.loader.systemd-boot.memtest86.entryFilename)
|
"gummiboot"
|
||||||
)
|
"enable"
|
||||||
(lib.mkChangedOptionModule
|
]
|
||||||
[ "boot" "loader" "systemd-boot" "netbootxyz" "entryFilename" ]
|
[
|
||||||
[ "boot" "loader" "systemd-boot" "netbootxyz" "sortKey" ]
|
"boot"
|
||||||
(config: lib.strings.removeSuffix ".conf" config.boot.loader.systemd-boot.netbootxyz.entryFilename)
|
"loader"
|
||||||
)
|
"systemd-boot"
|
||||||
];
|
"enable"
|
||||||
|
]
|
||||||
|
)
|
||||||
|
(lib.mkChangedOptionModule
|
||||||
|
[
|
||||||
|
"boot"
|
||||||
|
"loader"
|
||||||
|
"systemd-boot"
|
||||||
|
"memtest86"
|
||||||
|
"entryFilename"
|
||||||
|
]
|
||||||
|
[
|
||||||
|
"boot"
|
||||||
|
"loader"
|
||||||
|
"systemd-boot"
|
||||||
|
"memtest86"
|
||||||
|
"sortKey"
|
||||||
|
]
|
||||||
|
(config: lib.strings.removeSuffix ".conf" config.boot.loader.systemd-boot.memtest86.entryFilename)
|
||||||
|
)
|
||||||
|
(lib.mkChangedOptionModule
|
||||||
|
[
|
||||||
|
"boot"
|
||||||
|
"loader"
|
||||||
|
"systemd-boot"
|
||||||
|
"netbootxyz"
|
||||||
|
"entryFilename"
|
||||||
|
]
|
||||||
|
[
|
||||||
|
"boot"
|
||||||
|
"loader"
|
||||||
|
"systemd-boot"
|
||||||
|
"netbootxyz"
|
||||||
|
"sortKey"
|
||||||
|
]
|
||||||
|
(config: lib.strings.removeSuffix ".conf" config.boot.loader.systemd-boot.netbootxyz.entryFilename)
|
||||||
|
)
|
||||||
|
];
|
||||||
|
|
||||||
options.boot.loader.systemd-boot = {
|
options.boot.loader.systemd-boot = {
|
||||||
enable = mkOption {
|
enable = mkOption {
|
||||||
|
@ -124,7 +182,7 @@ in {
|
||||||
|
|
||||||
sortKey = mkOption {
|
sortKey = mkOption {
|
||||||
default = "nixos";
|
default = "nixos";
|
||||||
type = lib.types.str;
|
type = types.str;
|
||||||
description = ''
|
description = ''
|
||||||
The sort key used for the NixOS bootloader entries.
|
The sort key used for the NixOS bootloader entries.
|
||||||
This key determines sorting relative to non-NixOS entries.
|
This key determines sorting relative to non-NixOS entries.
|
||||||
|
@ -218,7 +276,15 @@ in {
|
||||||
consoleMode = mkOption {
|
consoleMode = mkOption {
|
||||||
default = "keep";
|
default = "keep";
|
||||||
|
|
||||||
type = types.enum [ "0" "1" "2" "5" "auto" "max" "keep" ];
|
type = types.enum [
|
||||||
|
"0"
|
||||||
|
"1"
|
||||||
|
"2"
|
||||||
|
"5"
|
||||||
|
"auto"
|
||||||
|
"max"
|
||||||
|
"keep"
|
||||||
|
];
|
||||||
|
|
||||||
description = ''
|
description = ''
|
||||||
The resolution of the console. The following values are valid:
|
The resolution of the console. The following values are valid:
|
||||||
|
@ -281,9 +347,32 @@ in {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
edk2-uefi-shell = {
|
||||||
|
enable = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
description = ''
|
||||||
|
Make the EDK2 UEFI Shell available from the systemd-boot menu.
|
||||||
|
It can be used to manually boot other operating systems or for debugging.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
sortKey = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "o_edk2-uefi-shell";
|
||||||
|
description = ''
|
||||||
|
`systemd-boot` orders the menu entries by their sort keys,
|
||||||
|
so if you want something to appear after all the NixOS entries,
|
||||||
|
it should start with {file}`o` or onwards.
|
||||||
|
|
||||||
|
See also {option}`boot.loader.systemd-boot.sortKey`..
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
extraEntries = mkOption {
|
extraEntries = mkOption {
|
||||||
type = types.attrsOf types.lines;
|
type = types.attrsOf types.lines;
|
||||||
default = {};
|
default = { };
|
||||||
example = literalExpression ''
|
example = literalExpression ''
|
||||||
{ "memtest86.conf" = '''
|
{ "memtest86.conf" = '''
|
||||||
title Memtest86+
|
title Memtest86+
|
||||||
|
@ -306,7 +395,7 @@ in {
|
||||||
|
|
||||||
extraFiles = mkOption {
|
extraFiles = mkOption {
|
||||||
type = types.attrsOf types.path;
|
type = types.attrsOf types.path;
|
||||||
default = {};
|
default = { };
|
||||||
example = literalExpression ''
|
example = literalExpression ''
|
||||||
{ "efi/memtest86/memtest.efi" = "''${pkgs.memtest86plus}/memtest.efi"; }
|
{ "efi/memtest86/memtest.efi" = "''${pkgs.memtest86plus}/memtest.efi"; }
|
||||||
'';
|
'';
|
||||||
|
@ -349,40 +438,126 @@ in {
|
||||||
Windows can unseal the encryption key.
|
Windows can unseal the encryption key.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
windows = mkOption {
|
||||||
|
default = { };
|
||||||
|
description = ''
|
||||||
|
Make Windows bootable from systemd-boot. This option is not necessary when Windows and
|
||||||
|
NixOS use the same EFI System Partition (ESP). In that case, Windows will automatically be
|
||||||
|
detected by systemd-boot.
|
||||||
|
|
||||||
|
However, if Windows is installed on a separate drive or ESP, you can use this option to add
|
||||||
|
a menu entry for each installation manually.
|
||||||
|
|
||||||
|
The attribute name is used for the title of the menu entry and internal file names.
|
||||||
|
'';
|
||||||
|
example = literalExpression ''
|
||||||
|
{
|
||||||
|
"10".efiDeviceHandle = "HD0c3";
|
||||||
|
"11-ame" = {
|
||||||
|
title = "Windows 11 Ameliorated Edition";
|
||||||
|
efiDeviceHandle = "HD0b1";
|
||||||
|
};
|
||||||
|
"11-home" = {
|
||||||
|
title = "Windows 11 Home";
|
||||||
|
efiDeviceHandle = "FS1";
|
||||||
|
sortKey = "z_windows";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
type = types.attrsOf (
|
||||||
|
types.submodule (
|
||||||
|
{ name, ... }:
|
||||||
|
{
|
||||||
|
options = {
|
||||||
|
efiDeviceHandle = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
example = "HD1b3";
|
||||||
|
description = ''
|
||||||
|
The device handle of the EFI System Partition (ESP) where the Windows bootloader is
|
||||||
|
located. This is the device handle that the EDK2 UEFI Shell uses to load the
|
||||||
|
bootloader.
|
||||||
|
|
||||||
|
To find this handle, follow these steps:
|
||||||
|
1. Set {option}`boot.loader.systemd-boot.edk2-uefi-shell.enable` to `true`
|
||||||
|
2. Run `nixos-rebuild boot`
|
||||||
|
3. Reboot and select "EDK2 UEFI Shell" from the systemd-boot menu
|
||||||
|
4. Run `map -c` to list all consistent device handles
|
||||||
|
5. For each device handle (for example, `HD0c1`), run `ls HD0c1:\EFI`
|
||||||
|
6. If the output contains the directory `Microsoft`, you might have found the correct device handle
|
||||||
|
7. Run `HD0c1:\EFI\Microsoft\Boot\Bootmgfw.efi` to check if Windows boots correctly
|
||||||
|
8. If it does, this device handle is the one you need (in this example, `HD0c1`)
|
||||||
|
|
||||||
|
This option is required, there is no useful default.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
title = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
example = "Michaelsoft Binbows";
|
||||||
|
default = "Windows ${name}";
|
||||||
|
defaultText = ''attribute name of this entry, prefixed with "Windows "'';
|
||||||
|
description = ''
|
||||||
|
The title of the boot menu entry.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
sortKey = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "o_windows_${name}";
|
||||||
|
defaultText = ''attribute name of this entry, prefixed with "o_windows_"'';
|
||||||
|
description = ''
|
||||||
|
`systemd-boot` orders the menu entries by their sort keys,
|
||||||
|
so if you want something to appear after all the NixOS entries,
|
||||||
|
it should start with {file}`o` or onwards.
|
||||||
|
|
||||||
|
See also {option}`boot.loader.systemd-boot.sortKey`..
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
assertions = [
|
assertions =
|
||||||
{
|
[
|
||||||
assertion = (hasPrefix "/" efi.efiSysMountPoint);
|
{
|
||||||
message = "The ESP mount point '${toString efi.efiSysMountPoint}' must be an absolute path";
|
assertion = (hasPrefix "/" efi.efiSysMountPoint);
|
||||||
}
|
message = "The ESP mount point '${toString efi.efiSysMountPoint}' must be an absolute path";
|
||||||
{
|
}
|
||||||
assertion = cfg.xbootldrMountPoint == null || (hasPrefix "/" cfg.xbootldrMountPoint);
|
{
|
||||||
message = "The XBOOTLDR mount point '${toString cfg.xbootldrMountPoint}' must be an absolute path";
|
assertion = cfg.xbootldrMountPoint == null || (hasPrefix "/" cfg.xbootldrMountPoint);
|
||||||
}
|
message = "The XBOOTLDR mount point '${toString cfg.xbootldrMountPoint}' must be an absolute path";
|
||||||
{
|
}
|
||||||
assertion = cfg.xbootldrMountPoint != efi.efiSysMountPoint;
|
{
|
||||||
message = "The XBOOTLDR mount point '${toString cfg.xbootldrMountPoint}' cannot be the same as the ESP mount point '${toString efi.efiSysMountPoint}'";
|
assertion = cfg.xbootldrMountPoint != efi.efiSysMountPoint;
|
||||||
}
|
message = "The XBOOTLDR mount point '${toString cfg.xbootldrMountPoint}' cannot be the same as the ESP mount point '${toString efi.efiSysMountPoint}'";
|
||||||
{
|
}
|
||||||
assertion = (config.boot.kernelPackages.kernel.features or { efiBootStub = true; }) ? efiBootStub;
|
{
|
||||||
message = "This kernel does not support the EFI boot stub";
|
assertion = (config.boot.kernelPackages.kernel.features or { efiBootStub = true; }) ? efiBootStub;
|
||||||
}
|
message = "This kernel does not support the EFI boot stub";
|
||||||
{
|
}
|
||||||
assertion = cfg.installDeviceTree -> config.hardware.deviceTree.enable -> config.hardware.deviceTree.name != null;
|
{
|
||||||
message = "Cannot install devicetree without 'config.hardware.deviceTree.enable' enabled and 'config.hardware.deviceTree.name' set";
|
assertion =
|
||||||
}
|
cfg.installDeviceTree
|
||||||
] ++ concatMap (filename: [
|
-> config.hardware.deviceTree.enable
|
||||||
{
|
-> config.hardware.deviceTree.name != null;
|
||||||
assertion = !(hasInfix "/" filename);
|
message = "Cannot install devicetree without 'config.hardware.deviceTree.enable' enabled and 'config.hardware.deviceTree.name' set";
|
||||||
message = "boot.loader.systemd-boot.extraEntries.${lib.strings.escapeNixIdentifier filename} is invalid: entries within folders are not supported";
|
}
|
||||||
}
|
]
|
||||||
{
|
++ concatMap (filename: [
|
||||||
assertion = hasSuffix ".conf" filename;
|
{
|
||||||
message = "boot.loader.systemd-boot.extraEntries.${lib.strings.escapeNixIdentifier filename} is invalid: entries must have a .conf file extension";
|
assertion = !(hasInfix "/" filename);
|
||||||
}
|
message = "boot.loader.systemd-boot.extraEntries.${lib.strings.escapeNixIdentifier filename} is invalid: entries within folders are not supported";
|
||||||
]) (builtins.attrNames cfg.extraEntries)
|
}
|
||||||
|
{
|
||||||
|
assertion = hasSuffix ".conf" filename;
|
||||||
|
message = "boot.loader.systemd-boot.extraEntries.${lib.strings.escapeNixIdentifier filename} is invalid: entries must have a .conf file extension";
|
||||||
|
}
|
||||||
|
]) (builtins.attrNames cfg.extraEntries)
|
||||||
++ concatMap (filename: [
|
++ concatMap (filename: [
|
||||||
{
|
{
|
||||||
assertion = !(hasPrefix "/" filename);
|
assertion = !(hasPrefix "/" filename);
|
||||||
|
@ -396,7 +571,13 @@ in {
|
||||||
assertion = !(hasInfix "nixos/.extra-files" (toLower filename));
|
assertion = !(hasInfix "nixos/.extra-files" (toLower filename));
|
||||||
message = "boot.loader.systemd-boot.extraFiles.${lib.strings.escapeNixIdentifier filename} is invalid: files cannot be placed in the nixos/.extra-files directory";
|
message = "boot.loader.systemd-boot.extraFiles.${lib.strings.escapeNixIdentifier filename} is invalid: files cannot be placed in the nixos/.extra-files directory";
|
||||||
}
|
}
|
||||||
]) (builtins.attrNames cfg.extraFiles);
|
]) (builtins.attrNames cfg.extraFiles)
|
||||||
|
++ concatMap (winVersion: [
|
||||||
|
{
|
||||||
|
assertion = lib.match "^[-_0-9A-Za-z]+$" winVersion != null;
|
||||||
|
message = "boot.loader.systemd-boot.windows.${winVersion} is invalid: key must only contain alphanumeric characters, hyphens, and underscores";
|
||||||
|
}
|
||||||
|
]) (builtins.attrNames cfg.windows);
|
||||||
|
|
||||||
boot.loader.grub.enable = mkDefault false;
|
boot.loader.grub.enable = mkDefault false;
|
||||||
|
|
||||||
|
@ -409,24 +590,44 @@ in {
|
||||||
(mkIf cfg.netbootxyz.enable {
|
(mkIf cfg.netbootxyz.enable {
|
||||||
"efi/netbootxyz/netboot.xyz.efi" = "${pkgs.netbootxyz-efi}";
|
"efi/netbootxyz/netboot.xyz.efi" = "${pkgs.netbootxyz-efi}";
|
||||||
})
|
})
|
||||||
|
(mkIf (cfg.edk2-uefi-shell.enable || cfg.windows != { }) {
|
||||||
|
${edk2ShellEspPath} = "${pkgs.edk2-uefi-shell}/shell.efi";
|
||||||
|
})
|
||||||
];
|
];
|
||||||
|
|
||||||
boot.loader.systemd-boot.extraEntries = mkMerge [
|
boot.loader.systemd-boot.extraEntries = mkMerge (
|
||||||
(mkIf cfg.memtest86.enable {
|
[
|
||||||
"memtest86.conf" = ''
|
(mkIf cfg.memtest86.enable {
|
||||||
title Memtest86+
|
"memtest86.conf" = ''
|
||||||
efi /efi/memtest86/memtest.efi
|
title Memtest86+
|
||||||
sort-key ${cfg.memtest86.sortKey}
|
efi /efi/memtest86/memtest.efi
|
||||||
|
sort-key ${cfg.memtest86.sortKey}
|
||||||
|
'';
|
||||||
|
})
|
||||||
|
(mkIf cfg.netbootxyz.enable {
|
||||||
|
"netbootxyz.conf" = ''
|
||||||
|
title netboot.xyz
|
||||||
|
efi /efi/netbootxyz/netboot.xyz.efi
|
||||||
|
sort-key ${cfg.netbootxyz.sortKey}
|
||||||
|
'';
|
||||||
|
})
|
||||||
|
(mkIf cfg.edk2-uefi-shell.enable {
|
||||||
|
"edk2-uefi-shell.conf" = ''
|
||||||
|
title EDK2 UEFI Shell
|
||||||
|
efi /${edk2ShellEspPath}
|
||||||
|
sort-key ${cfg.edk2-uefi-shell.sortKey}
|
||||||
|
'';
|
||||||
|
})
|
||||||
|
]
|
||||||
|
++ (mapAttrsToList (winVersion: cfg: {
|
||||||
|
"windows_${winVersion}.conf" = ''
|
||||||
|
title ${cfg.title}
|
||||||
|
efi /${edk2ShellEspPath}
|
||||||
|
options -nointerrupt -nomap -noversion ${cfg.efiDeviceHandle}:EFI\Microsoft\Boot\Bootmgfw.efi
|
||||||
|
sort-key ${cfg.sortKey}
|
||||||
'';
|
'';
|
||||||
})
|
}) cfg.windows)
|
||||||
(mkIf cfg.netbootxyz.enable {
|
);
|
||||||
"netbootxyz.conf" = ''
|
|
||||||
title netboot.xyz
|
|
||||||
efi /efi/netbootxyz/netboot.xyz.efi
|
|
||||||
sort-key ${cfg.netbootxyz.sortKey}
|
|
||||||
'';
|
|
||||||
})
|
|
||||||
];
|
|
||||||
|
|
||||||
boot.bootspec.extensions."org.nixos.systemd-boot" = {
|
boot.bootspec.extensions."org.nixos.systemd-boot" = {
|
||||||
inherit (config.boot.loader.systemd-boot) sortKey;
|
inherit (config.boot.loader.systemd-boot) sortKey;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
{ system ? builtins.currentSystem,
|
{
|
||||||
config ? {},
|
system ? builtins.currentSystem,
|
||||||
pkgs ? import ../.. { inherit system config; }
|
config ? { },
|
||||||
|
pkgs ? import ../.. { inherit system config; },
|
||||||
}:
|
}:
|
||||||
|
|
||||||
with import ../lib/testing-python.nix { inherit system pkgs; };
|
with import ../lib/testing-python.nix { inherit system pkgs; };
|
||||||
|
@ -16,7 +17,13 @@ let
|
||||||
system.switch.enable = true;
|
system.switch.enable = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
commonXbootldr = { config, lib, pkgs, ... }:
|
commonXbootldr =
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
let
|
let
|
||||||
diskImage = import ../lib/make-disk-image.nix {
|
diskImage = import ../lib/make-disk-image.nix {
|
||||||
inherit config lib pkgs;
|
inherit config lib pkgs;
|
||||||
|
@ -85,7 +92,10 @@ in
|
||||||
{
|
{
|
||||||
basic = makeTest {
|
basic = makeTest {
|
||||||
name = "systemd-boot";
|
name = "systemd-boot";
|
||||||
meta.maintainers = with pkgs.lib.maintainers; [ danielfullmer julienmalka ];
|
meta.maintainers = with pkgs.lib.maintainers; [
|
||||||
|
danielfullmer
|
||||||
|
julienmalka
|
||||||
|
];
|
||||||
|
|
||||||
nodes.machine = common;
|
nodes.machine = common;
|
||||||
|
|
||||||
|
@ -117,22 +127,25 @@ in
|
||||||
virtualisation.useSecureBoot = true;
|
virtualisation.useSecureBoot = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
testScript = let
|
testScript =
|
||||||
efiArch = pkgs.stdenv.hostPlatform.efiArch;
|
let
|
||||||
in { nodes, ... }: ''
|
efiArch = pkgs.stdenv.hostPlatform.efiArch;
|
||||||
machine.start(allow_reboot=True)
|
in
|
||||||
machine.wait_for_unit("multi-user.target")
|
{ nodes, ... }:
|
||||||
|
''
|
||||||
|
machine.start(allow_reboot=True)
|
||||||
|
machine.wait_for_unit("multi-user.target")
|
||||||
|
|
||||||
machine.succeed("sbctl create-keys")
|
machine.succeed("sbctl create-keys")
|
||||||
machine.succeed("sbctl enroll-keys --yes-this-might-brick-my-machine")
|
machine.succeed("sbctl enroll-keys --yes-this-might-brick-my-machine")
|
||||||
machine.succeed('sbctl sign /boot/EFI/systemd/systemd-boot${efiArch}.efi')
|
machine.succeed('sbctl sign /boot/EFI/systemd/systemd-boot${efiArch}.efi')
|
||||||
machine.succeed('sbctl sign /boot/EFI/BOOT/BOOT${toUpper efiArch}.EFI')
|
machine.succeed('sbctl sign /boot/EFI/BOOT/BOOT${toUpper efiArch}.EFI')
|
||||||
machine.succeed('sbctl sign /boot/EFI/nixos/*${nodes.machine.system.boot.loader.kernelFile}.efi')
|
machine.succeed('sbctl sign /boot/EFI/nixos/*${nodes.machine.system.boot.loader.kernelFile}.efi')
|
||||||
|
|
||||||
machine.reboot()
|
machine.reboot()
|
||||||
|
|
||||||
assert "Secure Boot: enabled (user)" in machine.succeed("bootctl status")
|
assert "Secure Boot: enabled (user)" in machine.succeed("bootctl status")
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
basicXbootldr = makeTest {
|
basicXbootldr = makeTest {
|
||||||
|
@ -141,80 +154,97 @@ in
|
||||||
|
|
||||||
nodes.machine = commonXbootldr;
|
nodes.machine = commonXbootldr;
|
||||||
|
|
||||||
testScript = { nodes, ... }: ''
|
testScript =
|
||||||
${customDiskImage nodes}
|
{ nodes, ... }:
|
||||||
|
''
|
||||||
|
${customDiskImage nodes}
|
||||||
|
|
||||||
machine.start()
|
machine.start()
|
||||||
machine.wait_for_unit("multi-user.target")
|
machine.wait_for_unit("multi-user.target")
|
||||||
|
|
||||||
machine.succeed("test -e /efi/EFI/systemd/systemd-bootx64.efi")
|
machine.succeed("test -e /efi/EFI/systemd/systemd-bootx64.efi")
|
||||||
machine.succeed("test -e /boot/loader/entries/nixos-generation-1.conf")
|
machine.succeed("test -e /boot/loader/entries/nixos-generation-1.conf")
|
||||||
|
|
||||||
# Ensure we actually booted using systemd-boot
|
# Ensure we actually booted using systemd-boot
|
||||||
# Magic number is the vendor UUID used by systemd-boot.
|
# Magic number is the vendor UUID used by systemd-boot.
|
||||||
machine.succeed(
|
machine.succeed(
|
||||||
"test -e /sys/firmware/efi/efivars/LoaderEntrySelected-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f"
|
"test -e /sys/firmware/efi/efivars/LoaderEntrySelected-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f"
|
||||||
)
|
)
|
||||||
|
|
||||||
# "bootctl install" should have created an EFI entry
|
# "bootctl install" should have created an EFI entry
|
||||||
machine.succeed('efibootmgr | grep "Linux Boot Manager"')
|
machine.succeed('efibootmgr | grep "Linux Boot Manager"')
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
# Check that specialisations create corresponding boot entries.
|
# Check that specialisations create corresponding boot entries.
|
||||||
specialisation = makeTest {
|
specialisation = makeTest {
|
||||||
name = "systemd-boot-specialisation";
|
name = "systemd-boot-specialisation";
|
||||||
meta.maintainers = with pkgs.lib.maintainers; [ lukegb julienmalka ];
|
meta.maintainers = with pkgs.lib.maintainers; [
|
||||||
|
lukegb
|
||||||
|
julienmalka
|
||||||
|
];
|
||||||
|
|
||||||
nodes.machine = { pkgs, lib, ... }: {
|
nodes.machine =
|
||||||
imports = [ common ];
|
{ pkgs, lib, ... }:
|
||||||
specialisation.something.configuration = {
|
{
|
||||||
boot.loader.systemd-boot.sortKey = "something";
|
imports = [ common ];
|
||||||
|
specialisation.something.configuration = {
|
||||||
|
boot.loader.systemd-boot.sortKey = "something";
|
||||||
|
|
||||||
# Since qemu will dynamically create a devicetree blob when starting
|
# Since qemu will dynamically create a devicetree blob when starting
|
||||||
# up, it is not straight forward to create an export of that devicetree
|
# up, it is not straight forward to create an export of that devicetree
|
||||||
# blob without knowing before-hand all the flags we would pass to qemu
|
# blob without knowing before-hand all the flags we would pass to qemu
|
||||||
# (we would then be able to use `dumpdtb`). Thus, the following config
|
# (we would then be able to use `dumpdtb`). Thus, the following config
|
||||||
# will not boot, but it does allow us to assert that the boot entry has
|
# will not boot, but it does allow us to assert that the boot entry has
|
||||||
# the correct contents.
|
# the correct contents.
|
||||||
boot.loader.systemd-boot.installDeviceTree = pkgs.stdenv.hostPlatform.isAarch64;
|
boot.loader.systemd-boot.installDeviceTree = pkgs.stdenv.hostPlatform.isAarch64;
|
||||||
hardware.deviceTree.name = "dummy.dtb";
|
hardware.deviceTree.name = "dummy.dtb";
|
||||||
hardware.deviceTree.package = lib.mkForce (pkgs.runCommand "dummy-devicetree-package" { } ''
|
hardware.deviceTree.package = lib.mkForce (
|
||||||
mkdir -p $out
|
pkgs.runCommand "dummy-devicetree-package" { } ''
|
||||||
cp ${pkgs.emptyFile} $out/dummy.dtb
|
mkdir -p $out
|
||||||
'');
|
cp ${pkgs.emptyFile} $out/dummy.dtb
|
||||||
|
''
|
||||||
|
);
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
|
||||||
|
|
||||||
testScript = { nodes, ... }: ''
|
testScript =
|
||||||
machine.start()
|
{ nodes, ... }:
|
||||||
machine.wait_for_unit("multi-user.target")
|
''
|
||||||
|
machine.start()
|
||||||
|
machine.wait_for_unit("multi-user.target")
|
||||||
|
|
||||||
machine.succeed(
|
machine.succeed(
|
||||||
"test -e /boot/loader/entries/nixos-generation-1-specialisation-something.conf"
|
"test -e /boot/loader/entries/nixos-generation-1-specialisation-something.conf"
|
||||||
)
|
)
|
||||||
machine.succeed(
|
machine.succeed(
|
||||||
"grep -q 'title NixOS (something)' /boot/loader/entries/nixos-generation-1-specialisation-something.conf"
|
"grep -q 'title NixOS (something)' /boot/loader/entries/nixos-generation-1-specialisation-something.conf"
|
||||||
)
|
)
|
||||||
machine.succeed(
|
machine.succeed(
|
||||||
"grep 'sort-key something' /boot/loader/entries/nixos-generation-1-specialisation-something.conf"
|
"grep 'sort-key something' /boot/loader/entries/nixos-generation-1-specialisation-something.conf"
|
||||||
)
|
)
|
||||||
'' + pkgs.lib.optionalString pkgs.stdenv.hostPlatform.isAarch64 ''
|
''
|
||||||
machine.succeed(
|
+ pkgs.lib.optionalString pkgs.stdenv.hostPlatform.isAarch64 ''
|
||||||
r"grep 'devicetree /EFI/nixos/[a-z0-9]\{32\}.*dummy' /boot/loader/entries/nixos-generation-1-specialisation-something.conf"
|
machine.succeed(
|
||||||
)
|
r"grep 'devicetree /EFI/nixos/[a-z0-9]\{32\}.*dummy' /boot/loader/entries/nixos-generation-1-specialisation-something.conf"
|
||||||
'';
|
)
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
# Boot without having created an EFI entry--instead using default "/EFI/BOOT/BOOTX64.EFI"
|
# Boot without having created an EFI entry--instead using default "/EFI/BOOT/BOOTX64.EFI"
|
||||||
fallback = makeTest {
|
fallback = makeTest {
|
||||||
name = "systemd-boot-fallback";
|
name = "systemd-boot-fallback";
|
||||||
meta.maintainers = with pkgs.lib.maintainers; [ danielfullmer julienmalka ];
|
meta.maintainers = with pkgs.lib.maintainers; [
|
||||||
|
danielfullmer
|
||||||
|
julienmalka
|
||||||
|
];
|
||||||
|
|
||||||
nodes.machine = { pkgs, lib, ... }: {
|
nodes.machine =
|
||||||
imports = [ common ];
|
{ pkgs, lib, ... }:
|
||||||
boot.loader.efi.canTouchEfiVariables = mkForce false;
|
{
|
||||||
};
|
imports = [ common ];
|
||||||
|
boot.loader.efi.canTouchEfiVariables = mkForce false;
|
||||||
|
};
|
||||||
|
|
||||||
testScript = ''
|
testScript = ''
|
||||||
machine.start()
|
machine.start()
|
||||||
|
@ -235,7 +265,10 @@ in
|
||||||
|
|
||||||
update = makeTest {
|
update = makeTest {
|
||||||
name = "systemd-boot-update";
|
name = "systemd-boot-update";
|
||||||
meta.maintainers = with pkgs.lib.maintainers; [ danielfullmer julienmalka ];
|
meta.maintainers = with pkgs.lib.maintainers; [
|
||||||
|
danielfullmer
|
||||||
|
julienmalka
|
||||||
|
];
|
||||||
|
|
||||||
nodes.machine = common;
|
nodes.machine = common;
|
||||||
|
|
||||||
|
@ -270,29 +303,35 @@ in
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
memtest86 = with pkgs.lib; optionalAttrs (meta.availableOn { inherit system; } pkgs.memtest86plus) (makeTest {
|
memtest86 =
|
||||||
name = "systemd-boot-memtest86";
|
with pkgs.lib;
|
||||||
meta.maintainers = with maintainers; [ julienmalka ];
|
optionalAttrs (meta.availableOn { inherit system; } pkgs.memtest86plus) (makeTest {
|
||||||
|
name = "systemd-boot-memtest86";
|
||||||
|
meta.maintainers = with maintainers; [ julienmalka ];
|
||||||
|
|
||||||
nodes.machine = { pkgs, lib, ... }: {
|
nodes.machine =
|
||||||
imports = [ common ];
|
{ pkgs, lib, ... }:
|
||||||
boot.loader.systemd-boot.memtest86.enable = true;
|
{
|
||||||
};
|
imports = [ common ];
|
||||||
|
boot.loader.systemd-boot.memtest86.enable = true;
|
||||||
|
};
|
||||||
|
|
||||||
testScript = ''
|
testScript = ''
|
||||||
machine.succeed("test -e /boot/loader/entries/memtest86.conf")
|
machine.succeed("test -e /boot/loader/entries/memtest86.conf")
|
||||||
machine.succeed("test -e /boot/efi/memtest86/memtest.efi")
|
machine.succeed("test -e /boot/efi/memtest86/memtest.efi")
|
||||||
'';
|
'';
|
||||||
});
|
});
|
||||||
|
|
||||||
netbootxyz = makeTest {
|
netbootxyz = makeTest {
|
||||||
name = "systemd-boot-netbootxyz";
|
name = "systemd-boot-netbootxyz";
|
||||||
meta.maintainers = with pkgs.lib.maintainers; [ julienmalka ];
|
meta.maintainers = with pkgs.lib.maintainers; [ julienmalka ];
|
||||||
|
|
||||||
nodes.machine = { pkgs, lib, ... }: {
|
nodes.machine =
|
||||||
imports = [ common ];
|
{ pkgs, lib, ... }:
|
||||||
boot.loader.systemd-boot.netbootxyz.enable = true;
|
{
|
||||||
};
|
imports = [ common ];
|
||||||
|
boot.loader.systemd-boot.netbootxyz.enable = true;
|
||||||
|
};
|
||||||
|
|
||||||
testScript = ''
|
testScript = ''
|
||||||
machine.succeed("test -e /boot/loader/entries/netbootxyz.conf")
|
machine.succeed("test -e /boot/loader/entries/netbootxyz.conf")
|
||||||
|
@ -300,15 +339,77 @@ in
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
edk2-uefi-shell = makeTest {
|
||||||
|
name = "systemd-boot-edk2-uefi-shell";
|
||||||
|
meta.maintainers = with pkgs.lib.maintainers; [ iFreilicht ];
|
||||||
|
|
||||||
|
nodes.machine = { ... }: {
|
||||||
|
imports = [ common ];
|
||||||
|
boot.loader.systemd-boot.edk2-uefi-shell.enable = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
testScript = ''
|
||||||
|
machine.succeed("test -e /boot/loader/entries/edk2-uefi-shell.conf")
|
||||||
|
machine.succeed("test -e /boot/efi/edk2-uefi-shell/shell.efi")
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
windows = makeTest {
|
||||||
|
name = "systemd-boot-windows";
|
||||||
|
meta.maintainers = with pkgs.lib.maintainers; [ iFreilicht ];
|
||||||
|
|
||||||
|
nodes.machine = { ... }: {
|
||||||
|
imports = [ common ];
|
||||||
|
boot.loader.systemd-boot.windows = {
|
||||||
|
"7" = {
|
||||||
|
efiDeviceHandle = "HD0c1";
|
||||||
|
sortKey = "before_all_others";
|
||||||
|
};
|
||||||
|
"Ten".efiDeviceHandle = "FS0";
|
||||||
|
"11" = {
|
||||||
|
title = "Title with-_-punctuation ...?!";
|
||||||
|
efiDeviceHandle = "HD0d4";
|
||||||
|
sortKey = "zzz";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
testScript = ''
|
||||||
|
machine.succeed("test -e /boot/efi/edk2-uefi-shell/shell.efi")
|
||||||
|
|
||||||
|
machine.succeed("test -e /boot/loader/entries/windows_7.conf")
|
||||||
|
machine.succeed("test -e /boot/loader/entries/windows_Ten.conf")
|
||||||
|
machine.succeed("test -e /boot/loader/entries/windows_11.conf")
|
||||||
|
|
||||||
|
machine.succeed("grep 'efi /efi/edk2-uefi-shell/shell.efi' /boot/loader/entries/windows_7.conf")
|
||||||
|
machine.succeed("grep 'efi /efi/edk2-uefi-shell/shell.efi' /boot/loader/entries/windows_Ten.conf")
|
||||||
|
machine.succeed("grep 'efi /efi/edk2-uefi-shell/shell.efi' /boot/loader/entries/windows_11.conf")
|
||||||
|
|
||||||
|
machine.succeed("grep 'HD0c1:EFI\\\\Microsoft\\\\Boot\\\\Bootmgfw.efi' /boot/loader/entries/windows_7.conf")
|
||||||
|
machine.succeed("grep 'FS0:EFI\\\\Microsoft\\\\Boot\\\\Bootmgfw.efi' /boot/loader/entries/windows_Ten.conf")
|
||||||
|
machine.succeed("grep 'HD0d4:EFI\\\\Microsoft\\\\Boot\\\\Bootmgfw.efi' /boot/loader/entries/windows_11.conf")
|
||||||
|
|
||||||
|
machine.succeed("grep 'sort-key before_all_others' /boot/loader/entries/windows_7.conf")
|
||||||
|
machine.succeed("grep 'sort-key o_windows_Ten' /boot/loader/entries/windows_Ten.conf")
|
||||||
|
machine.succeed("grep 'sort-key zzz' /boot/loader/entries/windows_11.conf")
|
||||||
|
|
||||||
|
machine.succeed("grep 'title Windows 7' /boot/loader/entries/windows_7.conf")
|
||||||
|
machine.succeed("grep 'title Windows Ten' /boot/loader/entries/windows_Ten.conf")
|
||||||
|
machine.succeed('grep "title Title with-_-punctuation ...?!" /boot/loader/entries/windows_11.conf')
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
memtestSortKey = makeTest {
|
memtestSortKey = makeTest {
|
||||||
name = "systemd-boot-memtest-sortkey";
|
name = "systemd-boot-memtest-sortkey";
|
||||||
meta.maintainers = with pkgs.lib.maintainers; [ julienmalka ];
|
meta.maintainers = with pkgs.lib.maintainers; [ julienmalka ];
|
||||||
|
|
||||||
nodes.machine = { pkgs, lib, ... }: {
|
nodes.machine =
|
||||||
imports = [ common ];
|
{ pkgs, lib, ... }:
|
||||||
boot.loader.systemd-boot.memtest86.enable = true;
|
{
|
||||||
boot.loader.systemd-boot.memtest86.sortKey = "apple";
|
imports = [ common ];
|
||||||
};
|
boot.loader.systemd-boot.memtest86.enable = true;
|
||||||
|
boot.loader.systemd-boot.memtest86.sortKey = "apple";
|
||||||
|
};
|
||||||
|
|
||||||
testScript = ''
|
testScript = ''
|
||||||
machine.succeed("test -e /boot/loader/entries/memtest86.conf")
|
machine.succeed("test -e /boot/loader/entries/memtest86.conf")
|
||||||
|
@ -321,35 +422,41 @@ in
|
||||||
name = "systemd-boot-entry-filename-xbootldr";
|
name = "systemd-boot-entry-filename-xbootldr";
|
||||||
meta.maintainers = with pkgs.lib.maintainers; [ sdht0 ];
|
meta.maintainers = with pkgs.lib.maintainers; [ sdht0 ];
|
||||||
|
|
||||||
nodes.machine = { pkgs, lib, ... }: {
|
nodes.machine =
|
||||||
imports = [ commonXbootldr ];
|
{ pkgs, lib, ... }:
|
||||||
boot.loader.systemd-boot.memtest86.enable = true;
|
{
|
||||||
};
|
imports = [ commonXbootldr ];
|
||||||
|
boot.loader.systemd-boot.memtest86.enable = true;
|
||||||
|
};
|
||||||
|
|
||||||
testScript = { nodes, ... }: ''
|
testScript =
|
||||||
${customDiskImage nodes}
|
{ nodes, ... }:
|
||||||
|
''
|
||||||
|
${customDiskImage nodes}
|
||||||
|
|
||||||
machine.start()
|
machine.start()
|
||||||
machine.wait_for_unit("multi-user.target")
|
machine.wait_for_unit("multi-user.target")
|
||||||
|
|
||||||
machine.succeed("test -e /efi/EFI/systemd/systemd-bootx64.efi")
|
machine.succeed("test -e /efi/EFI/systemd/systemd-bootx64.efi")
|
||||||
machine.succeed("test -e /boot/loader/entries/memtest86.conf")
|
machine.succeed("test -e /boot/loader/entries/memtest86.conf")
|
||||||
machine.succeed("test -e /boot/EFI/memtest86/memtest.efi")
|
machine.succeed("test -e /boot/EFI/memtest86/memtest.efi")
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
extraEntries = makeTest {
|
extraEntries = makeTest {
|
||||||
name = "systemd-boot-extra-entries";
|
name = "systemd-boot-extra-entries";
|
||||||
meta.maintainers = with pkgs.lib.maintainers; [ julienmalka ];
|
meta.maintainers = with pkgs.lib.maintainers; [ julienmalka ];
|
||||||
|
|
||||||
nodes.machine = { pkgs, lib, ... }: {
|
nodes.machine =
|
||||||
imports = [ common ];
|
{ pkgs, lib, ... }:
|
||||||
boot.loader.systemd-boot.extraEntries = {
|
{
|
||||||
"banana.conf" = ''
|
imports = [ common ];
|
||||||
title banana
|
boot.loader.systemd-boot.extraEntries = {
|
||||||
'';
|
"banana.conf" = ''
|
||||||
|
title banana
|
||||||
|
'';
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
|
||||||
|
|
||||||
testScript = ''
|
testScript = ''
|
||||||
machine.succeed("test -e /boot/loader/entries/banana.conf")
|
machine.succeed("test -e /boot/loader/entries/banana.conf")
|
||||||
|
@ -361,12 +468,14 @@ in
|
||||||
name = "systemd-boot-extra-files";
|
name = "systemd-boot-extra-files";
|
||||||
meta.maintainers = with pkgs.lib.maintainers; [ julienmalka ];
|
meta.maintainers = with pkgs.lib.maintainers; [ julienmalka ];
|
||||||
|
|
||||||
nodes.machine = { pkgs, lib, ... }: {
|
nodes.machine =
|
||||||
imports = [ common ];
|
{ pkgs, lib, ... }:
|
||||||
boot.loader.systemd-boot.extraFiles = {
|
{
|
||||||
"efi/fruits/tomato.efi" = pkgs.netbootxyz-efi;
|
imports = [ common ];
|
||||||
|
boot.loader.systemd-boot.extraFiles = {
|
||||||
|
"efi/fruits/tomato.efi" = pkgs.netbootxyz-efi;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
|
||||||
|
|
||||||
testScript = ''
|
testScript = ''
|
||||||
machine.succeed("test -e /boot/efi/fruits/tomato.efi")
|
machine.succeed("test -e /boot/efi/fruits/tomato.efi")
|
||||||
|
@ -381,55 +490,62 @@ in
|
||||||
nodes = {
|
nodes = {
|
||||||
inherit common;
|
inherit common;
|
||||||
|
|
||||||
machine = { pkgs, nodes, ... }: {
|
machine =
|
||||||
imports = [ common ];
|
{ pkgs, nodes, ... }:
|
||||||
boot.loader.systemd-boot.extraFiles = {
|
{
|
||||||
"efi/fruits/tomato.efi" = pkgs.netbootxyz-efi;
|
imports = [ common ];
|
||||||
|
boot.loader.systemd-boot.extraFiles = {
|
||||||
|
"efi/fruits/tomato.efi" = pkgs.netbootxyz-efi;
|
||||||
|
};
|
||||||
|
|
||||||
|
# These are configs for different nodes, but we'll use them here in `machine`
|
||||||
|
system.extraDependencies = [
|
||||||
|
nodes.common.system.build.toplevel
|
||||||
|
nodes.with_netbootxyz.system.build.toplevel
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
# These are configs for different nodes, but we'll use them here in `machine`
|
with_netbootxyz =
|
||||||
system.extraDependencies = [
|
{ pkgs, ... }:
|
||||||
nodes.common.system.build.toplevel
|
{
|
||||||
nodes.with_netbootxyz.system.build.toplevel
|
imports = [ common ];
|
||||||
];
|
boot.loader.systemd-boot.netbootxyz.enable = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
with_netbootxyz = { pkgs, ... }: {
|
|
||||||
imports = [ common ];
|
|
||||||
boot.loader.systemd-boot.netbootxyz.enable = true;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
testScript = { nodes, ... }: let
|
testScript =
|
||||||
originalSystem = nodes.machine.system.build.toplevel;
|
{ nodes, ... }:
|
||||||
baseSystem = nodes.common.system.build.toplevel;
|
let
|
||||||
finalSystem = nodes.with_netbootxyz.system.build.toplevel;
|
originalSystem = nodes.machine.system.build.toplevel;
|
||||||
in ''
|
baseSystem = nodes.common.system.build.toplevel;
|
||||||
machine.succeed("test -e /boot/efi/fruits/tomato.efi")
|
finalSystem = nodes.with_netbootxyz.system.build.toplevel;
|
||||||
machine.succeed("test -e /boot/efi/nixos/.extra-files/efi/fruits/tomato.efi")
|
in
|
||||||
|
''
|
||||||
|
machine.succeed("test -e /boot/efi/fruits/tomato.efi")
|
||||||
|
machine.succeed("test -e /boot/efi/nixos/.extra-files/efi/fruits/tomato.efi")
|
||||||
|
|
||||||
with subtest("remove files when no longer needed"):
|
with subtest("remove files when no longer needed"):
|
||||||
machine.succeed("${baseSystem}/bin/switch-to-configuration boot")
|
machine.succeed("${baseSystem}/bin/switch-to-configuration boot")
|
||||||
machine.fail("test -e /boot/efi/fruits/tomato.efi")
|
machine.fail("test -e /boot/efi/fruits/tomato.efi")
|
||||||
machine.fail("test -d /boot/efi/fruits")
|
machine.fail("test -d /boot/efi/fruits")
|
||||||
machine.succeed("test -d /boot/efi/nixos/.extra-files")
|
machine.succeed("test -d /boot/efi/nixos/.extra-files")
|
||||||
machine.fail("test -e /boot/efi/nixos/.extra-files/efi/fruits/tomato.efi")
|
machine.fail("test -e /boot/efi/nixos/.extra-files/efi/fruits/tomato.efi")
|
||||||
machine.fail("test -d /boot/efi/nixos/.extra-files/efi/fruits")
|
machine.fail("test -d /boot/efi/nixos/.extra-files/efi/fruits")
|
||||||
|
|
||||||
with subtest("files are added back when needed again"):
|
with subtest("files are added back when needed again"):
|
||||||
machine.succeed("${originalSystem}/bin/switch-to-configuration boot")
|
machine.succeed("${originalSystem}/bin/switch-to-configuration boot")
|
||||||
machine.succeed("test -e /boot/efi/fruits/tomato.efi")
|
machine.succeed("test -e /boot/efi/fruits/tomato.efi")
|
||||||
machine.succeed("test -e /boot/efi/nixos/.extra-files/efi/fruits/tomato.efi")
|
machine.succeed("test -e /boot/efi/nixos/.extra-files/efi/fruits/tomato.efi")
|
||||||
|
|
||||||
with subtest("simultaneously removing and adding files works"):
|
with subtest("simultaneously removing and adding files works"):
|
||||||
machine.succeed("${finalSystem}/bin/switch-to-configuration boot")
|
machine.succeed("${finalSystem}/bin/switch-to-configuration boot")
|
||||||
machine.fail("test -e /boot/efi/fruits/tomato.efi")
|
machine.fail("test -e /boot/efi/fruits/tomato.efi")
|
||||||
machine.fail("test -e /boot/efi/nixos/.extra-files/efi/fruits/tomato.efi")
|
machine.fail("test -e /boot/efi/nixos/.extra-files/efi/fruits/tomato.efi")
|
||||||
machine.succeed("test -e /boot/loader/entries/netbootxyz.conf")
|
machine.succeed("test -e /boot/loader/entries/netbootxyz.conf")
|
||||||
machine.succeed("test -e /boot/efi/netbootxyz/netboot.xyz.efi")
|
machine.succeed("test -e /boot/efi/netbootxyz/netboot.xyz.efi")
|
||||||
machine.succeed("test -e /boot/efi/nixos/.extra-files/loader/entries/netbootxyz.conf")
|
machine.succeed("test -e /boot/efi/nixos/.extra-files/loader/entries/netbootxyz.conf")
|
||||||
machine.succeed("test -e /boot/efi/nixos/.extra-files/efi/netbootxyz/netboot.xyz.efi")
|
machine.succeed("test -e /boot/efi/nixos/.extra-files/efi/netbootxyz/netboot.xyz.efi")
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
garbage-collect-entry = makeTest {
|
garbage-collect-entry = makeTest {
|
||||||
|
@ -438,17 +554,20 @@ in
|
||||||
|
|
||||||
nodes = {
|
nodes = {
|
||||||
inherit common;
|
inherit common;
|
||||||
machine = { pkgs, nodes, ... }: {
|
machine =
|
||||||
imports = [ common ];
|
{ pkgs, nodes, ... }:
|
||||||
|
{
|
||||||
|
imports = [ common ];
|
||||||
|
|
||||||
# These are configs for different nodes, but we'll use them here in `machine`
|
# These are configs for different nodes, but we'll use them here in `machine`
|
||||||
system.extraDependencies = [
|
system.extraDependencies = [
|
||||||
nodes.common.system.build.toplevel
|
nodes.common.system.build.toplevel
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
testScript = { nodes, ... }:
|
testScript =
|
||||||
|
{ nodes, ... }:
|
||||||
let
|
let
|
||||||
baseSystem = nodes.common.system.build.toplevel;
|
baseSystem = nodes.common.system.build.toplevel;
|
||||||
in
|
in
|
||||||
|
@ -461,19 +580,18 @@ in
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
no-bootspec = makeTest
|
no-bootspec = makeTest {
|
||||||
{
|
name = "systemd-boot-no-bootspec";
|
||||||
name = "systemd-boot-no-bootspec";
|
meta.maintainers = with pkgs.lib.maintainers; [ julienmalka ];
|
||||||
meta.maintainers = with pkgs.lib.maintainers; [ julienmalka ];
|
|
||||||
|
|
||||||
nodes.machine = {
|
nodes.machine = {
|
||||||
imports = [ common ];
|
imports = [ common ];
|
||||||
boot.bootspec.enable = false;
|
boot.bootspec.enable = false;
|
||||||
};
|
|
||||||
|
|
||||||
testScript = ''
|
|
||||||
machine.start()
|
|
||||||
machine.wait_for_unit("multi-user.target")
|
|
||||||
'';
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
testScript = ''
|
||||||
|
machine.start()
|
||||||
|
machine.wait_for_unit("multi-user.target")
|
||||||
|
'';
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue