From 19a8570ec93e861d752fc5d84cf1a516e4057187 Mon Sep 17 00:00:00 2001 From: Travis Staton Date: Wed, 24 Jan 2024 11:16:46 -0500 Subject: [PATCH 1/5] booting --- rpi/default.nix | 74 ++++++++++++++++++++++++++++++++++++++++---- sd-image/default.nix | 52 ++++++++++++++++++++++++------- 2 files changed, 108 insertions(+), 18 deletions(-) diff --git a/rpi/default.nix b/rpi/default.nix index 6ed0563..f1e3087 100644 --- a/rpi/default.nix +++ b/rpi/default.nix @@ -1,6 +1,8 @@ { core-overlay, libcamera-overlay }: { lib, pkgs, config, ... }: +let cfg = config.raspberry-pi-nix; +in { imports = [ ../sd-image ./config.nix ./i2c.nix ]; @@ -18,18 +20,41 @@ type = types.bool; }; }; + uboot = { + enable = mkOption { + default = true; + type = types.bool; + }; + }; }; }; config = { + boot.kernelParams = + if cfg.uboot.enable then [ ] + else [ + "root=PARTUUID=2178694e-02" # todo: use option + "rootfstype=ext4" + "fsck.repair=yes" + "rootwait" + "init=/sbin/init" + ]; systemd.services = { "raspberry-pi-firmware-migrate" = - lib.mkIf config.raspberry-pi-nix.firmware-migration-service.enable { + { description = "update the firmware partition"; - wantedBy = [ "multi-user.target" ]; + wantedBy = if cfg.firmware-migration-service.enable then [ "multi-user.target" ] else [ ]; serviceConfig = - let firmware-path = "/boot/firmware"; - in { + let + firmware-path = "/boot/firmware"; + kernel-params = pkgs.writeTextFile { + name = "cmdline.txt"; + text = '' + ${lib.strings.concatStringsSep " " config.boot.kernelParams} + ''; + }; + in + { Type = "oneshot"; MountImages = "/dev/disk/by-label/${config.sdImage.firmwarePartitionName}:${firmware-path}"; @@ -41,6 +66,8 @@ TARGET_OVERLAYS_DIR="$TARGET_FIRMWARE_DIR/overlays" TMPFILE="$TARGET_FIRMWARE_DIR/tmp" UBOOT="${pkgs.uboot_rpi_arm64}/u-boot.bin" + KERNEL="${pkgs.rpi-kernels.latest.kernel}/Image" + SHOULD_UBOOT=${if cfg.uboot.enable then "1" else "0"} SRC_FIRMWARE_DIR="${pkgs.raspberrypifw}/share/raspberrypi/boot" STARTFILES=("$SRC_FIRMWARE_DIR"/start*.elf) DTBS=("$SRC_FIRMWARE_DIR"/*.dtb) @@ -61,6 +88,28 @@ rm "$STATE_DIRECTORY/uboot-migration-in-progress" } + migrate_kernel() { + echo "migrating kernel" + touch "$STATE_DIRECTORY/kernel-migration-in-progress" + cp "$KERNEL" "$TMPFILE" + mv -T "$TMPFILE" "$TARGET_FIRMWARE_DIR/kernel.img" + echo "${ + builtins.toString pkgs.rpi-kernels.latest.kernel + }" > "$STATE_DIRECTORY/kernel-version" + rm "$STATE_DIRECTORY/kernel-migration-in-progress" + } + + migrate_cmdline() { + echo "migrating cmdline" + touch "$STATE_DIRECTORY/cmdline-migration-in-progress" + cp "${kernel-params}" "$TMPFILE" + mv -T "$TMPFILE" "$TARGET_FIRMWARE_DIR/cmdline.txt" + echo "${ + builtins.toString kernel-params + }" > "$STATE_DIRECTORY/cmdline-version" + rm "$STATE_DIRECTORY/cmdline-migration-in-progress" + } + migrate_config() { echo "migrating config.txt" touch "$STATE_DIRECTORY/config-migration-in-progress" @@ -94,12 +143,24 @@ rm "$STATE_DIRECTORY/firmware-migration-in-progress" } - if [[ -f "$STATE_DIRECTORY/uboot-migration-in-progress" || ! -f "$STATE_DIRECTORY/uboot-version" || $(< "$STATE_DIRECTORY/uboot-version") != ${ + if [[ "$SHOULD_UBOOT" -eq 1 ]] && [[ -f "$STATE_DIRECTORY/uboot-migration-in-progress" || ! -f "$STATE_DIRECTORY/uboot-version" || $(< "$STATE_DIRECTORY/uboot-version") != ${ builtins.toString pkgs.uboot_rpi_arm64 } ]]; then migrate_uboot fi + if [[ "$SHOULD_UBOOT" -ne 1 ]] && [[ ! -f "$STATE_DIRECTORY/kernel-version" || $(< "$STATE_DIRECTORY/kernel-version") != ${ + builtins.toString pkgs.rpi-kernels.latest.kernel + } ]]; then + migrate_kernel + fi + + if [[ "$SHOULD_UBOOT" -ne 1 ]] && [[ ! -f "$STATE_DIRECTORY/cmdline-version" || $(< "$STATE_DIRECTORY/cmdline-version") != ${ + builtins.toString kernel-params + } ]]; then + migrate_cmdline + fi + if [[ -f "$STATE_DIRECTORY/config-migration-in-progress" || ! -f "$STATE_DIRECTORY/config-version" || $(< "$STATE_DIRECTORY/config-version") != ${ builtins.toString config.hardware.raspberry-pi.config-output } ]]; then @@ -194,8 +255,9 @@ loader = { grub.enable = lib.mkDefault false; + initScript.enable = !cfg.uboot.enable; generic-extlinux-compatible = { - enable = lib.mkDefault true; + enable = lib.mkDefault cfg.uboot.enable; # We want to use the device tree provided by firmware, so don't # add FDTDIR to the extlinux conf file. useGenerationDeviceTree = false; diff --git a/sd-image/default.nix b/sd-image/default.nix index 2804d06..c14e50b 100644 --- a/sd-image/default.nix +++ b/sd-image/default.nix @@ -5,23 +5,51 @@ config = { boot.loader.grub.enable = false; - boot.loader.generic-extlinux-compatible.enable = true; boot.consoleLogLevel = lib.mkDefault 7; # https://github.com/raspberrypi/firmware/issues/1539#issuecomment-784498108 boot.kernelParams = [ "console=serial0,115200n8" "console=tty1" ]; - sdImage = { - populateFirmwareCommands = '' - cp ${pkgs.uboot_rpi_arm64}/u-boot.bin firmware/u-boot-rpi-arm64.bin - cp -r ${pkgs.raspberrypifw}/share/raspberrypi/boot/{start*.elf,*.dtb,bootcode.bin,fixup*.dat,overlays} firmware - cp ${config.hardware.raspberry-pi.config-output} firmware/config.txt - ''; - populateRootCommands = '' - mkdir -p ./files/boot - ${config.boot.loader.generic-extlinux-compatible.populateCmd} -c ${config.system.build.toplevel} -d ./files/boot - ''; - }; + sdImage = + let + kernel-params = pkgs.writeTextFile { + name = "cmdline.txt"; + text = '' + ${lib.strings.concatStringsSep " " config.boot.kernelParams} + ''; + }; + populate-kernel = + if config.raspberry-pi-nix.uboot.enable + then '' + cp ${pkgs.uboot_rpi_arm64}/u-boot.bin firmware/u-boot-rpi-arm64.bin + '' + else '' + cp "${pkgs.rpi-kernels.latest.kernel}/Image" firmware/kernel.img + cp "${kernel-params}" firmware/cmdline.txt + ''; + in + { + populateFirmwareCommands = '' + ${populate-kernel} + cp -r ${pkgs.raspberrypifw}/share/raspberrypi/boot/{start*.elf,*.dtb,bootcode.bin,fixup*.dat,overlays} firmware + cp ${config.hardware.raspberry-pi.config-output} firmware/config.txt + ''; + populateRootCommands = + if config.raspberry-pi-nix.uboot.enable + then '' + mkdir -p ./files/boot + ${config.boot.loader.generic-extlinux-compatible.populateCmd} -c ${config.system.build.toplevel} -d ./files/boot + '' + else '' + mkdir -p ./files/sbin + content="$( + echo "#!${config.system.build.toplevel.pkgs.bashInteractive}/bin/bash" + echo "exec ${config.system.build.toplevel}/init" + )" + echo "$content" > ./files/sbin/init + chmod 744 ./files/sbin/init + ''; + }; }; } From 462167cc9355770e7b9322375ab82b005073936b Mon Sep 17 00:00:00 2001 From: Travis Staton Date: Tue, 20 Feb 2024 12:43:24 -0500 Subject: [PATCH 2/5] add udev rules --- rpi/default.nix | 53 +++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 47 insertions(+), 6 deletions(-) diff --git a/rpi/default.nix b/rpi/default.nix index f1e3087..24d3a45 100644 --- a/rpi/default.nix +++ b/rpi/default.nix @@ -202,7 +202,7 @@ in # linux kernel. kernel = { enable = true; - value = "u-boot-rpi-arm64.bin"; + value = if cfg.uboot.enable then "u-boot-rpi-arm64.bin" else "kernel.img"; }; arm_64bit = { enable = true; @@ -267,11 +267,52 @@ in hardware.enableRedistributableFirmware = true; services = { - udev.extraRules = '' - SUBSYSTEM=="dma_heap", GROUP="video", MODE="0660" - KERNEL=="gpiomem", GROUP="gpio", MODE="0660" - KERNEL=="gpiochip*", GROUP="gpio", MODE="0660" - ''; + udev.extraRules = + let shell = "${pkgs.bash}/bin/bash"; + in '' + # https://raw.githubusercontent.com/RPi-Distro/raspberrypi-sys-mods/master/etc.armhf/udev/rules.d/99-com.rules + SUBSYSTEM=="input", GROUP="input", MODE="0660" + SUBSYSTEM=="i2c-dev", GROUP="i2c", MODE="0660" + SUBSYSTEM=="spidev", GROUP="spi", MODE="0660" + SUBSYSTEM=="*gpiomem*", GROUP="gpio", MODE="0660" + SUBSYSTEM=="rpivid-*", GROUP="video", MODE="0660" + + KERNEL=="vcsm-cma", GROUP="video", MODE="0660" + SUBSYSTEM=="dma_heap", GROUP="video", MODE="0660" + + SUBSYSTEM=="gpio", GROUP="gpio", MODE="0660" + SUBSYSTEM=="gpio", KERNEL=="gpiochip*", ACTION=="add", PROGRAM="${shell} -c 'chgrp -R gpio /sys/class/gpio && chmod -R g=u /sys/class/gpio'" + SUBSYSTEM=="gpio", ACTION=="add", PROGRAM="${shell} -c 'chgrp -R gpio /sys%p && chmod -R g=u /sys%p'" + + # PWM export results in a "change" action on the pwmchip device (not "add" of a new device), so match actions other than "remove". + SUBSYSTEM=="pwm", ACTION!="remove", PROGRAM="${shell} -c 'chgrp -R gpio /sys%p && chmod -R g=u /sys%p'" + + KERNEL=="ttyAMA[0-9]*|ttyS[0-9]*", PROGRAM="${shell} -c '\ + ALIASES=/proc/device-tree/aliases; \ + TTYNODE=$$(readlink /sys/class/tty/%k/device/of_node | sed 's/base/:/' | cut -d: -f2); \ + if [ -e $$ALIASES/bluetooth ] && [ $$TTYNODE/bluetooth = $$(strings $$ALIASES/bluetooth) ]; then \ + echo 1; \ + elif [ -e $$ALIASES/console ]; then \ + if [ $$TTYNODE = $$(strings $$ALIASES/console) ]; then \ + echo 0;\ + else \ + exit 1; \ + fi \ + elif [ $$TTYNODE = $$(strings $$ALIASES/serial0) ]; then \ + echo 0; \ + elif [ $$TTYNODE = $$(strings $$ALIASES/serial1) ]; then \ + echo 1; \ + else \ + exit 1; \ + fi \ + '", SYMLINK+="serial%c" + + ACTION=="add", SUBSYSTEM=="vtconsole", KERNEL=="vtcon1", RUN+="${shell} -c '\ + if echo RPi-Sense FB | cmp -s /sys/class/graphics/fb0/name; then \ + echo 0 > /sys$devpath/bind; \ + fi; \ + '" + ''; }; }; From adf670acf27505fb8119055003155a1c68b575d9 Mon Sep 17 00:00:00 2001 From: Travis Staton Date: Mon, 18 Mar 2024 20:28:06 -0400 Subject: [PATCH 3/5] don't hardcode root partition uuid --- rpi/default.nix | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/rpi/default.nix b/rpi/default.nix index 24d3a45..475c9ad 100644 --- a/rpi/default.nix +++ b/rpi/default.nix @@ -33,7 +33,11 @@ in boot.kernelParams = if cfg.uboot.enable then [ ] else [ - "root=PARTUUID=2178694e-02" # todo: use option + # This is ugly and fragile, but the sdImage image has an msdos + # table, so the partition table id is a 1-indexed hex + # number. So, we drop the hex prefix and stick on a "02" to + # refer to the root partition. + "root=PARTUUID=${lib.strings.removePrefix "0x" config.sdImage.firmwarePartitionID}-02" "rootfstype=ext4" "fsck.repair=yes" "rootwait" From bc745f7dc1089b2fae2b54cb69e8f0a35bf5a688 Mon Sep 17 00:00:00 2001 From: Travis Staton Date: Mon, 18 Mar 2024 20:46:27 -0400 Subject: [PATCH 4/5] document new options --- rpi/default.nix | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/rpi/default.nix b/rpi/default.nix index 475c9ad..1652799 100644 --- a/rpi/default.nix +++ b/rpi/default.nix @@ -12,18 +12,35 @@ in enable = mkOption { default = true; type = types.bool; + description = '' + Whether to run the migration service automatically or not. + ''; }; }; libcamera-overlay = { enable = mkOption { default = true; type = types.bool; + description = '' + If enabled then the libcamera overlay is applied which + overrides libcamera with the rpi fork. + ''; }; }; uboot = { enable = mkOption { default = true; type = types.bool; + description = '' + If enabled then uboot is used as the bootloader. If disabled + then the linux kernel is installed directly into the + firmware directory as expected by the raspberry pi boot + process. + + This can be useful for newer hardware that doesn't yet have + uboot compatibility or less common setups, like booting a + cm4 with an nvme drive. + ''; }; }; }; From 9405f0c18ace1c0fb3f1b1b7b63ba9d4b487457c Mon Sep 17 00:00:00 2001 From: Travis Staton Date: Mon, 18 Mar 2024 22:02:20 -0400 Subject: [PATCH 5/5] init script bash --- sd-image/default.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sd-image/default.nix b/sd-image/default.nix index c14e50b..52016a2 100644 --- a/sd-image/default.nix +++ b/sd-image/default.nix @@ -44,7 +44,7 @@ else '' mkdir -p ./files/sbin content="$( - echo "#!${config.system.build.toplevel.pkgs.bashInteractive}/bin/bash" + echo "#!${pkgs.bash}/bin/bash" echo "exec ${config.system.build.toplevel}/init" )" echo "$content" > ./files/sbin/init