about summary refs log tree commit diff
path: root/pkgs/build-support/kernel
diff options
context:
space:
mode:
authorLinus Heckemann <git@sphalerite.org>2020-09-04 18:18:32 +0200
committerLinus Heckemann <git@sphalerite.org>2020-12-17 11:37:04 +0100
commit14fbf575ecd47451dc1b2b3122f56ce8ac670030 (patch)
tree949750beda5e2f4dcfccd76410caf3792a66e8b0 /pkgs/build-support/kernel
parent2ee35e1fcecdae598651fd9b1452f451ac221384 (diff)
make-initrd: various improvements
- Generate a link to the initramfs file with an appropriate file
  extension, guessed based on the compressor by default
- Use correct metadata in u-boot images if generated, up to now this
  was hardcoded to gzip and would silently generate an erroneous image
  if another compressor was specified
- Document all the parameters
- Improve cross-building compatibility, by allowing passing either a
  string as before, or a function taking a package set and returning the
  path to a compressor in the "compressor" argument of the
  function.
- Support more compression algorithms
- Place compressor executable function and arguments in passthru, for
  reuse when appending initramfses

Co-Authored-By: Dominik Xaver Hörl <hoe.dom@gmx.de>
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.nix91
-rw-r--r--pkgs/build-support/kernel/make-initrd.sh9
3 files changed, 135 insertions, 18 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 0000000000000..443e599a239e5
--- /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 f0a61d3476e82..901eb311a883f 100644
--- a/pkgs/build-support/kernel/make-initrd.nix
+++ b/pkgs/build-support/kernel/make-initrd.nix
@@ -1,24 +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.platform.kernelTarget == "uImage"
-, uInitrdArch ? stdenvNoCC.hostPlatform.parsed.cpu.family
+
+# 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.kernelArch
+
+# 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
@@ -26,13 +76,26 @@ let
     lib.concatStringsSep "-" (filter (x: !(isList x)) (split "[^a-zA-Z0-9_=.?-]+" x));
 
 in stdenvNoCC.mkDerivation rec {
-  inherit name makeUInitrd uInitrdArch;
+  inherit name makeUInitrd extension uInitrdArch prepend;
+
+  ${if makeUInitrd then "uinitrdCompression" else null} = uInitrdCompression;
 
   builder = ./make-initrd.sh;
 
   nativeBuildInputs = [ perl cpio ]
     ++ stdenvNoCC.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;
   symlinks = map (x: x.symlink) 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 8243736ba4677..c0619ef14ae01 100644
--- a/pkgs/build-support/kernel/make-initrd.sh
+++ b/pkgs/build-support/kernel/make-initrd.sh
@@ -40,9 +40,12 @@ for PREP in $prepend; do
   cat $PREP >> $out/initrd
 done
 (cd root && find * .[^.*] -exec 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 * .[^.*] -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 $uInitrdArch -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