Skip to content

Instantly share code, notes, and snippets.

@angerman
Created May 28, 2020 13:53
Show Gist options
  • Star 10 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save angerman/70c69c71bd91de3b9ea1ac1f438a8c62 to your computer and use it in GitHub Desktop.
Save angerman/70c69c71bd91de3b9ea1ac1f438a8c62 to your computer and use it in GitHub Desktop.
NixOS on RockPi4

Installing NixOS on the RockPi4 (B)

The general plan is to build an sd-image-aarch64 from nixpkgs/nixos/modules/installer/cd-dvd/sd-image-aarch64.nix flash it to the eMMC and have the system come up, similar to how this “just works” for raspberry-pis.

The RockPi 4 is a RockChip RK3399 based board, build by radxa with the same formfactor as a rasperry Pi. One noticable difference is that the Rock Pi’s cpu is at the bottom to better allow for the installation of a heatsink. The heatsink as such will prevent it from fitting into raspberry pi enclosures, however together with the heatsink it forms a relatively stable package.

RockPi disk layout

From Rock Pi 4 Partitions we can see that the official linux image partitions are layed out like this:

Part NumberOffsetNameDescription
132KBloader1First stage loader
28MBloader2U-boot image
312MBtrustATF
416MBbootKernel partition
5128MBrootfsRootsfs

Thus we should be able to just dd the files onto it if we had the files prepared like so:

dd if=idbloader.img   of=/dev/sdx seek=64
dd if=uboot.img       of=/dev/sdx seek=16384
dd if=trust.img       of=/dev/sdx seek=24576
dd if=boot.img        of=/dev/sdx seek=32768
dd if=rootfs.img      of=/dev/sdx seek=262144

Inspecting the exampe rockpi4b-ubuntu-bionic-minimal-20191127_1942-gpt.img, we’ll find

$ sfdisk -l rockpi4b-ubuntu-bionic-minimal-20191127_1942-gpt.img -d
label: gpt
label-id: 992DF2C2-0170-4F66-9492-FBF320673EEF
device: rockpi4b-ubuntu-bionic-minimal-20191127_1942-gpt.img
unit: sectors
first-lba: 34
last-lba: 4458462

rockpi4b-ubuntu-bionic-minimal-20191127_1942-gpt.img1 : start=          64, size=        8000, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, uuid=95D89D52-CA00-42D6-883F-50F5720EF37E, name="loader1"
rockpi4b-ubuntu-bionic-minimal-20191127_1942-gpt.img2 : start=       16384, size=        8192, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, uuid=78BE2786-ACB9-4885-BB6C-77DDDEF5AAC9, name="loader2"
rockpi4b-ubuntu-bionic-minimal-20191127_1942-gpt.img3 : start=       24576, size=        8192, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, uuid=A36BC2FB-B345-417B-8AEF-B49EA06C1F7B, name="trust"
rockpi4b-ubuntu-bionic-minimal-20191127_1942-gpt.img4 : start=       32768, size=      229376, type=C12A7328-F81F-11D2-BA4B-00A0C93EC93B, uuid=CEE6EBD4-DA8F-4378-A430-05693004C5DA, name="boot"
rockpi4b-ubuntu-bionic-minimal-20191127_1942-gpt.img5 : start=      262144, size=     4196319, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, uuid=B921B045-1DF0-41C3-AF44-4C6F280D3FAE, name="rootfs"

The debian-stretch-desktop image has almost the identical layout:

sfdisk -l rockpi4-debian-stretch-desktop-arm64-20190730_2022-gpt.img -d
label: gpt
label-id: 69E3E4E5-2BF4-4C94-8774-841F0A4EE8CB
device: rockpi4-debian-stretch-desktop-arm64-20190730_2022-gpt.img
unit: sectors
first-lba: 34
last-lba: 7331806

rockpi4-debian-stretch-desktop-arm64-20190730_2022-gpt.img1 : start=          64, size=        8000, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, uuid=4C98C92E-398A-4FB8-AFD1-1529095B79B8, name="loader1"
rockpi4-debian-stretch-desktop-arm64-20190730_2022-gpt.img2 : start=       16384, size=        8192, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, uuid=C8BDD4F5-12D8-42B8-8F69-147391C0438A, name="loader2"
rockpi4-debian-stretch-desktop-arm64-20190730_2022-gpt.img3 : start=       24576, size=        8192, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, uuid=8E58643E-760F-452C-94F9-8703182E8FB2, name="trust"
rockpi4-debian-stretch-desktop-arm64-20190730_2022-gpt.img4 : start=       32768, size=     1048576, type=C12A7328-F81F-11D2-BA4B-00A0C93EC93B, uuid=BBF86B96-61B3-446D-A789-BED7E5B85490, name="boot"
rockpi4-debian-stretch-desktop-arm64-20190730_2022-gpt.img5 : start=     1081344, size=     6250463, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, uuid=B921B045-1DF0-41C3-AF44-4C6F280D3FAE, name="rootfs"

radxa provides their build repo on github, where we can find the mk-image.sh for some additonal assistence.

A gpt based image

As of this writing sd-image-aarch64.nix will use sd-image.nix to build the disk. However sd-image will generate a MBR partitioned image. With a Fat32 /boot/firmware partition, and an ext4 / nixos root partition. Thus for the rockpi; this is not very useful.

For the rock64, thefloweringash already built a gpt based sd-image-rockchip.nix.

The Boot options as described in the Rockchip wiki make be believe we can get away with three partition. The SPL (idbloader.img), u-boot.itb, and the rootfs (containg the kernel) as boot partition.

{ config, lib, pkgs, ... }: {
imports = [
<nixpkgs/nixos/modules/installer/cd-dvd/sd-image-aarch64.nix>
./configuration.nix
];
# bzip2 compression takes loads of time with emulation, skip it. Enable this if you're low
# on space.
sdImage.compressImage = false;
system.build.sdImage = with lib;
let
rootfsImage = pkgs.callPackage <nixpkgs/nixos/lib/make-ext4-fs.nix> ({
inherit (config.sdImage) storePaths;
compressImage = true;
populateImageCommands = config.sdImage.populateRootCommands;
volumeLabel = "NIXOS_SD";
} // optionalAttrs (config.sdImage.rootPartitionUUID != null) {
uuid = config.sdImage.rootPartitionUUID;
});
in pkgs.callPackage ({ stdenv, dosfstools, e2fsprogs,
mtools, libfaketime, utillinux, bzip2, zstd }: stdenv.mkDerivation {
name = config.sdImage.imageName;
nativeBuildInputs = [ dosfstools e2fsprogs mtools libfaketime utillinux bzip2 zstd ];
inherit (config.sdImage) compressImage;
diskUUID = "A8ABB0FA-2FD7-4FB8-ABB0-2EEB7CD66AFA";
loadUUID = "534078AF-3BB4-EC43-B6C7-828FB9A788C6";
bootUUID = "95D89D52-CA00-42D6-883F-50F5720EF37E";
rootUUID = "0340EA1D-C827-8048-B631-0C60D4478796";
buildCommand = ''
mkdir -p $out/nix-support $out/sd-image
export img=$out/sd-image/${config.sdImage.imageName}
echo "${pkgs.stdenv.buildPlatform.system}" > $out/nix-support/system
if test -n "$compressImage"; then
echo "file sd-image $img.bz2" >> $out/nix-support/hydra-build-products
else
echo "file sd-image $img" >> $out/nix-support/hydra-build-products
fi
echo "Decompressing rootfs image"
zstd -d --no-progress "${rootfsImage}" -o ./root-fs.img
# Create the image file sized to fit /boot/firmware and /, plus slack for the gap.
rootSizeBlocks=$(du -B 512 --apparent-size ./root-fs.img | awk '{ print $1 }')
# rootfs will be at offset 0x8000, so we'll need to account for that.
# And add an additional 20mb slack at the end.
imageSize=$((0x8000 + rootSizeBlocks * 512 + 20 * 1024 * 1024))
truncate -s $imageSize $img
sfdisk --no-reread --no-tell-kernel $img <<EOF
label: gpt
label-id: $diskUUID
first-lba: 64
start=64, size=8000, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, uuid=$loadUUID, name=loader1
start=16384, size=8192, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, uuid=$bootUUID, name=loader2
start=32768, type=B921B045-1DF0-41C3-AF44-4C6F280D3FAE, uuid=$rootUUID, name=boot, attrs=LegacyBIOSBootable
EOF
# Copy the rootfs into the SD image
eval $(partx $img -o START,SECTORS --nr 3 --pairs)
dd conv=notrunc if=./root-fs.img of=$img seek=$START count=$SECTORS
# Copy u-boot into the SD image
eval $(partx $img -o START,SECTORS --nr 2 --pairs)
dd conv=notrunc if=${pkgs.ubootRockPi4}/u-boot.itb of=$img seek=$START count=$SECTORS
# Copy bootloader into the SD image
eval $(partx $img -o START,SECTORS --nr 1 --pairs)
dd conv=notrunc if=${pkgs.ubootRockPi4}/idbloader.img of=$img seek=$START count=$SECTORS
if test -n "$compressImage"; then
bzip2 $img
fi
'';
}) {};
}
final: prev: {
ubootRockPi4 =
let plat = if builtins.currentSystem == "aarch64-linux" then prev
else prev.pkgsCross.aarch64-multiplatform;
in plat.buildUBoot {
defconfig = "rock-pi-4-rk3399_defconfig";
extraMeta.platforms = ["aarch64-linux"];
BL31 = "${plat.armTrustedFirmwareRK3399}/bl31.elf";
filesToInstall = ["idbloader.img" "u-boot.itb" ".config"];
};
}
@Tomaszal
Copy link

Hi @angerman, thanks for trying to get NixOS to work on RockPi4. How would I go about running this? I'm trying to compile the image as suggested on NixOS documentation: nix-build '<nixpkgs/nixos>' -A config.system.build.sdImage -I nixos-config=./sd-image.nix --argstr system aarch64-linux

However, that leads to the following error:

error: The option `system.build.sdImage' is defined multiple times.

       Definition values:
       - In `..../sd-image.nix'
       - In `/nix/var/nix/profiles/per-user/root/channels/nixpkgs/nixos/modules/installer/sd-card/sd-image.nix': <derivation /nix/store/3ncjdwbfvhf44ri1pmmy6wvvlcsy91a2-nixos-sd-image-22.11pre391248.49546f4413f-aarch64-linux.img.drv>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment