Cached at:
09/26/26, 03:26 PM
# Infecting the Steam Link with NixOS
Source: [https://feyor.sh/blog/infecting-the-steam-link-with-nixos/](https://feyor.sh/blog/infecting-the-steam-link-with-nixos/)
While rummaging through my closet the other day I discovered a[Steam Link](https://en.wikipedia.org/wiki/Steam_Link#Hardware_device)I had bought on flash sale way back in 2018 still dutifully humming away all these years later\. It occured to me that having an always\-on low power Arm device with Ethernet, WiFi, Bluetooth, and several USB ports would be handy, so thus began my journey to get NixOS running on the Steam Link\.
As it turns out, a fellow named[fijam](https://heap.ovh/getting-linux-on-valve-steam-link.html)already figured out the hard parts involved in running a custom Linux distro on the Steam Link\. The most notable obstacle is that the bootloader will only boot kernels signed by Valve; to get around this, we can boot into the Valve\-blessed kernel and thenkexecour new kernel\. However, the kernel shipped with the Steam Link was not built with`CONFIG\_KEXEC`enabled\. This is where things get*really*clever: we can cobble the pertinent kexec source files into a minimal kernel module that adds thekexecsyscall to the running system\!
Several people have successfully used this technique to get other distros[1](https://feyor.sh/blog/infecting-the-steam-link-with-nixos/#fn:1)booting, but they all seem to have just copied thekexecbinary and kernel module from fijam’s website\. fijam seems like a lovely person and all, but I’m wary of downloading kernel modules from the interwebs so I decided to compile it myself\.
## Booting the thing
Compiling a NixOS userspace and kernel/initrd is pretty simple; you just pass the correctsystem\(and because I’m using\_\_splicedPackages/crossSystem, alsopkgs\) tolib\.nixosSystemand add your modules\. Choosing the target architecture was slightly less straightforward: Valve’s steamlink toolchain uses`armv7a`, but importing nixpkgs withcrossSystem\.config = “armv7a\-unknown\-linux\-gnueabihf”interacts[poorly with the Go build plumbing](https://github.com/NixOS/nixpkgs/blob/fbe840e7184ed15fd5b1ca8f1a8746462a38d59c/lib/systems/default.nix#L596-L599), so I used the \(seemingly\) equivalent`armv7l`instead\.
Nix```
{
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
outputs = { self, nixpkgs }:
let
inherit (nixpkgs) lib;
system = "armv7l-linux";
# hostSystem should be linux but does not have to be arm (x86 should work)
hostSystem = "aarch64-linux";
pkgs = (import nixpkgs {
system = hostSystem;
crossSystem = {
config = "armv7l-unknown-linux-gnueabihf";
};
}).__splicedPackages;
in {
nixosConfigurations.steamlink = lib.nixosSystem {
inherit system pkgs;
modules = [
# ...
];
};
};
}
```
The real challenge is compiling a kernel module for a vendored fork of a 13 year old kernel; the[NixOS wiki](https://wiki.nixos.org/wiki/Linux_kernel#Packaging_out-of-tree_kernel_modules)is actually pretty helpful here and points out some footguns related to the default hardening flags in stdenv\.
Nix```
kexecMod = let
inherit (pkgs) stdenv;
inherit (self.nixosConfigurations.steamlink.config.system.build) kernel oldKernel;
in stdenv.mkDerivation {
pname = "kexec_mod";
version = "0.0.1";
src = ./kexec_mod;
postPatch = ''
for f in machine_kexec.c kexec.c relocate_kernel.S; do
substituteInPlace "$f" --subst-var-by KERNEL ${oldKernel}
done
'';
nativeBuildInputs = kernel.moduleBuildDependencies;
makeFlags = [
"ARCH=${stdenv.hostPlatform.linuxArch}"
"CROSS_COMPILE=${stdenv.cc.targetPrefix}"
"KDIR=${oldKernel}"
"INSTALL_MOD_PATH=$(out)"
];
env.NIX_CFLAGS_COMPILE = toString [
"-std=gnu89"
"-fno-pie"
];
inherit (kernel) hardeningDisable;
meta = {
description = "kexec functionality as a kernel module for old kernels";
homepage = "https://github.com/lukas2511/steamlink-sdk";
license = lib.licenses.gpl2;
platforms = [ system ];
};
};
```
\(See[Files](https://feyor.sh/blog/infecting-the-steam-link-with-nixos/#files)for the kexec\_mod source code\.\)
In order to get this to build we need to point Kbuild to a Linux kernel checkout that has been built withmake modules[2](https://feyor.sh/blog/infecting-the-steam-link-with-nixos/#fn:2)\. \(Note that I’m using themoduleBuildDependenciesattribute of the comparatively modernkernelfrom my NixOS configuration\.\)
Nix```
oldKernel = let
inherit (pkgs) stdenv fetchFromGitHub buildPackages fetchpatch writeText;
inherit (self.nixosConfigurations.steamlink.config.system.build) kernel;
in stdenv.mkDerivation {
pname = "linux-steamlink";
version = "3.8.13";
src = fetchFromGitHub {
owner = "ValveSoftware";
repo = "steamlink-sdk";
rootDir = "kernel";
rev = "62b4d098d1472c3534dd098ca2a0e0e10712f1c6";
hash = "sha256-3Q8JjNmkRFCkdt8E+ol+E/c2sy+X5I7UYhsHAfYBdWs=";
};
sourceRoot = "source";
patches = [
(fetchpatch {
url = "https://gitlab.com/postmarketOS/pmaports/-/raw/aa289aa350071e6afc54f6b6704ba28971b50466/device/.shared-patches/linux/linux3.4-ARM-8933-1-replace-Sun-Solaris-style-flag-on-section.patch";
hash = "sha256-KRNI4070H0AFMCZl7pYnIbin6lbp68/xuf6yOPvmYdI=";
})
(fetchpatch {
url = "https://gitlab.com/postmarketOS/pmaports/-/raw/aa289aa350071e6afc54f6b6704ba28971b50466/device/.shared-patches/linux/gcc10-extern_YYLOC_global_declaration.patch";
hash = "sha256-9hq5xGeJRL/ESHofOh4MAOAGV2IlDRYvvpxyxk3MXlw=";
})
(writeText "0001-gcc-bug85745.diff"
''
diff --git a/arch/arm/include/asm/uaccess.h b/arch/arm/include/asm/uaccess.h
index 74b17d0..dc64fa2 100644
--- a/arch/arm/include/asm/uaccess.h
+++ b/arch/arm/include/asm/uaccess.h
@@ -164,7 +164,7 @@
#define __put_user_check(x,p)''\t''\t''\t''\t''\t''\t''\t${"\\"}
''\t({''\t''\t''\t''\t''\t''\t''\t''\t${"\\"}
''\t''\tunsigned long __limit = current_thread_info()->addr_limit - 1; ${"\\"}
-''\t''\tregister const typeof(*(p)) __r2 asm("r2") = (x);''\t${"\\"}
+''\t''\tregister typeof(*(p)) __r2 asm("r2") = (x);''\t${"\\"}
''\t''\tregister const typeof(*(p)) __user *__p asm("r0") = (p);${"\\"}
''\t''\tregister unsigned long __l asm("r1") = __limit;''\t''\t${"\\"}
''\t''\tregister int __e asm("r0");''\t''\t''\t''\t${"\\"}
'')
];
postPatch = ''
substituteInPlace arch/arm/boot/compressed/piggy.xzkern.S --replace-fail '#alloc' ' "a"'
substituteInPlace arch/arm/mach-berlin/Makefile.boot --replace-fail '/bin/bash' '${stdenv.shell}'
substituteInPlace arch/arm/boot/compressed/Makefile --replace-fail '${"\t"}@$(check_for_multiple_zreladdr)' '${"\t"}echo LDFLAGS_vmlinux = ''${LDFLAGS_vmlinux}${"\n\t"}@$(check_for_multiple_zreladdr)'
cp include/linux/compiler-gcc4.h include/linux/compiler-gcc${lib.versions.major buildPackages.stdenv.cc.version}.h
'';
inherit (kernel) nativeBuildInputs;
depsBuildBuild = [
buildPackages.stdenv.cc
];
makeFlags = [
"ARCH=${stdenv.hostPlatform.linuxArch}"
"LOCALVERSION=-mrvl"
"CROSS_COMPILE=${stdenv.cc.targetPrefix}"
];
env.NIX_CFLAGS_COMPILE = toString [
"-std=gnu89"
"-Wno-error=address"
"-Wno-error=dangling-pointer"
"-Wno-error=missing-attributes"
];
inherit (kernel) hardeningDisable;
configurePhase = ''
make bg2cd_penguin_mlc_defconfig $makeFlags
echo "CONFIG_KEXEC=y" >> .config
echo "CONFIG_KERNEL_XZ=y" >> .config
make olddefconfig $makeFlags
'';
postBuild = ''
make modules $makeFlags -j$NIX_BUILD_CORES
'';
installPhase = ''
mkdir $out
cp -r * $out/
'';
dontFixup = true;
};
```
It took several hacks to get things building on a modern version of GCC, but eventually I was able to get the 3\.8\.13\-mrvl kernel and the kexec\_mod kernel module building\.
Now that we have`kexec\_mod\.ko`, we need our new initrd and kernel \(which all come from our NixOS config\), the device tree blob for the Steam Link \(which has been[upstreamed](https://github.com/torvalds/linux/blob/6812ce4e4379ffc99c52401ec28f0d7ffbc36206/arch/arm/boot/dts/synaptics/berlin2cd-valve-steamlink.dts)to Linux so we can get it fromhardware\.deviceTree\.package\), a copy of thekexecuserland binary \(compiled withpkgsStaticso we can run it on non\-NixOS\), and a small script to tie everything together:
Bash```
fts-set steamlink.crashcounter 0 # required to prevent factory reset after a few reboots
mkdir -p /mnt/disk/proc /mnt/disk/sys /mnt/disk/dev
mount -t proc proc /mnt/disk/proc
mount -o rbind /sys /mnt/disk/sys
mount -o rbind /dev /mnt/disk/dev
insmod /mnt/disk/kexec_load.ko
chroot /mnt/disk/ /kexec --load /zImage \
--initrd /initrd \
--dtb /berlin2cd-valve-steamlink.dtb \
--command-line "init=/init root=/dev/sda2 rootwait rw usbcore.autosuspend=-1"
chroot /mnt/disk/ /kexec -e
```
You could juggle these files manually and upload them to a USB drive yourself, but it’s much easier to use the[sd\-image](https://github.com/NixOS/nixpkgs/blob/5f5458dc42bf4391dc5f85e7682decb8c78e8756/nixos/modules/installer/sd-card/sd-image.nix)NixOS module to create a disk image instead:
Nix```
usb-image = { modulesPath, config, ... }: {
imports = [
(modulesPath + "/installer/sd-card/sd-image.nix")
];
image.extension = lib.mkForce "img";
sdImage = let
dtb = "berlin2cd-valve-steamlink.dtb";
kexecScript = ./kexec-nixos;
inherit (config.system.build) kernel initialRamdisk;
in {
compressImage = false;
firmwarePartitionName = "STEAMLINK";
rootVolumeLabel = "NIXOS";
populateFirmwareCommands = ''
pushd firmware
files=(
${kernel}/${config.system.boot.loader.kernelFile}
${initialRamdisk}/${config.system.boot.loader.initrdFile}
${config.hardware.deviceTree.package}/${dtb}
${self.packages.${system}.kexecMod}/lib/modules/3.8.13-mrvl/extra/kexec_load.ko
${pkgs.pkgsStatic.kexec-tools}/bin/kexec
)
for f in ''${files[@]}; do
cp $f ./
done
# factory_test/run.sh will run before this has a chance to
# enable ssh; uncomment if not booting straight into NixOS
# mkdir -p steamlink/config/system
# touch steamlink/config/system/enable_ssh.txt
mkdir -p steamlink/factory_test
cp ${kexecScript} steamlink/factory_test/run.sh
popd
'';
populateRootCommands = "";
};
};
```
Testing that thekexechandoff works was really tricky because the HDMI output doesn’t work with the kernel I’m using, and since I decided not to open up the device to get at the UART I was flying completely blind\. I decided to test with a minimal \(slop\) Busybox\-based initramfs that rebooted after a variable amount of time to indicate success\.
Nix```
initramfs = pkgs.buildPackages.runCommand "build-initramfs" {}
''
mkdir initramfs; cd initramfs
mkdir -pv {etc,proc,sys,usr/{bin,sbin}}
cp -a ${pkgs.pkgsStatic.busybox}/{bin,sbin} .
chmod 755 ./{bin,sbin}
cat <<EOF > init
#!/bin/sh
mount -t proc none /proc
mount -t sysfs none /sys
mount -t devtmpfs devtmpfs /dev
mkdir -p /mnt
try_mount() {
dev="$1"
fs="$2"
if [ "$fs" = auto ]; then
mount -o rw "$dev" /mnt 2>/dev/null || return 1
else
mount -t "$fs" -o rw "$dev" /mnt 2>/dev/null || return 1
fi
marker=kexec-mounted-ok
if [ -f /mnt/zImage ]; then
marker=kexec-steamlink-ok
fi
{
echo "device=$dev"
echo "fs=$fs"
cat /proc/partitions
} > "/mnt/$marker" 2>/dev/null && sync
umount /mnt
sleep 10
reboot -f
}
for dev in /dev/mmcblk*p* /dev/sd[a-z][0-9]* /dev/vd[a-z][0-9]*; do
[ -b "$dev" ] || continue
try_mount "$dev" vfat
try_mount "$dev" ext4
try_mount "$dev" auto
done
sleep 45
reboot -f
EOF
chmod +x init
find . -print0 | ${lib.getExe pkgs.buildPackages.cpio} --null -ov --format=newc > $out
'';
```
Once I knew that worked, I switched to the NixOS initrd withboot\.initrd\.network\.enable = trueand used a Netcat based reverse shell to my laptop’s IP for further debugging\.
Nix```
debugModule = { lib, ... }: {
boot.initrd.systemd.enable = lib.mkForce false;
boot.initrd.kernelModules = [ "pxa168_eth" ];
boot.initrd.availableKernelModules = [ "reset_berlin" ];
boot.initrd.network.enable = true;
boot.initrd.network.udhcpc.enable = false;
boot.kernelParams = [
"ip=192.168.2.2::192.168.2.1:255.255.255.0:stm-link:eth0:off"
];
boot.initrd.network.postCommands = ''
mac_peer=192.168.2.1
stm_link_ip=192.168.2.2
echo "initrd net debug: interfaces: $(ls /sys/class/net)" > /dev/kmsg
for iface_path in /sys/class/net/*; do
iface="''${iface_path##*/}"
[ "$iface" != lo ] || continue
echo "initrd net debug: configuring $iface" > /dev/kmsg
ip link set dev "$iface" up || true
ip address flush dev "$iface" || true
ip address add "$stm_link_ip/24" dev "$iface" || true
done
(
while true; do
ping -c 1 -W 1 "$mac_peer"
sleep 2
done
) &
(
while true; do
rm -f /tmp/revsh
mkfifo /tmp/revsh
/bin/ash -i < /tmp/revsh 2>&1 | nc "$mac_peer" 4444 > /tmp/revsh
rm -f /tmp/revsh
sleep 2
done
) &
'';
};
```
The main things I needed to figure out at this stage were adding`reset\_berlin`toboot\.initrd\.availableKernelModulesto allow reading from the USB drive and using the old NixOS initrd system in lieu of the new systemd\-based version \(boot\.initrd\.systemd\.enable = lib\.mkForce false\)\.
Finally I was able to boot into userspace and connect over SSH\! 🥳
That having been said, the USB image I was booting from was weighing in at a hefty 2\.3GB… surely we can do better\.
## Trimming the fat
I was surprised that there wasn’t a definitive guide for reducing NixOS closure sizes; I found some NixOS Discourse questions and a few blog posts, but the most useful writeups were[NixOS is a good server OS, except when it isn’t](https://sidhion.com/blog/nixos_server_issues)and[I can haz smoller NixOS ISOs?](https://natkr.com/2026-06-19-nixos-but-smol/)\. Those are good resources, but because we’re targeting actual hardware instead of a VM we must necessarily be more conservative in what we cut\.
Nix```
minimal = { modulesPath, pkgs, ... }: {
imports = [
(modulesPath + "/profiles/minimal.nix")
(modulesPath + "/profiles/headless.nix")
# (modulesPath + "/profiles/perlless.nix")
];
disabledModules = [
(modulesPath + "/profiles/base.nix")
];
boot.loader = {
grub.enable = false;
systemd-boot.enable = false;
supportsInitrdSecrets = false;
};
boot.initrd.systemd.enable = lib.mkForce false;
boot.initrd.availableKernelModules = lib.mkForce [
"reset_berlin"
"uas"
];
boot.kernelModules = [
"pxa168_eth"
"mwifiex_sdio"
"btmrvl_sdio"
];
hardware.firmware = lib.mkForce (with pkgs; [
(runCommand "marvell-firmware" {} ''
mkdir -p $out/lib/firmware/mrvl
cp ${linux-firmware}/lib/firmware/mrvl/sd8897_uapsta.bin $out/lib/firmware/mrvl/
'')
wireless-regdb
]);
documentation.enable = false;
programs.command-not-found.enable = lib.mkDefault false;
networking.networkmanager.enable = false;
networking.firewall.enable = false;
xdg.icons.enable = false;
xdg.mime.enable = false;
xdg.sounds.enable = false;
fonts.fontconfig.enable = false;
programs.nano.enable = false;
system.disableInstallerTools = true;
system.switch.enable = false;
system.nixos-init.enable = false;
nix.enable = false;
systemd.services.register-nix-paths = lib.mkForce {};
};
```
Here are the main things that came up during the slim\-ening:
- We only need one firmware blob from the massivelinux\-firmwarepackage \(1\.8GB compressed\!\), so we can save a huge amount of space by only adding that blob tohardware\.firmware- On a similar note it should be possible to use a kconfig tailored for the Steam Link hardware to build a smaller kernel, but this seemed like more trouble than it was worth
- OpenSSH does not seem to like it wheni18n\.glibcLocalesor thesecurity\.wrappersmodule are removed
- Thekexecboot flow renders most of the NixOS system administration utilities irrelevant; as a matter of fact, Nix itself is not very useful on such a system, so we can save space by getting rid of that too
- I feel like it should be possible to disableboot\.initrdandboot\.kernelbecause we provide the kernel/initrd/DTB from the FAT32 partition when wekexec, but I was never able to disable these without breaking the boot process
- If I could switch to the systemd\-based initrd I could enable the “perlless” NixOS module to remove Perl from the system closure for additional savings
After reaching a point of diminshing returns and most new changes breaking my system, I declared the 1\.2GB disk image I had to be “good enough”\.
## Files
The Nix flake I used and the source for thekexec\_modkernel module can be downloaded[here](https://feyor.sh/infecting-the-steam-link-with-nixos/steamlink-nixos.tar.gz)\. The same`flake\.nix`is reproduced below for your convenience\.
Nixflake\.nix
```
{
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
outputs = { self, nixpkgs }:
let
inherit (nixpkgs) lib;
system = "armv7l-linux";
# hostSystem should be linux but does not have to be arm (x86 should work)
hostSystem = "aarch64-linux";
pkgs = (import nixpkgs {
system = hostSystem;
crossSystem = {
config = "armv7l-unknown-linux-gnueabihf";
};
overlays = [
# https://github.com/NixOS/nixpkgs/issues/388309
(self: super: {
efivar = self.emptyDirectory;
efibootmgr = self.emptyDirectory;
})
];
}).__splicedPackages;
in {
nixosModules = {
# https://sidhion.com/blog/nixos_server_issues
# https://discourse.nixos.org/t/how-to-have-a-minimal-nixos/22652/4
minimal = { modulesPath, pkgs, ... }: {
imports = [
(modulesPath + "/profiles/minimal.nix")
(modulesPath + "/profiles/headless.nix")
];
disabledModules = [
(modulesPath + "/profiles/base.nix")
];
boot.loader = {
grub.enable = false;
systemd-boot.enable = false;
supportsInitrdSecrets = false;
};
# systemd initrd did not work for me; you could add the perlless profile if you got it working
boot.initrd.systemd.enable = lib.mkForce false;
boot.initrd.availableKernelModules = lib.mkForce [
"reset_berlin"
"uas"
];
boot.kernelModules = [
"pxa168_eth"
"mwifiex_sdio"
"btmrvl_sdio"
];
hardware.firmware = lib.mkForce (with pkgs; [
(runCommand "marvell-firmware" {} ''
mkdir -p $out/lib/firmware/mrvl
cp ${linux-firmware}/lib/firmware/mrvl/sd8897_uapsta.bin $out/lib/firmware/mrvl/
'')
wireless-regdb
]);
documentation.enable = false;
programs.command-not-found.enable = lib.mkDefault false;
networking.networkmanager.enable = false;
networking.firewall.enable = false;
xdg.icons.enable = false;
xdg.mime.enable = false;
xdg.sounds.enable = false;
fonts.fontconfig.enable = false;
programs.nano.enable = false;
system.disableInstallerTools = true;
system.switch.enable = false;
system.nixos-init.enable = false;
nix.enable = false;
systemd.services.register-nix-paths = lib.mkForce {};
};
usb-image = { modulesPath, config, ... }: {
imports = [
(modulesPath + "/installer/sd-card/sd-image.nix")
];
# in theory it should be possible to disable the kernel
# and initrd for the nixos rootfs for some significant
# space savings (because we're passing a copy of the
# kernel and initrd from the STEAMLINK partition to kexec
# directly, but in practice I never got that working)
boot.kernelParams = [
"root=/dev/disk/by-label/${config.sdImage.rootVolumeLabel}" "rootwait" "rw"
"usbcore.autosuspend=-1"
];
image.extension = lib.mkForce "img";
sdImage = let
dtb = "berlin2cd-valve-steamlink.dtb";
kexecScript = pkgs.buildPackages.writeScript "kexec-nixos" ''
#!/bin/sh
fts-set steamlink.crashcounter 0
mkdir -p /mnt/disk/proc /mnt/disk/sys /mnt/disk/dev
mount -t proc proc /mnt/disk/proc
mount -o rbind /sys /mnt/disk/sys
mount -o rbind /dev /mnt/disk/dev
insmod /mnt/disk/kexec_load.ko
chroot /mnt/disk/ /kexec --load /zImage \
--initrd /initrd \
--dtb /berlin2cd-valve-steamlink.dtb \
--command-line "init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams}"
chroot /mnt/disk/ /kexec -e
'';
inherit (self.packages.${system}) kernel initialRamdisk;
in {
compressImage = false;
firmwarePartitionName = "STEAMLINK";
rootVolumeLabel = "NIXOS";
populateFirmwareCommands = ''
pushd firmware
files=(
${kernel}/${config.system.boot.loader.kernelFile}
${initialRamdisk}/${config.system.boot.loader.initrdFile}
${config.hardware.deviceTree.package}/${dtb}
${self.packages.${system}.kexecMod}/lib/modules/3.8.13-mrvl/extra/kexec_load.ko
${pkgs.pkgsStatic.kexec-tools}/bin/kexec
)
for f in ''${files[@]}; do
cp $f ./
done
# factory_test/run.sh will run before this has a chance to
# enable ssh; uncomment if not booting straight into NixOS
# mkdir -p steamlink/config/system
# touch steamlink/config/system/enable_ssh.txt
mkdir -p steamlink/factory_test
cp ${kexecScript} steamlink/factory_test/run.sh
popd
'';
populateRootCommands = "";
};
};
};
nixosConfigurations.steamlink = lib.nixosSystem {
inherit system pkgs;
modules = [
self.nixosModules.minimal
self.nixosModules.usb-image
({ ... }: {
# your NixOS config here!
services.tailscale.enable = true;
services.openssh = {
# might be able to remove security wrappers if using static openssh
# see https://sidhion.com/blog/nixos_server_issues#:~:text=While%20looking%20through%20the%20lvm%20stuff
# package = pkgs.pkgsStatic.openssh;
enable = true;
settings = {
PermitRootLogin = "yes";
};
};
users.users.root.openssh.authorizedKeys.keys = [ "..." ];
hardware.bluetooth.enable = true;
networking = {
hostName = "steamlink";
useDHCP = true;
interfaces.eth0 = {
useDHCP = true;
# prefer DHCP but use a static IP for debugging over a direct ethernet serial line to your host machine
ipv4.addresses = [{
address = "169.254.31.216";
prefixLength = 16;
}];
};
wireless = {
enable = true;
networks = {
"WiFi" = {
psk = "hunter2";
};
};
};
};
})
];
};
packages.${system} = {
inherit (self.nixosConfigurations.steamlink.config.system.build) kernel initialRamdisk sdImage;
default = self.packages.${system}.sdImage;
oldKernel = let
inherit (pkgs) stdenv fetchFromGitHub buildPackages fetchpatch writeText;
inherit (self.packages.${system}) kernel;
in stdenv.mkDerivation {
pname = "linux-steamlink";
version = "3.8.13";
src = fetchFromGitHub {
owner = "ValveSoftware";
repo = "steamlink-sdk";
rootDir = "kernel";
rev = "62b4d098d1472c3534dd098ca2a0e0e10712f1c6";
hash = "sha256-3Q8JjNmkRFCkdt8E+ol+E/c2sy+X5I7UYhsHAfYBdWs=";
};
sourceRoot = "source";
patches = [
(fetchpatch {
url = "https://gitlab.com/postmarketOS/pmaports/-/raw/aa289aa350071e6afc54f6b6704ba28971b50466/device/.shared-patches/linux/linux3.4-ARM-8933-1-replace-Sun-Solaris-style-flag-on-section.patch";
hash = "sha256-KRNI4070H0AFMCZl7pYnIbin6lbp68/xuf6yOPvmYdI=";
})
(fetchpatch {
url = "https://gitlab.com/postmarketOS/pmaports/-/raw/aa289aa350071e6afc54f6b6704ba28971b50466/device/.shared-patches/linux/gcc10-extern_YYLOC_global_declaration.patch";
hash = "sha256-9hq5xGeJRL/ESHofOh4MAOAGV2IlDRYvvpxyxk3MXlw=";
})
(writeText "0001-gcc-bug85745.diff"
''
diff --git a/arch/arm/include/asm/uaccess.h b/arch/arm/include/asm/uaccess.h
index 74b17d0..dc64fa2 100644
--- a/arch/arm/include/asm/uaccess.h
+++ b/arch/arm/include/asm/uaccess.h
@@ -164,7 +164,7 @@
#define __put_user_check(x,p)''\t''\t''\t''\t''\t''\t''\t${"\\"}
''\t({''\t''\t''\t''\t''\t''\t''\t''\t${"\\"}
''\t''\tunsigned long __limit = current_thread_info()->addr_limit - 1; ${"\\"}
-''\t''\tregister const typeof(*(p)) __r2 asm("r2") = (x);''\t${"\\"}
+''\t''\tregister typeof(*(p)) __r2 asm("r2") = (x);''\t${"\\"}
''\t''\tregister const typeof(*(p)) __user *__p asm("r0") = (p);${"\\"}
''\t''\tregister unsigned long __l asm("r1") = __limit;''\t''\t${"\\"}
''\t''\tregister int __e asm("r0");''\t''\t''\t''\t${"\\"}
'')
];
postPatch = ''
substituteInPlace arch/arm/boot/compressed/piggy.xzkern.S --replace-fail '#alloc' ' "a"'
substituteInPlace arch/arm/mach-berlin/Makefile.boot --replace-fail '/bin/bash' '${stdenv.shell}'
substituteInPlace arch/arm/boot/compressed/Makefile --replace-fail '${"\t"}@$(check_for_multiple_zreladdr)' '${"\t"}echo LDFLAGS_vmlinux = ''${LDFLAGS_vmlinux}${"\n\t"}@$(check_for_multiple_zreladdr)'
cp include/linux/compiler-gcc4.h include/linux/compiler-gcc${lib.versions.major buildPackages.stdenv.cc.version}.h
'';
inherit (kernel) nativeBuildInputs;
depsBuildBuild = [
buildPackages.stdenv.cc
];
makeFlags = [
"ARCH=${stdenv.hostPlatform.linuxArch}"
"LOCALVERSION=-mrvl"
"CROSS_COMPILE=${stdenv.cc.targetPrefix}"
];
env.NIX_CFLAGS_COMPILE = toString [
"-std=gnu89"
"-Wno-error=address"
"-Wno-error=dangling-pointer"
"-Wno-error=missing-attributes"
];
inherit (kernel) hardeningDisable;
configurePhase = ''
make bg2cd_penguin_mlc_defconfig $makeFlags
echo "CONFIG_KEXEC=y" >> .config
echo "CONFIG_KERNEL_XZ=y" >> .config
make olddefconfig $makeFlags
'';
postBuild = ''
make modules $makeFlags -j$NIX_BUILD_CORES
'';
installPhase = ''
mkdir $out
cp -r * $out/
'';
dontFixup = true;
};
kexecMod = let
inherit (pkgs) stdenv;
inherit (self.packages.${system}) kernel oldKernel;
in stdenv.mkDerivation {
pname = "kexec_mod";
version = "0.0.1";
src = ./kexec_mod;
postPatch = ''
for f in machine_kexec.c kexec.c relocate_kernel.S; do
substituteInPlace "$f" --subst-var-by KERNEL ${oldKernel}
done
'';
nativeBuildInputs = kernel.moduleBuildDependencies;
makeFlags = [
"ARCH=${stdenv.hostPlatform.linuxArch}"
"CROSS_COMPILE=${stdenv.cc.targetPrefix}"
"KDIR=${oldKernel}"
"INSTALL_MOD_PATH=$(out)"
];
env.NIX_CFLAGS_COMPILE = toString [
"-std=gnu89"
"-fno-pie"
];
inherit (kernel) hardeningDisable;
meta = {
description = "kexec functionality as a kernel module for old kernels";
homepage = "https://github.com/lukas2511/steamlink-sdk";
license = lib.licenses.gpl2;
platforms = [ system ];
};
};
};
};
}
```