Jump to content

Linux kernel: Difference between revisions

m
Fix usage of template
imported>Khoi
m (Fix usage of template)
 
(20 intermediate revisions by 13 users not shown)
Line 3: Line 3:
== Configuration ==
== Configuration ==


You can choose your kernel simply by setting the <code>boot.kernelPackages</code> option
You can change the installed kernel using {{nixos:option|boot.kernelPackages}}. To use the latest release:


For example by adding this to  <code>/etc/nixos/configuration.nix</code>:
{{file|/etc/nixos/configuration.nix|nix|<nowiki>
<syntaxHighlight lang="nix">
{
boot.kernelPackages = pkgs.linuxPackages_latest;
  boot.kernelPackages = pkgs.linuxPackages_latest;
</syntaxHighlight>
}
And rebuild your system and reboot to use your new kernel:
</nowiki>}}
 
Then rebuild your system and reboot to use your new kernel:
<syntaxHighlight lang="console">
<syntaxHighlight lang="console">
$ sudo nixos-rebuild boot
$ sudo nixos-rebuild boot
Line 17: Line 19:
=== List available kernels ===
=== List available kernels ===
You can list available kernels using  <code>nix repl</code> (previously <code>nix-repl</code>) by typing the package name and using the tab completion:
You can list available kernels using  <code>nix repl</code> (previously <code>nix-repl</code>) by typing the package name and using the tab completion:
 
 
<syntaxHighlight lang="console">
<syntaxHighlight lang="console">
$ nix repl
$ nix repl
Line 26: Line 28:


nix-repl> pkgs.linuxPackages
nix-repl> pkgs.linuxPackages
pkgs.linuxPackages                          pkgs.linuxPackages_latest
pkgs.linuxPackages                          pkgs.linuxPackages_custom
pkgs.linuxPackages-libre                    pkgs.linuxPackages_latest-libre
pkgs.linuxPackages-libre                    pkgs.linuxPackages_custom_tinyconfig_kernel
pkgs.linuxPackages-rt                        pkgs.linuxPackages_latest_hardened
pkgs.linuxPackages-rt                        pkgs.linuxPackages_hardened
pkgs.linuxPackages-rt_5_4                    pkgs.linuxPackages_latest_xen_dom0
pkgs.linuxPackages-rt_latest                pkgs.linuxPackages_latest
pkgs.linuxPackages-rt_5_6                    pkgs.linuxPackages_latest_xen_dom0_hardened
pkgs.linuxPackagesFor                        pkgs.linuxPackages_latest-libre
pkgs.linuxPackages-rt_latest                pkgs.linuxPackages_mptcp
pkgs.linuxPackages_4_14                      pkgs.linuxPackages_latest_hardened
pkgs.linuxPackagesFor                        pkgs.linuxPackages_rpi0
pkgs.linuxPackages_4_19                      pkgs.linuxPackages_latest_xen_dom0
pkgs.linuxPackages_4_14                     pkgs.linuxPackages_rpi1
pkgs.linuxPackages_4_19_hardened            pkgs.linuxPackages_latest_xen_dom0_hardened
pkgs.linuxPackages_4_19                      pkgs.linuxPackages_rpi2
pkgs.linuxPackages_4_9                      pkgs.linuxPackages_lqx
pkgs.linuxPackages_4_4                      pkgs.linuxPackages_rpi3
pkgs.linuxPackages_5_10                      pkgs.linuxPackages_rpi0
pkgs.linuxPackages_4_9                      pkgs.linuxPackages_rpi4
pkgs.linuxPackages_5_10_hardened            pkgs.linuxPackages_rpi02w
pkgs.linuxPackages_5_4                      pkgs.linuxPackages_testing
pkgs.linuxPackages_5_15                     pkgs.linuxPackages_rpi1
pkgs.linuxPackages_5_8                       pkgs.linuxPackages_testing_bcachefs
pkgs.linuxPackages_5_15_hardened            pkgs.linuxPackages_rpi2
pkgs.linuxPackages_5_9                       pkgs.linuxPackages_testing_hardened
pkgs.linuxPackages_5_18                      pkgs.linuxPackages_rpi3
pkgs.linuxPackages_custom                    pkgs.linuxPackages_xen_dom0
pkgs.linuxPackages_5_19                      pkgs.linuxPackages_rpi4
pkgs.linuxPackages_custom_tinyconfig_kernel  pkgs.linuxPackages_xen_dom0_hardened
pkgs.linuxPackages_5_4                      pkgs.linuxPackages_rt_5_10
pkgs.linuxPackages_hardened                  pkgs.linuxPackages_zen
pkgs.linuxPackages_5_4_hardened              pkgs.linuxPackages_rt_5_15
pkgs.linuxPackages_hardkernel_4_14
pkgs.linuxPackages_6_0                      pkgs.linuxPackages_rt_5_4
pkgs.linuxPackages_hardkernel_latest
pkgs.linuxPackages_6_1                      pkgs.linuxPackages_rt_6_1
pkgs.linuxPackages_6_1_hardened              pkgs.linuxPackages_testing
pkgs.linuxPackages_6_2                       pkgs.linuxPackages_testing_bcachefs
pkgs.linuxPackages_6_3                       pkgs.linuxPackages_xanmod
pkgs.linuxPackages_6_4                      pkgs.linuxPackages_xanmod_latest
pkgs.linuxPackages_6_5                      pkgs.linuxPackages_xanmod_stable
pkgs.linuxPackages_6_6                      pkgs.linuxPackages_xen_dom0
pkgs.linuxPackages_6_6_hardened              pkgs.linuxPackages_xen_dom0_hardened
pkgs.linuxPackages_6_7                      pkgs.linuxPackages_zen
pkgs.linuxPackages_6_8
</syntaxhighlight>
</syntaxhighlight>


Line 51: Line 62:
Note that if you deviate from the default kernel version, you should also take extra care that extra kernel modules must match the same version. The safest way to do this is to use <code>config.boot.kernelPackages</code> to select the correct module set:
Note that if you deviate from the default kernel version, you should also take extra care that extra kernel modules must match the same version. The safest way to do this is to use <code>config.boot.kernelPackages</code> to select the correct module set:


<syntaxHighlight lang="nix">
{{file|/etc/nixos/configuration.nix|nix|<nowiki>
{ config, ... }:
{ config, ... }:
{
{
   boot.extraModulePackages = with config.boot.kernelPackages; [ wireguard ];
   boot.extraModulePackages = with config.boot.kernelPackages; [ bbswitch ];
}
</nowiki>}}
 
=== Customizing kernel module parameters ===
 
You can use {{nixos:option|boot.extraModprobeConfig}}, which is analogous to creating modprobe.conf files in /etc/modprobe.d/ in regular Linux distributions. This can be used for both built-in and loadable kernel modules.
 
{{file|/etc/nixos/configuration.nix|nix|<nowiki>
{
  boot.extraModprobeConfig = ''
    # example settings
    options yourmodulename optionA=valueA optionB=valueB # syntax
    options thinkpad_acpi  fan_control=1                # example #1 kernel module parameter
    options usbcore        blinkenlights=1              # example #2 kernel module parameter
  '';
}
}
</syntaxHighlight>
</nowiki>}}


Note that wireguard has been merged into the mainline kernel, so on newer (21.05+) versions of NixOS with the default kernel wireguard is no longer an option available.
{{nixos:option|boot.kernelParams}} can be used to set additional kernel command line arguments at boot time. It can only be used for built-in modules. For example:


=== Custom kernel commandline ===
{{file|/etc/nixos/configuration.nix|nix|<nowiki>
{
  boot.kernelParams = [
    "quiet"
    "splash"
    "usbcore.blinkenlights=1"
  ];
}
</nowiki>}}


The config attribute <code>boot.kernelParams</code> can be set to supply the Linux kernel with additional command line arguments at boot time.
=== Enable SysRq ===


<syntaxHighlight lang="nix">
The Linux kernel is known<ref>https://github.com/hakavlad/nohang?tab=readme-ov-file#what-is-the-problem</ref> to not handle out-of-memory situation properly and can freeze for a long time, often leaving no option but doing a hard reboot. The [https://en.wikipedia.org/wiki/Magic_SysRq_key SysRq shortcuts] can be used to trigger a more graceful reboot. However, most keys are disabled by default on NixOS. To enable:
{ pkgs, config, ... }:


{{file|/etc/nixos/configuration.nix|nix|<nowiki>
{
{
   boot.kernelParams = [ /* list of command line arguments */ ];
   boot.kernel.sysctl."kernel.sysrq" = 1;
}
}
</syntaxHighlight>
</nowiki>}}
 
Useful shortcuts, triggered using {{ic|Alt+SysRq+<key>}}:
 
* {{ic|h}}: Print help to the system log.
* {{ic|f}}: Trigger the kernel oom killer.
* {{ic|s}}: Sync data to disk before triggering the reset options below.
* {{ic|e}}: SIGTERM all processes except PID 0.
* {{ic|i}}: SIGKILL all processes except PID 0.
* {{ic|b}}: Reboot the system.
 
Check <code>journalctl</code> to see if you are triggering the shortcuts correctly, which might be different for your keyboard, as noted in the Wikipedia page.
 
Also see {{nixos:option|services.earlyoom.enable}} and {{nixos:option|systemd.oomd.enable}}.


=== Custom configuration ===
=== Custom configuration ===


It is sometimes desirable to change the configuration of your kernel, while keeping the kernel version itself managed through Nixpkgs. To do so, you can add the configuration to a dummy {{nixos:option|boot.kernelPatches}},<ref>[https://logs.nix.samueldr.com/nixos/2018-05-09#1525898458-1525898534; #nixos 2018-05-09]</ref><ref>[https://github.com/NixOS/nixpkgs/blob/03d4694e6110fa9c16e88ee74085ea2068c27494/nixos/modules/misc/crashdump.nix#L63-L73 <tt>nixos/modules/misc/crashdump.nix#L63-L73</tt>]</ref> which will then be merged and applied to the current kernel. As with kernel configuration with NixOS, drop the <tt>CONFIG_</tt> prefix from the kernel configuration names.
It is sometimes desirable to change the configuration of your kernel, while keeping the kernel version itself managed through Nixpkgs.


This example is from the {{nixos:option|boot.crashDump.enable}} option:
One way is to use {{nixos:option|boot.kernelPatches}}<ref>[https://logs.nix.samueldr.com/nixos/2018-05-09#1525898458-1525898534; #nixos 2018-05-09]</ref><ref>[https://github.com/NixOS/nixpkgs/blob/03d4694e6110fa9c16e88ee74085ea2068c27494/nixos/modules/misc/crashdump.nix#L63-L73 <tt>nixos/modules/misc/crashdump.nix#L63-L73</tt>]</ref>. For example, {{nixos:option|boot.crashDump.enable}} is configured as shown below. Note that the {{ic|CONFIG_}} prefix is not used in the configuration names.


<syntaxhighlight lang=nix>
<syntaxhighlight lang=nix>
Line 94: Line 141:
</syntaxhighlight>
</syntaxhighlight>


Another way to build a kernel with custom configuration is to create a overlay and use either <tt>extraConfig</tt> or <tt>structuredExtraConfig</tt>. This allows for more flexibility, since you can basically override any kernel option available here <ref>[https://github.com/NixOS/nixpkgs/blob/e6db435973160591fe7348876a5567c729495175/pkgs/os-specific/linux/kernel/generic.nix#L11-L56<tt>pkgs/os-specific/linux/kernel/generic.nix#L11-L56</tt>]</ref>. Using <tt>structuredExtraConfig</tt> is recommended since there is some sanity check if the options you're passing to your kernel is correct. Also, setting <tt>ignoreConfigErrors</tt> is useful to avoid <tt>error: unused option</tt> during build.
Another way is to create a overlay to configure either {{ic|extraConfig}} or {{ic|structuredExtraConfig}}. This allows for more flexibility, since you can basically override any available kernel option<ref>[https://github.com/NixOS/nixpkgs/blob/e6db435973160591fe7348876a5567c729495175/pkgs/os-specific/linux/kernel/generic.nix#L11-L56<tt>pkgs/os-specific/linux/kernel/generic.nix#L11-L56</tt>]</ref>. Using {{ic|structuredExtraConfig}} is recommended as it checks if the configured option are correct. You may also want to set {{ic|ignoreConfigErrors}} to avoid {{ic|error: unused option}} during builds.


<syntaxhighlight lang=nix>
{{file|/etc/nixos/configuration.nix|nix|<nowiki>
{
{
   nixpkgs = {
   nixpkgs = {
     overlays = [
     overlays = [
       (self: super: {
       (self: super: {
         linuxZenWMuQSS = pkgs.linuxPackagesFor (pkgs.linux_zen.override {
         linuxZenWMuQSS = pkgs.linuxPackagesFor (pkgs.linux_zen.kernel.override {
           structuredExtraConfig = with lib.kernel; {
           structuredExtraConfig = with lib.kernel; {
             SCHED_MUQSS = yes;
             SCHED_MUQSS = yes;
Line 111: Line 158:
   };
   };
}
}
</syntaxhighlight>
</nowiki>}}


=== Pinning a kernel version ===
=== Pinning a kernel version ===


<syntaxhighlight lang=nix>
{{file|/etc/nixos/configuration.nix|nix|<nowiki>
boot.kernelPackages = pkgs.linuxPackagesFor (pkgs.linux_4_19.override {
{
  boot.kernelPackages = pkgs.linuxPackagesFor (pkgs.linux_4_19.override {
     argsOverride = rec {
     argsOverride = rec {
       src = pkgs.fetchurl {
       src = pkgs.fetchurl {
Line 126: Line 174:
       };
       };
   });
   });
</syntaxhighlight>
}
 
</nowiki>}}


=== Debugging a failed configuration  ===
=== Debugging a failed configuration  ===


As dependencies between kernel configurations items need to be addressed manually, use <code>--keep-failed</code> to inspect the intermediate nix config file after for instance the error
As dependencies between kernel configurations need to be addressed manually, use [https://nixos.org/manual/nix/stable/command-ref/nix-build#opt-keep-failed --keep-failed] to inspect the intermediate nix config file after any build failures:
{{bc|note: keeping build directory '/tmp/nix-build-linux-config-4.19.0-mptcp_v0.94.1.drv-0'}}
{{bc|note: keeping build directory '/tmp/nix-build-linux-config-4.19.0-mptcp_v0.94.1.drv-0'}}
by opening {{ic|/tmp/nix-build-linux-config-4.19.0-mptcp_v0.94.1.drv-0/.attr-0}}.


== Embedded Linux Cross-compile xconfig and menuconfig ==
== Embedded Linux Cross-compile ==
This section details the on how to get an environment that can be used to configure and cross-compile the kernel for embedded Linux development. The kernel source won't come from nix unpack phase but rather gotten externally(such as from the chip vendor github). So first clone the kernel source, then use the shell.nix below to set up the dev environment(example below is for aarch64):
 
To configure and cross-compile Linux kernels for embedded development, often distributed separately instead of using the stock kernel, you can setup a development environment as shown below:  


<syntaxHighlight lang=nix>
{{file|shell.nix|nix|3=let
let
   pkgs = import <nixpkgs> { };
   pkgs = import <nixpkgs> { };
in
in
Line 163: Line 210:
     exec bash
     exec bash
   '';
   '';
}).env
}).env}}
</syntaxHighlight>


Finally, cd to the kernel source dir and do development normally.
Clone the kernel sources, enter the environment using {{ic|nix-shell}}, and then do development normally.


== make menuconfig ==
== make menuconfig ==
Line 209: Line 255:
           src = fetchurl {
           src = fetchurl {
             url = "https://github.com/jsakkine-intel/linux-sgx/archive/v23.tar.gz";
             url = "https://github.com/jsakkine-intel/linux-sgx/archive/v23.tar.gz";
             sha256 = "11rwlwv7s071ia889dk1dgrxprxiwgi7djhg47vi56dj81jgib20";
             # After the first build attempt, look for "hash mismatch" and then 2 lines below at the "got:" line.
            # Use "sha256-....." value here.
            hash = "";
           };
           };
           kernelPatches = [];
           kernelPatches = [];
Line 306: Line 354:
</syntaxHighlight>
</syntaxHighlight>


If wishing to develop out-of-tree kernel modules for kernels aside from the default variant shipped under <code>pkgs.linuxPackages</code>, a flow similar to the example below will be used.
If wishing to develop out-of-tree kernel modules for kernels aside from the default variant shipped under <code>pkgs.linuxPackages</code>, you can replace <code>linux.dev</code> with (for instance) <code>linuxPackages_latest.kernel.dev</code>.
The example below illustrates a flow for building kernel modules for <code>pkgs.linuxPackages_latest</code>.


If you want a local development environment and are only interested in Module.symvers, then you can do instead:
<syntaxHighlight lang="console>
<syntaxHighlight lang="console>
$ nix-shell '<nixpkgs>' -A linuxPackages_latest.kernel.dev
$ cp $(nix-build -E '(import <nixpkgs> {}).linux.dev' --no-out-link)/lib/modules/*/build/Module.symvers .
$ make -C $(nix-build -E '(import <nixpkgs> {}).linuxPackages_latest.kernel.dev' --no-out-link)/lib/modules/*/build M=$(pwd) modules
$ insmod ./hello.ko
$ dmesg | grep hello
[  82.027229] hello world!
</syntaxHighlight>
</syntaxHighlight>


Line 391: Line 435:
</syntaxHighlight>
</syntaxHighlight>


Than you can run the following commands (in the nix-shell <code>$makeFlags</code> will contain
Then you can run the following commands (in the nix-shell <code>$makeFlags</code> will contain
the necessary cross-compiling arguments)
the necessary cross-compiling arguments)


Line 413: Line 457:
</syntaxHighlight>
</syntaxHighlight>


Than you can use:
Then you can use:


<syntaxHighlight lang=console>
<syntaxHighlight lang=console>
Line 451: Line 495:
</syntaxHighlight>
</syntaxHighlight>


== Patching a single In-tree kernel module ==
If you wish to patch a single kernel module, you can avoid rebuilding the entire linux kernel
by packaging that module applying patches to it.
=== Packaging a single kernel module ===
Here is an example for how to package the <code>amdgpu</code> kernel module.
<syntaxHighlight lang=nix>
{ pkgs
, lib
, kernel ? pkgs.linuxPackages_latest.kernel
}:
pkgs.stdenv.mkDerivation {
  pname = "amdgpu-kernel-module";
  inherit (kernel) src version postPatch nativeBuildInputs;
  kernel_dev = kernel.dev;
  kernelVersion = kernel.modDirVersion;
  modulePath = "drivers/gpu/drm/amd/amdgpu";
  buildPhase = ''
    BUILT_KERNEL=$kernel_dev/lib/modules/$kernelVersion/build
    cp $BUILT_KERNEL/Module.symvers .
    cp $BUILT_KERNEL/.config        .
    cp $kernel_dev/vmlinux          .
    make "-j$NIX_BUILD_CORES" modules_prepare
    make "-j$NIX_BUILD_CORES" M=$modulePath modules
  '';
  installPhase = ''
    make \
      INSTALL_MOD_PATH="$out" \
      XZ="xz -T$NIX_BUILD_CORES" \
      M="$modulePath" \
      modules_install
  '';
  meta = {
    description = "AMD GPU kernel module";
    license = lib.licenses.gpl3;
  };
}
</syntaxHighlight>
=== Replacing default kernel modules ===
After packaging the kernel module you can add it to your system just like an out-of-tree kernel module, it will replace the default module provided by the linux package because it has the same name:
<syntaxHighlight lang=nix>
{pkgs, config, ...}:
let
  amdgpu-kernel-module = pkgs.callPackage ./amdgpu-kernel-module.nix {
    # Make sure the module targets the same kernel as your system is using.
    kernel = config.boot.kernelPackages.kernel;
  };
in
{
  boot.extraModulePackages = [
    (amdgpu-kernel-module.overrideAttrs (_: {
      patches = [ ./patches/amdgpu-foo-bar.patch ];
    })
  ];
}
</syntaxHighlight>


== Troubleshooting ==
== Troubleshooting ==