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 serviceConfig =
232 { # Ignore failed module loads. Typically some of the
233 # modules in ‘boot.kernelModules’ are "nice to have but
234 # not required" (e.g. acpi-cpufreq), so we don't want to
235 # barf on those.
236 SuccessExitStatus = "0 1";
237 };
238 };
239
240 lib.kernelConfig = {
241 isYes = option: {
242 assertion = config: config.isYes option;
243 message = "CONFIG_${option} is not yes!";
244 configLine = "CONFIG_${option}=y";
245 };
246
247 isNo = option: {
248 assertion = config: config.isNo option;
249 message = "CONFIG_${option} is not no!";
250 configLine = "CONFIG_${option}=n";
251 };
252
253 isModule = option: {
254 assertion = config: config.isModule option;
255 message = "CONFIG_${option} is not built as a module!";
256 configLine = "CONFIG_${option}=m";
257 };
258
259 ### Usually you will just want to use these two
260 # True if yes or module
261 isEnabled = option: {
262 assertion = config: config.isEnabled option;
263 message = "CONFIG_${option} is not enabled!";
264 configLine = "CONFIG_${option}=y";
265 };
266
267 # True if no or omitted
268 isDisabled = option: {
269 assertion = config: config.isDisabled option;
270 message = "CONFIG_${option} is not disabled!";
271 configLine = "CONFIG_${option}=n";
272 };
273 };
274
275 # The config options that all modules can depend upon
276 system.requiredKernelConfig = with config.lib.kernelConfig; [
277 # !!! Should this really be needed?
278 (isYes "MODULES")
279 (isYes "BINFMT_ELF")
280 ];
281
282 # nixpkgs kernels are assumed to have all required features
283 assertions = if config.boot.kernelPackages.kernel ? features then [] else
284 let cfg = config.boot.kernelPackages.kernel.config; in map (attrs:
285 { assertion = attrs.assertion cfg; inherit (attrs) message; }
286 ) config.system.requiredKernelConfig;
287
288 };
289
290}