about summary refs log tree commit diff
path: root/nixpkgs/pkgs/os-specific/linux/kernel/manual-config.nix
diff options
context:
space:
mode:
Diffstat (limited to 'nixpkgs/pkgs/os-specific/linux/kernel/manual-config.nix')
-rw-r--r--nixpkgs/pkgs/os-specific/linux/kernel/manual-config.nix282
1 files changed, 282 insertions, 0 deletions
diff --git a/nixpkgs/pkgs/os-specific/linux/kernel/manual-config.nix b/nixpkgs/pkgs/os-specific/linux/kernel/manual-config.nix
new file mode 100644
index 000000000000..6adc3a33bb06
--- /dev/null
+++ b/nixpkgs/pkgs/os-specific/linux/kernel/manual-config.nix
@@ -0,0 +1,282 @@
+{ buildPackages, runCommand, nettools, bc, bison, flex, perl, rsync, gmp, libmpc, mpfr, openssl
+, libelf
+, utillinux
+, writeTextFile
+}:
+
+let
+  readConfig = configfile: import (runCommand "config.nix" {} ''
+    echo "{" > "$out"
+    while IFS='=' read key val; do
+      [ "x''${key#CONFIG_}" != "x$key" ] || continue
+      no_firstquote="''${val#\"}";
+      echo '  "'"$key"'" = "'"''${no_firstquote%\"}"'";' >> "$out"
+    done < "${configfile}"
+    echo "}" >> $out
+  '').outPath;
+in {
+  # Allow overriding stdenv on each buildLinux call
+  stdenv,
+  # The kernel version
+  version,
+  # The version of the kernel module directory
+  modDirVersion ? version,
+  # The kernel source (tarball, git checkout, etc.)
+  src,
+  # a list of { name=..., patch=..., extraConfig=...} patches
+  kernelPatches ? [],
+  # The kernel .config file
+  configfile,
+  # Manually specified nixexpr representing the config
+  # If unspecified, this will be autodetected from the .config
+  config ? stdenv.lib.optionalAttrs allowImportFromDerivation (readConfig configfile),
+  # Use defaultMeta // extraMeta
+  extraMeta ? {},
+  # Whether to utilize the controversial import-from-derivation feature to parse the config
+  allowImportFromDerivation ? false,
+  # ignored
+  features ? null,
+}:
+
+let
+  inherit (stdenv.lib)
+    hasAttr getAttr optional optionals optionalString optionalAttrs maintainers platforms;
+
+  # Dependencies that are required to build kernel modules
+  moduleBuildDependencies = optional (stdenv.lib.versionAtLeast version "4.14") libelf;
+
+  installkernel = writeTextFile { name = "installkernel"; executable=true; text = ''
+    #!${stdenv.shell} -e
+    mkdir -p $4
+    cp -av $2 $4
+    cp -av $3 $4
+  ''; };
+
+  commonMakeFlags = [
+    "O=$(buildRoot)"
+  ] ++ stdenv.lib.optionals (stdenv.hostPlatform.platform ? kernelMakeFlags)
+    stdenv.hostPlatform.platform.kernelMakeFlags;
+
+  drvAttrs = config_: platform: kernelPatches: configfile:
+    let
+      config = let attrName = attr: "CONFIG_" + attr; in {
+        isSet = attr: hasAttr (attrName attr) config;
+
+        getValue = attr: if config.isSet attr then getAttr (attrName attr) config else null;
+
+        isYes = attr: (config.getValue attr) == "y";
+
+        isNo = attr: (config.getValue attr) == "n";
+
+        isModule = attr: (config.getValue attr) == "m";
+
+        isEnabled = attr: (config.isModule attr) || (config.isYes attr);
+
+        isDisabled = attr: (!(config.isSet attr)) || (config.isNo attr);
+      } // config_;
+
+      isModular = config.isYes "MODULES";
+
+      installsFirmware = (config.isEnabled "FW_LOADER") &&
+        (isModular || (config.isDisabled "FIRMWARE_IN_KERNEL")) &&
+        (stdenv.lib.versionOlder version "4.14");
+    in (optionalAttrs isModular { outputs = [ "out" "dev" ]; }) // {
+      passthru = {
+        inherit version modDirVersion config kernelPatches configfile
+          moduleBuildDependencies stdenv;
+      };
+
+      inherit src;
+
+      patches = map (p: p.patch) kernelPatches;
+
+      prePatch = ''
+        for mf in $(find -name Makefile -o -name Makefile.include -o -name install.sh); do
+            echo "stripping FHS paths in \`$mf'..."
+            sed -i "$mf" -e 's|/usr/bin/||g ; s|/bin/||g ; s|/sbin/||g'
+        done
+        sed -i Makefile -e 's|= depmod|= ${buildPackages.kmod}/bin/depmod|'
+        sed -i scripts/ld-version.sh -e "s|/usr/bin/awk|${buildPackages.gawk}/bin/awk|"
+      '';
+
+      configurePhase = ''
+        runHook preConfigure
+
+        mkdir build
+        export buildRoot="$(pwd)/build"
+
+        echo "manual-config configurePhase buildRoot=$buildRoot pwd=$PWD"
+
+        if [ -f "$buildRoot/.config" ]; then
+          echo "Could not link $buildRoot/.config : file exists"
+          exit 1
+        fi
+        ln -sv ${configfile} $buildRoot/.config
+
+        # reads the existing .config file and prompts the user for options in
+        # the current kernel source that are not found in the file.
+        make $makeFlags "''${makeFlagsArray[@]}" oldconfig
+        runHook postConfigure
+
+        make $makeFlags "''${makeFlagsArray[@]}" prepare
+        actualModDirVersion="$(cat $buildRoot/include/config/kernel.release)"
+        if [ "$actualModDirVersion" != "${modDirVersion}" ]; then
+          echo "Error: modDirVersion ${modDirVersion} specified in the Nix expression is wrong, it should be: $actualModDirVersion"
+          exit 1
+        fi
+
+        # Note: we can get rid of this once http://permalink.gmane.org/gmane.linux.kbuild.devel/13800 is merged.
+        buildFlagsArray+=("KBUILD_BUILD_TIMESTAMP=$(date -u -d @$SOURCE_DATE_EPOCH)")
+
+        cd $buildRoot
+      '';
+
+      buildFlags = [
+        "KBUILD_BUILD_VERSION=1-NixOS"
+        platform.kernelTarget
+        "vmlinux"  # for "perf" and things like that
+      ] ++ optional isModular "modules";
+
+      installFlags = [
+        "INSTALLKERNEL=${installkernel}"
+        "INSTALL_PATH=$(out)"
+      ] ++ (optional isModular "INSTALL_MOD_PATH=$(out)")
+      ++ optional installsFirmware "INSTALL_FW_PATH=$(out)/lib/firmware";
+
+      # Some image types need special install targets (e.g. uImage is installed with make uinstall)
+      installTargets = [ (
+        if platform ? kernelInstallTarget then platform.kernelInstallTarget
+        else if platform.kernelTarget == "uImage" then "uinstall"
+        else if platform.kernelTarget == "zImage" || platform.kernelTarget == "Image.gz" then "zinstall"
+        else "install"
+      ) ];
+
+      postInstall = (optionalString installsFirmware ''
+        mkdir -p $out/lib/firmware
+      '') + (if (platform ? kernelDTB && platform.kernelDTB) then ''
+        make $makeFlags "''${makeFlagsArray[@]}" dtbs dtbs_install INSTALL_DTBS_PATH=$out/dtbs
+      '' else "") + (if isModular then ''
+        mkdir -p $dev
+        cp vmlinux $dev/
+        if [ -z "$dontStrip" ]; then
+          installFlagsArray+=("INSTALL_MOD_STRIP=1")
+        fi
+        make modules_install $makeFlags "''${makeFlagsArray[@]}" \
+          $installFlags "''${installFlagsArray[@]}"
+        unlink $out/lib/modules/${modDirVersion}/build
+        unlink $out/lib/modules/${modDirVersion}/source
+
+        mkdir -p $dev/lib/modules/${modDirVersion}/{build,source}
+
+        # To save space, exclude a bunch of unneeded stuff when copying.
+        (cd .. && rsync --archive --prune-empty-dirs \
+            --exclude='/build/' \
+            --exclude='/Documentation/' \
+            * $dev/lib/modules/${modDirVersion}/source/)
+
+        cd $dev/lib/modules/${modDirVersion}/source
+
+        cp $buildRoot/{.config,Module.symvers} $dev/lib/modules/${modDirVersion}/build
+        make modules_prepare $makeFlags "''${makeFlagsArray[@]}" O=$dev/lib/modules/${modDirVersion}/build
+
+        # Keep some extra files on some arches (powerpc, aarch64)
+        for f in arch/powerpc/lib/crtsavres.o arch/arm64/kernel/ftrace-mod.o; do
+          if [ -f "$buildRoot/$f" ]; then
+            cp $buildRoot/$f $dev/lib/modules/${modDirVersion}/build/$f
+          fi
+        done
+
+        # !!! No documentation on how much of the source tree must be kept
+        # If/when kernel builds fail due to missing files, you can add
+        # them here. Note that we may see packages requiring headers
+        # from drivers/ in the future; it adds 50M to keep all of its
+        # headers on 3.10 though.
+
+        chmod u+w -R ..
+        arch=$(cd $dev/lib/modules/${modDirVersion}/build/arch; ls)
+
+        # Remove unused arches
+        for d in $(cd arch/; ls); do
+          if [ "$d" = "$arch" ]; then continue; fi
+          if [ "$arch" = arm64 ] && [ "$d" = arm ]; then continue; fi
+          rm -rf arch/$d
+        done
+
+        # Remove all driver-specific code (50M of which is headers)
+        rm -fR drivers
+
+        # Keep all headers
+        find .  -type f -name '*.h' -print0 | xargs -0 chmod u-w
+
+        # Keep linker scripts (they are required for out-of-tree modules on aarch64)
+        find .  -type f -name '*.lds' -print0 | xargs -0 chmod u-w
+
+        # Keep root and arch-specific Makefiles
+        chmod u-w Makefile
+        chmod u-w arch/$arch/Makefile*
+
+        # Keep whole scripts dir
+        chmod u-w -R scripts
+
+        # Delete everything not kept
+        find . -type f -perm -u=w -print0 | xargs -0 rm
+
+        # Delete empty directories
+        find -empty -type d -delete
+
+        # Remove reference to kmod
+        sed -i Makefile -e 's|= ${buildPackages.kmod}/bin/depmod|= depmod|'
+      '' else optionalString installsFirmware ''
+        make firmware_install $makeFlags "''${makeFlagsArray[@]}" \
+          $installFlags "''${installFlagsArray[@]}"
+      '');
+
+      requiredSystemFeatures = [ "big-parallel" ];
+
+      meta = {
+        description =
+          "The Linux kernel" +
+          (if kernelPatches == [] then "" else
+            " (with patches: "
+            + stdenv.lib.concatStringsSep ", " (map (x: x.name) kernelPatches)
+            + ")");
+        license = stdenv.lib.licenses.gpl2;
+        homepage = https://www.kernel.org/;
+        repositories.git = https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git;
+        maintainers = [
+          maintainers.thoughtpolice
+        ];
+        platforms = platforms.linux;
+        timeout = 14400; # 4 hours
+      } // extraMeta;
+    };
+in
+
+assert stdenv.lib.versionAtLeast version "4.14" -> libelf != null;
+assert stdenv.lib.versionAtLeast version "4.15" -> utillinux != null;
+stdenv.mkDerivation ((drvAttrs config stdenv.hostPlatform.platform kernelPatches configfile) // {
+  name = "linux-${version}";
+
+  enableParallelBuilding = true;
+
+  depsBuildBuild = [ buildPackages.stdenv.cc ];
+  nativeBuildInputs = [ perl bc nettools openssl rsync gmp libmpc mpfr ]
+      ++ optional (stdenv.hostPlatform.platform.kernelTarget == "uImage") buildPackages.ubootTools
+      ++ optional (stdenv.lib.versionAtLeast version "4.14") libelf
+      ++ optional (stdenv.lib.versionAtLeast version "4.15") utillinux
+      ++ optionals (stdenv.lib.versionAtLeast version "4.16") [ bison flex ]
+      ;
+
+  hardeningDisable = [ "bindnow" "format" "fortify" "stackprotector" "pic" "pie" ];
+
+  # Absolute paths for compilers avoid any PATH-clobbering issues.
+  makeFlags = commonMakeFlags ++ [
+    "CC=${stdenv.cc}/bin/${stdenv.cc.targetPrefix}cc"
+    "HOSTCC=${buildPackages.stdenv.cc}/bin/${buildPackages.stdenv.cc.targetPrefix}cc"
+    "ARCH=${stdenv.hostPlatform.platform.kernelArch}"
+  ] ++ stdenv.lib.optional (stdenv.hostPlatform != stdenv.buildPlatform) [
+    "CROSS_COMPILE=${stdenv.cc.targetPrefix}"
+  ];
+
+  karch = stdenv.hostPlatform.platform.kernelArch;
+})