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-unwrapped,
15 rustPlatform,
16 rust-bindgen-unwrapped,
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 and lib/systems/platform.nix;
42 # if `false` then only `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 isLTS ? false,
76 isZen ? false,
77 isLibre ? false,
78 isHardened ? false,
79
80 # easy overrides to stdenv.hostPlatform.linux-kernel members
81 autoModules ? stdenv.hostPlatform.linux-kernel.autoModules,
82 preferBuiltin ? stdenv.hostPlatform.linux-kernel.preferBuiltin or false,
83 kernelArch ? stdenv.hostPlatform.linuxArch,
84 kernelTests ? { },
85
86 stdenv ? args'.stdenv,
87 buildPackages ? args'.buildPackages,
88 pkgsBuildBuild ? args'.pkgsBuildBuild,
89
90 ...
91 }@args:
92
93 # Note: this package is used for bootstrapping fetchurl, and thus
94 # cannot use fetchpatch! All mutable patches (generated by GitHub or
95 # cgit) that are needed here should be included directly in Nixpkgs as
96 # files.
97
98 let
99 # Dirty hack to make sure that `version` & `src` have
100 # `<nixpkgs/pkgs/os-specific/linux/kernel/linux-x.y.nix>` as position
101 # when using `builtins.unsafeGetAttrPos`.
102 #
103 # This is to make sure that ofborg actually detects changes in the kernel derivation
104 # and pings all maintainers.
105 #
106 # For further context, see https://github.com/NixOS/nixpkgs/pull/143113#issuecomment-953319957
107 basicArgs = builtins.removeAttrs args (
108 lib.filter (
109 x:
110 !(builtins.elem x [
111 "version"
112 "pname"
113 "src"
114 ])
115 ) (lib.attrNames args)
116 );
117
118 # Combine the `features' attribute sets of all the kernel patches.
119 kernelFeatures = lib.foldr (x: y: (x.features or { }) // y) (
120 {
121 efiBootStub = true;
122 netfilterRPFilter = true;
123 ia32Emulation = true;
124 }
125 // features
126 ) kernelPatches;
127
128 commonStructuredConfig = import ./common-config.nix {
129 inherit lib stdenv version;
130 rustAvailable = lib.meta.availableOn stdenv.hostPlatform rustc-unwrapped;
131
132 features = kernelFeatures; # Ensure we know of all extra patches, etc.
133 };
134
135 intermediateNixConfig =
136 configfile.moduleStructuredConfig.intermediateNixConfig
137 # extra config in legacy string format
138 + extraConfig
139 # need the 'or ""' at the end in case enableCommonConfig = true and extraConfig is not present
140 + lib.optionalString enableCommonConfig stdenv.hostPlatform.linux-kernel.extraConfig or "";
141
142 structuredConfigFromPatches = map (
143 {
144 structuredExtraConfig ? { },
145 ...
146 }@args:
147 if args ? extraStructuredConfig then
148 throw ''
149 Passing `extraStructuredConfig` to the Linux kernel (e.g.
150 via `boot.kernelPatches` in NixOS) is not supported anymore. Use
151 `structuredExtraConfig` instead.
152 ''
153 else
154 {
155 settings = structuredExtraConfig;
156 }
157 ) kernelPatches;
158
159 # appends kernel patches extraConfig
160 kernelConfigFun =
161 baseConfigStr:
162 let
163 configFromPatches = map (
164 {
165 extraConfig ? "",
166 ...
167 }:
168 extraConfig
169 ) kernelPatches;
170 in
171 lib.concatStringsSep "\n" ([ baseConfigStr ] ++ configFromPatches);
172
173 withRust = ((configfile.moduleStructuredConfig.settings.RUST or { }).tristate or null) == "y";
174
175 configfile = stdenv.mkDerivation {
176 inherit
177 ignoreConfigErrors
178 autoModules
179 preferBuiltin
180 kernelArch
181 extraMakeFlags
182 ;
183 pname = "linux-config";
184 inherit version;
185
186 generateConfig = ./generate-config.pl;
187
188 kernelConfig = kernelConfigFun intermediateNixConfig;
189 passAsFile = [ "kernelConfig" ];
190
191 depsBuildBuild = [ buildPackages.stdenv.cc ];
192 nativeBuildInputs = [
193 perl
194 gmp
195 libmpc
196 mpfr
197 bison
198 flex
199 ]
200 ++ lib.optional (lib.versionAtLeast version "5.2") pahole
201 ++ lib.optionals withRust [
202 rust-bindgen-unwrapped
203 rustc-unwrapped
204 ];
205
206 RUST_LIB_SRC = lib.optionalString withRust rustPlatform.rustLibSrc;
207
208 platformName = stdenv.hostPlatform.linux-kernel.name;
209 # e.g. "defconfig"
210 kernelBaseConfig =
211 if defconfig != null then defconfig else stdenv.hostPlatform.linux-kernel.baseConfig;
212
213 makeFlags = import ./common-flags.nix {
214 inherit
215 lib
216 stdenv
217 buildPackages
218 extraMakeFlags
219 ;
220 };
221
222 postPatch = kernel.postPatch + ''
223 # Patch kconfig to print "###" after every question so that
224 # generate-config.pl from the generic builder can answer them.
225 sed -e '/fflush(stdout);/i\printf("###");' -i scripts/kconfig/conf.c
226 '';
227
228 preUnpack = kernel.preUnpack or "";
229
230 inherit (kernel) src patches;
231
232 buildPhase = ''
233 export buildRoot="''${buildRoot:-build}"
234
235 # Get a basic config file for later refinement with $generateConfig.
236 make $makeFlags \
237 -C . O="$buildRoot" $kernelBaseConfig \
238 ARCH=$kernelArch CROSS_COMPILE=${stdenv.cc.targetPrefix} \
239 $makeFlags
240
241 # Create the config file.
242 echo "generating kernel configuration..."
243 ln -s "$kernelConfigPath" "$buildRoot/kernel-config"
244 DEBUG=1 ARCH=$kernelArch CROSS_COMPILE=${stdenv.cc.targetPrefix} \
245 KERNEL_CONFIG="$buildRoot/kernel-config" AUTO_MODULES=$autoModules \
246 PREFER_BUILTIN=$preferBuiltin BUILD_ROOT="$buildRoot" SRC=. MAKE_FLAGS="$makeFlags" \
247 perl -w $generateConfig
248 ''
249 + lib.optionalString stdenv.cc.isClang ''
250 if ! grep -Fq CONFIG_CC_IS_CLANG=y $buildRoot/.config; then
251 echo "Kernel config didn't recognize the clang compiler?"
252 exit 1
253 fi
254 ''
255 + lib.optionalString stdenv.cc.bintools.isLLVM ''
256 if ! grep -Fq CONFIG_LD_IS_LLD=y $buildRoot/.config; then
257 echo "Kernel config didn't recognize the LLVM linker?"
258 exit 1
259 fi
260 ''
261 + lib.optionalString withRust ''
262 if ! grep -Fq CONFIG_RUST_IS_AVAILABLE=y $buildRoot/.config; then
263 echo "Kernel config didn't find Rust toolchain?"
264 exit 1
265 fi
266 '';
267
268 installPhase = "mv $buildRoot/.config $out";
269
270 enableParallelBuilding = true;
271
272 passthru = rec {
273 module = import ../../../../nixos/modules/system/boot/kernel_config.nix;
274 # used also in apache
275 # { modules = [ { options = res.options; config = svc.config or svc; } ];
276 # check = false;
277 # The result is a set of two attributes
278 moduleStructuredConfig =
279 (lib.evalModules {
280 modules = [
281 module
282 ]
283 ++ lib.optionals enableCommonConfig [
284 {
285 settings = commonStructuredConfig;
286 _file = "pkgs/os-specific/linux/kernel/common-config.nix";
287 }
288 ]
289 ++ [
290 {
291 settings = structuredExtraConfig;
292 _file = "structuredExtraConfig";
293 }
294 ]
295 ++ structuredConfigFromPatches;
296 }).config;
297
298 structuredConfig = moduleStructuredConfig.settings;
299 };
300 }; # end of configfile derivation
301
302 kernel = (callPackage ./manual-config.nix { inherit lib stdenv buildPackages; }) (
303 basicArgs
304 // {
305 inherit
306 kernelPatches
307 randstructSeed
308 extraMakeFlags
309 extraMeta
310 configfile
311 modDirVersion
312 ;
313 pos = builtins.unsafeGetAttrPos "version" args;
314
315 config = {
316 CONFIG_MODULES = "y";
317 CONFIG_FW_LOADER = "y";
318 CONFIG_RUST = if withRust then "y" else "n";
319 };
320 }
321 );
322
323 in
324 kernel.overrideAttrs (
325 finalAttrs: previousAttrs: {
326
327 passthru =
328 previousAttrs.passthru or { }
329 // extraPassthru
330 // basicArgs
331 // {
332 features = kernelFeatures;
333 inherit
334 commonStructuredConfig
335 structuredExtraConfig
336 extraMakeFlags
337 isLTS
338 isZen
339 isHardened
340 isLibre
341 ;
342 isXen = lib.warn "The isXen attribute is deprecated. All Nixpkgs kernels that support it now have Xen enabled." true;
343
344 # Adds dependencies needed to edit the config:
345 # nix-shell '<nixpkgs>' -A linux.configEnv --command 'make nconfig'
346 configEnv = finalAttrs.finalPackage.overrideAttrs (previousAttrs: {
347 depsBuildBuild =
348 previousAttrs.depsBuildBuild or [ ]
349 ++ (with pkgsBuildBuild; [
350 pkg-config
351 ncurses
352 ]);
353 });
354
355 tests =
356 let
357 overridableKernel = finalAttrs.finalPackage // {
358 override =
359 args:
360 lib.warn (
361 "override is stubbed for NixOS kernel tests, not applying changes these arguments: "
362 + toString (lib.attrNames (lib.toFunction args { }))
363 ) overridableKernel;
364 };
365 /*
366 Certain arguments must be evaluated lazily; so that only the output(s) depend on them.
367 Original reproducer / simplified use case:
368 */
369 versionDoesNotDependOnPatchesEtcNixOS =
370 builtins.seq
371 (nixos (
372 { config, pkgs, ... }:
373 {
374 boot.kernelPatches = [
375 (builtins.seq config.boot.kernelPackages.kernel.version { patch = pkgs.emptyFile; })
376 ];
377 }
378 )).config.boot.kernelPackages.kernel.outPath
379 emptyFile;
380 versionDoesNotDependOnPatchesEtc =
381 builtins.seq
382 (import ./generic.nix args' (
383 args
384 // (
385 let
386 explain = attrName: ''
387 The ${attrName} attribute must be able to access the kernel.version attribute without an infinite recursion.
388 That means that the kernel attrset (attrNames) and the kernel.version attribute must not depend on the ${attrName} argument.
389 The fact that this exception is raised shows that such a dependency does exist.
390 This is a problem for the configurability of ${attrName} in version-aware logic such as that in NixOS.
391 Strictness can creep in through optional attributes, or assertions and warnings that run as part of code that shouldn't access what is checked.
392 '';
393 in
394 {
395 kernelPatches = throw (explain "kernelPatches");
396 structuredExtraConfig = throw (explain "structuredExtraConfig");
397 modDirVersion = throw (explain "modDirVersion");
398 }
399 )
400 )).version
401 emptyFile;
402 in
403 {
404 inherit versionDoesNotDependOnPatchesEtc;
405 testsForKernel = nixosTests.kernel-generic.passthru.testsForKernel overridableKernel;
406 # Disabled by default, because the infinite recursion is hard to understand. The other test's error is better and produces a shorter trace.
407 # inherit versionDoesNotDependOnPatchesEtcNixOS;
408 }
409 // kernelTests;
410 };
411
412 }
413 )
414 );
415in
416overridableKernel