From a8bc568d2497b5287afe6a45da79c080662fa8b9 Mon Sep 17 00:00:00 2001 From: DS Date: Mon, 23 Oct 2023 19:37:04 -0700 Subject: [PATCH] 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. --- doc/builders/packages/linux.section.md | 116 +++++++++++++++--- .../configuration/linux-kernel.chapter.md | 66 +--------- pkgs/os-specific/linux/kernel/README.md | 27 ++++ 3 files changed, 128 insertions(+), 81 deletions(-) create mode 100644 pkgs/os-specific/linux/kernel/README.md diff --git a/doc/builders/packages/linux.section.md b/doc/builders/packages/linux.section.md index b64da85791a0d95..f2f66098a472cd5 100644 --- a/doc/builders/packages/linux.section.md +++ b/doc/builders/packages/linux.section.md @@ -2,9 +2,20 @@ The Nix expressions to build the Linux kernel are in [`pkgs/os-specific/linux/kernel`](https://github.com/NixOS/nixpkgs/blob/master/pkgs/os-specific/linux/kernel). -The function that builds the kernel has 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 kernel’s `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 function [`pkgs.buildLinux`](https://github.com/NixOS/nixpkgs/blob/f9d4f5f23ce7ccb7ad91d6d2150e367baf7014f6/pkgs/os-specific/linux/kernel/generic.nix) builds a kernel with [common configuration values](hthttps://github.com/NixOS/nixpkgs/blob/f9d4f5f23ce7ccb7ad91d6d2150e367baf7014f6/pkgs/os-specific/linux/kernel/common-config.nix). +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`](https://github.com/NixOS/nixpkgs/blob/f9d4f5f23ce7ccb7ad91d6d2150e367baf7014f6/pkgs/os-specific/linux/kernel/manual-config.nix) requires a complete configuration to be passed, and has less additional features than `pkgs.buildLinux`, such as the use of common configuration values and exposing the `features` attribute, as explained below. -The kernel derivation exports an attribute `features` specifying whether optional functionality is or isn’t enabled. This is used in NixOS to implement kernel-specific behaviour. For instance, if the kernel has the `iwlwifi` feature (i.e., has built-in support for Intel wireless chipsets), then NixOS doesn’t have to build the external `iwlwifi` package: +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 kernel’s `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 isn’t 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 doesn’t have to build the external `iwlwifi` package: ```nix modulesTree = [kernel] @@ -12,30 +23,99 @@ modulesTree = [kernel] ++ ...; ``` -How to add a new (major) version of the Linux kernel to Nixpkgs: +::: -1. Copy the old Nix expression (e.g., `linux-2.6.21.nix`) to the new one (e.g., `linux-2.6.22.nix`) and update it. +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 source](https://github.com/NixOS/nixpkgs/blob/f9d4f5f23ce7ccb7ad91d6d2150e367baf7014f6/pkgs/os-specific/linux/kernel/generic.nix) for `pkgs.buildLinux`. -2. Add the new kernel to the `kernels` attribute set in `linux-kernels.nix` (e.g., create an attribute `kernel_2_6_22`). +:::{.example #ex-overriding-kernel-derivation} -3. Now we’re going to update the kernel configuration. First unpack the kernel. Then for each supported platform (`i686`, `x86_64`, `uml`) do the following: +# Overriding the kernel derivation - 1. Make a copy from the old config (e.g., `config-2.6.21-i686-smp`) to the new one (e.g., `config-2.6.22-i686-smp`). +Assuming you are using the kernel from `pkgs.linux_latest`: - 2. Copy the config file for this platform (e.g., `config-2.6.22-i686-smp`) to `.config` in the kernel source tree. +```nix +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; + }; +} +``` - 3. Run `make oldconfig ARCH={i386,x86_64,um}` and answer all questions. (For the uml configuration, also add `SHELL=bash`.) Make sure to keep the configuration consistent between platforms (i.e., don’t enable some feature on `i686` and disable it on `x86_64`). +::: - 4. If needed, you can also run `make menuconfig`: +## Manual kernel configuration {#sec-manual-kernel-configuration} - ```ShellSession - $ nix-env -f "" -iA ncurses - $ export NIX_CFLAGS_LINK=-lncurses - $ make menuconfig ARCH=arch - ``` +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. - 5. Copy `.config` over the new config file (e.g., `config-2.6.22-i686-smp`). +:::{.example #ex-using-linux-manual-config} -4. Test building the kernel: `nix-build -A linuxKernel.kernels.kernel_2_6_22`. If it compiles, ship it! For extra credit, try booting NixOS with it. +# Using `pkgs.linuxManualConfig` with a specific source, version, and config file -5. It may be that the new kernel requires updating the external kernel modules and kernel-dependent packages listed in the `linuxPackagesFor` function in `linux-kernels.nix` (such as the NVIDIA drivers, AUFS, etc.). If the updated packages aren’t backwards compatible with older kernels, you may need to keep the older versions around. +```nix +{ 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. + +```nix +{ 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 [`pkgs/os-specific/linux/kernel/manual-config.nix`](https://github.com/NixOS/nixpkgs/blob/master/pkgs/os-specific/linux/kernel/manual-config.nix) to understand how to use them. + +To edit the `.config` file for Linux X.Y, proceed as follows: + +```ShellSession +$ nix-shell '' -A linuxKernel.kernels.linux_X_Y.configEnv +$ unpackPhase +$ cd linux-* +$ make nconfig +``` + +## Developing kernel modules {#sec-linux-kernel-developing-modules} + +When developing kernel modules it's often convenient to run +edit-compile-run loop as quickly as possible. See below snippet as an +example of developing `mellanox` drivers. + +```ShellSession +$ nix-build '' -A linuxPackages.kernel.dev +$ nix-shell '' -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 +``` diff --git a/nixos/doc/manual/configuration/linux-kernel.chapter.md b/nixos/doc/manual/configuration/linux-kernel.chapter.md index f5bce99dd1bbea1..2f458a5dc68040c 100644 --- a/nixos/doc/manual/configuration/linux-kernel.chapter.md +++ b/nixos/doc/manual/configuration/linux-kernel.chapter.md @@ -84,26 +84,7 @@ available parameters, run `sysctl -a`. ## Building a custom kernel {#sec-linux-config-customizing} -You can customize the default kernel configuration by overriding the arguments for your kernel package: - -```nix -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; - }; -} -``` - -See `pkgs/os-specific/linux/kernel/generic.nix` for details on how these arguments -affect the generated configuration. You can also build a custom version of Linux by calling -`pkgs.buildLinux` directly, which requires the `src` and `version` arguments to be specified. +Refer to the Nixpkgs manual for the various ways of [building a custom kernel](https://nixos.org/nixpkgs/manual#sec-linux-kernel). To use your custom kernel package in your NixOS configuration, set @@ -111,50 +92,9 @@ To use your custom kernel package in your NixOS configuration, set boot.kernelPackages = pkgs.linuxPackagesFor yourCustomKernel; ``` -Note that this method will use the common configuration defined in `pkgs/os-specific/linux/kernel/common-config.nix`, -which is suitable for a NixOS system. - -If you already have a generated configuration file, you can build a kernel that uses it with `pkgs.linuxManualConfig`: - -```nix -let - baseKernel = pkgs.linux_latest; -in pkgs.linuxManualConfig { - inherit (baseKernel) src modDirVersion; - version = "${baseKernel.version}-custom"; - configfile = ./my_kernel_config; - allowImportFromDerivation = true; -} -``` - -::: {.note} -The build will fail if `modDirVersion` does not match the source's `kernel.release` file, -so `modDirVersion` should remain tied to `src`. -::: - -To edit the `.config` file for Linux X.Y, proceed as follows: - -```ShellSession -$ nix-shell '' -A linuxKernel.kernels.linux_X_Y.configEnv -$ unpackPhase -$ cd linux-* -$ make nconfig -``` - ## Developing kernel modules {#sec-linux-config-developing-modules} -When developing kernel modules it's often convenient to run -edit-compile-run loop as quickly as possible. See below snippet as an -example of developing `mellanox` drivers. - -```ShellSession -$ nix-build '' -A linuxPackages.kernel.dev -$ nix-shell '' -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 -``` +[Moved](https://nixos.org/nixpkgs/manual#sec-linux-kernel-developing-modules) to the Nixpkgs manual. ## ZFS {#sec-linux-zfs} @@ -163,7 +103,7 @@ available Linux kernel. It is recommended to use the latest available LTS that's with ZFS. Usually this is the default kernel provided by nixpkgs (i.e. `pkgs.linuxPackages`). Alternatively, it's possible to pin the system to the latest available kernel -version *that is supported by ZFS* like this: +version _that is supported by ZFS_ like this: ```nix { diff --git a/pkgs/os-specific/linux/kernel/README.md b/pkgs/os-specific/linux/kernel/README.md new file mode 100644 index 000000000000000..59c38d83f4e0790 --- /dev/null +++ b/pkgs/os-specific/linux/kernel/README.md @@ -0,0 +1,27 @@ +# How to add a new (major) version of the Linux kernel to Nixpkgs: + +1. Copy the old Nix expression (e.g., `linux-2.6.21.nix`) to the new one (e.g., `linux-2.6.22.nix`) and update it. + +2. Add the new kernel to the `kernels` attribute set in `linux-kernels.nix` (e.g., create an attribute `kernel_2_6_22`). + +3. Now we’re going to update the kernel configuration. First unpack the kernel. Then for each supported platform (`i686`, `x86_64`, `uml`) do the following: + + 1. Make a copy from the old config (e.g., `config-2.6.21-i686-smp`) to the new one (e.g., `config-2.6.22-i686-smp`). + + 2. Copy the config file for this platform (e.g., `config-2.6.22-i686-smp`) to `.config` in the kernel source tree. + + 3. Run `make oldconfig ARCH={i386,x86_64,um}` and answer all questions. (For the uml configuration, also add `SHELL=bash`.) Make sure to keep the configuration consistent between platforms (i.e., don’t enable some feature on `i686` and disable it on `x86_64`). + + 4. If needed, you can also run `make menuconfig`: + + ```ShellSession + $ nix-env -f "" -iA ncurses + $ export NIX_CFLAGS_LINK=-lncurses + $ make menuconfig ARCH=arch + ``` + + 5. Copy `.config` over the new config file (e.g., `config-2.6.22-i686-smp`). + +4. Test building the kernel: `nix-build -A linuxKernel.kernels.kernel_2_6_22`. If it compiles, ship it! For extra credit, try booting NixOS with it. + +5. It may be that the new kernel requires updating the external kernel modules and kernel-dependent packages listed in the `linuxPackagesFor` function in `linux-kernels.nix` (such as the NVIDIA drivers, AUFS, etc.). If the updated packages aren’t backwards compatible with older kernels, you may need to keep the older versions around.