1{
2 buildPackages,
3 callPackage,
4 perl,
5 bison ? null,
6 flex ? null,
7 gmp ? null,
8 libmpc ? null,
9 mpfr ? null,
10 pahole,
11 lib,
12 stdenv,
13 rustc,
14 rustPlatform,
15 rust-bindgen,
16 # testing
17 emptyFile,
18 nixos,
19 nixosTests,
20}@args':
21
22let
23 overridableKernel = lib.makeOverridable (
24 # The kernel source tarball.
25 {
26 src,
27
28 # The kernel version.
29 version,
30
31 # Allows overriding the default defconfig
32 defconfig ? null,
33
34 # Legacy overrides to the intermediate kernel config, as string
35 extraConfig ? "",
36
37 # Additional make flags passed to kbuild
38 extraMakeFlags ? [ ],
39
40 # enables the options in ./common-config.nix; if `false` then only
41 # `structuredExtraConfig` is used
42 enableCommonConfig ? true
43
44 , # kernel intermediate config overrides, as a set
45 structuredExtraConfig ? { },
46
47 # The version number used for the module directory
48 # If unspecified, this is determined automatically from the version.
49 modDirVersion ? null,
50
51 # An attribute set whose attributes express the availability of
52 # certain features in this kernel. E.g. `{ia32Emulation = true;}'
53 # indicates a kernel that provides Intel wireless support. Used in
54 # NixOS to implement kernel-specific behaviour.
55 features ? { },
56
57 # Custom seed used for CONFIG_GCC_PLUGIN_RANDSTRUCT if enabled. This is
58 # automatically extended with extra per-version and per-config values.
59 randstructSeed ? "",
60
61 # A list of patches to apply to the kernel. Each element of this list
62 # should be an attribute set {name, patch} where `name' is a
63 # symbolic name and `patch' is the actual patch. The patch may
64 # optionally be compressed with gzip or bzip2.
65 kernelPatches ? [ ],
66 ignoreConfigErrors ?
67 !lib.elem stdenv.hostPlatform.linux-kernel.name [
68 "aarch64-multiplatform"
69 "pc"
70 ],
71 extraMeta ? { },
72
73 isZen ? false,
74 isLibre ? false,
75 isHardened ? false,
76
77 # easy overrides to stdenv.hostPlatform.linux-kernel members
78 autoModules ? stdenv.hostPlatform.linux-kernel.autoModules,
79 preferBuiltin ? stdenv.hostPlatform.linux-kernel.preferBuiltin or false,
80 kernelArch ? stdenv.hostPlatform.linuxArch,
81 kernelTests ? { },
82
83 stdenv ? args'.stdenv,
84 buildPackages ? args'.buildPackages,
85
86 ...
87 }@args:
88
89 # Note: this package is used for bootstrapping fetchurl, and thus
90 # cannot use fetchpatch! All mutable patches (generated by GitHub or
91 # cgit) that are needed here should be included directly in Nixpkgs as
92 # files.
93
94 assert stdenv.hostPlatform.isLinux;
95
96 let
97 # Dirty hack to make sure that `version` & `src` have
98 # `<nixpkgs/pkgs/os-specific/linux/kernel/linux-x.y.nix>` as position
99 # when using `builtins.unsafeGetAttrPos`.
100 #
101 # This is to make sure that ofborg actually detects changes in the kernel derivation
102 # and pings all maintainers.
103 #
104 # For further context, see https://github.com/NixOS/nixpkgs/pull/143113#issuecomment-953319957
105 basicArgs = builtins.removeAttrs args (
106 lib.filter (
107 x:
108 !(builtins.elem x [
109 "version"
110 "pname"
111 "src"
112 ])
113 ) (lib.attrNames args)
114 );
115
116 # Combine the `features' attribute sets of all the kernel patches.
117 kernelFeatures = lib.foldr (x: y: (x.features or { }) // y) (
118 {
119 efiBootStub = true;
120 netfilterRPFilter = true;
121 ia32Emulation = true;
122 }
123 // features
124 ) kernelPatches;
125
126 commonStructuredConfig = import ./common-config.nix {
127 inherit lib stdenv version;
128 rustAvailable = lib.meta.availableOn stdenv.hostPlatform rustc;
129
130 features = kernelFeatures; # Ensure we know of all extra patches, etc.
131 };
132
133 intermediateNixConfig =
134 configfile.moduleStructuredConfig.intermediateNixConfig
135 # extra config in legacy string format
136 + extraConfig
137 + stdenv.hostPlatform.linux-kernel.extraConfig or "";
138
139 structuredConfigFromPatches = map (
140 {
141 extraStructuredConfig ? { },
142 ...
143 }:
144 {
145 settings = extraStructuredConfig;
146 }
147 ) kernelPatches;
148
149 # appends kernel patches extraConfig
150 kernelConfigFun =
151 baseConfigStr:
152 let
153 configFromPatches = map (
154 {
155 extraConfig ? "",
156 ...
157 }:
158 extraConfig
159 ) kernelPatches;
160 in
161 lib.concatStringsSep "\n" ([ baseConfigStr ] ++ configFromPatches);
162
163 withRust = ((configfile.moduleStructuredConfig.settings.RUST or { }).tristate or null) == "y";
164
165 configfile = stdenv.mkDerivation {
166 inherit
167 ignoreConfigErrors
168 autoModules
169 preferBuiltin
170 kernelArch
171 extraMakeFlags
172 ;
173 pname = "linux-config";
174 inherit version;
175
176 generateConfig = ./generate-config.pl;
177
178 kernelConfig = kernelConfigFun intermediateNixConfig;
179 passAsFile = [ "kernelConfig" ];
180
181 depsBuildBuild = [ buildPackages.stdenv.cc ];
182 nativeBuildInputs =
183 [
184 perl
185 gmp
186 libmpc
187 mpfr
188 bison
189 flex
190 ]
191 ++ lib.optional (lib.versionAtLeast version "5.2") pahole
192 ++ lib.optionals withRust [
193 rust-bindgen
194 rustc
195 ];
196
197 RUST_LIB_SRC = lib.optionalString withRust rustPlatform.rustLibSrc;
198
199 platformName = stdenv.hostPlatform.linux-kernel.name;
200 # e.g. "defconfig"
201 kernelBaseConfig =
202 if defconfig != null then defconfig else stdenv.hostPlatform.linux-kernel.baseConfig;
203
204 makeFlags =
205 lib.optionals (
206 stdenv.hostPlatform.linux-kernel ? makeFlags
207 ) stdenv.hostPlatform.linux-kernel.makeFlags
208 ++ extraMakeFlags;
209
210 postPatch =
211 kernel.postPatch
212 + ''
213 # Patch kconfig to print "###" after every question so that
214 # generate-config.pl from the generic builder can answer them.
215 sed -e '/fflush(stdout);/i\printf("###");' -i scripts/kconfig/conf.c
216 '';
217
218 preUnpack = kernel.preUnpack or "";
219
220 inherit (kernel) src patches;
221
222 buildPhase = ''
223 export buildRoot="''${buildRoot:-build}"
224
225 # Get a basic config file for later refinement with $generateConfig.
226 make $makeFlags \
227 -C . O="$buildRoot" $kernelBaseConfig \
228 ARCH=$kernelArch CROSS_COMPILE=${stdenv.cc.targetPrefix} \
229 $makeFlags
230
231 # Create the config file.
232 echo "generating kernel configuration..."
233 ln -s "$kernelConfigPath" "$buildRoot/kernel-config"
234 DEBUG=1 ARCH=$kernelArch CROSS_COMPILE=${stdenv.cc.targetPrefix} \
235 KERNEL_CONFIG="$buildRoot/kernel-config" AUTO_MODULES=$autoModules \
236 PREFER_BUILTIN=$preferBuiltin BUILD_ROOT="$buildRoot" SRC=. MAKE_FLAGS="$makeFlags" \
237 perl -w $generateConfig
238 '';
239
240 installPhase = "mv $buildRoot/.config $out";
241
242 enableParallelBuilding = true;
243
244 passthru = rec {
245 module = import ../../../../nixos/modules/system/boot/kernel_config.nix;
246 # used also in apache
247 # { modules = [ { options = res.options; config = svc.config or svc; } ];
248 # check = false;
249 # The result is a set of two attributes
250 moduleStructuredConfig =
251 (lib.evalModules {
252 modules =
253 [
254 module
255 ]
256 ++ lib.optionals enableCommonConfig [
257 {
258 settings = commonStructuredConfig;
259 _file = "pkgs/os-specific/linux/kernel/common-config.nix";
260 }
261 ]
262 ++ [
263 {
264 settings = structuredExtraConfig;
265 _file = "structuredExtraConfig";
266 }
267 ]
268 ++ structuredConfigFromPatches;
269 }).config;
270
271 structuredConfig = moduleStructuredConfig.settings;
272 };
273 }; # end of configfile derivation
274
275 kernel = (callPackage ./manual-config.nix { inherit lib stdenv buildPackages; }) (
276 basicArgs
277 // {
278 inherit
279 kernelPatches
280 randstructSeed
281 extraMakeFlags
282 extraMeta
283 configfile
284 modDirVersion
285 ;
286 pos = builtins.unsafeGetAttrPos "version" args;
287
288 config = {
289 CONFIG_MODULES = "y";
290 CONFIG_FW_LOADER = "y";
291 CONFIG_RUST = if withRust then "y" else "n";
292 };
293 }
294 );
295
296 in
297 kernel.overrideAttrs (
298 finalAttrs: previousAttrs: {
299
300 passthru =
301 previousAttrs.passthru or { }
302 // basicArgs
303 // {
304 features = kernelFeatures;
305 inherit
306 commonStructuredConfig
307 structuredExtraConfig
308 extraMakeFlags
309 isZen
310 isHardened
311 isLibre
312 ;
313 isXen = lib.warn "The isXen attribute is deprecated. All Nixpkgs kernels that support it now have Xen enabled." true;
314
315 # Adds dependencies needed to edit the config:
316 # nix-shell '<nixpkgs>' -A linux.configEnv --command 'make nconfig'
317 configEnv = finalAttrs.finalPackage.overrideAttrs (previousAttrs: {
318 nativeBuildInputs =
319 previousAttrs.nativeBuildInputs or [ ]
320 ++ (with buildPackages; [
321 pkg-config
322 ncurses
323 ]);
324 });
325
326 tests =
327 let
328 overridableKernel = finalAttrs.finalPackage // {
329 override =
330 args:
331 lib.warn (
332 "override is stubbed for NixOS kernel tests, not applying changes these arguments: "
333 + toString (lib.attrNames (lib.toFunction args { }))
334 ) overridableKernel;
335 };
336 /*
337 Certain arguments must be evaluated lazily; so that only the output(s) depend on them.
338 Original reproducer / simplified use case:
339 */
340 versionDoesNotDependOnPatchesEtcNixOS =
341 builtins.seq
342 (nixos (
343 { config, pkgs, ... }:
344 {
345 boot.kernelPatches = [
346 (builtins.seq config.boot.kernelPackages.kernel.version { patch = pkgs.emptyFile; })
347 ];
348 }
349 )).config.boot.kernelPackages.kernel.outPath
350 emptyFile;
351 versionDoesNotDependOnPatchesEtc =
352 builtins.seq
353 (import ./generic.nix args' (
354 args
355 // (
356 let
357 explain = attrName: ''
358 The ${attrName} attribute must be able to access the kernel.version attribute without an infinite recursion.
359 That means that the kernel attrset (attrNames) and the kernel.version attribute must not depend on the ${attrName} argument.
360 The fact that this exception is raised shows that such a dependency does exist.
361 This is a problem for the configurability of ${attrName} in version-aware logic such as that in NixOS.
362 Strictness can creep in through optional attributes, or assertions and warnings that run as part of code that shouldn't access what is checked.
363 '';
364 in
365 {
366 kernelPatches = throw (explain "kernelPatches");
367 structuredExtraConfig = throw (explain "structuredExtraConfig");
368 modDirVersion = throw (explain "modDirVersion");
369 }
370 )
371 )).version
372 emptyFile;
373 in
374 {
375 inherit versionDoesNotDependOnPatchesEtc;
376 testsForKernel = nixosTests.kernel-generic.passthru.testsForKernel overridableKernel;
377 # Disabled by default, because the infinite recursion is hard to understand. The other test's error is better and produces a shorter trace.
378 # inherit versionDoesNotDependOnPatchesEtcNixOS;
379 }
380 // kernelTests;
381 };
382
383 }
384 )
385 );
386in
387overridableKernel