typioca: 2.7.0 -> 2.8.0
[NixPkgs.git] / nixos / modules / system / boot / kernel.nix
bloba46331ccd431d99dccd1a1c5660c85003ef35dde
1 { config, lib, pkgs, ... }:
3 with lib;
5 let
7   inherit (config.boot) kernelPatches;
8   inherit (config.boot.kernel) features randstructSeed;
9   inherit (config.boot.kernelPackages) kernel;
11   kernelModulesConf = pkgs.writeText "nixos.conf"
12     ''
13       ${concatStringsSep "\n" config.boot.kernelModules}
14     '';
20   ###### interface
22   options = {
23     boot.kernel.enable = mkEnableOption (lib.mdDoc "the Linux kernel. This is useful for systemd-like containers which do not require a kernel") // {
24       default = true;
25     };
27     boot.kernel.features = mkOption {
28       default = {};
29       example = literalExpression "{ debug = true; }";
30       internal = true;
31       description = lib.mdDoc ''
32         This option allows to enable or disable certain kernel features.
33         It's not API, because it's about kernel feature sets, that
34         make sense for specific use cases. Mostly along with programs,
35         which would have separate nixos options.
36         `grep features pkgs/os-specific/linux/kernel/common-config.nix`
37       '';
38     };
40     boot.kernelPackages = mkOption {
41       default = pkgs.linuxPackages;
42       type = types.raw;
43       apply = kernelPackages: kernelPackages.extend (self: super: {
44         kernel = super.kernel.override (originalArgs: {
45           inherit randstructSeed;
46           kernelPatches = (originalArgs.kernelPatches or []) ++ kernelPatches;
47           features = lib.recursiveUpdate super.kernel.features features;
48         });
49       });
50       # We don't want to evaluate all of linuxPackages for the manual
51       # - some of it might not even evaluate correctly.
52       defaultText = literalExpression "pkgs.linuxPackages";
53       example = literalExpression "pkgs.linuxKernel.packages.linux_5_10";
54       description = lib.mdDoc ''
55         This option allows you to override the Linux kernel used by
56         NixOS.  Since things like external kernel module packages are
57         tied to the kernel you're using, it also overrides those.
58         This option is a function that takes Nixpkgs as an argument
59         (as a convenience), and returns an attribute set containing at
60         the very least an attribute {var}`kernel`.
61         Additional attributes may be needed depending on your
62         configuration.  For instance, if you use the NVIDIA X driver,
63         then it also needs to contain an attribute
64         {var}`nvidia_x11`.
66         Please note that we strictly support kernel versions that are
67         maintained by the Linux developers only. More information on the
68         availability of kernel versions is documented
69         [in the Linux section of the manual](https://nixos.org/manual/nixos/unstable/index.html#sec-kernel-config).
70       '';
71     };
73     boot.kernelPatches = mkOption {
74       type = types.listOf types.attrs;
75       default = [];
76       example = literalExpression ''
77         [
78           {
79             name = "foo";
80             patch = ./foo.patch;
81             extraStructuredConfig.FOO = lib.kernel.yes;
82             features.foo = true;
83           }
84         ]
85       '';
86       description = lib.mdDoc ''
87         A list of additional patches to apply to the kernel.
89         Every item should be an attribute set with the following attributes:
91         ```nix
92         {
93           name = "foo";                 # descriptive name, required
95           patch = ./foo.patch;          # path or derivation that contains the patch source
96                                         # (required, but can be null if only config changes
97                                         # are needed)
99           extraStructuredConfig = {     # attrset of extra configuration parameters without the CONFIG_ prefix
100             FOO = lib.kernel.yes;       # (optional)
101           };                            # values should generally be lib.kernel.yes,
102                                         # lib.kernel.no or lib.kernel.module
104           features = {                  # attrset of extra "features" the kernel is considered to have
105             foo = true;                 # (may be checked by other NixOS modules, optional)
106           };
108           extraConfig = "FOO y";        # extra configuration options in string form without the CONFIG_ prefix
109                                         # (optional, multiple lines allowed to specify multiple options)
110                                         # (deprecated, use extraStructuredConfig instead)
111         }
112         ```
114         There's a small set of existing kernel patches in Nixpkgs, available as `pkgs.kernelPatches`,
115         that follow this format and can be used directly.
116       '';
117     };
119     boot.kernel.randstructSeed = mkOption {
120       type = types.str;
121       default = "";
122       example = "my secret seed";
123       description = lib.mdDoc ''
124         Provides a custom seed for the {var}`RANDSTRUCT` security
125         option of the Linux kernel. Note that {var}`RANDSTRUCT` is
126         only enabled in NixOS hardened kernels. Using a custom seed requires
127         building the kernel and dependent packages locally, since this
128         customization happens at build time.
129       '';
130     };
132     boot.kernelParams = mkOption {
133       type = types.listOf (types.strMatching ''([^"[:space:]]|"[^"]*")+'' // {
134         name = "kernelParam";
135         description = "string, with spaces inside double quotes";
136       });
137       default = [ ];
138       description = lib.mdDoc "Parameters added to the kernel command line.";
139     };
141     boot.consoleLogLevel = mkOption {
142       type = types.int;
143       default = 4;
144       description = lib.mdDoc ''
145         The kernel console `loglevel`. All Kernel Messages with a log level smaller
146         than this setting will be printed to the console.
147       '';
148     };
150     boot.vesa = mkOption {
151       type = types.bool;
152       default = false;
153       description = lib.mdDoc ''
154         (Deprecated) This option, if set, activates the VESA 800x600 video
155         mode on boot and disables kernel modesetting. It is equivalent to
156         specifying `[ "vga=0x317" "nomodeset" ]` in the
157         {option}`boot.kernelParams` option. This option is
158         deprecated as of 2020: Xorg now works better with modesetting, and
159         you might want a different VESA vga setting, anyway.
160       '';
161     };
163     boot.extraModulePackages = mkOption {
164       type = types.listOf types.package;
165       default = [];
166       example = literalExpression "[ config.boot.kernelPackages.nvidia_x11 ]";
167       description = lib.mdDoc "A list of additional packages supplying kernel modules.";
168     };
170     boot.kernelModules = mkOption {
171       type = types.listOf types.str;
172       default = [];
173       description = lib.mdDoc ''
174         The set of kernel modules to be loaded in the second stage of
175         the boot process.  Note that modules that are needed to
176         mount the root file system should be added to
177         {option}`boot.initrd.availableKernelModules` or
178         {option}`boot.initrd.kernelModules`.
179       '';
180     };
182     boot.initrd.availableKernelModules = mkOption {
183       type = types.listOf types.str;
184       default = [];
185       example = [ "sata_nv" "ext3" ];
186       description = lib.mdDoc ''
187         The set of kernel modules in the initial ramdisk used during the
188         boot process.  This set must include all modules necessary for
189         mounting the root device.  That is, it should include modules
190         for the physical device (e.g., SCSI drivers) and for the file
191         system (e.g., ext3).  The set specified here is automatically
192         closed under the module dependency relation, i.e., all
193         dependencies of the modules list here are included
194         automatically.  The modules listed here are available in the
195         initrd, but are only loaded on demand (e.g., the ext3 module is
196         loaded automatically when an ext3 filesystem is mounted, and
197         modules for PCI devices are loaded when they match the PCI ID
198         of a device in your system).  To force a module to be loaded,
199         include it in {option}`boot.initrd.kernelModules`.
200       '';
201     };
203     boot.initrd.kernelModules = mkOption {
204       type = types.listOf types.str;
205       default = [];
206       description = lib.mdDoc "List of modules that are always loaded by the initrd.";
207     };
209     boot.initrd.includeDefaultModules = mkOption {
210       type = types.bool;
211       default = true;
212       description = lib.mdDoc ''
213         This option, if set, adds a collection of default kernel modules
214         to {option}`boot.initrd.availableKernelModules` and
215         {option}`boot.initrd.kernelModules`.
216       '';
217     };
219     system.modulesTree = mkOption {
220       type = types.listOf types.path;
221       internal = true;
222       default = [];
223       description = lib.mdDoc ''
224         Tree of kernel modules.  This includes the kernel, plus modules
225         built outside of the kernel.  Combine these into a single tree of
226         symlinks because modprobe only supports one directory.
227       '';
228       # Convert the list of path to only one path.
229       apply = pkgs.aggregateModules;
230     };
232     system.requiredKernelConfig = mkOption {
233       default = [];
234       example = literalExpression ''
235         with config.lib.kernelConfig; [
236           (isYes "MODULES")
237           (isEnabled "FB_CON_DECOR")
238           (isEnabled "BLK_DEV_INITRD")
239         ]
240       '';
241       internal = true;
242       type = types.listOf types.attrs;
243       description = lib.mdDoc ''
244         This option allows modules to specify the kernel config options that
245         must be set (or unset) for the module to work. Please use the
246         lib.kernelConfig functions to build list elements.
247       '';
248     };
250   };
253   ###### implementation
255   config = mkMerge
256     [ (mkIf config.boot.initrd.enable {
257         boot.initrd.availableKernelModules =
258           optionals config.boot.initrd.includeDefaultModules ([
259             # Note: most of these (especially the SATA/PATA modules)
260             # shouldn't be included by default since nixos-generate-config
261             # detects them, but I'm keeping them for now for backwards
262             # compatibility.
264             # Some SATA/PATA stuff.
265             "ahci"
266             "sata_nv"
267             "sata_via"
268             "sata_sis"
269             "sata_uli"
270             "ata_piix"
271             "pata_marvell"
273             # NVMe
274             "nvme"
276             # Standard SCSI stuff.
277             "sd_mod"
278             "sr_mod"
280             # SD cards and internal eMMC drives.
281             "mmc_block"
283             # Support USB keyboards, in case the boot fails and we only have
284             # a USB keyboard, or for LUKS passphrase prompt.
285             "uhci_hcd"
286             "ehci_hcd"
287             "ehci_pci"
288             "ohci_hcd"
289             "ohci_pci"
290             "xhci_hcd"
291             "xhci_pci"
292             "usbhid"
293             "hid_generic" "hid_lenovo" "hid_apple" "hid_roccat"
294             "hid_logitech_hidpp" "hid_logitech_dj" "hid_microsoft" "hid_cherry"
296           ] ++ optionals pkgs.stdenv.hostPlatform.isx86 [
297             # Misc. x86 keyboard stuff.
298             "pcips2" "atkbd" "i8042"
300             # x86 RTC needed by the stage 2 init script.
301             "rtc_cmos"
302           ]);
304         boot.initrd.kernelModules =
305           optionals config.boot.initrd.includeDefaultModules [
306             # For LVM.
307             "dm_mod"
308           ];
309       })
311       (mkIf config.boot.kernel.enable {
312         system.build = { inherit kernel; };
314         system.modulesTree = [ kernel ] ++ config.boot.extraModulePackages;
316         # Not required for, e.g., containers as they don't have their own kernel or initrd.
317         # They boot directly into stage 2.
318         system.systemBuilderArgs.kernelParams = config.boot.kernelParams;
319         system.systemBuilderCommands =
320           let
321             kernelPath = "${config.boot.kernelPackages.kernel}/" +
322               "${config.system.boot.loader.kernelFile}";
323             initrdPath = "${config.system.build.initialRamdisk}/" +
324               "${config.system.boot.loader.initrdFile}";
325           in
326           ''
327             if [ ! -f ${kernelPath} ]; then
328               echo "The bootloader cannot find the proper kernel image."
329               echo "(Expecting ${kernelPath})"
330               false
331             fi
333             ln -s ${kernelPath} $out/kernel
334             ln -s ${config.system.modulesTree} $out/kernel-modules
335             ${optionalString (config.hardware.deviceTree.package != null) ''
336               ln -s ${config.hardware.deviceTree.package} $out/dtbs
337             ''}
339             echo -n "$kernelParams" > $out/kernel-params
341             ln -s ${initrdPath} $out/initrd
343             ln -s ${config.system.build.initialRamdiskSecretAppender}/bin/append-initrd-secrets $out
345             ln -s ${config.hardware.firmware}/lib/firmware $out/firmware
346           '';
348         # Implement consoleLogLevel both in early boot and using sysctl
349         # (so you don't need to reboot to have changes take effect).
350         boot.kernelParams =
351           [ "loglevel=${toString config.boot.consoleLogLevel}" ] ++
352           optionals config.boot.vesa [ "vga=0x317" "nomodeset" ];
354         boot.kernel.sysctl."kernel.printk" = mkDefault config.boot.consoleLogLevel;
356         boot.kernelModules = [ "loop" "atkbd" ];
358         # Create /etc/modules-load.d/nixos.conf, which is read by
359         # systemd-modules-load.service to load required kernel modules.
360         environment.etc =
361           { "modules-load.d/nixos.conf".source = kernelModulesConf;
362           };
364         systemd.services.systemd-modules-load =
365           { wantedBy = [ "multi-user.target" ];
366             restartTriggers = [ kernelModulesConf ];
367             serviceConfig =
368               { # Ignore failed module loads.  Typically some of the
369                 # modules in ‘boot.kernelModules’ are "nice to have but
370                 # not required" (e.g. acpi-cpufreq), so we don't want to
371                 # barf on those.
372                 SuccessExitStatus = "0 1";
373               };
374           };
376         lib.kernelConfig = {
377           isYes = option: {
378             assertion = config: config.isYes option;
379             message = "CONFIG_${option} is not yes!";
380             configLine = "CONFIG_${option}=y";
381           };
383           isNo = option: {
384             assertion = config: config.isNo option;
385             message = "CONFIG_${option} is not no!";
386             configLine = "CONFIG_${option}=n";
387           };
389           isModule = option: {
390             assertion = config: config.isModule option;
391             message = "CONFIG_${option} is not built as a module!";
392             configLine = "CONFIG_${option}=m";
393           };
395           ### Usually you will just want to use these two
396           # True if yes or module
397           isEnabled = option: {
398             assertion = config: config.isEnabled option;
399             message = "CONFIG_${option} is not enabled!";
400             configLine = "CONFIG_${option}=y";
401           };
403           # True if no or omitted
404           isDisabled = option: {
405             assertion = config: config.isDisabled option;
406             message = "CONFIG_${option} is not disabled!";
407             configLine = "CONFIG_${option}=n";
408           };
409         };
411         # The config options that all modules can depend upon
412         system.requiredKernelConfig = with config.lib.kernelConfig;
413           [
414             # !!! Should this really be needed?
415             (isYes "MODULES")
416             (isYes "BINFMT_ELF")
417           ] ++ (optional (randstructSeed != "") (isYes "GCC_PLUGIN_RANDSTRUCT"));
419         # nixpkgs kernels are assumed to have all required features
420         assertions = if config.boot.kernelPackages.kernel ? features then [] else
421           let cfg = config.boot.kernelPackages.kernel.config; in map (attrs:
422             { assertion = attrs.assertion cfg; inherit (attrs) message; }
423           ) config.system.requiredKernelConfig;
425       })
427     ];