kernel development with nix
See also Kernel Debugging with QEMU.
This nix file should be placed in the root directory of kernel source code.
{ system ? builtins.currentSystem
, configuration ? null
, nixpkgs ? import <nixpkgs> { }
, extraConfigFile ? "config"
, ...
}@args:
with nixpkgs.pkgs;
let
buildLinuxArgs = builtins.removeAttrs args [
"system"
"configuration"
"nixpkgs"
"extraConfigFile"
];
makeKernelVersion = src:
stdenvNoCC.mkDerivation {
name = "my-kernel-version";
inherit src;
phases = "installPhase";
# make kernelversion also works.
installPhase = ''
set -x
s="$(< "$src/Makefile")"
get() {
awk "/^$1 = / "'{print $3}' <<< "$s"
}
printf '%s.%s.%s%s' "$(get VERSION)" "$(get PATCHLEVEL)" "$(get SUBLEVEL)" "$(get EXTRAVERSION)" | tee $out
'';
};
getKernelVersion = src: builtins.readFile "${makeKernelVersion src}";
kernelSrc =
let
filter = name: type:
let baseName = builtins.baseNameOf (builtins.toString name);
in
lib.cleanSourceFilter name type && !(baseName == ".ccls-cache"
|| baseName == extraConfigFile || lib.hasSuffix ".nix" baseName);
in
lib.cleanSourceWith {
inherit filter;
src = ./.;
};
kernelVersion = getKernelVersion kernelSrc;
latestConfigFile = linuxPackages_latest.kernel.configfile;
defaultConfigFile = (linuxConfig {
src = kernelSrc;
version = kernelVersion;
}).overrideAttrs ({ prePatch ? "", ... }: {
prePatch = linuxPackages_latest.kernel.prePatch + prePatch;
});
# We need to merge some `CONFIG_` to make qemu happy.
allConfigFiles =
let
p = "${builtins.toPath ./.}/${extraConfigFile}";
extraConfig = lib.optionals (builtins.pathExists p) [
"${builtins.path {
name = "extra-kernel-config";
path = p;
}}"
];
in
[ defaultConfigFile latestConfigFile ] ++ extraConfig;
mergedConfigFile = (stdenv.mkDerivation {
name = "merged-kernel-config";
src = kernelSrc;
phases = "unpackPhase prePatchPhase installPhase";
prePatchPhase = linuxPackages_latest.kernel.prePatch;
# make qemu happy with `CONFIG_EXPERIMENTAL=y`.
installPhase = ''
set -x
KCONFIG_CONFIG=$out RUNMAKE=false "$src/scripts/kconfig/merge_config.sh" ${
builtins.concatStringsSep " " allConfigFiles
}
grep -q '^CONFIG_EXPERIMENTAL=' $out && sed -i 's/^CONFIG_EXPERIMENTAL=.*/CONFIG_EXPERIMENTAL=y/' $out || echo 'CONFIG_EXPERIMENTAL=y' >> $out
'';
}).overrideAttrs ({ prePatch ? "", ... }: {
prePatch = linuxPackages_latest.kernel.prePatch + prePatch;
});
nixosConfiguration = { config, pkgs, ... }: {
imports = [ ] ++ lib.optionals (configuration != null) [ configuration ];
boot.kernelPackages =
# TODO: Does not work yet.
# buildLinux {
# src = kernelSrc;
# version = kernelVersion;
# };
linuxPackages_custom {
src = kernelSrc;
version = kernelVersion;
configfile = "${mergedConfigFile}";
};
environment = {
enableDebugInfo = true;
etc =
let
getHome = x: builtins.elemAt (builtins.split ":" x) 10;
entries = builtins.filter (x: x != "" && x != [ ])
(builtins.split "\n" (builtins.readFile /etc/passwd));
homes = builtins.map getHome entries;
currentFile = "${builtins.toPath ./.}";
possibleUserHomes =
builtins.filter (x: lib.hasPrefix x currentFile) homes;
keyFiles = builtins.filter (x: builtins.pathExists x)
(builtins.map (x: "${x}/.ssh/authorized_keys") possibleUserHomes);
keys = builtins.concatStringsSep "\n"
(builtins.map (x: builtins.readFile x) keyFiles);
in
lib.optionalAttrs (keys != "") {
"ssh/authorized_keys.d/root" = {
text = builtins.trace "Added the following keys for ssh access.\n${keys}\n" keys;
mode = "0444";
};
};
};
# Generate with mkpasswd -m sha-512 pwFuerRoot
users.users.root.initialHashedPassword = "$6$3zAawH1uhs$dlOiT.ckvpbBQ21tax1J4RI1EGm/1j1HDBoe5u1jy.gHw0QXCKA1dVEwKF.LD0bvzqBu4co.eaZCIK7b2E17k1";
services.sshd.enable = true;
};
nixos = import (nixpkgs.path + "/nixos/") {
inherit system;
configuration = nixosConfiguration;
};
in
nixos // {
inherit allConfigFiles defaultConfigFile latestConfigFile mergedConfigFile
kernelSrc;
}
To build a vm image, run it and connect to it with ssh
nix-build . -A vmWithBootLoader
QEMU_OPTS=-nographic QEMU_NET_OPTS="hostfwd=tcp::2222-:22" ./result/bin/run-*-vm # password is pwFuerRoot
ssh -p 2222 root@localhost
TODO:
- [] Incremental build