nixpkgs/doc/packages/linux.section.md
Maximilian Bosch 1965f3c77d
linux: manual-config.nix -> build.nix
Since I started touching this subsystem, I found the name confusing
since this is the part where we actually compile the kernel and we have
a ready-to-use configuration.

The stated goal of the commit introducing it[1] is to provide a function
to

> make it possible to build a kernel with a user provided .config.

Considering that this is supposed to be a differentiation from other
build mechanisms and nowadays this is the only way to build kernels in
nixpkgs, I figured that `build.nix` is a better name.

`pkgs.linuxManualConfig` isn't renamed on purpose: Kloenk and I are
planning to do more involved work and it may become necessary to change
parts of the API. So asking users to do a migration now just to add
another one soon isn't worth it.

[1] bf7467cbb1
2025-10-24 18:06:29 +02:00

161 lines
7.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Linux kernel {#sec-linux-kernel}
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 [`pkgs.buildLinux`](https://github.com/NixOS/nixpkgs/blob/d77bda728d5041c1294a68fb25c79e2d161f62b9/pkgs/os-specific/linux/kernel/generic.nix) builds a kernel with [common configuration values](https://github.com/NixOS/nixpkgs/blob/d77bda728d5041c1294a68fb25c79e2d161f62b9/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/d77bda728d5041c1294a68fb25c79e2d161f62b9/pkgs/os-specific/linux/kernel/build.nix) 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.
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](https://github.com/NixOS/nixpkgs/blob/d77bda728d5041c1294a68fb25c79e2d161f62b9/pkgs/os-specific/linux/kernel/generic.nix).
:::{.example #ex-overriding-kernel-derivation}
# Overriding the kernel derivation
Assuming you are using the kernel from `pkgs.linux_latest`:
```nix
pkgs.linux_latest.override {
ignoreConfigErrors = true;
autoModules = false;
kernelPreferBuiltin = true;
structuredExtraConfig = with lib.kernel; {
DEBUG_KERNEL = yes;
FRAME_POINTER = yes;
KGDB = yes;
KGDB_SERIAL_CONSOLE = yes;
DEBUG_INFO = yes;
};
}
```
:::
## Manual kernel configuration {#sec-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.linuxPackages_custom` in these cases. It requires the `src`, `version`, and `configfile` attributes to be specified.
:::{.example #ex-using-linux-manual-config}
# Using `pkgs.linuxPackages_custom` with a specific source, version, and config file
```nix
{ pkgs, ... }:
pkgs.linuxPackages_custom {
version = "6.1.55";
src = pkgs.fetchurl {
url = "https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-${version}.tar.xz";
hash = "sha256-qH4kHsFdU0UsTv4hlxOjdp2IzENrW5jPbvsmLEr/FcA=";
};
configfile = ./path_to_config_file;
}
```
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, ... }:
pkgs.linuxPackages_custom {
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-qH4kHsFdU0UsTv4hlxOjdp2IzENrW5jPbvsmLEr/FcA=";
};
configfile = ./path_to_config_file;
}
```
:::
Additional attributes can be used with `linuxManualConfig` for further customisation instead of `linuxPackages_custom`. You're encouraged to read [the `pkgs.linuxManualConfig` source code](https://github.com/NixOS/nixpkgs/blob/d77bda728d5041c1294a68fb25c79e2d161f62b9/pkgs/os-specific/linux/kernel/build.nix) to understand how to use them.
To edit the `.config` file for Linux X.Y from within Nix, proceed as follows:
```ShellSession
$ nix-shell '<nixpkgs>' -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 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
```ShellSession
$ 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
```
:::
## Maintainer information {#sec-linux-kernel-maintainer-information}
### Updating kernels {#sec-linux-updates}
Updating all kernels can be done with the following script:
```ShellSession
$ pkgs/os-specific/linux/kernel/update.sh
```
The change gets submitted like this:
* File a PR against `staging-nixos`.
* Add a `backport release-XX.XX` label for an automated backport.
We don't expect many other changes on that branch to require a backport, hence there's no such branch for stable.
By using an additional PR, we get the automatic backport against stable without manual cherry-picks.
* Merge into `staging-nixos`.
* File as PR from `staging-nixos` against `master`.
* When all status checks are green, merge.
### Add a new (major) version of the Linux kernel {#sec-linux-add-new-kernel-version}
* When running `./pkgs/os-specific/linux/kernel/update.sh`, new kernel majors get discovered automatically.
* Prepare all Nix expressions for the new kernel
* Instantiate the new kernel in `pkgs/top-level/linux-kernels.nix` in the `kernels`-section.
```nix
{
linux_X_Y = callPackage ../os-specific/linux/kernel/mainline.nix {
branch = "X.Y";
kernelPatches = [
# any new patches required (it makes to look which patches are used by its predecessor)
];
};
}
```
* Instantiate the package-set in `vanillaPackages`:
```nix
{
linux_X_Y = recurseIntoAttrs (packagesFor kernels.linux_X_Y);
}
```
* Update `linux_latest` to the new attribute.
* __SQUASH__ the changes into the `linux: init at …` commit.
* If a new hardened is available:
* Instantiate a `linux_X_Y_hardened = hardenedKernelsFor kernels.linux_X_Y { };` in `kernels` and
`linux_X_Y_hardened = hardenedKernelFor kernels.linux_X_Y { };` in the `packages`-section.
* Make sure to remove the hardened variant of the previous kernel version unless it's LTS.
We only support the latest and latest LTS version of hardened.
* If no new hardened kernel is available:
* Keep the previously latest kernel until its mainline counterpart gets removed.
After that `linux_hardened` points to the latest LTS supported by hardened.
* __SQUASH__ the changes into the `linux_X_Y_hardened: init at …` commit.