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