From a1b4cadb531bc5777ac5910a42b53bca12d35c22 Mon Sep 17 00:00:00 2001 From: Travis Staton Date: Wed, 24 May 2023 09:33:32 -0400 Subject: [PATCH] populate firmware partition via systemd service Only copy files from modified packages. --- README.md | 15 ++++--- rpi/default.nix | 117 +++++++++++++++++++++++++++++++++++------------- 2 files changed, 93 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index 3e30cc2..2924949 100644 --- a/README.md +++ b/README.md @@ -87,8 +87,8 @@ the aarch64 installation media from nixpkgs: There is a firmware partition that contains necessary firmware, u-boot, and config.txt. Then there is another partition (labeled `NIXOS_SD`) that contains everything else. The firmware and `config.txt` file are -managed by NixOS modules defined in this package. Additionally, NixOS -system activation will update the firmware and `config.txt` in the +managed by NixOS modules defined in this package. Additionally, a +systemd service will update the firmware and `config.txt` in the firmware partition __in place__. Linux kernels are stored in the `NIXOS_SD` partition and will be booted by u-boot in the firmware partition. @@ -96,7 +96,8 @@ partition. ## `config.txt` generation As noted, the `config.txt` file is generated by the NixOS -configuration and automatically updated on system activation. +configuration and automatically updated on when the nix configuration +is modified. The relevant nixos option is `hardware.raspberry-pi.config`. Configuration is partitioned into @@ -254,8 +255,8 @@ device tree configuration is controlled via the [config.txt file](https://www.raspberrypi.com/documentation/computers/config_txt.html). Additionally, the firmware, device trees, and overlays from the -`raspberrypifw` package populate the firmware partition on system -activation. This package is kept up to date by the overlay applied by -this package, so you don't need configure this. However, if you want -to use different firmware you can override that package to do so. +`raspberrypifw` package populate the firmware partition. This package +is kept up to date by the overlay applied by this package, so you +don't need configure this. However, if you want to use different +firmware you can override that package to do so. diff --git a/rpi/default.nix b/rpi/default.nix index 27ce29f..671369d 100644 --- a/rpi/default.nix +++ b/rpi/default.nix @@ -4,43 +4,96 @@ { imports = [ ../sd-image ./config.nix ./i2c.nix ]; - # On activation install u-boot, Raspberry Pi firmware, and our - # generated config.txt - system.activationScripts.raspberrypi = { - text = '' - shopt -s nullglob + systemd.services = { + "raspberry-pi-firmware-migrate" = { + description = "update the firmware partition"; + wantedBy = [ "multi-user.target" ]; + serviceConfig = let firmware-path = "/boot/firmware"; + in { + Type = "oneshot"; + MountImages = + "/dev/disk/by-label/${config.sdImage.firmwarePartitionName}:${firmware-path}"; + StateDirectory = "raspberrypi-firmware"; + ExecStart = pkgs.writeShellScript "migrate-rpi-firmware" '' + shopt -s nullglob - TARGET_FIRMWARE_DIR="/boot/firmware" - TARGET_OVERLAYS_DIR="$TARGET_FIRMWARE_DIR/overlays" - TMPFILE="$TARGET_FIRMWARE_DIR/tmp" - UBOOT="${pkgs.uboot_rpi_arm64}/u-boot.bin" - SRC_FIRMWARE_DIR="${pkgs.raspberrypifw}/share/raspberrypi/boot" - STARTFILES=("$SRC_FIRMWARE_DIR"/start*.elf) - DTBS=("$SRC_FIRMWARE_DIR"/*.dtb) - BOOTCODE="$SRC_FIRMWARE_DIR/bootcode.bin" - FIXUPS=("$SRC_FIRMWARE_DIR"/fixup*.dat) - SRC_OVERLAYS_DIR="$SRC_FIRMWARE_DIR/overlays" - SRC_OVERLAYS=("$SRC_OVERLAYS_DIR"/*) - CONFIG="${config.hardware.raspberry-pi.config-output}" + TARGET_FIRMWARE_DIR="${firmware-path}" + TARGET_OVERLAYS_DIR="$TARGET_FIRMWARE_DIR/overlays" + TMPFILE="$TARGET_FIRMWARE_DIR/tmp" + UBOOT="${pkgs.uboot_rpi_arm64}/u-boot.bin" + SRC_FIRMWARE_DIR="${pkgs.raspberrypifw}/share/raspberrypi/boot" + STARTFILES=("$SRC_FIRMWARE_DIR"/start*.elf) + DTBS=("$SRC_FIRMWARE_DIR"/*.dtb) + BOOTCODE="$SRC_FIRMWARE_DIR/bootcode.bin" + FIXUPS=("$SRC_FIRMWARE_DIR"/fixup*.dat) + SRC_OVERLAYS_DIR="$SRC_FIRMWARE_DIR/overlays" + SRC_OVERLAYS=("$SRC_OVERLAYS_DIR"/*) + CONFIG="${config.hardware.raspberry-pi.config-output}" - cp "$UBOOT" "$TMPFILE" - mv -T "$TMPFILE" "$TARGET_FIRMWARE_DIR/u-boot-rpi-arm64.bin" + migrate_uboot() { + echo "migrating uboot" + touch "$STATE_DIRECTORY/uboot-migration-in-progress" + cp "$UBOOT" "$TMPFILE" + mv -T "$TMPFILE" "$TARGET_FIRMWARE_DIR/u-boot-rpi-arm64.bin" + echo "${ + builtins.toString pkgs.uboot_rpi_arm64 + }" > "$STATE_DIRECTORY/uboot-version" + rm "$STATE_DIRECTORY/uboot-migration-in-progress" + } - cp "$CONFIG" "$TMPFILE" - mv -T "$TMPFILE" "$TARGET_FIRMWARE_DIR/config.txt" + migrate_config() { + echo "migrating config.txt" + touch "$STATE_DIRECTORY/config-migration-in-progress" + cp "$CONFIG" "$TMPFILE" + mv -T "$TMPFILE" "$TARGET_FIRMWARE_DIR/config.txt" + echo "${config.hardware.raspberry-pi.config-output}" > "$STATE_DIRECTORY/config-version" + rm "$STATE_DIRECTORY/config-migration-in-progress" + } - for SRC in "''${STARTFILES[@]}" "''${DTBS[@]}" "$BOOTCODE" "''${FIXUPS[@]}" - do - cp "$SRC" "$TMPFILE" - mv -T "$TMPFILE" "$TARGET_FIRMWARE_DIR/$(basename "$SRC")" - done + migrate_firmware() { + echo "migrating raspberrypi firmware" + touch "$STATE_DIRECTORY/firmware-migration-in-progress" + for SRC in "''${STARTFILES[@]}" "''${DTBS[@]}" "$BOOTCODE" "''${FIXUPS[@]}" + do + cp "$SRC" "$TMPFILE" + mv -T "$TMPFILE" "$TARGET_FIRMWARE_DIR/$(basename "$SRC")" + done - for SRC in "''${SRC_OVERLAYS[@]}" - do - cp "$SRC" "$TMPFILE" - mv -T "$TMPFILE" "$TARGET_OVERLAYS_DIR/$(basename "$SRC")" - done - ''; + if [[ ! -d "$TARGET_OVERLAYS_DIR" ]]; then + mkdir "$TARGET_OVERLAYS_DIR" + fi + + for SRC in "''${SRC_OVERLAYS[@]}" + do + cp "$SRC" "$TMPFILE" + mv -T "$TMPFILE" "$TARGET_OVERLAYS_DIR/$(basename "$SRC")" + done + echo "${ + builtins.toString pkgs.raspberrypifw + }" > "$STATE_DIRECTORY/firmware-version" + rm "$STATE_DIRECTORY/firmware-migration-in-progress" + } + + if [[ -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 [[ -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 + migrate_config + fi + + if [[ -f "$STATE_DIRECTORY/firmware-migration-in-progress" || ! -f "$STATE_DIRECTORY/firmware-version" || $(< "$STATE_DIRECTORY/firmware-version") != ${ + builtins.toString pkgs.raspberrypifw + } ]]; then + migrate_firmware + fi + ''; + }; + }; }; # Default config.txt on Raspberry Pi OS: