vuls: init at 0.27.0
[NixPkgs.git] / nixos / modules / system / boot / kernel.nix
blob4854119b25382da117df1d994b29ec88a56a14c4
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 "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 = ''
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 = ''
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             name = "foo-ml-mbox";
86             patch = (fetchurl {
87               url = "https://lore.kernel.org/lkml/19700205182810.58382-1-email@domain/t.mbox.gz";
88               hash = "sha256-...";
89             });
90           }
91         ]
92       '';
93       description = ''
94         A list of additional patches to apply to the kernel.
96         Every item should be an attribute set with the following attributes:
98         ```nix
99         {
100           name = "foo";                 # descriptive name, required
102           patch = ./foo.patch;          # path or derivation that contains the patch source
103                                         # (required, but can be null if only config changes
104                                         # are needed)
106           extraStructuredConfig = {     # attrset of extra configuration parameters without the CONFIG_ prefix
107             FOO = lib.kernel.yes;       # (optional)
108           };                            # values should generally be lib.kernel.yes,
109                                         # lib.kernel.no or lib.kernel.module
111           features = {                  # attrset of extra "features" the kernel is considered to have
112             foo = true;                 # (may be checked by other NixOS modules, optional)
113           };
115           extraConfig = "FOO y";        # extra configuration options in string form without the CONFIG_ prefix
116                                         # (optional, multiple lines allowed to specify multiple options)
117                                         # (deprecated, use extraStructuredConfig instead)
118         }
119         ```
121         There's a small set of existing kernel patches in Nixpkgs, available as `pkgs.kernelPatches`,
122         that follow this format and can be used directly.
123       '';
124     };
126     boot.kernel.randstructSeed = mkOption {
127       type = types.str;
128       default = "";
129       example = "my secret seed";
130       description = ''
131         Provides a custom seed for the {var}`RANDSTRUCT` security
132         option of the Linux kernel. Note that {var}`RANDSTRUCT` is
133         only enabled in NixOS hardened kernels. Using a custom seed requires
134         building the kernel and dependent packages locally, since this
135         customization happens at build time.
136       '';
137     };
139     boot.kernelParams = mkOption {
140       type = types.listOf (types.strMatching ''([^"[:space:]]|"[^"]*")+'' // {
141         name = "kernelParam";
142         description = "string, with spaces inside double quotes";
143       });
144       default = [ ];
145       description = "Parameters added to the kernel command line.";
146     };
148     boot.consoleLogLevel = mkOption {
149       type = types.int;
150       default = 4;
151       description = ''
152         The kernel console `loglevel`. All Kernel Messages with a log level smaller
153         than this setting will be printed to the console.
154       '';
155     };
157     boot.vesa = mkOption {
158       type = types.bool;
159       default = false;
160       description = ''
161         (Deprecated) This option, if set, activates the VESA 800x600 video
162         mode on boot and disables kernel modesetting. It is equivalent to
163         specifying `[ "vga=0x317" "nomodeset" ]` in the
164         {option}`boot.kernelParams` option. This option is
165         deprecated as of 2020: Xorg now works better with modesetting, and
166         you might want a different VESA vga setting, anyway.
167       '';
168     };
170     boot.extraModulePackages = mkOption {
171       type = types.listOf types.package;
172       default = [];
173       example = literalExpression "[ config.boot.kernelPackages.nvidia_x11 ]";
174       description = "A list of additional packages supplying kernel modules.";
175     };
177     boot.kernelModules = mkOption {
178       type = types.listOf types.str;
179       default = [];
180       description = ''
181         The set of kernel modules to be loaded in the second stage of
182         the boot process.  Note that modules that are needed to
183         mount the root file system should be added to
184         {option}`boot.initrd.availableKernelModules` or
185         {option}`boot.initrd.kernelModules`.
186       '';
187     };
189     boot.initrd.availableKernelModules = mkOption {
190       type = types.listOf types.str;
191       default = [];
192       example = [ "sata_nv" "ext3" ];
193       description = ''
194         The set of kernel modules in the initial ramdisk used during the
195         boot process.  This set must include all modules necessary for
196         mounting the root device.  That is, it should include modules
197         for the physical device (e.g., SCSI drivers) and for the file
198         system (e.g., ext3).  The set specified here is automatically
199         closed under the module dependency relation, i.e., all
200         dependencies of the modules list here are included
201         automatically.  The modules listed here are available in the
202         initrd, but are only loaded on demand (e.g., the ext3 module is
203         loaded automatically when an ext3 filesystem is mounted, and
204         modules for PCI devices are loaded when they match the PCI ID
205         of a device in your system).  To force a module to be loaded,
206         include it in {option}`boot.initrd.kernelModules`.
207       '';
208     };
210     boot.initrd.kernelModules = mkOption {
211       type = types.listOf types.str;
212       default = [];
213       description = "List of modules that are always loaded by the initrd.";
214     };
216     boot.initrd.includeDefaultModules = mkOption {
217       type = types.bool;
218       default = true;
219       description = ''
220         This option, if set, adds a collection of default kernel modules
221         to {option}`boot.initrd.availableKernelModules` and
222         {option}`boot.initrd.kernelModules`.
223       '';
224     };
226     system.modulesTree = mkOption {
227       type = types.listOf types.path;
228       internal = true;
229       default = [];
230       description = ''
231         Tree of kernel modules.  This includes the kernel, plus modules
232         built outside of the kernel.  Combine these into a single tree of
233         symlinks because modprobe only supports one directory.
234       '';
235       # Convert the list of path to only one path.
236       apply = let
237         kernel-name = config.boot.kernelPackages.kernel.name or "kernel";
238       in modules: (pkgs.aggregateModules modules).override { name = kernel-name + "-modules"; };
239     };
241     system.requiredKernelConfig = mkOption {
242       default = [];
243       example = literalExpression ''
244         with config.lib.kernelConfig; [
245           (isYes "MODULES")
246           (isEnabled "FB_CON_DECOR")
247           (isEnabled "BLK_DEV_INITRD")
248         ]
249       '';
250       internal = true;
251       type = types.listOf types.attrs;
252       description = ''
253         This option allows modules to specify the kernel config options that
254         must be set (or unset) for the module to work. Please use the
255         lib.kernelConfig functions to build list elements.
256       '';
257     };
259   };
262   ###### implementation
264   config = mkMerge
265     [ (mkIf config.boot.initrd.enable {
266         boot.initrd.availableKernelModules =
267           optionals config.boot.initrd.includeDefaultModules ([
268             # Note: most of these (especially the SATA/PATA modules)
269             # shouldn't be included by default since nixos-generate-config
270             # detects them, but I'm keeping them for now for backwards
271             # compatibility.
273             # Some SATA/PATA stuff.
274             "ahci"
275             "sata_nv"
276             "sata_via"
277             "sata_sis"
278             "sata_uli"
279             "ata_piix"
280             "pata_marvell"
282             # NVMe
283             "nvme"
285             # Standard SCSI stuff.
286             "sd_mod"
287             "sr_mod"
289             # SD cards and internal eMMC drives.
290             "mmc_block"
292             # Support USB keyboards, in case the boot fails and we only have
293             # a USB keyboard, or for LUKS passphrase prompt.
294             "uhci_hcd"
295             "ehci_hcd"
296             "ehci_pci"
297             "ohci_hcd"
298             "ohci_pci"
299             "xhci_hcd"
300             "xhci_pci"
301             "usbhid"
302             "hid_generic" "hid_lenovo" "hid_apple" "hid_roccat"
303             "hid_logitech_hidpp" "hid_logitech_dj" "hid_microsoft" "hid_cherry"
304             "hid_corsair"
306           ] ++ optionals pkgs.stdenv.hostPlatform.isx86 [
307             # Misc. x86 keyboard stuff.
308             "pcips2" "atkbd" "i8042"
310             # x86 RTC needed by the stage 2 init script.
311             "rtc_cmos"
312           ]);
314         boot.initrd.kernelModules =
315           optionals config.boot.initrd.includeDefaultModules [
316             # For LVM.
317             "dm_mod"
318           ];
319       })
321       (mkIf config.boot.kernel.enable {
322         system.build = { inherit kernel; };
324         system.modulesTree = [ kernel ] ++ config.boot.extraModulePackages;
326         # Not required for, e.g., containers as they don't have their own kernel or initrd.
327         # They boot directly into stage 2.
328         system.systemBuilderArgs.kernelParams = config.boot.kernelParams;
329         system.systemBuilderCommands =
330           let
331             kernelPath = "${config.boot.kernelPackages.kernel}/" +
332               "${config.system.boot.loader.kernelFile}";
333             initrdPath = "${config.system.build.initialRamdisk}/" +
334               "${config.system.boot.loader.initrdFile}";
335           in
336           ''
337             if [ ! -f ${kernelPath} ]; then
338               echo "The bootloader cannot find the proper kernel image."
339               echo "(Expecting ${kernelPath})"
340               false
341             fi
343             ln -s ${kernelPath} $out/kernel
344             ln -s ${config.system.modulesTree} $out/kernel-modules
345             ${optionalString (config.hardware.deviceTree.package != null) ''
346               ln -s ${config.hardware.deviceTree.package} $out/dtbs
347             ''}
349             echo -n "$kernelParams" > $out/kernel-params
351             ln -s ${initrdPath} $out/initrd
353             ln -s ${config.system.build.initialRamdiskSecretAppender}/bin/append-initrd-secrets $out
355             ln -s ${config.hardware.firmware}/lib/firmware $out/firmware
356           '';
358         # Implement consoleLogLevel both in early boot and using sysctl
359         # (so you don't need to reboot to have changes take effect).
360         boot.kernelParams =
361           [ "loglevel=${toString config.boot.consoleLogLevel}" ] ++
362           optionals config.boot.vesa [ "vga=0x317" "nomodeset" ];
364         boot.kernel.sysctl."kernel.printk" = mkDefault config.boot.consoleLogLevel;
366         boot.kernelModules = [ "loop" "atkbd" ];
368         # Create /etc/modules-load.d/nixos.conf, which is read by
369         # systemd-modules-load.service to load required kernel modules.
370         environment.etc =
371           { "modules-load.d/nixos.conf".source = kernelModulesConf;
372           };
374         systemd.services.systemd-modules-load =
375           { wantedBy = [ "multi-user.target" ];
376             restartTriggers = [ kernelModulesConf ];
377             serviceConfig =
378               { # Ignore failed module loads.  Typically some of the
379                 # modules in ‘boot.kernelModules’ are "nice to have but
380                 # not required" (e.g. acpi-cpufreq), so we don't want to
381                 # barf on those.
382                 SuccessExitStatus = "0 1";
383               };
384           };
386         lib.kernelConfig = {
387           isYes = option: {
388             assertion = config: config.isYes option;
389             message = "CONFIG_${option} is not yes!";
390             configLine = "CONFIG_${option}=y";
391           };
393           isNo = option: {
394             assertion = config: config.isNo option;
395             message = "CONFIG_${option} is not no!";
396             configLine = "CONFIG_${option}=n";
397           };
399           isModule = option: {
400             assertion = config: config.isModule option;
401             message = "CONFIG_${option} is not built as a module!";
402             configLine = "CONFIG_${option}=m";
403           };
405           ### Usually you will just want to use these two
406           # True if yes or module
407           isEnabled = option: {
408             assertion = config: config.isEnabled option;
409             message = "CONFIG_${option} is not enabled!";
410             configLine = "CONFIG_${option}=y";
411           };
413           # True if no or omitted
414           isDisabled = option: {
415             assertion = config: config.isDisabled option;
416             message = "CONFIG_${option} is not disabled!";
417             configLine = "CONFIG_${option}=n";
418           };
419         };
421         # The config options that all modules can depend upon
422         system.requiredKernelConfig = with config.lib.kernelConfig;
423           [
424             # !!! Should this really be needed?
425             (isYes "MODULES")
426             (isYes "BINFMT_ELF")
427           ] ++ (optional (randstructSeed != "") (isYes "GCC_PLUGIN_RANDSTRUCT"));
429         # nixpkgs kernels are assumed to have all required features
430         assertions = if config.boot.kernelPackages.kernel ? features then [] else
431           let cfg = config.boot.kernelPackages.kernel.config; in map (attrs:
432             { assertion = attrs.assertion cfg; inherit (attrs) message; }
433           ) config.system.requiredKernelConfig;
435       })
437     ];