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