summary refs log tree commit diff
path: root/pkgs/build-support/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'pkgs/build-support/kernel')
-rw-r--r--pkgs/build-support/kernel/initrd-compressor-meta.nix53
-rw-r--r--pkgs/build-support/kernel/make-initrd.nix95
-rw-r--r--pkgs/build-support/kernel/make-initrd.sh11
-rw-r--r--pkgs/build-support/kernel/modules-closure.sh15
4 files changed, 151 insertions, 23 deletions
diff --git a/pkgs/build-support/kernel/initrd-compressor-meta.nix b/pkgs/build-support/kernel/initrd-compressor-meta.nix
new file mode 100644
index 00000000000..443e599a239
--- /dev/null
+++ b/pkgs/build-support/kernel/initrd-compressor-meta.nix
@@ -0,0 +1,53 @@
+rec {
+  cat = {
+    executable = pkgs: "cat";
+    ubootName = "none";
+    extension = ".cpio";
+  };
+  gzip = {
+    executable = pkgs: "${pkgs.gzip}/bin/gzip";
+    defaultArgs = ["-9n"];
+    ubootName = "gzip";
+    extension = ".gz";
+  };
+  bzip2 = {
+    executable = pkgs: "${pkgs.bzip2}/bin/bzip2";
+    ubootName = "bzip2";
+    extension = ".bz2";
+  };
+  xz = {
+    executable = pkgs: "${pkgs.xz}/bin/xz";
+    defaultArgs = ["--check=crc32" "--lzma2=dict=512KiB"];
+    extension = ".xz";
+  };
+  lzma = {
+    executable = pkgs: "${pkgs.xz}/bin/lzma";
+    defaultArgs = ["--check=crc32" "--lzma1=dict=512KiB"];
+    ubootName = "lzma";
+    extension = ".lzma";
+  };
+  lz4 = {
+    executable = pkgs: "${pkgs.lz4}/bin/lz4";
+    defaultArgs = ["-l"];
+    ubootName = "lz4";
+    extension = ".lz4";
+  };
+  lzop = {
+    executable = pkgs: "${pkgs.lzop}/bin/lzop";
+    ubootName = "lzo";
+    extension = ".lzo";
+  };
+  zstd = {
+    executable = pkgs: "${pkgs.zstd}/bin/zstd";
+    defaultArgs = ["-10"];
+    ubootName = "zstd";
+    extension = ".zst";
+  };
+  pigz = gzip // {
+    executable = pkgs: "${pkgs.pigz}/bin/pigz";
+  };
+  pixz = xz // {
+    executable = pkgs: "${pkgs.pixz}/bin/pixz";
+    defaultArgs = [];
+  };
+}
diff --git a/pkgs/build-support/kernel/make-initrd.nix b/pkgs/build-support/kernel/make-initrd.nix
index ed5dbdaee17..83d3bb65bae 100644
--- a/pkgs/build-support/kernel/make-initrd.nix
+++ b/pkgs/build-support/kernel/make-initrd.nix
@@ -1,22 +1,74 @@
-# Create an initial ramdisk containing the closure of the specified
-# file system objects.  An initial ramdisk is used during the initial
+# Create an initramfs containing the closure of the specified
+# file system objects.  An initramfs is used during the initial
 # stages of booting a Linux system.  It is loaded by the boot loader
 # along with the kernel image.  It's supposed to contain everything
 # (such as kernel modules) necessary to allow us to mount the root
 # file system.  Once the root file system is mounted, the `real' boot
 # script can be called.
 #
-# An initrd is really just a gzipped cpio archive.
-#
-# Symlinks are created for each top-level file system object.  E.g.,
-# `contents = {object = ...; symlink = /init;}' is a typical
-# argument.
-
-{ stdenvNoCC, perl, cpio, contents, ubootTools
+# An initramfs is a cpio archive, and may be compressed with a number
+# of algorithms.
+let
+  # Some metadata on various compression programs, relevant to naming
+  # the initramfs file and, if applicable, generating a u-boot image
+  # from it.
+  compressors = import ./initrd-compressor-meta.nix;
+  # Get the basename of the actual compression program from the whole
+  # compression command, for the purpose of guessing the u-boot
+  # compression type and filename extension.
+  compressorName = fullCommand: builtins.elemAt (builtins.match "([^ ]*/)?([^ ]+).*" fullCommand) 1;
+in
+{ stdenvNoCC, perl, cpio, ubootTools, lib, pkgsBuildHost
+# Name of the derivation (not of the resulting file!)
 , name ? "initrd"
-, compressor ? "gzip -9n"
+
+# Program used to compress the cpio archive; use "cat" for no compression.
+# This can also be a function which takes a package set and returns the path to the compressor,
+# such as `pkgs: "${pkgs.lzop}/bin/lzop"`.
+, compressor ? "gzip"
+, _compressorFunction ?
+  if lib.isFunction compressor then compressor
+  else if ! builtins.hasContext compressor && builtins.hasAttr compressor compressors then compressors.${compressor}.executable
+  else _: compressor
+, _compressorExecutable ? _compressorFunction pkgsBuildHost
+, _compressorName ? compressorName _compressorExecutable
+, _compressorMeta ? compressors.${_compressorName} or {}
+
+# List of arguments to pass to the compressor program, or null to use its defaults
+, compressorArgs ? null
+, _compressorArgsReal ? if compressorArgs == null then _compressorMeta.defaultArgs or [] else compressorArgs
+
+# Filename extension to use for the compressed initramfs. This is
+# included for clarity, but $out/initrd will always be a symlink to
+# the final image.
+# If this isn't guessed, you may want to complete the metadata above and send a PR :)
+, extension ? _compressorMeta.extension or
+    (throw "Unrecognised compressor ${_compressorName}, please specify filename extension")
+
+# List of { object = path_or_derivation; symlink = "/path"; }
+# The paths are copied into the initramfs in their nix store path
+# form, then linked at the root according to `symlink`.
+, contents
+
+# List of uncompressed cpio files to prepend to the initramfs. This
+# can be used to add files in specified paths without them becoming
+# symlinks to store paths.
 , prepend ? []
-, lib
+
+# Whether to wrap the initramfs in a u-boot image.
+, makeUInitrd ? stdenvNoCC.hostPlatform.linux-kernel.target == "uImage"
+
+# If generating a u-boot image, the architecture to use. The default
+# guess may not align with u-boot's nomenclature correctly, so it can
+# be overridden.
+# See https://gitlab.denx.de/u-boot/u-boot/-/blob/9bfb567e5f1bfe7de8eb41f8c6d00f49d2b9a426/common/image.c#L81-106 for a list.
+, uInitrdArch ? stdenvNoCC.hostPlatform.linuxArch
+
+# The name of the compression, as recognised by u-boot.
+# See https://gitlab.denx.de/u-boot/u-boot/-/blob/9bfb567e5f1bfe7de8eb41f8c6d00f49d2b9a426/common/image.c#L195-204 for a list.
+# If this isn't guessed, you may want to complete the metadata above and send a PR :)
+, uInitrdCompression ? _compressorMeta.ubootName or
+    (throw "Unrecognised compressor ${_compressorName}, please specify uInitrdCompression")
 }:
 let
   # !!! Move this into a public lib function, it is probably useful for others
@@ -24,14 +76,25 @@ let
     lib.concatStringsSep "-" (filter (x: !(isList x)) (split "[^a-zA-Z0-9_=.?-]+" x));
 
 in stdenvNoCC.mkDerivation rec {
-  inherit name;
+  inherit name makeUInitrd extension uInitrdArch prepend;
 
-  builder = ./make-initrd.sh;
+  ${if makeUInitrd then "uinitrdCompression" else null} = uInitrdCompression;
 
-  makeUInitrd = stdenvNoCC.hostPlatform.platform.kernelTarget == "uImage";
+  builder = ./make-initrd.sh;
 
   nativeBuildInputs = [ perl cpio ]
-    ++ stdenvNoCC.lib.optional makeUInitrd ubootTools;
+    ++ lib.optional makeUInitrd ubootTools;
+
+  compress = "${_compressorExecutable} ${lib.escapeShellArgs _compressorArgsReal}";
+
+  # Pass the function through, for reuse in append-initrd-secrets. The
+  # function is used instead of the string, in order to support
+  # cross-compilation (append-initrd-secrets running on a different
+  # architecture than what the main initramfs is built on).
+  passthru = {
+    compressorExecutableFunction = _compressorFunction;
+    compressorArgs = _compressorArgsReal;
+  };
 
   # !!! should use XML.
   objects = map (x: x.object) contents;
@@ -47,6 +110,4 @@ in stdenvNoCC.mkDerivation rec {
       contents
       (lib.range 0 (lib.length contents - 1));
   pathsFromGraph = ./paths-from-graph.pl;
-
-  inherit compressor prepend;
 }
diff --git a/pkgs/build-support/kernel/make-initrd.sh b/pkgs/build-support/kernel/make-initrd.sh
index 0aeaedeb372..c0619ef14ae 100644
--- a/pkgs/build-support/kernel/make-initrd.sh
+++ b/pkgs/build-support/kernel/make-initrd.sh
@@ -39,10 +39,13 @@ mkdir -p $out
 for PREP in $prepend; do
   cat $PREP >> $out/initrd
 done
-(cd root && find * -print0 | xargs -0r touch -h -d '@1')
-(cd root && find * -print0 | sort -z | cpio -o -H newc -R +0:+0 --reproducible --null | $compressor >> $out/initrd)
+(cd root && find * .[^.*] -exec touch -h -d '@1' '{}' +)
+(cd root && find * .[^.*] -print0 | sort -z | cpio -o -H newc -R +0:+0 --reproducible --null | eval -- $compress >> "$out/initrd")
 
 if [ -n "$makeUInitrd" ]; then
-    mv $out/initrd $out/initrd.gz
-    mkimage -A arm -O linux -T ramdisk -C gzip -d $out/initrd.gz $out/initrd
+    mkimage -A $uInitrdArch -O linux -T ramdisk -C "$uInitrdCompression" -d $out/initrd"$extension" $out/initrd.img
+    # Compatibility symlink
+    ln -s "initrd.img" "$out/initrd"
+else
+    ln -s "initrd" "$out/initrd$extension"
 fi
diff --git a/pkgs/build-support/kernel/modules-closure.sh b/pkgs/build-support/kernel/modules-closure.sh
index 68d840f1614..3b3a38ea1d3 100644
--- a/pkgs/build-support/kernel/modules-closure.sh
+++ b/pkgs/build-support/kernel/modules-closure.sh
@@ -68,10 +68,21 @@ done
 
 mkdir -p $out/lib/firmware
 for module in $(cat closure); do
-    for i in $(modinfo -F firmware $module); do
+    # for builtin modules, modinfo will reply with a wrong output looking like:
+    #   $ modinfo -F firmware unix
+    #   name:           unix
+    #
+    # There is a pending attempt to fix this:
+    #   https://github.com/NixOS/nixpkgs/pull/96153
+    #   https://lore.kernel.org/linux-modules/20200823215433.j5gc5rnsmahpf43v@blumerang/T/#u
+    #
+    # For now, the workaround is just to filter out the extraneous lines out
+    # of its output.
+    for i in $(modinfo -b $kernel --set-version "$version" -F firmware $module | grep -v '^name:'); do
         mkdir -p "$out/lib/firmware/$(dirname "$i")"
         echo "firmware for $module: $i"
-        cp "$firmware/lib/firmware/$i" "$out/lib/firmware/$i" 2>/dev/null || if test -z "$allowMissing"; then exit 1; fi
+        cp "$firmware/lib/firmware/$i" "$out/lib/firmware/$i" 2>/dev/null \
+            || echo "WARNING: missing firmware $i for module $module"
     done
 done