1{ config, lib, pkgs, ... }: 2 3with lib; 4 5let 6 7 kernel = config.boot.kernelPackages.kernel; 8 9 kernelModulesConf = pkgs.writeText "nixos.conf" 10 '' 11 ${concatStringsSep "\n" config.boot.kernelModules} 12 ''; 13 14in 15 16{ 17 18 ###### interface 19 20 options = { 21 22 boot.kernelPackages = mkOption { 23 default = pkgs.linuxPackages; 24 # We don't want to evaluate all of linuxPackages for the manual 25 # - some of it might not even evaluate correctly. 26 defaultText = "pkgs.linuxPackages"; 27 example = literalExample "pkgs.linuxPackages_2_6_25"; 28 description = '' 29 This option allows you to override the Linux kernel used by 30 NixOS. Since things like external kernel module packages are 31 tied to the kernel you're using, it also overrides those. 32 This option is a function that takes Nixpkgs as an argument 33 (as a convenience), and returns an attribute set containing at 34 the very least an attribute <varname>kernel</varname>. 35 Additional attributes may be needed depending on your 36 configuration. For instance, if you use the NVIDIA X driver, 37 then it also needs to contain an attribute 38 <varname>nvidia_x11</varname>. 39 ''; 40 }; 41 42 boot.kernelParams = mkOption { 43 type = types.listOf types.str; 44 default = [ ]; 45 description = "Parameters added to the kernel command line."; 46 }; 47 48 boot.consoleLogLevel = mkOption { 49 type = types.int; 50 default = 4; 51 description = '' 52 The kernel console log level. Log messages with a priority 53 numerically less than this will not appear on the console. 54 ''; 55 }; 56 57 boot.vesa = mkOption { 58 type = types.bool; 59 default = false; 60 description = '' 61 Whether to activate VESA video mode on boot. 62 ''; 63 }; 64 65 boot.extraModulePackages = mkOption { 66 type = types.listOf types.package; 67 default = []; 68 example = literalExample "[ pkgs.linuxPackages.nvidia_x11 ]"; 69 description = "A list of additional packages supplying kernel modules."; 70 }; 71 72 boot.kernelModules = mkOption { 73 type = types.listOf types.str; 74 default = []; 75 description = '' 76 The set of kernel modules to be loaded in the second stage of 77 the boot process. Note that modules that are needed to 78 mount the root file system should be added to 79 <option>boot.initrd.availableKernelModules</option> or 80 <option>boot.initrd.kernelModules</option>. 81 ''; 82 }; 83 84 boot.initrd.availableKernelModules = mkOption { 85 type = types.listOf types.str; 86 default = []; 87 example = [ "sata_nv" "ext3" ]; 88 description = '' 89 The set of kernel modules in the initial ramdisk used during the 90 boot process. This set must include all modules necessary for 91 mounting the root device. That is, it should include modules 92 for the physical device (e.g., SCSI drivers) and for the file 93 system (e.g., ext3). The set specified here is automatically 94 closed under the module dependency relation, i.e., all 95 dependencies of the modules list here are included 96 automatically. The modules listed here are available in the 97 initrd, but are only loaded on demand (e.g., the ext3 module is 98 loaded automatically when an ext3 filesystem is mounted, and 99 modules for PCI devices are loaded when they match the PCI ID 100 of a device in your system). To force a module to be loaded, 101 include it in <option>boot.initrd.kernelModules</option>. 102 ''; 103 }; 104 105 boot.initrd.kernelModules = mkOption { 106 type = types.listOf types.str; 107 default = []; 108 description = "List of modules that are always loaded by the initrd."; 109 }; 110 111 system.modulesTree = mkOption { 112 type = types.listOf types.path; 113 internal = true; 114 default = []; 115 description = '' 116 Tree of kernel modules. This includes the kernel, plus modules 117 built outside of the kernel. Combine these into a single tree of 118 symlinks because modprobe only supports one directory. 119 ''; 120 # Convert the list of path to only one path. 121 apply = pkgs.aggregateModules; 122 }; 123 124 system.requiredKernelConfig = mkOption { 125 default = []; 126 example = literalExample '' 127 with config.lib.kernelConfig; [ 128 (isYes "MODULES") 129 (isEnabled "FB_CON_DECOR") 130 (isEnabled "BLK_DEV_INITRD") 131 ] 132 ''; 133 internal = true; 134 type = types.listOf types.attrs; 135 description = '' 136 This option allows modules to specify the kernel config options that 137 must be set (or unset) for the module to work. Please use the 138 lib.kernelConfig functions to build list elements. 139 ''; 140 }; 141 142 }; 143 144 145 ###### implementation 146 147 config = mkIf (!config.boot.isContainer) { 148 149 system.build = { inherit kernel; }; 150 151 system.modulesTree = [ kernel ] ++ config.boot.extraModulePackages; 152 153 # Implement consoleLogLevel both in early boot and using sysctl 154 # (so you don't need to reboot to have changes take effect). 155 boot.kernelParams = 156 [ "loglevel=${toString config.boot.consoleLogLevel}" ] ++ 157 optionals config.boot.vesa [ "vga=0x317" ]; 158 159 boot.kernel.sysctl."kernel.printk" = config.boot.consoleLogLevel; 160 161 boot.kernelModules = [ "loop" "atkbd" ]; 162 163 boot.initrd.availableKernelModules = 164 [ # Note: most of these (especially the SATA/PATA modules) 165 # shouldn't be included by default since nixos-hardware-scan 166 # detects them, but I'm keeping them for now for backwards 167 # compatibility. 168 169 # Some SATA/PATA stuff. 170 "ahci" 171 "sata_nv" 172 "sata_via" 173 "sata_sis" 174 "sata_uli" 175 "ata_piix" 176 "pata_marvell" 177 178 # Standard SCSI stuff. 179 "sd_mod" 180 "sr_mod" 181 182 # Standard IDE stuff. 183 "ide_cd" 184 "ide_disk" 185 "ide_generic" 186 187 # SD cards and internal eMMC drives. 188 "mmc_block" 189 190 # Support USB keyboards, in case the boot fails and we only have 191 # a USB keyboard. 192 "uhci_hcd" 193 "ehci_hcd" 194 "ehci_pci" 195 "ohci_hcd" 196 "ohci_pci" 197 "xhci_hcd" 198 "xhci_pci" 199 "usbhid" 200 "hid_generic" "hid_lenovo" 201 "hid_apple" "hid_logitech_dj" "hid_lenovo_tpkbd" "hid_roccat" 202 203 # Misc. stuff. 204 "pcips2" "atkbd" 205 206 # To wait for SCSI devices to appear. 207 "scsi_wait_scan" 208 209 # Needed by the stage 2 init script. 210 "rtc_cmos" 211 ]; 212 213 boot.initrd.kernelModules = 214 [ # For LVM. 215 "dm_mod" 216 ]; 217 218 # The Linux kernel >= 2.6.27 provides firmware. 219 hardware.firmware = [ kernel ]; 220 221 # Create /etc/modules-load.d/nixos.conf, which is read by 222 # systemd-modules-load.service to load required kernel modules. 223 environment.etc = singleton 224 { target = "modules-load.d/nixos.conf"; 225 source = kernelModulesConf; 226 }; 227 228 systemd.services."systemd-modules-load" = 229 { wantedBy = [ "multi-user.target" ]; 230 restartTriggers = [ kernelModulesConf ]; 231 environment.MODULE_DIR = "/run/booted-system/kernel-modules/lib/modules"; 232 serviceConfig = 233 { # Ignore failed module loads. Typically some of the 234 # modules in ‘boot.kernelModules’ are "nice to have but 235 # not required" (e.g. acpi-cpufreq), so we don't want to 236 # barf on those. 237 SuccessExitStatus = "0 1"; 238 }; 239 }; 240 241 systemd.services.kmod-static-nodes = 242 { environment.MODULE_DIR = "/run/booted-system/kernel-modules/lib/modules"; 243 }; 244 245 lib.kernelConfig = { 246 isYes = option: { 247 assertion = config: config.isYes option; 248 message = "CONFIG_${option} is not yes!"; 249 configLine = "CONFIG_${option}=y"; 250 }; 251 252 isNo = option: { 253 assertion = config: config.isNo option; 254 message = "CONFIG_${option} is not no!"; 255 configLine = "CONFIG_${option}=n"; 256 }; 257 258 isModule = option: { 259 assertion = config: config.isModule option; 260 message = "CONFIG_${option} is not built as a module!"; 261 configLine = "CONFIG_${option}=m"; 262 }; 263 264 ### Usually you will just want to use these two 265 # True if yes or module 266 isEnabled = option: { 267 assertion = config: config.isEnabled option; 268 message = "CONFIG_${option} is not enabled!"; 269 configLine = "CONFIG_${option}=y"; 270 }; 271 272 # True if no or omitted 273 isDisabled = option: { 274 assertion = config: config.isDisabled option; 275 message = "CONFIG_${option} is not disabled!"; 276 configLine = "CONFIG_${option}=n"; 277 }; 278 }; 279 280 # The config options that all modules can depend upon 281 system.requiredKernelConfig = with config.lib.kernelConfig; [ 282 # !!! Should this really be needed? 283 (isYes "MODULES") 284 (isYes "BINFMT_ELF") 285 ]; 286 287 # nixpkgs kernels are assumed to have all required features 288 assertions = if config.boot.kernelPackages.kernel ? features then [] else 289 let cfg = config.boot.kernelPackages.kernel.config; in map (attrs: 290 { assertion = attrs.assertion cfg; inherit (attrs) message; } 291 ) config.system.requiredKernelConfig; 292 293 }; 294 295}