about summary refs log tree commit diff
path: root/nixpkgs/nixos/modules/system
diff options
context:
space:
mode:
authorAlyssa Ross <hi@alyssa.is>2021-04-09 18:28:16 +0000
committerAlyssa Ross <hi@alyssa.is>2021-04-12 18:46:15 +0000
commitfd2e737e0678ee7d8081baef05b305146a2c0034 (patch)
treeac3e9b27576a0382335532d126f9a66d486bc638 /nixpkgs/nixos/modules/system
parentcc207d720b6aa836e256c1ee9842bc739e630a8a (diff)
parent9e377a6ce42dccd9b624ae4ce8f978dc892ba0e2 (diff)
downloadnixlib-fd2e737e0678ee7d8081baef05b305146a2c0034.tar
nixlib-fd2e737e0678ee7d8081baef05b305146a2c0034.tar.gz
nixlib-fd2e737e0678ee7d8081baef05b305146a2c0034.tar.bz2
nixlib-fd2e737e0678ee7d8081baef05b305146a2c0034.tar.lz
nixlib-fd2e737e0678ee7d8081baef05b305146a2c0034.tar.xz
nixlib-fd2e737e0678ee7d8081baef05b305146a2c0034.tar.zst
nixlib-fd2e737e0678ee7d8081baef05b305146a2c0034.zip
Merge remote-tracking branch 'nixpkgs/nixos-unstable'
Diffstat (limited to 'nixpkgs/nixos/modules/system')
-rw-r--r--nixpkgs/nixos/modules/system/boot/initrd-openvpn.nix2
-rw-r--r--nixpkgs/nixos/modules/system/boot/kernel_config.nix22
-rw-r--r--nixpkgs/nixos/modules/system/boot/loader/generic-extlinux-compatible/extlinux-conf-builder.sh2
-rw-r--r--nixpkgs/nixos/modules/system/boot/loader/grub/install-grub.pl225
-rw-r--r--nixpkgs/nixos/modules/system/boot/loader/init-script/init-script-builder.sh1
-rw-r--r--nixpkgs/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py49
-rw-r--r--nixpkgs/nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix15
-rw-r--r--nixpkgs/nixos/modules/system/boot/luksroot.nix56
-rw-r--r--nixpkgs/nixos/modules/system/boot/networkd.nix110
-rw-r--r--nixpkgs/nixos/modules/system/boot/plymouth.nix89
-rw-r--r--nixpkgs/nixos/modules/system/boot/stage-1-init.sh15
-rw-r--r--nixpkgs/nixos/modules/system/boot/stage-1.nix15
-rw-r--r--nixpkgs/nixos/modules/system/boot/stage-2-init.sh3
-rw-r--r--nixpkgs/nixos/modules/system/boot/stage-2.nix15
-rw-r--r--nixpkgs/nixos/modules/system/boot/systemd.nix18
15 files changed, 420 insertions, 217 deletions
diff --git a/nixpkgs/nixos/modules/system/boot/initrd-openvpn.nix b/nixpkgs/nixos/modules/system/boot/initrd-openvpn.nix
index e59bc7b6678f..b35fb0b57c05 100644
--- a/nixpkgs/nixos/modules/system/boot/initrd-openvpn.nix
+++ b/nixpkgs/nixos/modules/system/boot/initrd-openvpn.nix
@@ -55,7 +55,7 @@ in
     # The shared libraries are required for DNS resolution
     boot.initrd.extraUtilsCommands = ''
       copy_bin_and_libs ${pkgs.openvpn}/bin/openvpn
-      copy_bin_and_libs ${pkgs.iproute}/bin/ip
+      copy_bin_and_libs ${pkgs.iproute2}/bin/ip
 
       cp -pv ${pkgs.glibc}/lib/libresolv.so.2 $out/lib
       cp -pv ${pkgs.glibc}/lib/libnss_dns.so.2 $out/lib
diff --git a/nixpkgs/nixos/modules/system/boot/kernel_config.nix b/nixpkgs/nixos/modules/system/boot/kernel_config.nix
index 783685c9dfe4..5d9534024b06 100644
--- a/nixpkgs/nixos/modules/system/boot/kernel_config.nix
+++ b/nixpkgs/nixos/modules/system/boot/kernel_config.nix
@@ -2,24 +2,6 @@
 
 with lib;
 let
-  findWinner = candidates: winner:
-    any (x: x == winner) candidates;
-
-  # winners is an ordered list where first item wins over 2nd etc
-  mergeAnswer = winners: locs: defs:
-    let
-      values = map (x: x.value) defs;
-      inter = intersectLists values winners;
-      winner = head winners;
-    in
-    if defs == [] then abort "This case should never happen."
-    else if winner == [] then abort "Give a valid list of winner"
-    else if inter == [] then mergeOneOption locs defs
-    else if findWinner values winner then
-      winner
-    else
-      mergeAnswer (tail winners) locs defs;
-
   mergeFalseByDefault = locs: defs:
     if defs == [] then abort "This case should never happen."
     else if any (x: x == false) (getValues defs) then false
@@ -28,9 +10,7 @@ let
   kernelItem = types.submodule {
     options = {
       tristate = mkOption {
-        type = types.enum [ "y" "m" "n" null ] // {
-          merge = mergeAnswer [ "y" "m" "n" ];
-        };
+        type = types.enum [ "y" "m" "n" null ];
         default = null;
         internal = true;
         visible = true;
diff --git a/nixpkgs/nixos/modules/system/boot/loader/generic-extlinux-compatible/extlinux-conf-builder.sh b/nixpkgs/nixos/modules/system/boot/loader/generic-extlinux-compatible/extlinux-conf-builder.sh
index 854684b87fac..5ffffb95edb1 100644
--- a/nixpkgs/nixos/modules/system/boot/loader/generic-extlinux-compatible/extlinux-conf-builder.sh
+++ b/nixpkgs/nixos/modules/system/boot/loader/generic-extlinux-compatible/extlinux-conf-builder.sh
@@ -109,7 +109,7 @@ addEntry() {
             exit 1
         fi
     fi
-    echo "  APPEND systemConfig=$path init=$path/init $extraParams"
+    echo "  APPEND init=$path/init $extraParams"
 }
 
 tmpFile="$target/extlinux/extlinux.conf.tmp.$$"
diff --git a/nixpkgs/nixos/modules/system/boot/loader/grub/install-grub.pl b/nixpkgs/nixos/modules/system/boot/loader/grub/install-grub.pl
index 59f5638044fe..e0167654748e 100644
--- a/nixpkgs/nixos/modules/system/boot/loader/grub/install-grub.pl
+++ b/nixpkgs/nixos/modules/system/boot/loader/grub/install-grub.pl
@@ -102,10 +102,10 @@ if (stat($bootPath)->dev != stat("/nix/store")->dev) {
 
 # Discover information about the location of the bootPath
 struct(Fs => {
-    device => '$',
-    type => '$',
-    mount => '$',
-});
+        device => '$',
+        type => '$',
+        mount => '$',
+    });
 sub PathInMount {
     my ($path, $mount) = @_;
     my @splitMount = split /\//, $mount;
@@ -154,16 +154,16 @@ sub GetFs {
     return $bestFs;
 }
 struct (Grub => {
-    path => '$',
-    search => '$',
-});
+        path => '$',
+        search => '$',
+    });
 my $driveid = 1;
 sub GrubFs {
     my ($dir) = @_;
     my $fs = GetFs($dir);
     my $path = substr($dir, length($fs->mount));
     if (substr($path, 0, 1) ne "/") {
-      $path = "/$path";
+        $path = "/$path";
     }
     my $search = "";
 
@@ -251,8 +251,8 @@ my $conf .= "# Automatically generated.  DO NOT EDIT THIS FILE!\n";
 
 if ($grubVersion == 1) {
     $conf .= "
-        default $defaultEntry
-        timeout $timeout
+    default $defaultEntry
+    timeout $timeout
     ";
     if ($splashImage) {
         copy $splashImage, "$bootPath/background.xpm.gz" or die "cannot copy $splashImage to $bootPath: $!\n";
@@ -302,51 +302,51 @@ else {
 
     if ($copyKernels == 0) {
         $conf .= "
-            " . $grubStore->search;
+        " . $grubStore->search;
     }
     # FIXME: should use grub-mkconfig.
     $conf .= "
-        " . $grubBoot->search . "
-        if [ -s \$prefix/grubenv ]; then
-          load_env
-        fi
-
-        # ‘grub-reboot’ sets a one-time saved entry, which we process here and
-        # then delete.
-        if [ \"\${next_entry}\" ]; then
-          set default=\"\${next_entry}\"
-          set next_entry=
-          save_env next_entry
-          set timeout=1
-        else
-          set default=$defaultEntry
-          set timeout=$timeout
-        fi
-
-        # Setup the graphics stack for bios and efi systems
-        if [ \"\${grub_platform}\" = \"efi\" ]; then
-          insmod efi_gop
-          insmod efi_uga
-        else
-          insmod vbe
-        fi
+    " . $grubBoot->search . "
+    if [ -s \$prefix/grubenv ]; then
+    load_env
+    fi
+
+    # ‘grub-reboot’ sets a one-time saved entry, which we process here and
+    # then delete.
+    if [ \"\${next_entry}\" ]; then
+    set default=\"\${next_entry}\"
+    set next_entry=
+    save_env next_entry
+    set timeout=1
+    else
+    set default=$defaultEntry
+    set timeout=$timeout
+    fi
+
+    # Setup the graphics stack for bios and efi systems
+    if [ \"\${grub_platform}\" = \"efi\" ]; then
+    insmod efi_gop
+    insmod efi_uga
+    else
+    insmod vbe
+    fi
     ";
 
     if ($font) {
         copy $font, "$bootPath/converted-font.pf2" or die "cannot copy $font to $bootPath: $!\n";
         $conf .= "
-            insmod font
-            if loadfont " . ($grubBoot->path eq "/" ? "" : $grubBoot->path) . "/converted-font.pf2; then
-              insmod gfxterm
-              if [ \"\${grub_platform}\" = \"efi\" ]; then
-                set gfxmode=$gfxmodeEfi
-                set gfxpayload=$gfxpayloadEfi
-              else
-                set gfxmode=$gfxmodeBios
-                set gfxpayload=$gfxpayloadBios
-              fi
-              terminal_output gfxterm
-            fi
+        insmod font
+        if loadfont " . ($grubBoot->path eq "/" ? "" : $grubBoot->path) . "/converted-font.pf2; then
+        insmod gfxterm
+        if [ \"\${grub_platform}\" = \"efi\" ]; then
+        set gfxmode=$gfxmodeEfi
+        set gfxpayload=$gfxpayloadEfi
+        else
+        set gfxmode=$gfxmodeBios
+        set gfxpayload=$gfxpayloadBios
+        fi
+        terminal_output gfxterm
+        fi
         ";
     }
     if ($splashImage) {
@@ -356,21 +356,21 @@ else {
         if ($suffix eq ".jpg") {
             $suffix = ".jpeg";
         }
-		if ($backgroundColor) {
-			$conf .= "
-		    background_color '$backgroundColor'
-		    ";
-		}
+        if ($backgroundColor) {
+            $conf .= "
+            background_color '$backgroundColor'
+            ";
+        }
         copy $splashImage, "$bootPath/background$suffix" or die "cannot copy $splashImage to $bootPath: $!\n";
         $conf .= "
-            insmod " . substr($suffix, 1) . "
-            if background_image --mode '$splashMode' " . ($grubBoot->path eq "/" ? "" : $grubBoot->path) . "/background$suffix; then
-              set color_normal=white/black
-              set color_highlight=black/white
-            else
-              set menu_color_normal=cyan/blue
-              set menu_color_highlight=white/blue
-            fi
+        insmod " . substr($suffix, 1) . "
+        if background_image --mode '$splashMode' " . ($grubBoot->path eq "/" ? "" : $grubBoot->path) . "/background$suffix; then
+        set color_normal=white/black
+        set color_highlight=black/white
+        else
+        set menu_color_normal=cyan/blue
+        set menu_color_highlight=white/blue
+        fi
         ";
     }
 
@@ -380,21 +380,21 @@ else {
         # Copy theme
         rcopy($theme, "$bootPath/theme") or die "cannot copy $theme to $bootPath\n";
         $conf .= "
-            # Sets theme.
-            set theme=" . ($grubBoot->path eq "/" ? "" : $grubBoot->path) . "/theme/theme.txt
-            export theme
-            # Load theme fonts, if any
-         ";
-
-         find( { wanted => sub {
-             if ($_ =~ /\.pf2$/i) {
-                 $font = File::Spec->abs2rel($File::Find::name, $theme);
-                 $conf .= "
-                     loadfont " . ($grubBoot->path eq "/" ? "" : $grubBoot->path) . "/theme/$font
-                 ";
-             }
-         }, no_chdir => 1 }, $theme );
-     }
+        # Sets theme.
+        set theme=" . ($grubBoot->path eq "/" ? "" : $grubBoot->path) . "/theme/theme.txt
+        export theme
+        # Load theme fonts, if any
+        ";
+
+        find( { wanted => sub {
+                    if ($_ =~ /\.pf2$/i) {
+                        $font = File::Spec->abs2rel($File::Find::name, $theme);
+                        $conf .= "
+                        loadfont " . ($grubBoot->path eq "/" ? "" : $grubBoot->path) . "/theme/$font
+                        ";
+                    }
+                }, no_chdir => 1 }, $theme );
+    }
 }
 
 $conf .= "$extraConfig\n";
@@ -433,25 +433,25 @@ sub addEntry {
 
     # Include second initrd with secrets
     if (-e -x "$path/append-initrd-secrets") {
-      my $initrdName = basename($initrd);
-      my $initrdSecretsPath = "$bootPath/kernels/$initrdName-secrets";
-
-      mkpath(dirname($initrdSecretsPath), 0, 0755);
-      my $oldUmask = umask;
-      # Make sure initrd is not world readable (won't work if /boot is FAT)
-      umask 0137;
-      my $initrdSecretsPathTemp = File::Temp::mktemp("$initrdSecretsPath.XXXXXXXX");
-      system("$path/append-initrd-secrets", $initrdSecretsPathTemp) == 0 or die "failed to create initrd secrets: $!\n";
-      # Check whether any secrets were actually added
-      if (-e $initrdSecretsPathTemp && ! -z _) {
-        rename $initrdSecretsPathTemp, $initrdSecretsPath or die "failed to move initrd secrets into place: $!\n";
-        $copied{$initrdSecretsPath} = 1;
-        $initrd .= " " . ($grubBoot->path eq "/" ? "" : $grubBoot->path) . "/kernels/$initrdName-secrets";
-      } else {
-        unlink $initrdSecretsPathTemp;
-        rmdir dirname($initrdSecretsPathTemp);
-      }
-      umask $oldUmask;
+        my $initrdName = basename($initrd);
+        my $initrdSecretsPath = "$bootPath/kernels/$initrdName-secrets";
+
+        mkpath(dirname($initrdSecretsPath), 0, 0755);
+        my $oldUmask = umask;
+        # Make sure initrd is not world readable (won't work if /boot is FAT)
+        umask 0137;
+        my $initrdSecretsPathTemp = File::Temp::mktemp("$initrdSecretsPath.XXXXXXXX");
+        system("$path/append-initrd-secrets", $initrdSecretsPathTemp) == 0 or die "failed to create initrd secrets: $!\n";
+        # Check whether any secrets were actually added
+        if (-e $initrdSecretsPathTemp && ! -z _) {
+            rename $initrdSecretsPathTemp, $initrdSecretsPath or die "failed to move initrd secrets into place: $!\n";
+            $copied{$initrdSecretsPath} = 1;
+            $initrd .= " " . ($grubBoot->path eq "/" ? "" : $grubBoot->path) . "/kernels/$initrdName-secrets";
+        } else {
+            unlink $initrdSecretsPathTemp;
+            rmdir dirname($initrdSecretsPathTemp);
+        }
+        umask $oldUmask;
     }
 
     my $xen = -e "$path/xen.gz" ? copyToKernelsDir(Cwd::abs_path("$path/xen.gz")) : undef;
@@ -459,9 +459,8 @@ sub addEntry {
     # FIXME: $confName
 
     my $kernelParams =
-        "systemConfig=" . Cwd::abs_path($path) . " " .
-        "init=" . Cwd::abs_path("$path/init") . " " .
-        readFile("$path/kernel-params");
+    "init=" . Cwd::abs_path("$path/init") . " " .
+    readFile("$path/kernel-params");
     my $xenParams = $xen && -e "$path/xen-params" ? readFile("$path/xen-params") : "";
 
     if ($grubVersion == 1) {
@@ -503,9 +502,9 @@ foreach my $link (@links) {
 
     my $date = strftime("%F", localtime(lstat($link)->mtime));
     my $version =
-        -e "$link/nixos-version"
-        ? readFile("$link/nixos-version")
-        : basename((glob(dirname(Cwd::abs_path("$link/kernel")) . "/lib/modules/*"))[0]);
+    -e "$link/nixos-version"
+    ? readFile("$link/nixos-version")
+    : basename((glob(dirname(Cwd::abs_path("$link/kernel")) . "/lib/modules/*"))[0]);
 
     if ($cfgName) {
         $entryName = $cfgName;
@@ -530,8 +529,8 @@ sub addProfile {
     sub nrFromGen { my ($x) = @_; $x =~ /\/\w+-(\d+)-link/; return $1; }
 
     my @links = sort
-        { nrFromGen($b) <=> nrFromGen($a) }
-        (glob "$profile-*-link");
+    { nrFromGen($b) <=> nrFromGen($a) }
+    (glob "$profile-*-link");
 
     my $curEntry = 0;
     foreach my $link (@links) {
@@ -542,9 +541,9 @@ sub addProfile {
         }
         my $date = strftime("%F", localtime(lstat($link)->mtime));
         my $version =
-            -e "$link/nixos-version"
-            ? readFile("$link/nixos-version")
-            : basename((glob(dirname(Cwd::abs_path("$link/kernel")) . "/lib/modules/*"))[0]);
+        -e "$link/nixos-version"
+        ? readFile("$link/nixos-version")
+        : basename((glob(dirname(Cwd::abs_path("$link/kernel")) . "/lib/modules/*"))[0]);
         addEntry("NixOS - Configuration " . nrFromGen($link) . " ($date - $version)", $link);
     }
 
@@ -566,7 +565,7 @@ $extraPrepareConfig =~ s/\@bootPath\@/$bootPath/g;
 
 # Run extraPrepareConfig in sh
 if ($extraPrepareConfig ne "") {
-  system((get("shell"), "-c", $extraPrepareConfig));
+    system((get("shell"), "-c", $extraPrepareConfig));
 }
 
 # write the GRUB config.
@@ -627,13 +626,13 @@ foreach my $fn (glob "$bootPath/kernels/*") {
 #
 
 struct(GrubState => {
-    name => '$',
-    version => '$',
-    efi => '$',
-    devices => '$',
-    efiMountPoint => '$',
-    extraGrubInstallArgs => '@',
-});
+        name => '$',
+        version => '$',
+        efi => '$',
+        devices => '$',
+        efiMountPoint => '$',
+        extraGrubInstallArgs => '@',
+    });
 # If you add something to the state file, only add it to the end
 # because it is read line-by-line.
 sub readGrubState {
diff --git a/nixpkgs/nixos/modules/system/boot/loader/init-script/init-script-builder.sh b/nixpkgs/nixos/modules/system/boot/loader/init-script/init-script-builder.sh
index 2a1ec479fea0..bd3fc64999da 100644
--- a/nixpkgs/nixos/modules/system/boot/loader/init-script/init-script-builder.sh
+++ b/nixpkgs/nixos/modules/system/boot/loader/init-script/init-script-builder.sh
@@ -49,7 +49,6 @@ addEntry() {
       echo "#!/bin/sh"
       echo "# $name"
       echo "# created by init-script-builder.sh"
-      echo "export systemConfig=$(readlink -f $path)"
       echo "exec $stage2"
     )"
 
diff --git a/nixpkgs/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py b/nixpkgs/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py
index 97e824fe629c..2ea191426ce9 100644
--- a/nixpkgs/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py
+++ b/nixpkgs/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py
@@ -15,12 +15,15 @@ import re
 import datetime
 import glob
 import os.path
+from typing import Tuple, List, Optional
 
-def copy_if_not_exists(source, dest):
+
+def copy_if_not_exists(source: str, dest: str) -> None:
     if not os.path.exists(dest):
         shutil.copyfile(source, dest)
 
-def system_dir(profile, generation):
+
+def system_dir(profile: Optional[str], generation: int) -> str:
     if profile:
         return "/nix/var/nix/profiles/system-profiles/%s-%d-link" % (profile, generation)
     else:
@@ -42,7 +45,8 @@ MEMTEST_BOOT_ENTRY = """title MemTest86
 efi /efi/memtest86/BOOTX64.efi
 """
 
-def write_loader_conf(profile, generation):
+
+def write_loader_conf(profile: Optional[str], generation: int) -> None:
     with open("@efiSysMountPoint@/loader/loader.conf.tmp", 'w') as f:
         if "@timeout@" != "":
             f.write("timeout @timeout@\n")
@@ -55,10 +59,12 @@ def write_loader_conf(profile, generation):
         f.write("console-mode @consoleMode@\n");
     os.rename("@efiSysMountPoint@/loader/loader.conf.tmp", "@efiSysMountPoint@/loader/loader.conf")
 
-def profile_path(profile, generation, name):
+
+def profile_path(profile: Optional[str], generation: int, name: str) -> str:
     return os.readlink("%s/%s" % (system_dir(profile, generation), name))
 
-def copy_from_profile(profile, generation, name, dry_run=False):
+
+def copy_from_profile(profile: Optional[str], generation: int, name: str, dry_run: bool = False) -> str:
     store_file_path = profile_path(profile, generation, name)
     suffix = os.path.basename(store_file_path)
     store_dir = os.path.basename(os.path.dirname(store_file_path))
@@ -67,7 +73,8 @@ def copy_from_profile(profile, generation, name, dry_run=False):
         copy_if_not_exists(store_file_path, "@efiSysMountPoint@%s" % (efi_file_path))
     return efi_file_path
 
-def describe_generation(generation_dir):
+
+def describe_generation(generation_dir: str) -> str:
     try:
         with open("%s/nixos-version" % generation_dir) as f:
             nixos_version = f.read()
@@ -87,7 +94,8 @@ def describe_generation(generation_dir):
 
     return description
 
-def write_entry(profile, generation, machine_id):
+
+def write_entry(profile: Optional[str], generation: int, machine_id: str) -> None:
     kernel = copy_from_profile(profile, generation, "kernel")
     initrd = copy_from_profile(profile, generation, "initrd")
     try:
@@ -101,7 +109,7 @@ def write_entry(profile, generation, machine_id):
         entry_file = "@efiSysMountPoint@/loader/entries/nixos-generation-%d.conf" % (generation)
     generation_dir = os.readlink(system_dir(profile, generation))
     tmp_path = "%s.tmp" % (entry_file)
-    kernel_params = "systemConfig=%s init=%s/init " % (generation_dir, generation_dir)
+    kernel_params = "init=%s/init " % generation_dir
 
     with open("%s/kernel-params" % (generation_dir)) as params_file:
         kernel_params = kernel_params + params_file.read()
@@ -116,14 +124,16 @@ def write_entry(profile, generation, machine_id):
             f.write("machine-id %s\n" % machine_id)
     os.rename(tmp_path, entry_file)
 
-def mkdir_p(path):
+
+def mkdir_p(path: str) -> None:
     try:
         os.makedirs(path)
     except OSError as e:
         if e.errno != errno.EEXIST or not os.path.isdir(path):
             raise
 
-def get_generations(profile=None):
+
+def get_generations(profile: Optional[str] = None) -> List[Tuple[Optional[str], int]]:
     gen_list = subprocess.check_output([
         "@nix@/bin/nix-env",
         "--list-generations",
@@ -137,7 +147,8 @@ def get_generations(profile=None):
     configurationLimit = @configurationLimit@
     return [ (profile, int(line.split()[0])) for line in gen_lines ][-configurationLimit:]
 
-def remove_old_entries(gens):
+
+def remove_old_entries(gens: List[Tuple[Optional[str], int]]) -> None:
     rex_profile = re.compile("^@efiSysMountPoint@/loader/entries/nixos-(.*)-generation-.*\.conf$")
     rex_generation = re.compile("^@efiSysMountPoint@/loader/entries/nixos.*-generation-(.*)\.conf$")
     known_paths = []
@@ -150,8 +161,8 @@ def remove_old_entries(gens):
                 prof = rex_profile.sub(r"\1", path)
             else:
                 prof = "system"
-            gen = int(rex_generation.sub(r"\1", path))
-            if not (prof, gen) in gens:
+            gen_number = int(rex_generation.sub(r"\1", path))
+            if not (prof, gen_number) in gens:
                 os.unlink(path)
         except ValueError:
             pass
@@ -159,7 +170,8 @@ def remove_old_entries(gens):
         if not path in known_paths and not os.path.isdir(path):
             os.unlink(path)
 
-def get_profiles():
+
+def get_profiles() -> List[str]:
     if os.path.isdir("/nix/var/nix/profiles/system-profiles/"):
         return [x
             for x in os.listdir("/nix/var/nix/profiles/system-profiles/")
@@ -167,7 +179,8 @@ def get_profiles():
     else:
         return []
 
-def main():
+
+def main() -> None:
     parser = argparse.ArgumentParser(description='Update NixOS-related systemd-boot files')
     parser.add_argument('default_config', metavar='DEFAULT-CONFIG', help='The default NixOS config to boot')
     args = parser.parse_args()
@@ -182,7 +195,9 @@ def main():
         # be there on newly installed systems, so let's generate one so that
         # bootctl can find it and we can also pass it to write_entry() later.
         cmd = ["@systemd@/bin/systemd-machine-id-setup", "--print"]
-        machine_id = subprocess.check_output(cmd).rstrip()
+        machine_id = subprocess.run(
+          cmd, text=True, check=True, stdout=subprocess.PIPE
+        ).stdout.rstrip()
 
     if os.getenv("NIXOS_INSTALL_GRUB") == "1":
         warnings.warn("NIXOS_INSTALL_GRUB env var deprecated, use NIXOS_INSTALL_BOOTLOADER", DeprecationWarning)
@@ -213,7 +228,6 @@ def main():
                 print("updating systemd-boot from %s to %s" % (sdboot_version, systemd_version))
                 subprocess.check_call(["@systemd@/bin/bootctl", "--path=@efiSysMountPoint@", "update"])
 
-
     mkdir_p("@efiSysMountPoint@/efi/nixos")
     mkdir_p("@efiSysMountPoint@/loader/entries")
 
@@ -252,5 +266,6 @@ def main():
     if rc != 0:
         print("could not sync @efiSysMountPoint@: {}".format(os.strerror(rc)), file=sys.stderr)
 
+
 if __name__ == '__main__':
     main()
diff --git a/nixpkgs/nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix b/nixpkgs/nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix
index f0bd76a3c1d2..ff304f570d35 100644
--- a/nixpkgs/nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix
+++ b/nixpkgs/nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix
@@ -7,7 +7,7 @@ let
 
   efi = config.boot.loader.efi;
 
-  gummibootBuilder = pkgs.substituteAll {
+  systemdBootBuilder = pkgs.substituteAll {
     src = ./systemd-boot-builder.py;
 
     isExecutable = true;
@@ -30,6 +30,17 @@ let
 
     memtest86 = if cfg.memtest86.enable then pkgs.memtest86-efi else "";
   };
+
+  checkedSystemdBootBuilder = pkgs.runCommand "systemd-boot" {
+    nativeBuildInputs = [ pkgs.mypy ];
+  } ''
+    install -m755 ${systemdBootBuilder} $out
+    mypy \
+      --no-implicit-optional \
+      --disallow-untyped-calls \
+      --disallow-untyped-defs \
+      $out
+  '';
 in {
 
   imports =
@@ -131,7 +142,7 @@ in {
     boot.loader.supportsInitrdSecrets = true;
 
     system = {
-      build.installBootLoader = gummibootBuilder;
+      build.installBootLoader = checkedSystemdBootBuilder;
 
       boot.loader.id = "systemd-boot";
 
diff --git a/nixpkgs/nixos/modules/system/boot/luksroot.nix b/nixpkgs/nixos/modules/system/boot/luksroot.nix
index 8dd2ea20519a..fa14d86e253d 100644
--- a/nixpkgs/nixos/modules/system/boot/luksroot.nix
+++ b/nixpkgs/nixos/modules/system/boot/luksroot.nix
@@ -56,7 +56,7 @@ let
 
         ykinfo -v 1>/dev/null 2>&1
         if [ $? != 0 ]; then
-            echo -n "Waiting $secs seconds for Yubikey to appear..."
+            echo -n "Waiting $secs seconds for YubiKey to appear..."
             local success=false
             for try in $(seq $secs); do
                 echo -n .
@@ -118,7 +118,7 @@ let
     # Cryptsetup locking directory
     mkdir -p /run/cryptsetup
 
-    # For Yubikey salt storage
+    # For YubiKey salt storage
     mkdir -p /crypt-storage
 
     ${optionalString luks.gpgSupport ''
@@ -218,7 +218,7 @@ let
     }
 
     ${optionalString (luks.yubikeySupport && (yubikey != null)) ''
-    # Yubikey
+    # YubiKey
     rbtohex() {
         ( od -An -vtx1 | tr -d ' \n' )
     }
@@ -244,7 +244,7 @@ let
         local new_k_luks
 
         mount -t ${yubikey.storage.fsType} ${yubikey.storage.device} /crypt-storage || \
-          die "Failed to mount Yubikey salt storage device"
+          die "Failed to mount YubiKey salt storage device"
 
         salt="$(cat /crypt-storage${yubikey.storage.path} | sed -n 1p | tr -d '\n')"
         iterations="$(cat /crypt-storage${yubikey.storage.path} | sed -n 2p | tr -d '\n')"
@@ -254,8 +254,27 @@ let
         for try in $(seq 3); do
             ${optionalString yubikey.twoFactor ''
             echo -n "Enter two-factor passphrase: "
-            read -r k_user
-            echo
+            k_user=
+            while true; do
+                if [ -e /crypt-ramfs/passphrase ]; then
+                    echo "reused"
+                    k_user=$(cat /crypt-ramfs/passphrase)
+                    break
+                else
+                    # Try reading it from /dev/console with a timeout
+                    IFS= read -t 1 -r k_user
+                    if [ -n "$k_user" ]; then
+                       ${if luks.reusePassphrases then ''
+                         # Remember it for the next device
+                         echo -n "$k_user" > /crypt-ramfs/passphrase
+                       '' else ''
+                         # Don't save it to ramfs. We are very paranoid
+                       ''}
+                       echo
+                       break
+                    fi
+                fi
+            done
             ''}
 
             if [ ! -z "$k_user" ]; then
@@ -268,6 +287,11 @@ let
 
             if [ $? == 0 ]; then
                 opened=true
+                ${if luks.reusePassphrases then ''
+                  # We don't rm here because we might reuse it for the next device
+                '' else ''
+                  rm -f /crypt-ramfs/passphrase
+                ''}
                 break
             else
                 opened=false
@@ -317,7 +341,7 @@ let
         if wait_yubikey ${toString yubikey.gracePeriod}; then
             do_open_yubikey
         else
-            echo "No yubikey found, falling back to non-yubikey open procedure"
+            echo "No YubiKey found, falling back to non-YubiKey open procedure"
             open_normally
         fi
     }
@@ -665,8 +689,8 @@ in
           yubikey = mkOption {
             default = null;
             description = ''
-              The options to use for this LUKS device in Yubikey-PBA.
-              If null (the default), Yubikey-PBA will be disabled for this device.
+              The options to use for this LUKS device in YubiKey-PBA.
+              If null (the default), YubiKey-PBA will be disabled for this device.
             '';
 
             type = with types; nullOr (submodule {
@@ -674,13 +698,13 @@ in
                 twoFactor = mkOption {
                   default = true;
                   type = types.bool;
-                  description = "Whether to use a passphrase and a Yubikey (true), or only a Yubikey (false).";
+                  description = "Whether to use a passphrase and a YubiKey (true), or only a YubiKey (false).";
                 };
 
                 slot = mkOption {
                   default = 2;
                   type = types.int;
-                  description = "Which slot on the Yubikey to challenge.";
+                  description = "Which slot on the YubiKey to challenge.";
                 };
 
                 saltLength = mkOption {
@@ -704,7 +728,7 @@ in
                 gracePeriod = mkOption {
                   default = 10;
                   type = types.int;
-                  description = "Time in seconds to wait for the Yubikey.";
+                  description = "Time in seconds to wait for the YubiKey.";
                 };
 
                 /* TODO: Add to the documentation of the current module:
@@ -779,9 +803,9 @@ in
       default = false;
       type = types.bool;
       description = ''
-            Enables support for authenticating with a Yubikey on LUKS devices.
+            Enables support for authenticating with a YubiKey on LUKS devices.
             See the NixOS wiki for information on how to properly setup a LUKS device
-            and a Yubikey to work with this feature.
+            and a YubiKey to work with this feature.
           '';
     };
 
@@ -799,7 +823,7 @@ in
 
     assertions =
       [ { assertion = !(luks.gpgSupport && luks.yubikeySupport);
-          message = "Yubikey and GPG Card may not be used at the same time.";
+          message = "YubiKey and GPG Card may not be used at the same time.";
         }
 
         { assertion = !(luks.gpgSupport && luks.fido2Support);
@@ -807,7 +831,7 @@ in
         }
 
         { assertion = !(luks.fido2Support && luks.yubikeySupport);
-          message = "FIDO2 and Yubikey may not be used at the same time.";
+          message = "FIDO2 and YubiKey may not be used at the same time.";
         }
       ];
 
diff --git a/nixpkgs/nixos/modules/system/boot/networkd.nix b/nixpkgs/nixos/modules/system/boot/networkd.nix
index 3b01bc00bafa..bbdd5a407060 100644
--- a/nixpkgs/nixos/modules/system/boot/networkd.nix
+++ b/nixpkgs/nixos/modules/system/boot/networkd.nix
@@ -436,7 +436,8 @@ let
           "IPv4ProxyARP"
           "IPv6ProxyNDP"
           "IPv6ProxyNDPAddress"
-          "IPv6PrefixDelegation"
+          "IPv6SendRA"
+          "DHCPv6PrefixDelegation"
           "IPv6MTUBytes"
           "Bridge"
           "Bond"
@@ -477,7 +478,8 @@ let
         (assertMinimum "IPv6HopLimit" 0)
         (assertValueOneOf "IPv4ProxyARP" boolValues)
         (assertValueOneOf "IPv6ProxyNDP" boolValues)
-        (assertValueOneOf "IPv6PrefixDelegation" ["static" "dhcpv6" "yes" "false"])
+        (assertValueOneOf "IPv6SendRA" boolValues)
+        (assertValueOneOf "DHCPv6PrefixDelegation" boolValues)
         (assertByteFormat "IPv6MTUBytes")
         (assertValueOneOf "ActiveSlave" boolValues)
         (assertValueOneOf "PrimarySlave" boolValues)
@@ -643,18 +645,63 @@ let
 
       sectionDHCPv6 = checkUnitConfig "DHCPv6" [
         (assertOnlyFields [
+          "UseAddress"
           "UseDNS"
           "UseNTP"
+          "RouteMetric"
           "RapidCommit"
+          "MUDURL"
+          "RequestOptions"
+          "SendVendorOption"
           "ForceDHCPv6PDOtherInformation"
           "PrefixDelegationHint"
-          "RouteMetric"
+          "WithoutRA"
+          "SendOption"
+          "UserClass"
+          "VendorClass"
         ])
+        (assertValueOneOf "UseAddress" boolValues)
         (assertValueOneOf "UseDNS" boolValues)
         (assertValueOneOf "UseNTP" boolValues)
+        (assertInt "RouteMetric")
         (assertValueOneOf "RapidCommit" boolValues)
         (assertValueOneOf "ForceDHCPv6PDOtherInformation" boolValues)
-        (assertInt "RouteMetric")
+        (assertValueOneOf "WithoutRA" ["solicit" "information-request"])
+        (assertRange "SendOption" 1 65536)
+      ];
+
+      sectionDHCPv6PrefixDelegation = checkUnitConfig "DHCPv6PrefixDelegation" [
+        (assertOnlyFields [
+          "SubnetId"
+          "Announce"
+          "Assign"
+          "Token"
+        ])
+        (assertValueOneOf "Announce" boolValues)
+        (assertValueOneOf "Assign" boolValues)
+      ];
+
+      sectionIPv6AcceptRA = checkUnitConfig "IPv6AcceptRA" [
+        (assertOnlyFields [
+          "UseDNS"
+          "UseDomains"
+          "RouteTable"
+          "UseAutonomousPrefix"
+          "UseOnLinkPrefix"
+          "RouterDenyList"
+          "RouterAllowList"
+          "PrefixDenyList"
+          "PrefixAllowList"
+          "RouteDenyList"
+          "RouteAllowList"
+          "DHCPv6Client"
+        ])
+        (assertValueOneOf "UseDNS" boolValues)
+        (assertValueOneOf "UseDomains" (boolValues ++ ["route"]))
+        (assertRange "RouteTable" 0 4294967295)
+        (assertValueOneOf "UseAutonomousPrefix" boolValues)
+        (assertValueOneOf "UseOnLinkPrefix" boolValues)
+        (assertValueOneOf "DHCPv6Client" (boolValues ++ ["always"]))
       ];
 
       sectionDHCPServer = checkUnitConfig "DHCPServer" [
@@ -685,7 +732,7 @@ let
         (assertValueOneOf "EmitTimezone" boolValues)
       ];
 
-      sectionIPv6PrefixDelegation = checkUnitConfig "IPv6PrefixDelegation" [
+      sectionIPv6SendRA = checkUnitConfig "IPv6SendRA" [
         (assertOnlyFields [
           "Managed"
           "OtherInformation"
@@ -1090,6 +1137,30 @@ let
       '';
     };
 
+    dhcpV6PrefixDelegationConfig = mkOption {
+      default = {};
+      example = { SubnetId = "auto"; Announce = true; };
+      type = types.addCheck (types.attrsOf unitOption) check.network.sectionDHCPv6PrefixDelegation;
+      description = ''
+        Each attribute in this set specifies an option in the
+        <literal>[DHCPv6PrefixDelegation]</literal> section of the unit. See
+        <citerefentry><refentrytitle>systemd.network</refentrytitle>
+        <manvolnum>5</manvolnum></citerefentry> for details.
+      '';
+    };
+
+    ipv6AcceptRAConfig = mkOption {
+      default = {};
+      example = { UseDNS = true; DHCPv6Client = "always"; };
+      type = types.addCheck (types.attrsOf unitOption) check.network.sectionIPv6AcceptRA;
+      description = ''
+        Each attribute in this set specifies an option in the
+        <literal>[IPv6AcceptRA]</literal> section of the unit. See
+        <citerefentry><refentrytitle>systemd.network</refentrytitle>
+        <manvolnum>5</manvolnum></citerefentry> for details.
+      '';
+    };
+
     dhcpServerConfig = mkOption {
       default = {};
       example = { PoolOffset = 50; EmitDNS = false; };
@@ -1102,13 +1173,20 @@ let
       '';
     };
 
+    # systemd.network.networks.*.ipv6PrefixDelegationConfig has been deprecated
+    # in 247 in favor of systemd.network.networks.*.ipv6SendRAConfig.
     ipv6PrefixDelegationConfig = mkOption {
+      visible = false;
+      apply = _: throw "The option `systemd.network.networks.*.ipv6PrefixDelegationConfig` has been replaced by `systemd.network.networks.*.ipv6SendRAConfig`.";
+    };
+
+    ipv6SendRAConfig = mkOption {
       default = {};
       example = { EmitDNS = true; Managed = true; OtherInformation = true; };
-      type = types.addCheck (types.attrsOf unitOption) check.network.sectionIPv6PrefixDelegation;
+      type = types.addCheck (types.attrsOf unitOption) check.network.sectionIPv6SendRA;
       description = ''
         Each attribute in this set specifies an option in the
-        <literal>[IPv6PrefixDelegation]</literal> section of the unit.  See
+        <literal>[IPv6SendRA]</literal> section of the unit.  See
         <citerefentry><refentrytitle>systemd.network</refentrytitle>
         <manvolnum>5</manvolnum></citerefentry> for details.
       '';
@@ -1457,13 +1535,21 @@ let
           [DHCPv6]
           ${attrsToSection def.dhcpV6Config}
         ''
+        + optionalString (def.dhcpV6PrefixDelegationConfig != { }) ''
+          [DHCPv6PrefixDelegation]
+          ${attrsToSection def.dhcpV6PrefixDelegationConfig}
+        ''
+        + optionalString (def.ipv6AcceptRAConfig != { }) ''
+          [IPv6AcceptRA]
+          ${attrsToSection def.ipv6AcceptRAConfig}
+        ''
         + optionalString (def.dhcpServerConfig != { }) ''
           [DHCPServer]
           ${attrsToSection def.dhcpServerConfig}
         ''
-        + optionalString (def.ipv6PrefixDelegationConfig != { }) ''
-          [IPv6PrefixDelegation]
-          ${attrsToSection def.ipv6PrefixDelegationConfig}
+        + optionalString (def.ipv6SendRAConfig != { }) ''
+          [IPv6SendRA]
+          ${attrsToSection def.ipv6SendRAConfig}
         ''
         + flip concatMapStrings def.ipv6Prefixes (x: ''
           [IPv6Prefix]
@@ -1479,7 +1565,6 @@ let
 in
 
 {
-
   options = {
 
     systemd.network.enable = mkOption {
@@ -1553,9 +1638,6 @@ in
         wantedBy = [ "multi-user.target" ];
         aliases = [ "dbus-org.freedesktop.network1.service" ];
         restartTriggers = map (x: x.source) (attrValues unitFiles);
-        # prevent race condition with interface renaming (#39069)
-        requires = [ "systemd-udev-settle.service" ];
-        after = [ "systemd-udev-settle.service" ];
       };
 
       systemd.services.systemd-networkd-wait-online = {
diff --git a/nixpkgs/nixos/modules/system/boot/plymouth.nix b/nixpkgs/nixos/modules/system/boot/plymouth.nix
index 662576888fc2..2a545e552513 100644
--- a/nixpkgs/nixos/modules/system/boot/plymouth.nix
+++ b/nixpkgs/nixos/modules/system/boot/plymouth.nix
@@ -4,8 +4,7 @@ with lib;
 
 let
 
-  inherit (pkgs) plymouth;
-  inherit (pkgs) nixos-icons;
+  inherit (pkgs) plymouth nixos-icons;
 
   cfg = config.boot.plymouth;
 
@@ -16,14 +15,37 @@ let
     osVersion = config.system.nixos.release;
   };
 
+  plymouthLogos = pkgs.runCommand "plymouth-logos" { inherit (cfg) logo; } ''
+    mkdir -p $out
+
+    # For themes that are compiled with PLYMOUTH_LOGO_FILE
+    mkdir -p $out/etc/plymouth
+    ln -s $logo $out/etc/plymouth/logo.png
+
+    # Logo for bgrt theme
+    # Note this is technically an abuse of watermark for the bgrt theme
+    # See: https://gitlab.freedesktop.org/plymouth/plymouth/-/issues/95#note_813768
+    mkdir -p $out/share/plymouth/themes/spinner
+    ln -s $logo $out/share/plymouth/themes/spinner/watermark.png
+
+    # Logo for spinfinity theme
+    # See: https://gitlab.freedesktop.org/plymouth/plymouth/-/issues/106
+    mkdir -p $out/share/plymouth/themes/spinfinity
+    ln -s $logo $out/share/plymouth/themes/spinfinity/header-image.png
+  '';
+
   themesEnv = pkgs.buildEnv {
     name = "plymouth-themes";
-    paths = [ plymouth ] ++ cfg.themePackages;
+    paths = [
+      plymouth
+      plymouthLogos
+    ] ++ cfg.themePackages;
   };
 
   configFile = pkgs.writeText "plymouthd.conf" ''
     [Daemon]
     ShowDelay=0
+    DeviceTimeout=8
     Theme=${cfg.theme}
     ${cfg.extraConfig}
   '';
@@ -38,8 +60,16 @@ in
 
       enable = mkEnableOption "Plymouth boot splash screen";
 
+      font = mkOption {
+        default = "${pkgs.dejavu_fonts.minimal}/share/fonts/truetype/DejaVuSans.ttf";
+        type = types.path;
+        description = ''
+          Font file made available for displaying text on the splash screen.
+        '';
+      };
+
       themePackages = mkOption {
-        default = [ nixosBreezePlymouth ];
+        default = lib.optional (cfg.theme == "breeze") nixosBreezePlymouth;
         type = types.listOf types.package;
         description = ''
           Extra theme packages for plymouth.
@@ -47,7 +77,7 @@ in
       };
 
       theme = mkOption {
-        default = "breeze";
+        default = "bgrt";
         type = types.str;
         description = ''
           Splash screen theme.
@@ -56,7 +86,8 @@ in
 
       logo = mkOption {
         type = types.path;
-        default = "${nixos-icons}/share/icons/hicolor/128x128/apps/nix-snowflake.png";
+        # Dimensions are 48x48 to match GDM logo
+        default = "${nixos-icons}/share/icons/hicolor/48x48/apps/nix-snowflake-white.png";
         defaultText = ''pkgs.fetchurl {
           url = "https://nixos.org/logo/nixos-hires.png";
           sha256 = "1ivzgd7iz0i06y36p8m5w48fd8pjqwxhdaavc0pxs7w1g7mcy5si";
@@ -102,37 +133,62 @@ in
     systemd.services.plymouth-poweroff.wantedBy = [ "poweroff.target" ];
     systemd.services.plymouth-reboot.wantedBy = [ "reboot.target" ];
     systemd.services.plymouth-read-write.wantedBy = [ "sysinit.target" ];
-    systemd.services.systemd-ask-password-plymouth.wantedBy = ["multi-user.target"];
-    systemd.paths.systemd-ask-password-plymouth.wantedBy = ["multi-user.target"];
+    systemd.services.systemd-ask-password-plymouth.wantedBy = [ "multi-user.target" ];
+    systemd.paths.systemd-ask-password-plymouth.wantedBy = [ "multi-user.target" ];
 
     boot.initrd.extraUtilsCommands = ''
-      copy_bin_and_libs ${pkgs.plymouth}/bin/plymouthd
-      copy_bin_and_libs ${pkgs.plymouth}/bin/plymouth
+      copy_bin_and_libs ${plymouth}/bin/plymouth
+      copy_bin_and_libs ${plymouth}/bin/plymouthd
+
+      # Check if the actual requested theme is here
+      if [[ ! -d ${themesEnv}/share/plymouth/themes/${cfg.theme} ]]; then
+          echo "The requested theme: ${cfg.theme} is not provided by any of the packages in boot.plymouth.themePackages"
+          exit 1
+      fi
 
       moduleName="$(sed -n 's,ModuleName *= *,,p' ${themesEnv}/share/plymouth/themes/${cfg.theme}/${cfg.theme}.plymouth)"
 
       mkdir -p $out/lib/plymouth/renderers
       # module might come from a theme
-      cp ${themesEnv}/lib/plymouth/{text,details,$moduleName}.so $out/lib/plymouth
+      cp ${themesEnv}/lib/plymouth/{text,details,label,$moduleName}.so $out/lib/plymouth
       cp ${plymouth}/lib/plymouth/renderers/{drm,frame-buffer}.so $out/lib/plymouth/renderers
 
       mkdir -p $out/share/plymouth/themes
       cp ${plymouth}/share/plymouth/plymouthd.defaults $out/share/plymouth
 
-      # copy themes into working directory for patching
+      # Copy themes into working directory for patching
       mkdir themes
-      # use -L to copy the directories proper, not the symlinks to them
-      cp -r -L ${themesEnv}/share/plymouth/themes/{text,details,${cfg.theme}} themes
 
-      # patch out any attempted references to the theme or plymouth's themes directory
+      # Use -L to copy the directories proper, not the symlinks to them.
+      # Copy all themes because they're not large assets, and bgrt depends on the ImageDir of
+      # the spinner theme.
+      cp -r -L ${themesEnv}/share/plymouth/themes/* themes
+
+      # Patch out any attempted references to the theme or plymouth's themes directory
       chmod -R +w themes
       find themes -type f | while read file
       do
         sed -i "s,/nix/.*/share/plymouth/themes,$out/share/plymouth/themes,g" $file
       done
 
+      # Install themes
       cp -r themes/* $out/share/plymouth/themes
-      cp ${cfg.logo} $out/share/plymouth/logo.png
+
+      # Install logo
+      mkdir -p $out/etc/plymouth
+      cp -r -L ${themesEnv}/etc/plymouth $out
+
+      # Setup font
+      mkdir -p $out/share/fonts
+      cp ${cfg.font} $out/share/fonts
+      mkdir -p $out/etc/fonts
+      cat > $out/etc/fonts/fonts.conf <<EOF
+      <?xml version="1.0"?>
+      <!DOCTYPE fontconfig SYSTEM "urn:fontconfig:fonts.dtd">
+      <fontconfig>
+          <dir>$out/share/fonts</dir>
+      </fontconfig>
+      EOF
     '';
 
     boot.initrd.extraUtilsCommandsTest = ''
@@ -154,6 +210,7 @@ in
       ln -s $extraUtils/share/plymouth/logo.png /etc/plymouth/logo.png
       ln -s $extraUtils/share/plymouth/themes /etc/plymouth/themes
       ln -s $extraUtils/lib/plymouth /etc/plymouth/plugins
+      ln -s $extraUtils/etc/fonts /etc/fonts
 
       plymouthd --mode=boot --pid-file=/run/plymouth/pid --attach-to-session
       plymouth show-splash
diff --git a/nixpkgs/nixos/modules/system/boot/stage-1-init.sh b/nixpkgs/nixos/modules/system/boot/stage-1-init.sh
index 5b39f34200cd..ddaf985878e0 100644
--- a/nixpkgs/nixos/modules/system/boot/stage-1-init.sh
+++ b/nixpkgs/nixos/modules/system/boot/stage-1-init.sh
@@ -614,11 +614,16 @@ echo /sbin/modprobe > /proc/sys/kernel/modprobe
 
 
 # Start stage 2.  `switch_root' deletes all files in the ramfs on the
-# current root.  Note that $stage2Init might be an absolute symlink,
-# in which case "-e" won't work because we're not in the chroot yet.
-if [ ! -e "$targetRoot/$stage2Init" ] && [ ! -L "$targetRoot/$stage2Init" ] ; then
-    echo "stage 2 init script ($targetRoot/$stage2Init) not found"
-    fail
+# current root.  The path has to be valid in the chroot not outside.
+if [ ! -e "$targetRoot/$stage2Init" ]; then
+    stage2Check=${stage2Init}
+    while [ "$stage2Check" != "${stage2Check%/*}" ] && [ ! -L "$targetRoot/$stage2Check" ]; do
+        stage2Check=${stage2Check%/*}
+    done
+    if [ ! -L "$targetRoot/$stage2Check" ]; then
+        echo "stage 2 init script ($targetRoot/$stage2Init) not found"
+        fail
+    fi
 fi
 
 mkdir -m 0755 -p $targetRoot/proc $targetRoot/sys $targetRoot/dev $targetRoot/run
diff --git a/nixpkgs/nixos/modules/system/boot/stage-1.nix b/nixpkgs/nixos/modules/system/boot/stage-1.nix
index 44287f3cf09b..d606d473d91e 100644
--- a/nixpkgs/nixos/modules/system/boot/stage-1.nix
+++ b/nixpkgs/nixos/modules/system/boot/stage-1.nix
@@ -205,13 +205,22 @@ let
     ''; # */
 
 
+  # Networkd link files are used early by udev to set up interfaces early.
+  # This must be done in stage 1 to avoid race conditions between udev and
+  # network daemons.
   linkUnits = pkgs.runCommand "link-units" {
       allowedReferences = [ extraUtils ];
       preferLocalBuild = true;
-    } ''
+    } (''
       mkdir -p $out
       cp -v ${udev}/lib/systemd/network/*.link $out/
-    '';
+      '' + (
+      let
+        links = filterAttrs (n: v: hasSuffix ".link" n) config.systemd.network.units;
+        files = mapAttrsToList (n: v: "${v.unit}/${n}") links;
+      in
+        concatMapStringsSep "\n" (file: "cp -v ${file} $out/") files
+      ));
 
   udevRules = pkgs.runCommand "udev-rules" {
       allowedReferences = [ extraUtils ];
@@ -377,7 +386,7 @@ let
           ) config.boot.initrd.secrets)
          }
 
-        (cd "$tmp" && find . -print0 | sort -z | cpio -o -H newc -R +0:+0 --reproducible --null) | \
+        (cd "$tmp" && find . -print0 | sort -z | cpio --quiet -o -H newc -R +0:+0 --reproducible --null) | \
           ${compressorExe} ${lib.escapeShellArgs initialRamdisk.compressorArgs} >> "$1"
       '';
 
diff --git a/nixpkgs/nixos/modules/system/boot/stage-2-init.sh b/nixpkgs/nixos/modules/system/boot/stage-2-init.sh
index 936077b9df1e..50ee0b8841e5 100644
--- a/nixpkgs/nixos/modules/system/boot/stage-2-init.sh
+++ b/nixpkgs/nixos/modules/system/boot/stage-2-init.sh
@@ -167,6 +167,7 @@ exec {logOutFd}>&- {logErrFd}>&-
 
 # Start systemd.
 echo "starting systemd..."
+
 PATH=/run/current-system/systemd/lib/systemd:@fsPackagesPath@ \
-    LOCALE_ARCHIVE=/run/current-system/sw/lib/locale/locale-archive \
+    LOCALE_ARCHIVE=/run/current-system/sw/lib/locale/locale-archive @systemdUnitPathEnvVar@ \
     exec @systemdExecutable@
diff --git a/nixpkgs/nixos/modules/system/boot/stage-2.nix b/nixpkgs/nixos/modules/system/boot/stage-2.nix
index 94bc34fea0db..f6b6a8e4b0b4 100644
--- a/nixpkgs/nixos/modules/system/boot/stage-2.nix
+++ b/nixpkgs/nixos/modules/system/boot/stage-2.nix
@@ -10,7 +10,7 @@ let
     src = ./stage-2-init.sh;
     shellDebug = "${pkgs.bashInteractive}/bin/bash";
     shell = "${pkgs.bash}/bin/bash";
-    inherit (config.boot) systemdExecutable;
+    inherit (config.boot) systemdExecutable extraSystemdUnitPaths;
     isExecutable = true;
     inherit (config.nix) readOnlyStore;
     inherit useHostResolvConf;
@@ -20,6 +20,10 @@ let
       pkgs.util-linux
     ] ++ lib.optional useHostResolvConf pkgs.openresolv);
     fsPackagesPath = lib.makeBinPath config.system.fsPackages;
+    systemdUnitPathEnvVar = lib.optionalString (config.boot.extraSystemdUnitPaths != [])
+      ("SYSTEMD_UNIT_PATH="
+      + builtins.concatStringsSep ":" config.boot.extraSystemdUnitPaths
+      + ":"); # If SYSTEMD_UNIT_PATH ends with an empty component (":"), the usual unit load path will be appended to the contents of the variable
     postBootCommands = pkgs.writeText "local-cmds"
       ''
         ${config.boot.postBootCommands}
@@ -82,6 +86,15 @@ in
           PATH.
         '';
       };
+
+      extraSystemdUnitPaths = mkOption {
+        default = [];
+        type = types.listOf types.str;
+        description = ''
+          Additional paths that get appended to the SYSTEMD_UNIT_PATH environment variable
+          that can contain mutable unit files.
+        '';
+      };
     };
 
   };
diff --git a/nixpkgs/nixos/modules/system/boot/systemd.nix b/nixpkgs/nixos/modules/system/boot/systemd.nix
index f5e6bd2903d0..484a455683aa 100644
--- a/nixpkgs/nixos/modules/system/boot/systemd.nix
+++ b/nixpkgs/nixos/modules/system/boot/systemd.nix
@@ -84,6 +84,7 @@ let
       # Kernel module loading.
       "systemd-modules-load.service"
       "kmod-static-nodes.service"
+      "modprobe@.service"
 
       # Filesystems.
       "systemd-fsck@.service"
@@ -175,8 +176,10 @@ let
       "timers.target.wants"
     ];
 
-  upstreamUserUnits =
-    [ "basic.target"
+    upstreamUserUnits = [
+      "app.slice"
+      "background.slice"
+      "basic.target"
       "bluetooth.target"
       "default.target"
       "exit.target"
@@ -184,6 +187,7 @@ let
       "graphical-session.target"
       "paths.target"
       "printer.target"
+      "session.slice"
       "shutdown.target"
       "smartcard.target"
       "sockets.target"
@@ -193,6 +197,7 @@ let
       "systemd-tmpfiles-clean.timer"
       "systemd-tmpfiles-setup.service"
       "timers.target"
+      "xdg-desktop-autostart.target"
     ];
 
   makeJobScript = name: text:
@@ -1185,9 +1190,12 @@ in
     systemd.services.systemd-remount-fs.unitConfig.ConditionVirtualization = "!container";
     systemd.services.systemd-random-seed.unitConfig.ConditionVirtualization = "!container";
 
-    boot.kernel.sysctl = mkIf (!cfg.coredump.enable) {
-      "kernel.core_pattern" = "core";
-    };
+    boot.kernel.sysctl."kernel.core_pattern" = mkIf (!cfg.coredump.enable) "core";
+
+    # Increase numeric PID range (set directly instead of copying a one-line file from systemd)
+    # https://github.com/systemd/systemd/pull/12226
+    boot.kernel.sysctl."kernel.pid_max" = mkIf pkgs.stdenv.is64bit (lib.mkDefault 4194304);
+
     boot.kernelParams = optional (!cfg.enableUnifiedCgroupHierarchy) "systemd.unified_cgroup_hierarchy=0";
   };