<chapter xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xml:id="sec-kernel-config">
  <title>Linux Kernel</title>
  <para>
    You can override the Linux kernel and associated packages using the
    option <literal>boot.kernelPackages</literal>. For instance, this
    selects the Linux 3.10 kernel:
  </para>
  <programlisting language="bash">
boot.kernelPackages = pkgs.linuxKernel.packages.linux_3_10;
</programlisting>
  <para>
    Note that this not only replaces the kernel, but also packages that
    are specific to the kernel version, such as the NVIDIA video
    drivers. This ensures that driver packages are consistent with the
    kernel.
  </para>
  <para>
    While <literal>pkgs.linuxKernel.packages</literal> contains all
    available kernel packages, you may want to use one of the
    unversioned <literal>pkgs.linuxPackages_*</literal> aliases such as
    <literal>pkgs.linuxPackages_latest</literal>, that are kept up to
    date with new versions.
  </para>
  <para>
    The default Linux kernel configuration should be fine for most
    users. You can see the configuration of your current kernel with the
    following command:
  </para>
  <programlisting>
zcat /proc/config.gz
</programlisting>
  <para>
    If you want to change the kernel configuration, you can use the
    <literal>packageOverrides</literal> feature (see
    <xref linkend="sec-customising-packages" />). For instance, to
    enable support for the kernel debugger KGDB:
  </para>
  <programlisting language="bash">
nixpkgs.config.packageOverrides = pkgs: pkgs.lib.recursiveUpdate pkgs {
  linuxKernel.kernels.linux_5_10 = pkgs.linuxKernel.kernels.linux_5_10.override {
    extraConfig = ''
      KGDB y
    '';
  };
};
</programlisting>
  <para>
    <literal>extraConfig</literal> takes a list of Linux kernel
    configuration options, one per line. The name of the option should
    not include the prefix <literal>CONFIG_</literal>. The option value
    is typically <literal>y</literal>, <literal>n</literal> or
    <literal>m</literal> (to build something as a kernel module).
  </para>
  <para>
    Kernel modules for hardware devices are generally loaded
    automatically by <literal>udev</literal>. You can force a module to
    be loaded via <xref linkend="opt-boot.kernelModules" />, e.g.
  </para>
  <programlisting language="bash">
boot.kernelModules = [ &quot;fuse&quot; &quot;kvm-intel&quot; &quot;coretemp&quot; ];
</programlisting>
  <para>
    If the module is required early during the boot (e.g. to mount the
    root file system), you can use
    <xref linkend="opt-boot.initrd.kernelModules" />:
  </para>
  <programlisting language="bash">
boot.initrd.kernelModules = [ &quot;cifs&quot; ];
</programlisting>
  <para>
    This causes the specified modules and their dependencies to be added
    to the initial ramdisk.
  </para>
  <para>
    Kernel runtime parameters can be set through
    <xref linkend="opt-boot.kernel.sysctl" />, e.g.
  </para>
  <programlisting language="bash">
boot.kernel.sysctl.&quot;net.ipv4.tcp_keepalive_time&quot; = 120;
</programlisting>
  <para>
    sets the kernel’s TCP keepalive time to 120 seconds. To see the
    available parameters, run <literal>sysctl -a</literal>.
  </para>
  <section xml:id="sec-linux-config-customizing">
    <title>Customize your kernel</title>
    <para>
      The first step before compiling the kernel is to generate an
      appropriate <literal>.config</literal> configuration. Either you
      pass your own config via the <literal>configfile</literal> setting
      of <literal>linuxKernel.manualConfig</literal>:
    </para>
    <programlisting language="bash">
custom-kernel = let base_kernel = linuxKernel.kernels.linux_4_9;
  in super.linuxKernel.manualConfig {
    inherit (super) stdenv hostPlatform;
    inherit (base_kernel) src;
    version = &quot;${base_kernel.version}-custom&quot;;

    configfile = /home/me/my_kernel_config;
    allowImportFromDerivation = true;
};
</programlisting>
    <para>
      You can edit the config with this snippet (by default
      <literal>make menuconfig</literal> won't work out of the box on
      nixos):
    </para>
    <programlisting>
nix-shell -E 'with import &lt;nixpkgs&gt; {}; kernelToOverride.overrideAttrs (o: {nativeBuildInputs=o.nativeBuildInputs ++ [ pkg-config ncurses ];})'
</programlisting>
    <para>
      or you can let nixpkgs generate the configuration. Nixpkgs
      generates it via answering the interactive kernel utility
      <literal>make config</literal>. The answers depend on parameters
      passed to
      <literal>pkgs/os-specific/linux/kernel/generic.nix</literal>
      (which you can influence by overriding
      <literal>extraConfig, autoModules, modDirVersion, preferBuiltin, extraConfig</literal>).
    </para>
    <programlisting language="bash">
mptcp93.override ({
  name=&quot;mptcp-local&quot;;

  ignoreConfigErrors = true;
  autoModules = false;
  kernelPreferBuiltin = true;

  enableParallelBuilding = true;

  extraConfig = ''
    DEBUG_KERNEL y
    FRAME_POINTER y
    KGDB y
    KGDB_SERIAL_CONSOLE y
    DEBUG_INFO y
  '';
});
</programlisting>
  </section>
  <section xml:id="sec-linux-config-developing-modules">
    <title>Developing kernel modules</title>
    <para>
      When developing kernel modules it's often convenient to run
      edit-compile-run loop as quickly as possible. See below snippet as
      an example of developing <literal>mellanox</literal> drivers.
    </para>
    <programlisting>
$ nix-build '&lt;nixpkgs&gt;' -A linuxPackages.kernel.dev
$ nix-shell '&lt;nixpkgs&gt;' -A linuxPackages.kernel
$ unpackPhase
$ cd linux-*
$ make -C $dev/lib/modules/*/build M=$(pwd)/drivers/net/ethernet/mellanox modules
# insmod ./drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.ko
</programlisting>
  </section>
</chapter>
