nixpkgs-suyu/doc/packages/linux.section.md
DS 1d7ee9ff09 doc: consolidate info on manual linux kernel configs
The Nixpkgs documentation on the linux kernel builders focused on
using and extending kernels that were already packaged, but never
mentioned that it's possible to also build a kernel almost "from
scratch".
The NixOS documentation went a bit deeper on manual linux kernel
configs, but that information wasn't particularly NixOS-specific.

This commit consolidates the information related to building the
kernel on Nixpkgs's documentation, while keeping any additional
NixOS-specific information on NixOS's documentation.

An additional README.md was created for contributor-facing
documentation.
2023-11-23 08:50:16 -08:00

5.6 KiB
Raw Blame History

Linux kernel

The Nix expressions to build the Linux kernel are in pkgs/os-specific/linux/kernel.

The function pkgs.buildLinux builds a kernel with common configuration values. This is the preferred option unless you have a very specific use case. Most kernels packaged in Nixpkgs are built that way, and it will also generate kernels suitable for NixOS. pkgs.linuxManualConfig requires a complete configuration to be passed. It has fewer additional features than pkgs.buildLinux, which provides common configuration values and exposes the features attribute, as explained below.

Both functions have an argument kernelPatches which should be a list of {name, patch, extraConfig} attribute sets, where name is the name of the patch (which is included in the kernels meta.description attribute), patch is the patch itself (possibly compressed), and extraConfig (optional) is a string specifying extra options to be concatenated to the kernel configuration file (.config).

The kernel derivation created with pkgs.buildLinux exports an attribute features specifying whether optional functionality is or isnt enabled. This is used in NixOS to implement kernel-specific behaviour.

:::{.example #ex-skip-package-from-kernel-feature}

Skipping an external package because of a kernel feature

For instance, if the kernel has the iwlwifi feature (i.e., has built-in support for Intel wireless chipsets), then NixOS doesnt have to build the external iwlwifi package:

modulesTree = [kernel]
  ++ pkgs.lib.optional (!kernel.features ? iwlwifi) kernelPackages.iwlwifi
  ++ ...;

:::

If you are using a kernel packaged in Nixpkgs, you can customize it by overriding its arguments. For details on how each argument affects the generated kernel, refer to the pkgs.buildLinux source code.

:::{.example #ex-overriding-kernel-derivation}

Overriding the kernel derivation

Assuming you are using the kernel from pkgs.linux_latest:

pkgs.linux_latest.override {
  ignoreConfigErrors = true;
  autoModules = false;
  kernelPreferBuiltin = true;
  extraStructuredConfig = with lib.kernel; {
    DEBUG_KERNEL = yes;
    FRAME_POINTER = yes;
    KGDB = yes;
    KGDB_SERIAL_CONSOLE = yes;
    DEBUG_INFO = yes;
  };
}

:::

Manual kernel configuration

Sometimes it may not be desirable to use kernels built with pkgs.buildLinux, especially if most of the common configuration has to be altered or disabled to achieve a kernel as expected by the target use case. An example of this is building a kernel for use in a VM or micro VM. You can use pkgs.linuxManualConfig in these cases. It requires the src, version, and configfile attributes to be specified.

:::{.example #ex-using-linux-manual-config}

Using pkgs.linuxManualConfig with a specific source, version, and config file

{ pkgs, ... }: {
  version = "6.1.55";
  src = pkgs.fetchurl {
    url = "https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-${version}.tar.xz";
    hash = "sha256:1h0mzx52q9pvdv7rhnvb8g68i7bnlc9rf8gy9qn4alsxq4g28zm8";
  };
  configfile = ./path_to_config_file;
  linux = pkgs.linuxManualConfig {
    inherit version src configfile;
    allowImportFromDerivation = true;
  };
}

If necessary, the version string can be slightly modified to explicitly mark it as a custom version. If you do so, ensure the modDirVersion attribute matches the source's version, otherwise the build will fail.

{ pkgs, ... }: {
  version = "6.1.55-custom";
  modDirVersion = "6.1.55";
  src = pkgs.fetchurl {
    url = "https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-${modDirVersion}.tar.xz";
    hash = "sha256:1h0mzx52q9pvdv7rhnvb8g68i7bnlc9rf8gy9qn4alsxq4g28zm8";
  };
  configfile = ./path_to_config_file;
  linux = pkgs.linuxManualConfig {
    inherit version modDirVersion src configfile;
    allowImportFromDerivation = true;
  };
}

:::

Additional attributes can be used with linuxManualConfig for further customisation. You're encouraged to read the pkgs.linuxManualConfig source code to understand how to use them.

To edit the .config file for Linux X.Y from within Nix, proceed as follows:

$ nix-shell '<nixpkgs>' -A linuxKernel.kernels.linux_X_Y.configEnv
$ unpackPhase
$ cd linux-*
$ make nconfig

Developing kernel modules

When developing kernel modules it's often convenient to run the edit-compile-run loop as quickly as possible. See the snippet below as an example.

:::{.example #ex-edit-compile-run-kernel-modules}

Edit-compile-run loop when developing mellanox drivers

$ nix-build '<nixpkgs>' -A linuxPackages.kernel.dev
$ nix-shell '<nixpkgs>' -A linuxPackages.kernel
$ unpackPhase
$ cd linux-*
$ make -C $dev/lib/modules/*/build M=$(pwd)/drivers/net/ethernet/mellanox modules
# insmod ./drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.ko

:::