Building linux-surface kernel takes too long. Looking for alternatives

Background:

  • new to Nix
  • not new to Linux
  • not new to kernel compilation (but forgot stuff since it’s been a while)

I have: [ Surface Laptop 1, MacBook Air M1 ]

I want: linux-surface kernel on my Surface, via NixOS/nixos-hardware, to enable touchscreen support

My issue: Surface is taking almost a day to build the kernel (this is the first time I’m doing it on this machine) and it’s still not complete (at the time of posting this)

Potential solutions (in order of preference):

  1. A few yrs ago I remember compiling Xanmod/Zen kernel for Arch on an even slower CPU in way less time (1-2 hrs) but I forgot how I did it. I think it was by probing what kernel modules I use and then only compiling those for the custom kernel. Any such thing possible on NixOS?
  2. Any public binary cache that has linux-surface prebuilt for the Surface Laptop 1 that I can use?
  3. Use distributed builds to make it on the Mac and use it
    • Potential problem: I suspect the different architecture might make it impossible/difficult/quirky (building x86-64 kernel on aarch64 machine)

Last Resort: Since the only thing missing is the touchscreen, I can live without the linux-surface kernel (never used touchscreen laptops before). But would be nice to solve the issue even if only as a learning exercise.


Any suggestions, advice, guides, etc. resource is greatly appreciated. Thanks. :dove:

1 Like

If it is just a missing kernel module you should be able to add it as boot.extraKernelModules (after packaging it) see Linux kernel - NixOS Wiki section out-of-tree kernel modules

1 Like

The NixOS kernel config is quite large by default. It attempts to build basically every possible kernel module. If you can find a more minimal kernel config for that device then you can cut down the build time by a factor of like 5 or something.

But really I would probably just try to use another machine to compile the kernel. Unfortunately you can’t currently cross-compile from darwin (macOS) to linux, but you can run a linux VM and cross-compile the kernel. So you could run an aarch64-linux VM on the mac and have it compile an x86_64-linux kernel for the surface. Your nixos config would need something like this though:

  boot.kernelPackages =
    let
      pkgsCross = import pkgs.path {
        localSystem = "aarch64-linux";
        crossSystem = "x86_64-linux";
      };
    in
    pkgsCross.linuxPackages;
2 Likes

Ah, hadn’t thunk of just installing the touchscreen module to the main kernel. Thanks.

Found this repo for the Surface touchscreen: linux-surface/intel-precise-touch

Following your link, I made this:

{ stdenv, lib, fetchFromGitHub, kernel, kmod }:

stdenv.mkDerivation rec {
  name = "ipts";

  src = fetchFromGitHub {
    owner = "linux-surface";
    repo = "intel-precise-touch";
    hash = "3b88a45360b4fdab85e2d4389fb4812f5867c1b7";
  };

  sourceRoot = "src";
  hardeningDisable = [ "pic" "format" ];                                    # 1
  nativeBuildInputs = kernel.moduleBuildDependencies;                       # 2

  makeFlags = [
    "KERNELRELEASE=${kernel.modDirVersion}"                                 # 3
    "KERNEL_DIR=${kernel.dev}/lib/modules/${kernel.modDirVersion}/build"    # 4
    "INSTALL_MOD_PATH=$(out)"                                               # 5
  ];

  meta = {
    description = "A kernel module for Intel Precise Touch and Stylus driver";
    homepage = "https://github.com/linux-surface/intel-precise-touch";
    license = lib.licenses.gpl2;
    maintainers = [ lib.maintainers.makefu ];
    platforms = lib.platforms.linux;
  };
}

Some questions:

  • Is this what’s needed?
  • Where do I place the package file?
  • How can I also apply the patches to the kernel before loading the module?

Thanks for the suggestion. I’ll try that option if specifically loading the touchscreen module fails, since that seems to be a bit more “repeatable” (can be done in the configs).

You would add it to boot.extraModulePackages.

Oh, if it requires kernel patches then you’ll be rebuilding your kernel anyway.

Ah, I was thinking it only accepts the name of the package file placed in a specific directory. If it accepts the path to the .ko file then great.

Oof. That’s sad then.

Well, the build just finished and the touchscreen works. Now I just have to figure out how to never allow the system to upgrade the kernel :slight_smile: (jk, I’ll do it, just explicitly when I’d be fine with the 1-day unavailability of the laptop).

Oh, no, you would do like

  boot.extraModulePackages = [ (pkgs.callPackage ./my-module-package.nix {}) ];
1 Like

On this topic: Is this possible? Is it a bad idea?

Basically, I want to use the current kernel I just built for the foreseeable future. Will it happen automatically, or does it update to the newest kernel (building it from source) whenever there’s a new kernel?

I ask cuz in Arch it would update to the latest prebuilt, except if I was running a custom kernel (like Zen/Xanmod); so was wondering if Nix has the same behaviour by default, or if I had to specify something in the config to keep the custom kernel “frozen”.

If you’re specifying a custom kernel then it’ll only rebuild when the build dependencies of the kernel change. That will happen from time to time though. To avoid this, you would have to build the kernel with a pinned version of nixpkgs.

1 Like

I can’t find if I can pin nixpkgs for a URL imported config part tho (like <nixos-hardware/microsoft/surface/common>). Any guide on how I can pin nixpkgs only for a specific package (linux-surface kernel) that gets imported from somewhere else?

Also, if I pin nixpkgs for that, will it start rebuilding the kernel? :sweat:

Marking this as solution because it seems there’s no way out of compiling the kernel for linux-surface.