Just enough NixOS for Kodi#
Sat, 26 Jun 2021 21:56:17 +0000
I've had an Odroid C2 sitting under the TV for a a year or so, mostly used for playing the Shaun the Sheep videos that live on my PC upstairs. I put LibreELEC on it when I bought it, and subsequntly tweaked it in a succession of ways that I basically don't remember.
Quite recently I decided that I didn't need this pocket of divergence in my otherwise mostly congruent domestic computing infrastructure, so I set about installing NixOS on it. There's a description in the NixOS Wiki of how to do this which is a good starting point, but there was some other stuff I had to figure out.
Caveat
I still don't have everything figured out. In particular, it seems to want to play audio slightly too fast, I think because somehow it has decided that my 48kHz sound device will accept 44.1kHz PCM without need of resampling. I probably won't update this blog entry when I figure that out, but I will update the repo it points to.
I would caution against following these notes from start to end and doing everything manually as I discovered it, because there's a configuration.nix at the end that has most of it automated.
Initial install
The board has some weird requirement to install a binary blob and an u-boot image in a very specific part of the storage medium. "Note this assumes u-boot is in partition 1 of your board's connected eMMC", say the instructions. I am happy to report that the same merry dance works just fine on an SD card if like me you were too stingy (or poor) to spring for the eMMC.
- It needs to use a traditional MBR partition scheme, not GPT
- I found that I needed to run the sd_fusing script again after each time I touched the partition table
Kernel rebuild
Although the generic NixOS aarch64 kernel will work to get you to a login prompt, it doesn't work well for video playback. This is because there's a meson_vdec
module needed for hardware video decoding that isn't in it. After some experimenting I came up with the following configuration snippet
nixpkgs.overlays = [
(self: super: {
linuxPackages = super.linuxPackages_latest.extend (lpself: lpsuper: {
kernel = super.linuxPackages_latest.kernel.override {
extraConfig = ''
STAGING y
STAGING_MEDIA y
VIDEO_MESON_VDEC m
'';
};
});
})]
but this is where I found that the machine is slow as molasses at compiling - although to be fair the default NixOS aarch64 kernel build is a huge task on any hardware due to the large number of modules it builds.
Hot cross bins
So, time to figure out how to cross-compile it on an x86_64, and given that I want this to be repeatable, how to cross-compile the entire system instead of cross-building bits and native-building other bits and copying artifacts around by hand. Like this, is the short answer (adjust pathnames/hostnames as needed)
# build the system
NIXOS_CONFIG=/home/dan/src/odroid/nixelec/configuration.nix \
nix-build -E 'let pkgs = (import /home/dan/src/nixpkgs) {};
in (pkgs.pkgsCross.aarch64-multiplatform.nixos
/home/dan/src/odroid/nixelec/configuration.nix)'.config.system.build.toplevel
# copy it to the target device
nix-copy-closure --to root@odroid.lan -v --include-outputs \
./result && ssh root@odroid.lan \
`readlink result`/bin/switch-to-configuration switch
As usual with cross-compilation, this unearthed a bunch of packages that don't cross-compile because nobody really understands when to use buildInputs
vs nativeBuildInputs
(I'm projecting here, it might just be me), one package that doesn't cross-compile because it's magic - I refer of course to gobject-introspection
- and some packages that need their derivations tweaking so that they don't depend on any of the other stuff that depends transitively on gobject-introspection
.
Image problems
Careful readers will observe that the shell incantations above are predicated on having a running NixOS Odroid system already that you can ssh into - so, how do you get that in the first place? I augmented the configuration further so that it can also be used to produce an SD card image which has builtin the faffage needed to get the firmware and U-boot binaries injected at the right offsets. To generate this, we do
NIXOS_CONFIG=/home/dan/src/odroid/nixelec/configuration.nix \
nix-build -E 'let pkgs = (import /home/dan/src/nixpkgs) {};
in (pkgs.pkgsCross.aarch64-multiplatform.nixos
/home/dan/src/odroid/cross/configuration.nix)'.config.system.build.sdImage
(this is very similar to the previous command except now we're building sdImage
instead of toplevel
)
and then find the output in result/sd-image/nixos-sd-image-21.11pre-git-aarch64-linux.img
- again, Your Pathnames May Vary. dd
this to whatever device corresponds to the SD card you plan to insert into the Odroid machine and you should be good to go. It should install a valid SSH key for the root user, but it would be as well to check.
Where is it?
https://github.com/telent/nixelec
What's left to do?
- make the sound work better
- more declarative config for Kodi itself, instead of configuring it through the UI
- push the cross-compile fixes upstream
- find out why it hangs when I ask it to reboot and fix that