Linux kernel: Difference between revisions
Copy edit |
Add sysfs example |
||
(30 intermediate revisions by 19 users not shown) | |||
Line 28: | Line 28: | ||
nix-repl> pkgs.linuxPackages | nix-repl> pkgs.linuxPackages | ||
pkgs.linuxPackages pkgs. | pkgs.linuxPackages pkgs.linuxPackages_custom | ||
pkgs.linuxPackages-libre pkgs. | pkgs.linuxPackages-libre pkgs.linuxPackages_custom_tinyconfig_kernel | ||
pkgs.linuxPackages-rt pkgs. | pkgs.linuxPackages-rt pkgs.linuxPackages_hardened | ||
pkgs.linuxPackages- | pkgs.linuxPackages-rt_latest pkgs.linuxPackages_latest | ||
pkgs. | pkgs.linuxPackagesFor pkgs.linuxPackages_latest-libre | ||
pkgs. | pkgs.linuxPackages_4_14 pkgs.linuxPackages_latest_hardened | ||
pkgs. | pkgs.linuxPackages_4_19 pkgs.linuxPackages_latest_xen_dom0 | ||
pkgs. | pkgs.linuxPackages_4_19_hardened pkgs.linuxPackages_latest_xen_dom0_hardened | ||
pkgs. | pkgs.linuxPackages_4_9 pkgs.linuxPackages_lqx | ||
pkgs. | pkgs.linuxPackages_5_10 pkgs.linuxPackages_rpi0 | ||
pkgs. | pkgs.linuxPackages_5_10_hardened pkgs.linuxPackages_rpi02w | ||
pkgs.linuxPackages_5_4 pkgs.linuxPackages_testing | pkgs.linuxPackages_5_15 pkgs.linuxPackages_rpi1 | ||
pkgs. | pkgs.linuxPackages_5_15_hardened pkgs.linuxPackages_rpi2 | ||
pkgs. | pkgs.linuxPackages_5_18 pkgs.linuxPackages_rpi3 | ||
pkgs. | pkgs.linuxPackages_5_19 pkgs.linuxPackages_rpi4 | ||
pkgs. | pkgs.linuxPackages_5_4 pkgs.linuxPackages_rt_5_10 | ||
pkgs. | pkgs.linuxPackages_5_4_hardened pkgs.linuxPackages_rt_5_15 | ||
pkgs. | pkgs.linuxPackages_6_0 pkgs.linuxPackages_rt_5_4 | ||
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 86: | Line 95: | ||
} | } | ||
</nowiki>}} | </nowiki>}} | ||
=== Enable SysRq === | |||
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: | |||
{{file|/etc/nixos/configuration.nix|nix|<nowiki> | |||
{ | |||
boot.kernel.sysctl."kernel.sysrq" = 1; | |||
} | |||
</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 === | ||
Line 109: | Line 141: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Another way is to create | Another way is to create an 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. | ||
{{file|/etc/nixos/configuration.nix|nix|<nowiki> | {{file|/etc/nixos/configuration.nix|nix|<nowiki> | ||
Line 116: | Line 148: | ||
overlays = [ | overlays = [ | ||
(self: super: { | (self: super: { | ||
linuxZenWMuQSS = pkgs.linuxPackagesFor (pkgs.linux_zen | linuxZenWMuQSS = pkgs.linuxPackagesFor (pkgs.linuxKernel.kernels.linux_zen.override { | ||
structuredExtraConfig = with lib.kernel; { | structuredExtraConfig = with lib.kernel; { | ||
SCHED_MUQSS = yes; | SCHED_MUQSS = yes; | ||
Line 132: | Line 164: | ||
{{file|/etc/nixos/configuration.nix|nix|<nowiki> | {{file|/etc/nixos/configuration.nix|nix|<nowiki> | ||
{ | { | ||
boot.kernelPackages = pkgs.linuxPackagesFor (pkgs.linux_4_19.override { | boot.kernelPackages = pkgs.linuxPackagesFor (pkgs.linuxKernel.kernels.linux_4_19.override { | ||
argsOverride = rec { | argsOverride = rec { | ||
src = pkgs.fetchurl { | src = pkgs.fetchurl { | ||
url = "mirror://kernel/linux/kernel/ | url = "mirror://kernel/linux/kernel/v${lib.versions.major version}.x/linux-${version}.tar.xz"; | ||
sha256 = "0ibayrvrnw2lw7si78vdqnr20mm1d3z0g6a0ykndvgn5vdax5x9a"; | sha256 = "0ibayrvrnw2lw7si78vdqnr20mm1d3z0g6a0ykndvgn5vdax5x9a"; | ||
}; | }; | ||
version = "4.19.60"; | version = "4.19.60"; | ||
modDirVersion = "4.19.60"; | modDirVersion = "4.19.60"; | ||
}; | |||
}); | }); | ||
} | } | ||
Line 150: | Line 182: | ||
{{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'}} | ||
== Embedded Linux Cross-compile | == Embedded Linux Cross-compile == | ||
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: | |||
{{file|shell.nix|nix|3=let | |||
let | |||
pkgs = import <nixpkgs> { }; | pkgs = import <nixpkgs> { }; | ||
in | in | ||
Line 162: | Line 193: | ||
targetPkgs = pkgs: (with pkgs; | targetPkgs = pkgs: (with pkgs; | ||
[ | [ | ||
pkg-config | |||
ncurses | ncurses | ||
qt5.qtbase | qt5.qtbase | ||
Line 179: | Line 210: | ||
exec bash | exec bash | ||
''; | ''; | ||
}).env | }).env}} | ||
Clone the kernel sources, enter the environment using {{ic|nix-shell}}, and then do development normally. | |||
== make menuconfig == | == make menuconfig == | ||
It is | It is not possible to run <code>make menuconfig</code> in the standard kernel shell. This is because <code>ncurses</code> is not part of your working environment when you start it with <code>nix-shell '<nixpkgs>' -A linuxPackages.kernel</code>. | ||
Use <code>linuxPackages.kernel.configEnv</code> instead, which adds ncurses as a build dependency to the kernel: | |||
<syntaxHighlight lang=console> | <syntaxHighlight lang=console> | ||
$ nix-shell | $ nix-shell '<nixpkgs>' -A linuxPackages.kernel.configEnv | ||
[nix-shell] $ unpackPhase && cd linux-* | [nix-shell] $ unpackPhase && cd linux-* | ||
[nix-shell] $ patchPhase | [nix-shell] $ patchPhase | ||
Line 246: | Line 276: | ||
=== Packaging out-of-tree kernel modules === | === Packaging out-of-tree kernel modules === | ||
There are a couple of steps that you will most likely need to do a couple of things. Here is an annotated example: | There are a couple of steps that you will most likely need to do a couple of things. Here is an annotated example: | ||
< | <syntaxhighlight lang="nix"> | ||
{ stdenv, lib, fetchFromGitHub, kernel, kmod }: | { stdenv, lib, fetchFromGitHub, kernel, kernelModuleMakeFlags, kmod }: | ||
stdenv.mkDerivation rec { | stdenv.mkDerivation rec { | ||
pname = "v4l2loopback-dc"; | |||
version = "1.6"; | version = "1.6"; | ||
Line 257: | Line 287: | ||
repo = "droidcam"; | repo = "droidcam"; | ||
rev = "v${version}"; | rev = "v${version}"; | ||
hash = "1d9qpnmqa3pfwsrpjnxdz76ipk4w37bbxyrazchh4vslnfc886fx"; | |||
}; | }; | ||
Line 264: | Line 294: | ||
nativeBuildInputs = kernel.moduleBuildDependencies; # 2 | nativeBuildInputs = kernel.moduleBuildDependencies; # 2 | ||
makeFlags = [ | makeFlags = kernelModuleMakeFlags ++ [ | ||
"KERNELRELEASE=${kernel.modDirVersion}" # 3 | "KERNELRELEASE=${kernel.modDirVersion}" # 3 | ||
"KERNEL_DIR=${kernel.dev}/lib/modules/${kernel.modDirVersion}/build" # 4 | "KERNEL_DIR=${kernel.dev}/lib/modules/${kernel.modDirVersion}/build" # 4 | ||
Line 270: | Line 300: | ||
]; | ]; | ||
meta = | meta = { | ||
description = "A kernel module to create V4L2 loopback devices"; | description = "A kernel module to create V4L2 loopback devices"; | ||
homepage = "https://github.com/aramg/droidcam"; | homepage = "https://github.com/aramg/droidcam"; | ||
license = licenses.gpl2; | license = lib.licenses.gpl2; | ||
maintainers = [ maintainers.makefu ]; | maintainers = [ lib.maintainers.makefu ]; | ||
platforms = platforms.linux; | platforms = lib.platforms.linux; | ||
}; | }; | ||
} | } | ||
</ | </syntaxhighlight> | ||
1. For kernel modules it is necessary to disable <code>pic</code> in compiler hardenings as the kernel need different compiler flags. | 1. For kernel modules it is necessary to disable <code>pic</code> in compiler hardenings as the kernel need different compiler flags. | ||
Line 293: | Line 323: | ||
=== Developing out-of-tree kernel modules === | === Developing out-of-tree kernel modules === | ||
See also: {{ | See also: {{Nixpkgs Manual|name=Nixpkgs Manual, Developing kernel modules|anchor=#sec-linux-kernel-developing-modules}} | ||
If you work on an out-of-tree kernel module the workflow could look as follow: | If you work on an out-of-tree kernel module the workflow could look as follow: | ||
Line 359: | Line 389: | ||
and the module will be automatically loaded after a reboot. If you want instead to load it at stage 1 (before the root is even mounted), you need to add it to <code>boot.initrd.availableKernelModules</code> and <code>boot.initrd.kernelModules</code>. | and the module will be automatically loaded after a reboot. If you want instead to load it at stage 1 (before the root is even mounted), you need to add it to <code>boot.initrd.availableKernelModules</code> and <code>boot.initrd.kernelModules</code>. | ||
Note that if you don't reboot, you can still load manually the module using <code>modprobe yourmodulename></code>, and to automatically enable a module during configuration switch/reboot, you can put <code>modprobe yourmodulename || true</code> inside the script of a systemctl service (it is for example what does wireguard). | Note that if you don't reboot, you can still load manually the module using <code>modprobe <yourmodulename></code>, and to automatically enable a module during configuration switch/reboot, you can put <code>modprobe yourmodulename || true</code> inside the script of a systemctl service (it is for example what does wireguard). | ||
Finally, if you want to define some options by default (used when you load manually a module using <code>modprobe</code>, or when the system boots), you can specify them in: | Finally, if you want to define some options by default (used when you load manually a module using <code>modprobe</code>, or when the system boots), you can specify them in: | ||
Line 393: | Line 423: | ||
Save the following as <code>shell.nix</code> for your nix-shell: | Save the following as <code>shell.nix</code> for your nix-shell: | ||
< | <syntaxhighlight lang="nix"> | ||
{ pkgs ? import <nixpkgs> {} }: | { pkgs ? import <nixpkgs> {} }: | ||
let | let | ||
Line 402: | Line 432: | ||
# the override is optional if you need for example more build dependencies | # the override is optional if you need for example more build dependencies | ||
nativeBuildInputs = old.nativeBuildInputs ++ [ pkgs.gllvm ]; | nativeBuildInputs = old.nativeBuildInputs ++ [ pkgs.gllvm ]; | ||
} | }) | ||
</ | </syntaxhighlight> | ||
Then 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 | ||
Line 519: | Line 549: | ||
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: | 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, ...}: | {pkgs, config, ...}: | ||
let | let | ||
Line 531: | Line 561: | ||
(amdgpu-kernel-module.overrideAttrs (_: { | (amdgpu-kernel-module.overrideAttrs (_: { | ||
patches = [ ./patches/amdgpu-foo-bar.patch ]; | patches = [ ./patches/amdgpu-foo-bar.patch ]; | ||
}) | })) | ||
]; | ]; | ||
} | } | ||
</ | </syntaxhighlight> | ||
== Sysctls == | |||
Example of configuring kernel sysctls: | |||
<syntaxhighlight lang="nix"> | |||
{ | |||
boot.kernel.sysctl."net.ipv4.tcp_ecn" = 1; | |||
} | |||
</syntaxhighlight> | |||
== Sysfs == | |||
Example of configuring kernel sysfs: | |||
<syntaxhighlight lang="nix"> | |||
{ | |||
boot.kernel.sysfs = { | |||
kernel.mm.transparent_hugepage = { | |||
enabled = "always"; | |||
defrag = "defer"; | |||
shmem_enabled = "within_size"; | |||
}; | |||
}; | |||
} | |||
</syntaxhighlight> | |||
== Troubleshooting == | == Troubleshooting == | ||
=== Build fails === | === Build fails === | ||
==== Too high ram usage ==== | ==== Too high ram usage ==== | ||
turn off | turn off <code>DEBUG_INFO_BTF</code> | ||
== See also == | == See also == |