Skip to content

Commit bb03752

Browse files
committed
Don't require using systemd-boot to get automated firmware updates
Using systemd-boot is not a requirement for applying capsule updates. We can make the firmware update process a systemd service, which gives us the behavior of running on every `switch-to-configuration` when the capsule update file changes. We do not apply the firmware update if we notice that the currently active nixos system (represented by /run/current-system) is not the same as the system profile that is persisted to /nix/var/nix/profiles/system. This allows us to retain the behavior from before this change where a user running `nixos-rebuild test` or similar will not have a capsule update applied.
1 parent 0739781 commit bb03752

File tree

2 files changed

+61
-36
lines changed

2 files changed

+61
-36
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ Weston and sway have been tested working on Orin devices, but do not work on Xav
129129
### Updating firmware from device
130130
Recent versions of Jetpack (>=5.1) support updating the device firmware from the device using the UEFI Capsule update mechanism.
131131
This can be done as a more convenient alternative to physically attaching to the device and re-running the flash script.
132-
These updates can be performed automatically after a `nixos-rebuild boot` if the `hardware.nvidia-jetpack.bootloader.autoUpdate` setting is set to true and systemd-boot is used.
132+
These updates can be performed automatically after a `nixos-rebuild boot` if the `hardware.nvidia-jetpack.bootloader.autoUpdate` setting is set to true.
133133
Otherwise, the instructions to apply the update manually are below.
134134

135135
To determine if the currently running firmware matches the software, run, `ota-check-firmware`:

modules/flash-script.nix

+60-35
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
{ config, pkgs, lib, ... }:
1+
{ config, pkgs, lib, utils, ... }:
22

33
# Convenience package that allows you to set options for the flash script using the NixOS module system.
44
# You could do the overrides yourself if you'd prefer.
@@ -403,42 +403,67 @@ in
403403
}.${cfg.som}
404404
)) else lib.mkOptionDefault [ ];
405405

406-
systemd.services = lib.mkIf (cfg.flashScriptOverrides.targetBoard != null) {
407-
setup-jetson-efi-variables = {
408-
enable = true;
409-
description = "Setup Jetson OTA UEFI variables";
410-
wantedBy = [ "multi-user.target" ];
411-
after = [ "opt-nvidia-esp.mount" ];
412-
serviceConfig.Type = "oneshot";
413-
serviceConfig.ExecStart = "${pkgs.nvidia-jetpack.otaUtils}/bin/ota-setup-efivars ${cfg.flashScriptOverrides.targetBoard}";
414-
};
406+
systemd.services.setup-jetson-efi-variables = lib.mkIf (cfg.flashScriptOverrides.targetBoard != null) {
407+
description = "Setup Jetson OTA UEFI variables";
408+
wantedBy = [ "multi-user.target" ];
409+
after = [ "opt-nvidia-esp.mount" ];
410+
serviceConfig.Type = "oneshot";
411+
serviceConfig.ExecStart = "${pkgs.nvidia-jetpack.otaUtils}/bin/ota-setup-efivars ${cfg.flashScriptOverrides.targetBoard}";
415412
};
416413

417-
boot.loader.systemd-boot.extraInstallCommands = lib.mkIf (cfg.firmware.autoUpdate && cfg.som != null && cfg.flashScriptOverrides.targetBoard != null) ''
418-
# Jetpack 5.0 didn't expose this DMI variable,
419-
if [[ ! -f /sys/devices/virtual/dmi/id/bios_version ]]; then
420-
echo "Unable to determine current Jetson firmware version."
421-
echo "You should reflash the firmware with the new version to ensure compatibility"
422-
else
423-
CUR_VER=$(cat /sys/devices/virtual/dmi/id/bios_version)
424-
NEW_VER=${pkgs.nvidia-jetpack.l4tVersion}
425-
426-
if [[ "$CUR_VER" != "$NEW_VER" ]]; then
427-
echo "Current Jetson firmware version is: $CUR_VER"
428-
echo "New Jetson firmware version is: $NEW_VER"
429-
echo
430-
431-
# Set efi vars here as well as in systemd service, in case we're
432-
# upgrading from an older nixos generation that doesn't have the
433-
# systemd service. Plus, this ota-setup-efivars will be from the
434-
# generation we're switching to, which can contain additional
435-
# fixes/improvements.
436-
${pkgs.nvidia-jetpack.otaUtils}/bin/ota-setup-efivars ${cfg.flashScriptOverrides.targetBoard}
437-
438-
${pkgs.nvidia-jetpack.otaUtils}/bin/ota-apply-capsule-update ${config.system.build.jetsonDevicePkgs.uefiCapsuleUpdate}
439-
fi
440-
fi
441-
'';
414+
systemd.services.firmware-update = lib.mkIf (cfg.firmware.autoUpdate && cfg.som != null && cfg.flashScriptOverrides.targetBoard != null) {
415+
wantedBy = [ "multi-user.target" ];
416+
path = [ pkgs.nvidia-jetpack.otaUtils ];
417+
after = [
418+
"${utils.escapeSystemdPath config.boot.loader.efi.efiSysMountPoint}.mount"
419+
"opt-nvidia-esp.mount"
420+
];
421+
unitConfig = {
422+
ConditionPathExists = "/sys/devices/virtual/dmi/id/bios_version";
423+
# This directory is populated by ota-apply-capsule-update, don't run
424+
# if we already have a capsule update present on the ESP.
425+
ConditionDirectoryNotEmpty = "!${config.boot.loader.efi.efiSysMountPoint}/EFI/UpdateCapsule";
426+
};
427+
script =
428+
# NOTE: Our intention is to not apply any capsule update if the
429+
# user's intention is to "test" a new nixos config without having it
430+
# persist across reboots. "nixos-rebuild test" does not append a new
431+
# generation to /nix/var/nix/profiles for the system profile, so we
432+
# can compare that symlink to /run/current-system to see if our
433+
# current active config has been persisted as a generation. Note that
434+
# this check _may_ break down if not using nixos-rebuild and using
435+
# switch-to-configuration directly, however it is well-documented
436+
# that a user would need to self-manage their system profile's
437+
# generations if switching a system in that manner.
438+
lib.optionalString config.system.switch.enable ''
439+
if [[ -f /nix/var/nix/profiles/system ]]; then
440+
latest_generation=$(readlink -f /nix/var/nix/profiles/system)
441+
current_system=$(readlink -f /run/current-system)
442+
if [[ $latest_generation == /nix/store* ]] && [[ $latest_generation != "$current_system" ]]; then
443+
echo "Skipping capsule update, current active system not persisted to /nix/var/nix/profiles/system"
444+
exit 0
445+
fi
446+
fi
447+
'' + ''
448+
CUR_VER=$(cat /sys/devices/virtual/dmi/id/bios_version)
449+
NEW_VER=${pkgs.nvidia-jetpack.l4tVersion}
450+
451+
if [[ "$CUR_VER" != "$NEW_VER" ]]; then
452+
echo "Current Jetson firmware version is: $CUR_VER"
453+
echo "New Jetson firmware version is: $NEW_VER"
454+
echo
455+
456+
# Set efi vars here as well as in systemd service, in case we're
457+
# upgrading from an older nixos generation that doesn't have the
458+
# systemd service. Plus, this ota-setup-efivars will be from the
459+
# generation we're switching to, which can contain additional
460+
# fixes/improvements.
461+
ota-setup-efivars ${cfg.flashScriptOverrides.targetBoard}
462+
463+
ota-apply-capsule-update ${config.system.build.jetsonDevicePkgs.uefiCapsuleUpdate}
464+
fi
465+
'';
466+
};
442467

443468
environment.systemPackages = lib.mkIf (cfg.firmware.autoUpdate && cfg.som != null && cfg.flashScriptOverrides.targetBoard != null) [
444469
(pkgs.writeShellScriptBin "ota-apply-capsule-update-included" ''

0 commit comments

Comments
 (0)