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