Jetson Xavier NX / AGX Xavier / TX2 Update and Redundancy

Applies to: Jetson Xavier NX series, Jetson AGX Xavier series, and Jetson TX2 series
Bootloader update process provides a safe Bootloader update and ensures that a workable Bootloader partition remains on boot storage during an update. It achieves this with A/B update, a feature that maintains two sets of Bootloader partitions, Slot A and Slot B, where a slot is a set of partitions that contain boot images.
A/B redundancy is a feature added on top of A/B update. It automatically maintains the same Bootloader image on both Bootloader slots, allowing the system to boot from the unused slot if the current slot is corrupted.
A/B update and A/B redundancy reduce the risk of boot failure after a Bootloader update and when images on the current Bootloader slot are corrupted.
A/B redundancy is disabled by default. To enable it, see Enabling A/B Redundancy.

A/B Slot Layout

The principle of shadow copies enables multiple placeholders. All placeholders, but one, holds backup copies. Each copy constitutes a potential candidate to boot from. However, based on runtime decisions, the correct copy of the binary is loaded to continue with the boot process. These two shadow copies are commonly referred to as Slot A and Slot B. This two-slot implementation is as follows:
The following diagram gives a conceptual example of the slot implementation.

A/B System Update

The A/B slot system updates affects these components:
Partition Selection
A/B system updates use two sets of partitions, known as slots. Each slot has several attributes:
The current slot is the slot that the system, if running, booted from. The other slot is called the unused slot. The system may exchange the roles of the current and unused slot in the course of an update, or when the slot fails repeatedly during or immediately after a boot from the current slot.
The active slot is the slot that the next boot operation will attempt to boot from. In the normal state the active slot is the same as the bootable slot. When the system is being updated it may be different.
The Bootable attribute indicates whether the slot contains a correct system that can be used to boot the device. When the system is running the current slot is bootable; the unused slot may have an older, identical, or newer version of the system, and may or may not be bootable.
The Successful attribute indicates that the system has attempted to boot from the slot, and the most recent attempt succeeded. It is set by the user space Update Engine (UE) the first time a newly updated slot boots successfully to the kernel. It is reset when a slot is updated or a boot attempt fails. This normally happens immediately after a system update when the updated software contains an error.
If a bootable slot fails to boot a certain number of times, Bootloader resets its Bootable attribute and switches the roles of the current and unused slots. The formerly unused, now current slot normally was the current slot before the last update, and contains the boot-related software that was used for the most recent successful boot.
The slot status details are defined in a structure stored in the slot metadata (SMD) partition:
A screenshot of a cell phone Description automatically generated
Where:
magic is a fixed value that identifies the SMD partition.
version specifies the version number of the software in the slot.
num_slots specifies the number of slots, which should be 2.
slot_info is an array of structures which contain information about the slots. In each slot:
priority is the priority of this slot.
suffix is a string, either “_a” or “_b,” that is suffixed to the A/B partitions’ names to make them unique.
retry_count is the number of boot retries remaining before Bootloader resets the current slot’s Successful and Bootable attributes and tries to boot from the unused slot.
boot_successful is the slot’s Successful attribute.
The bootable slot is the slot with priority and retry_count both greater than 0.
The current slot is the slot with the highest priority and a retry_count greater than 0. This slot is booted by the next power cycle.
Update Engine
The A/B system update uses the Update Engine to update A/B slots and to prepare the system to boot an updated version of Bootloader. The Update Engine performs these actions:
1. Reads the bl_update_payload and writes data to the unused slot’s partitions as instructed by payload
2. Calls the boot_control interface in a pre-defined workflow
3. Switches the roles of the current and unused slots
4. Reboots the system
5. Updates images on the unused, previously current slot to ensure that both slots contain the update
For more information, see:

Bootloader Implementation

The A/B system uses the boot slot metadata to store the slot status. It communicates between the Update Engine and Bootloader. Bootloader runs the state machine to select the boot slot. It handles the update failure cases as follows:
A screenshot of a cell phone Description automatically generated
MB1 uses the slot metadata to find the current slot. It caches the current slot number, 0 (slot A) or 1 (slot B), along with a “valid” flag, in scratch register 99 to be used by MB2, CBoot, or later stage loaders.
Scratch register 99 layout
Bits
31-30
29-26
25-22
21-19
18-16
15-0
Flag
Slot A
retry count
Slot B
retry count
Maximum slots
Current slot number
Magic pattern café
If MB1 does not find a current slot, the device hangs.
The name of the partition that is being loaded is derived as follows:
partition_name = <base_name>_<slot_value>”
slot value = “” for slot 0
slot value = “_b” for slot 1
Partition Settings
All A/B partitions must be named as follows:
mb1
mb1_b
mb2
mb2_b
cboot
cboot_b
etc
The empty suffix for Slot A is to ensure backward compatibility with legacy A/B unaware partition loading mechanisms.
Update Engine States
The Update Engine (UE), nv_update_engine, uses the slot metadata to instruct Bootloader what slot to boot from. The following scenarios identify all UE states.
Normal State
The system has booted from the current slot, which may be Slot A or Slot B.
No updates have been applied.
The current slot is Bootable and Successful, and is the active slot.
This table shows the status of a system in the normal state with slot B current. Slot A is the unused slot because its priority is lower than that of slot B.
Slot
Priority
Retry count
Successful
Slot A
14
7
1
Slot B
15
7
1
Update in Progress
The system booted from the current slot. It is updating the unused slot.
The current slot is Bootable and Successful, and is the active slot.
The unused slot is not Bootable because it is being updated and the update is not yet complete.
This table shows the status of a system with slot B current and an update of slot A in progress. If the system must reboot in this state, it reboots from slot B.
Slot
Priority
Retry count
Successful
Slot A
0
0
0
Slot B
15
7
1
Update Applied, Reboot Pending
The roles of the now-current and unused slots are about to be switched. Thus the system will attempt to boot from the now-unused slot.
The now-unused slot is marked as Bootable and becomes the active slot, but is not yet marked as Successful.
Bootloader attempts to boot from the newly updated slot some number of times.
This table shows the status of a system with an update applied to slot A and a reboot pending from slot A.
Slot
Priority
Retry count
Successful
Slot A
15
7
0
Slot B
14
7
1
System Reboot into a New Update
The system is booting from the newly updated, now current slot for the first time.
The formerly current, now unused slot is still Bootable and Successful, while the now current slot is Bootable and is the active slot, but is not Successful.
The Update Engine marks the now current slot Successful after a successful boot and some system checks.
This table shows the status of a system that is booting from a new update on slot A.
Slot
Priority
Retry count
Successful
Slot A
15
6
0
Slot B
14
7
1
Slot Duplication in Progress
The system has booted from the newly updated slot for the first time.
The formerly current, now unused slot is marked as not Bootable because it is being updated.
If the system must reboot in this state it boots from the newly updated, now current slot.
This table shows the status of a system with slot duplication in progress from slot A to slot B.
Slot
Priority
Retry count
Successful
Slot A
15
6
0
Slot B
0
0
0
Slot Duplication Complete
The system has booted from the current slot for the first time and has duplicated the current slot to the unused slot.
The current slot is marked as Bootable and Successful. The unused, newly duplicated slot is marked as Bootable and Successful, but with lower priority.
This table shows the status of a system with completed slot duplication from slot A to slot B.
Slot
Priority
Retry count
Successful
Slot A
15
7
1
Slot B
14
7
1
Boot Failure and Recovery
The system fails to boot from the current slot due to data corruption or I/O errors.
After some number of failed attempts to boot from the current slot, Bootloader marks the current slot not Bootable and boots from the unused slot.
This table shows the status of a system that failed to boot from slot A and recovered by booting from slot B.
Slot
Priority
Retry count
Successful
Slot A
0
0
0
Slot B
14
7
1
In this state the Update Engine is not allowed to duplicate a slot. Duplication is not allowed until the system updates the now-unused slot and boots from it successfully. The Update Engine also is not allowed to modify the partition table or the contents of partitions not assigned to slot A or B.

When the Update Engine is Launched

The update engine is launched under these scenarios:
6. An explicit launch by the user to update partitions with newer versions, with the command:
$ sudo nv_update_engine --install
The update engine applies Bootloader update payload (BUP) during the update. The BUP must be named bl_update_payload and must be placed under:
/opt/ota_package
7. Update Engine is launched by the boot service during a system boot with the command:
$ sudo nv_update_engine --verify
The update engine loads the slot metadata, evaluates the current state, and runs a pre-defined workflow. In normal boot, the update engine is in normal boot state, where an update is not applied and a duplicate is not required. The update engine simply exits.

Enabling A/B Redundancy

There are two methods for enabling A/B redundancy:
Creating an SMD image and setting redundancy settings.
Using the nv_update_engine tool to enable redundancy.
Jetson Linux can enable A/B redundancy with a single file system partition, that is, without rootfs redundancy. To get the full benefit of A/B redundancy, though, you must enable root file system redundancy as well. For more information, see the section Root File System Redundancy in the topic Setting Up Your File System.
To enable redundancy by creating an SMD image
1. Modify the SMD configuration file smd_info.cfg to enable A/B slots.
2. Run the host tool nv_smd_generator on the x86 system to generate the SMD image with the updated SMD configuration file.
For instructions on generating the SMD image, consult SMD Image Generator.
3. Run the flash.sh script to perform a fresh flash of the device with all the partitions.
To enable redundancy by using the nv_update_engine
On the target system launch the nv_update_engine tool to enable A/B for the flashed device with A/B disabled SMD image.
For instructions consult Running the Update Engine.

Bootloader Tools

The following NVIDIA tools are provided for ease-of-use of Bootloader update process.
Boot Control
The nvbootctrl tool is intended for debugging purposes to load in the SMD image and dump the slot information. It can also be used to set the active slot to forcefully change the boot slot in the next boot.
To display the command usage
Enter the command:
$ sudo nvbootctrl
Bootloader Update Payload Generator
The Bootloader Update Payload (BUP) is the payload that is applied by the update engine during an update. The BUP is generated by the host script build_l4t_bup.sh, which is packaged along with the flash.sh script in the Linux for Jetson Board Support Package (BSP).
This section describes procedures for generating a multi-spec BUP or a single-spec BUP. A multi-spec BUP includes multiple binaries and BCT images which can be used to update all of the Jetson devices that contain a particular processor. When you run the updater, it uses the appropriate binary of each type for the device you are updating. A single-spec BUP contains just one binary of each type, and can be used to update just one Jetson device.
To generate a multi-spec BUP
Enter the commands:
$ cd <top>
$ sudo ./l4t_generate_soc_bup.sh [-u <pkc_key_file>] [‑p <options>] [-d] <processor>
Where:
<top> is the pathname of the directory that contains the PDK installation package. The flash.sh script is in this directory.
<pkc_key_file> is the RSA private key file for your Jetson carrier board. If it is a relative pathname, it is interpreted relative to the <top>/bootloader directory.
-d causes the script to run in debug mode, which keeps all boot firmware blob images in bootloader/signed and bootloader/multi-signed
<options> is a string containing command line options to be passed to flash.sh to generate the BUP. If the string contains whitespace characters, it must be enclosed in quotes.
<processor> is t19x for a Jetson AGX Xavier series device, or t18x for a Jetson TX2 series device.
The procedure stores the BUP in the file:
<top>/bootloader/<payload_dir>/bl_update_payload
Where <payload_dir> is a directory for BUPs that apply to a specific type of Jetson or Tegra® processor. For more information, see Where the BUP File is Stored, below.
For more information about generating BUPs, see Generating the Bootloader Update Payload (BUP).
To generate a single-spec BUP
Enter the command:
$ sudo [env={value}, …] ./build_l4t_bup.sh [options] <board> <rootdev>
Where:
<board> is the value of $(BOARD) for your Jetson module and configuration, as shown in the table Jetson Modules and Configurations in the topic Quick Start.
<rootdev> is the partition where the root file system is to be flashed.
The procedure stores the BUP in the file:
<top>/bootloader/<payload_dir>/bl_update_payload
Where <payload_dir> is a directory for BUPs that apply to a specific type of Jetson or Tegra processor. For more information, see Where the BUP File is Stored, below.
For more information about generating BUPs, see Generating the Bootloader Update Payload (BUP).
Where the BUP File is Stored
Both procedures store the BUP file at:
<top>/bootloader/<payload_dir>/bl_update_payload
Where <payload_dir> is:
For Jetson Xavier NX series and Jetson AGX Xavier series devices: payloads_t19x
For Jetson TX2 series devices: payloads_t18x
For Jetson Nano and Jetson TX1 devices: payloads_t21x
The multi-spec procedure stores a BUP at each of these locations for the respective group of processors. The single-spec procedure stores a BUP at just one location for the appropriate type of processor.
You must place the BUP file in the target system under this directory before the Update Engine is run:
/opt/ota_package/
SMD Image Generator
Run the nv_smd_generator tool on X86 host systems to generate the default SMD image slot_metadata.bin that is flashed into the SMD partition.
To launch the image generator
Enter the command:
$ nv_smd_generator <config_file> <output_file>
Where:
<config_file> is the SMD configuration file.
<output_file> is the slot_metadata.bin output SMD image.
For example:
$ sudo nv_smd_generator smd_info.cfg slot_metadata.bin
In the Linux for Jetson Board Support Package, nv_smd_generator, the default SMD configuration file smd_info.cfg, and the default image file slot_metadata.bin, are installed under the directory:
<top>/bootloader
By default, the smd_info.cfg configuration file is set so that Slot A is the only available slot. This effectively disables redundancy:
< VERSION 4 >
# Set the maximum boot slot retry count
# Please make sure this field is set before slot info config
< MAX_BL_RETRY_COUNT 7 >
#
# Config 1: Disable A/B support (Default)
#
 
# slot info order is important!
# <priority> <suffix> <boot_successful>
15 _a 1
 
#
# Config 2: Enable redundancy support (by removing comments ##)
#
##< REDUNDANCY_USER 1 >
#
# To disable bootloader autosync, use < BL_AUTOSYNC_DISABLE 1>
# REDUNDANCY_ENABLE or REDUNDANCY_USER must be defined before BL_AUTOSYNC DISABLE!
##< BL_AUTOSYNC_DISABLE 1 >
 
# slot info order is important!
# <priority> <suffix> <boot_successful>
##15 _a 1
##14 _b 1
Use Config 2 to create the SMD image and enable A/B redundancy.
To enable A/B update and A/B redundancy
1. Comment out the configuration that disables A/B update by adding a ‘#’ to the beginning of the parameter line below Config 1:
15 _a 1
2. “Uncomment” the configuration that enables A/B update by removing ‘##’ from the beginning of the parameter lines below Config 2:
##15 _a 1
##14 _b 1
Now the Bootloader-related partitions, the kernel partition, and the kernel-dtb partition all have A/B slots.
3. If you want to enable A/B redundancy as well as A/B update, uncomment the <REDUNDANCY_USER x> statement. Replace x with a number that specifies the type of redundancy support you want:
0: Support for redundancy at Bootloader only, i.e, from mb1, mb2, until cboot.
1: Support for redundancy at Bootloader, images at kernel, and kernel-dtb partitions.
4. Bootloader slot duplication is enabled by default. You can disable it by uncommenting the configuration:
##< BL_AUTOSYNC_DISABLE 1 >
Maximum Boot Slot Retry Count
MAX_BL_RETRY_COUNT specifies the maximum boot slot retry count. Its default value is 7. You can set any value between 0 and 7.

Running the Update Engine

Run the update Engine script on the target system.
To enable/disable A/B redundancy
Enter this command to enable redundancy:
$ sudo nv_update_engine –-enable-ab
Enter this command to disable redundancy:
$ sudo nv_update_engine –-disable-ab
The command fails if the current boot slot is NOT 0.
To update Bootloader
5. Enter this command to switch to superuser mode:
$ sudo su
6. Enable A/B redundancy (a one-time command):
$ nv_update_engine --enable-ab
7. If a BUP directory does not exist, create one by executing the command:
$ mkdir /opt/ota_package
8. Copy the BUP from the host system to this newly created BUP directory with the command:
$ scp <host_loc:bl_update_payload> /opt/ota_package/
Where:
<host_loc:bl_update_payload> is where the BUP is built on the host system. You can also use a USB key to copy the BUP from the host system to the target system.
See Generating the Bootloader Update Payload for information about how to generate the BUP.
9. Launch the Update Engine to update Bootloader on the non-current slot with the command:
$ nv_update_engine --install

Update Engine State Machine

The Update Engine state machine flow is as follows:
Diagram, schematic Description automatically generated

Manually Modifying Boot Slots

NVIDIA provides the nvbootctrl tool for testing and development purposes. However, you may wish to manually change the boot slots or make modifications to the SMD partition from the userspace.
To manually modify the boot slots
1. Enter this command to switch to superuser mode:
$ sudo su
2. Enter this command:
$ nvbootctrl <command>
Where <command> is as follows:
The default setting for both Slot 0 and Slot 1 is “bootable,” with Slot 0 having higher priority.
Command
Description
get-number-slots
Printer the number of slots.
get-current-slot
Prints the currently running slot.
mark-boot-successful
Marks the current slot as GOOD.
set-active-boot-slot <slot>
On next boot, loads and executes <slot>.
set-slot-as-unbootable <slot>
Marks SLOT as invalid.
is-slot-bootable <slot>
Returns 0 if SLOT is bootable.
is-slot-marked-successful <slot>
Returns 0 if SLOT is marked GOOD.
get-suffix <slot>
Prints the suffix for <slot>.
is-autosync-enabled
Prints enablement status of slot duplication (it is enabled by default).
toggle-autosync
Toggles enablement of slot duplication.
dump-slots-info
Prints the information for the slots.
<slot> is the zero-based slot number.
To show the current boot slot
Enter this command:
root@tegra-ubuntu:/home/nvidia# nvbootctrl get-current-slot
0
root@tegra-ubuntu:/home/nvidia#
To show the slot status
Enter one of the following commands:
Before enabling A/B redundancy:
root@tegra-ubuntu:/home/nvidia# nvbootctrl dump-slots-info
magic:0x43424e00, version: 3 features: 0 num_slots: 1
slot: 0, priority: 15, suffix: _a, retry_count: 7, boot_successful: 1
slot: 1, priority: 0, suffix: , retry_count: 0, boot_successful: 0
root@tegra-ubuntu:/home/nvidia#
After enabling A/B redundancy:
root@tegra-ubuntu:/home/nvidia# nvbootctrl dump-slots-info magic:0x43424e00, version: 3 features: 3 num_slots: 2
slot: 0, priority: 15, suffix: _a, retry_count: 7, boot_successful: 1
slot: 1, priority: 14, suffix: _b, retry_count: 7, boot_successful: 1
root@tegra-ubuntu:/home/nvidia#

Sample Boot Log

The boot slot is selected by MB1. The following sample log shows that Slot 1 is selected as the boot slot. The message displayed from MB1 is available from a debug build of MB1 that has messages enabled. Messages from MB2 are always available.
[0000.040] I> Welcome to MB1-coldboot(dev-version : 14.00.170822-t186-M-00.00-96e265a3)
[0000.048] I> rst_source : 0xb
[0000.051] I> rst_level : 0x1
[0000.053] I> Read lock all AES keyslots
[0000.057] I> Read lock all RSA keyslots
[0000.061] I> Clear SE keyslots left open by BR
[0000.065] I> Last mts-fallback status: 0x00000000
[0000.070] I> Boot-device: eMMC
[0000.094] I> sdmmc ddr50 mode
[0000.098] I> A/B: bin_type (19) slot 0
[0000.102] I> Binary(19) of size 512 is loaded @ 0x40043400
[0000.108] I> Boot chain chosen: 1
[0000.111] I> Boot chain chosen: 1
[0000.114] I> magic:0x43424e00, version: 259, num_slots: 2
[0000.119] I> slot: 0, pri: 14, suffix: _a, retry: 7, boot_succ: 1
[0000.125] I> slot: 1, pri: 15, suffix: _b, retry: 6, boot_succ: 1
[0000.131] I> Loading MB1-BCT to SysRAM
[0000.135] I> A/B: bin_type (0) slot 1
[0000.138] I> Boot-device: eMMC
. . .
. . .
[0000.888] I> Welcome to MB2(TBoot-BPMP)(version: 01.00.160913-t186-M-00.00-mobile-09b4fbd4)
[0000.897] I> Default Heap @ [0xd486400 - 0xd488400]
[0000.901] I> DMA Heap @ [0x84a00000 - 0x85300000]
[0000.906] I> bit @ 0xd480000
[0000.909] I> BR-BCT relocated to 0xd7020000
[0000.913] I> Boot-device: eMMC
[0000.917] I> sdmmc bdev is already initialized
[0000.922] I> pmic: reset reason (nverc) : 0x0
[0000.926] I> Reading GPT from 512 for device 00000003
[0000.932] I> Reading GPT from 8388096 for device 00000003
[0000.939] I> Found 13 partitions in 00000003 device
[0000.944] I> Reading GPT from 512 for device 00010003
[0000.950] I> Found 27 partitions in 00010003 device
[0000.956] I> A/B: bin_type (16) slot 1
[0000.959] I> Loading partition bpmp-fw_b at 0xd7800000
[0000.964] I> Reading two headers - addr:0xd7800000 blocks:1
[0000.970] I> Addr: 0xd7800000, start-block: 58762425, num_blocks: 1
[0000.985] I> Binary(16) of size 528848 is loaded @ 0xd7800000
. . .
. . .

Generating the Bootloader Update Payload (BUP)

A Bootloader Update Payload (BUP) is used to implement bootloader update. It contains firmware binaries of each type needed to update a Jetson device.
This section describes the procedure for generating a single-spec BUP, which contains just one binary of each type and can be used to update just one Jetson device configuration.
There is also a procedure for generating a multi-spec BUP, which includes multiple firmware binaries and BCT images of each type, and can be used to update any supported type of Jetson device. When you run the updater, it uses the appropriate binary for each type for the device you are updating. See the section To generate a multi-spec BUP, below, for information.
To generate a single-spec BUP
Enter these commands to create the BUP image to be stored in a file for a board that is not connected to the host system.
With the indicated FAB/BOARDID/FUSELEVEL Jetson Xavier NX series board:
$ cd <top>
$ sudo FAB=100 BOARDID=3668 FUSELEVEL=fuselevel_production BOARDSKU=0001./build_l4t_bup.sh jetson-xavier-nx-devkit-emmc mmcblk0p1
With the indicated FAB/BOARDID/FUSELEVEL Jetson AGX Xavier series board:
$ cd <top>
$ sudo FAB=400 BOARDID=2888 FUSELEVEL=fuselevel_production BOARDSKU=0001 BOARDREV=H.0 ./build_l4t_bup.sh jetson-agx-xavier-devkit mmcblk0p1
With the indicated FAB/BOARDID/FUSELEVEL Jetson TX2 board:
$ cd <top>
$ sudo FAB=C04 BOARDID=3310 FUSELEVEL=fuselevel_production ./build_l4t_bup.sh jetson-tx2-devkit mmcblk0p1
Enter these commands to create the BUP image for a board that is connected to the host system:
1. Place the target board into force recovery mode.
2. Enter the commands:
$ cd <top>
$ sudo ./build_l4t_bup.sh <device> mmcblk0p1
Where <device> is:
For Jetson Xavier NX series: jetson-xavier-nx-devkit-emmc
For Jetson AGX AGX Xavier series: jetson-agx-xavier-devkit
For Jetson TX2 series: jetson-tx2-devkit
Enter these commands to create the PKC signed BUP image for the indicated FAB/BOARDID/FUSELEVEL Jetson TX2 board:
$ cd <top>
$ sudo FAB=C04 BOARDID=3310 FUSELEVEL=fuselevel_production ./build_l4t_bup.sh -s <pkc_key_file> jetson-tx2-devkit mmcblk0p1
Where:
The target is an original Jetson TX2 board. Contact NVIDIA for assistance in generating the BUP for other boards in the Jetson TX2 series.
<top> is the location of the parent directory of the PDK installation package, where flash.sh command is located.
<pkc_key_file> is the RSA private key file for your board. It must be located under the <top>/bootloader directory or be specified by a complete (absolute) pathname.
Enter these commands to create the PKC signed BUP image for the board connected to the host system:
1. Place the target board into force recovery mode.
2. Enter the following commands:
$ cd <top>
$ sudo ./build_l4t_bup.sh -s <pkc_key_file> -u <pkc_key_file> <device> mmcblk0p1
Where:
<top> is the location to parent directory of the PDK installation package, where the flash.sh command is located.
<pkc_key_file> is the RSA private key file for your board. It must be located under <top>/bootloader directory or a complete (absolute) pathname.
<device> is:
For Jetson Xavier NX series: jetson-xavier-nx-devkit-emmc
For Jetson AGX Xavier series: jetson-agx-xavier-devkit
For Jetson TX2 series: jetson-tx2-devkit
To generate a multi-spec BUP
The section Generating the Bootloader Update Payload (BUP) in the topic Jetson Nano / TX1 Update and Redundancy describes a procedure for generating a multi-spec BUP. When you run the updater, it uses the appropriate binary of each type for the device you are updating.
To use the multi-spec BUP procedure with a Jetson Xavier NX series or Jetson AGX Xavier series device, replace t21x with t19x in the command that generates the BUP. To use the procedure with a Jetson TX2 series device, replace t21x with t18x.