Allow to pass extra initrd archives to the bootloader (#534265)

This commit is contained in:
Florian Klink
2026-06-26 10:46:37 +00:00
committed by GitHub
8 changed files with 591 additions and 266 deletions
+1
View File
@@ -1914,6 +1914,7 @@
./system/boot/clevis-luks-askpass.nix
./system/boot/clevis.nix
./system/boot/emergency-mode.nix
./system/boot/extra-initrd.nix
./system/boot/grow-partition.nix
./system/boot/initrd-network.nix
./system/boot/initrd-openvpn.nix
@@ -0,0 +1,21 @@
{ config, lib, ... }:
{
options.system.boot.extraInitrd = {
paths = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ ];
description = ''
List of paths relative to the ESP that are combined with the NixOS
main initrd before being passed to the kernel.
'';
};
};
config = {
boot.bootspec.extensions = lib.mkIf (config.system.boot.extraInitrd.paths != [ ]) {
"org.nixos.extra-initrd.v1" = {
inherit (config.system.boot.extraInitrd) paths;
};
};
};
}
File diff suppressed because it is too large Load Diff
@@ -205,6 +205,17 @@ in
'';
};
extraInstallCommands = lib.mkOption {
default = "";
type = lib.types.lines;
description = ''
Additional shell commands inserted in the bootloader installer
script after generating menu entries. It can be used to expand
on extra boot entries that cannot incorporate certain pieces of
information (such as the resulting `init=` kernel parameter).
'';
};
secureBoot = {
enable = lib.mkEnableOption null // {
description = ''
@@ -443,14 +454,25 @@ in
system = {
boot.loader.id = "limine";
build.installBootLoader = pkgs.replaceVarsWith {
src = ./limine-install.py;
isExecutable = true;
replacements = {
python3 = pkgs.python3.withPackages (python-packages: [ python-packages.psutil ]);
configPath = limineInstallConfig;
};
};
build.installBootLoader =
let
install = pkgs.replaceVarsWith {
src = ./limine-install.py;
isExecutable = true;
replacements = {
python3 = pkgs.python3.withPackages (python-packages: [ python-packages.psutil ]);
configPath = limineInstallConfig;
};
};
final = pkgs.writeScript "limine-install.sh" ''
#!${pkgs.runtimeShell}
set -euo pipefail
${install} "$@"
${cfg.extraInstallCommands}
'';
in
final;
};
})
(lib.mkIf (cfg.enable && cfg.secureBoot.enable) {
@@ -45,6 +45,7 @@ BOOT_COUNTING = "@bootCounting@" == "True"
class BootSpec:
init: Path
initrd: Path
extraInitrdPaths: list[Path]
kernel: Path
kernelParams: list[str] # noqa: N815
label: str
@@ -306,9 +307,7 @@ def get_bootspec(profile: str | None, generation: int) -> BootSpec | None:
try:
bootspec_json = json.load(f)
except ValueError as e:
print(
f"error: Malformed Json: {e}, in {boot_json_path}", file=sys.stderr
)
print(f"error: Malformed Json: {e}, in {boot_json_path}", file=sys.stderr)
sys.exit(1)
return bootspec_from_json(bootspec_json)
@@ -320,6 +319,11 @@ def bootspec_from_json(bootspec_json: dict[str, Any]) -> BootSpec:
sortKey = systemdBootExtension.get("sortKey", "nixos")
devicetree = systemdBootExtension.get("devicetree")
extraInitrdExtension = bootspec_json.get("org.nixos.extra-initrd.v1", {})
extraInitrdPaths = list(
map(lambda path: Path(path), extraInitrdExtension.get("paths", []))
)
if devicetree:
devicetree = Path(devicetree)
@@ -332,6 +336,7 @@ def bootspec_from_json(bootspec_json: dict[str, Any]) -> BootSpec:
specialisations=specialisations,
sortKey=sortKey,
devicetree=devicetree,
extraInitrdPaths=extraInitrdPaths,
)
@@ -374,16 +379,21 @@ def boot_file(
specialisation=" (%s)" % specialisation if specialisation else "",
)
description = f"Generation {generation} {bootspec.label}, built on {build_date}"
boot_entry = [
f"title {title}",
f"version {description}",
f"linux /{str(kernel.path)}",
f"initrd /{str(initrd.path)}",
f"options {kernel_params}",
f"machine-id {machine_id}" if machine_id is not None else None,
f"devicetree /{str(devicetree.path)}" if devicetree is not None else None,
f"sort-key {bootspec.sortKey}",
]
boot_entry = (
[
f"title {title}",
f"version {description}",
f"linux /{str(kernel.path)}",
f"initrd /{str(initrd.path)}",
]
+ list(map(lambda initrd: f"initrd /{initrd}", bootspec.extraInitrdPaths))
+ [
f"options {kernel_params}",
f"machine-id {machine_id}" if machine_id is not None else None,
f"devicetree /{str(devicetree.path)}" if devicetree is not None else None,
f"sort-key {bootspec.sortKey}",
]
)
contents = "\n".join(filter(None, boot_entry))
entry, bootctl_id = BootFile.from_entry(contents.encode("utf-8"))
return (list(filter(None, [kernel, initrd, devicetree, entry])), bootctl_id)
+3
View File
@@ -554,6 +554,9 @@ in
etebase-server = runTest ./etebase-server.nix;
etesync-dav = runTest ./etesync-dav.nix;
evcc = runTest ./evcc.nix;
extra-initrd = import ./extra-initrd.nix {
inherit runTest pkgs;
};
facter = runTest ./facter;
fail2ban = runTest ./fail2ban.nix;
fakeroute = runTest ./fakeroute.nix;
+96
View File
@@ -0,0 +1,96 @@
{
runTest,
...
}:
let
common =
{ config, pkgs, ... }:
{
virtualisation.useBootLoader = true;
virtualisation.useEFIBoot = true;
system.boot.extraInitrd.paths = [
extraInitrdPath
];
boot.loader.timeout = 2;
boot.initrd.systemd.mounts = [
{
what = "/canary.txt";
where = "/sysroot/run/canary.txt";
type = "none";
options = "bind";
unitConfig = {
DefaultDependencies = false;
};
requiredBy = [ "initrd-fs.target" ];
before = [ "initrd-fs.target" ];
}
];
};
extraInitrdPath = "custom.cpio";
canaryCpio =
pkgs:
pkgs.runCommand "canary.cpio"
{
nativeBuildInputs = [ pkgs.cpio ];
}
''
echo canary > canary.txt
find . -print0 | cpio --null -o --format=newc > $out
'';
testScript =
# python
''
machine.wait_for_unit("multi-user.target")
# Check that the extra cpio archive is on the ESP
machine.succeed("test -e /boot/custom.cpio")
# Check that the initrd that we booted with contained the file from
# the extra initrd and our initrd mount unit bound it into sysroot
assert machine.succeed("cat /run/canary.txt").strip() == "canary"
'';
in
{
systemd-boot = runTest (
{ pkgs, ... }: {
name = "systemd-boot-extra-initrd";
nodes.machine = { config, ... }: {
imports = [ common ];
boot.loader.systemd-boot = {
enable = true;
extraInstallCommands = ''
cp ${canaryCpio pkgs} ${config.boot.loader.efi.efiSysMountPoint}/${extraInitrdPath}
'';
};
};
inherit testScript;
}
);
limine = runTest {
name = "limine-extra-initrd";
nodes.machine = { pkgs, config, ... }: {
imports = [ common ];
boot.loader.limine = {
enable = true;
efiSupport = true;
enableEditor = true;
extraInstallCommands = ''
cp ${canaryCpio pkgs} ${config.boot.loader.efi.efiSysMountPoint}/${extraInitrdPath}
'';
};
};
inherit testScript;
};
}
+11
View File
@@ -1,5 +1,6 @@
# Derivation containing the Limine host tool and the compiled bootloader
{
fetchpatch,
fetchurl,
lib,
llvmPackages,
@@ -57,6 +58,16 @@ stdenv.mkDerivation (finalAttrs: {
hash = "sha256-8aUp2lzVClyje6WHMTOnuOclhLEn1zMf6U5VTl5gEvc=";
};
patches = [
# Merged upstream in https://github.com/Limine-Bootloader/Limine/pull/599,
# remove on the next release.
(fetchpatch {
name = "align-linux-modules.patch";
url = "https://github.com/Limine-Bootloader/Limine/commit/6635ae4ff2321f9a3c85116a57a00e3b6edc100b.patch";
hash = "sha256-poAcZND5xwS8npHCytS9lwcQi9oCEcc4bR+6HKVXJ78=";
})
];
enableParallelBuilding = true;
hardeningDisable = lib.optionals missingZerocallusedregs [