Preparing a Jetson to flash and boot an encrypted and non-encrypted image for an SSD
![]() |
|
Problems running the pipelines shown on this page? Please see our GStreamer Debugging guide for help.
Why is this useful?
There are moments when we need to flash an external partitions from the Jetson platform. Some scripts might need to be modified for that, there are flashing scripts tgat are useful for these cases. This wiki shows how to create an encrypted (or non encrypted) minimal JetPack environment for an external partition (SSD) that will be prepared and built from a local PC, and then flashed and decrypted from a Jetson platform. This document will guide you on:
- How to create a minimal filesytem.
- How to encrypt a Jetson Image.
- How to flash the encrypted/non encrypted Image from a Jetson platform to an external partition (an SSD).
- How to encrypt, decrypt, and boot the external partition.
- How to format and arrange the memory blocks of the external partition.
Getting started
Get the JetPack sources
This section details how to generate the JetPack environment needed for flashing the SSD. The goal is to create a compressed directory with the JetPack environment that will be used on the flash process from the Jetson. This final JetPack environment weighs around ~4.2GB (using the minimal image packages that NVIDIA provides).
1.1 Get the sources:
cd /tmp
mkdir linux-tegra && cd "$_"
wget -N https://developer.nvidia.com/embedded/l4t/r35_release_v1.0/release/jetson_linux_r35.1.0_aarch64.tbz2
wget -N https://developer.nvidia.com/embedded/L4T/r35_Release_v1.0/Release/secureboot_R35.1.0_aarch64.tbz2
1.2 Build the environment:
sudo tar xpvf jetson_linux_r35.1.0_aarch64.tbz2
sudo tar xvjf secureboot_R35.1.0_aarch64.tbz2
Create a minimal filesystem
This method creates a minimal filesystem. It does not include a desktop GUI.
On the host computer:
1. Add the desired packages to the minimal image package list file (this file already comes with a set of packages for a minimal image). This file is located in:
<JetPack_root_directory>/Linux_for_Tegra/tools/samplefs/nvubuntu-focal-minimal-aarch64-packages
- The <JetPack_root_directory>
might be in this case the linux-tegra directory already created.
- It is recommended to at least add the network-manager package to be able to ssh into the unit later:
xterm xtrans-dev xxd zlib1g zlib1g-dev +network-manager
![]() | Make sure to save the changes to the file. |
2. Initialize a docker container to create the environment for filesystem creation:
sudo apt-get install docker.io
sudo docker run --privileged -it --rm -v <JetPack_root_directory>/Linux_for_Tegra:/l4t ubuntu:20.04
3. Once in the docker container, generate the filesystem:
apt-get update
apt install -y qemu-user-static wget sudo
cd /l4t/tools/samplefs
sudo ./nv_build_samplefs.sh --abi aarch64 --distro ubuntu --flavor minimal --version focal
![]() | This might take a while. |
4. Copy the generated filesystem tarball to the JetPack environment. In another terminal outside the container do:
docker cp <container id>:/l4t/tools/samplefs/sample_fs.tbz2 <JetPack_root_directory>/Linux_for_Tegra/tools/samplefs
![]() | The container can be exited after this. |
5. Untar the filesystem tarball into the rootfs directory:
![]() | Important: This step will erase the current rootfs, make a backup if needed. |
cd <JetPack_root_directory>/Linux_for_Tegra
sudo rm -rf rootfs
mkdir rootfs && cd "$_"
sudo tar xpvf ../tools/samplefs/sample_fs.tbz2
cd ..
5.5 [Optional] If you wish to generate a full filesystem instead of a minimal one, follow the next commands:
![]() | With a full filesystem, the final JetPack environment will weigh significantly more. |
cd <JetPack_root_directory>
wget -N https://developer.nvidia.com/embedded/l4t/r35_release_v1.0/release/tegra_linux_sample-root-filesystem_r35.1.0_aarch64.tbz2
sudo rm -rf Linux_for_Tegra/rootfs
mkdir Linux_for_Tegra/rootfs && cd "$_"
sudo tar xpvf ../../tegra_linux_sample-root-filesystem_r35.1.0_aarch64.tbz2
cd ..
6. Apply the NVIDIA binaries:
sudo apt-get install qemu-user-static
sudo ./apply_binaries.sh --t
7. Install dependencies:
sudo apt-get install abootimg
sudo apt-get install libxml2-utils
sudo apt install uuid-runtime
8. Create an user:
- If a user is not created at this stage, then a mouse, keyboard and monitor are going to be needed to complete the Ubuntu setup when booting for the first time.
- Specifying a machine name is optional, if not specified, the machine name will be tegra-ubuntu.
sudo ./tools/l4t_create_default_user.sh -u <username> -p <password> -n <machine name>
Choose 'Accept' and press Enter.
Congratulations. The minimal filesystem has been created. Now the next step is to create the images and flash them to the Jetson platform.
Flash and create a Non Encrypted Image for the SSD
- The following instructions assume that an SSD NVMe card is already installed on the AGX module.
- The following instructions assume that the Jetson platform is already flashed. You can use any JetPack version, these instructions were tested on JetPack 5.0.2.
- The following instructions do not cover image and kernel compilation, but any image can be compiled and used normally.
Create the JetPack environment for the SSD
This is the JetPack environment that is going to live inside the SSD NVMe. The main idea is to prepare images from the minimal filesystem that was built earlier, compress it, and then sending it to the Jetson platform.
2.1.1. Create the images:
![]() | The image size is specified with the -S flag. It can be smaller than 8GiB if a smaller filesystem is generated. |
sudo BOARDID=2888 BOARDSKU=0004 FAB=400 BOARDREV=K.0 ./tools/kernel_flash/l4t_initrd_flash.sh --no-flash -S 8GiB -c tools/kernel_flash/flash_l4t_external.xml --external-only --external-device nvme0n1p1 --direct nvme0n1 jetson-agx-xavier-devkit external
![]() | The environment variables at the beginning depend on the platform. The ones provided already select Jetson AGX Xavier 32GB. |
Environment variables value table: # # BOARDID BOARDSKU FAB BOARDREV # --------------------------------+--------+---------+----+--------- # jetson-agx-xavier-industrial 2888 0008 600 A.0 # clara-agx-xavier-devkit" 3900 0000 001 C.0 # jetson-xavier-nx-devkit 3668 0000 100 N/A # jetson-xavier-nx-devkit-emmc 3668 0001 100 N/A # jetson-xavier-nx-devkit-emmc 3668 0003 N/A N/A # jetson-agx-xavier-devkit (16GB) 2888 0001 400 H.0 # jetson-agx-xavier-devkit (32GB) 2888 0004 400 K.0 # jetson-agx-orin-devkit 3701 0001 TS1 C.2 # jetson-agx-orin-devkit 3701 0000 TS4 A.0 # jetson-agx-xavier-devkit (64GB) 2888 0005 402 B.0 # holoscan-devkit 3701 0002 TS1 A.0 # jetson-agx-orin-devkit 3701 0004 TS4 A.0 # --------------------------------+--------+---------+----+---------
2.1.2. Delete the rootfs and unnecessary raw image:
sudo rm -rf rootfs
sudo rm -f bootloader/system.img.raw
2.1.3. Create the tarball:
- Note: This might take a while.
cd ..
tar cjf tegra_env.tbz2 Linux_for_Tegra/ --verbose
2.1.4. Store the JetPack environment.
Follow section Store the JetPack environment
2.2 Flash and format the SDD
- The next steps assume the JetPack environment tarball is already available in the Jetson.
- These steps are meant to be followed in the Jetson.
- The Jetson can be accessed through ssh if connected to a network (applies if the minimal FS was flashed).
2.2.1. Untar the JetPack environment tarball:
sudo tar xvjf tegra_env.tbz2 --verbose
- Note: Remove the tar file if it is copied to the eMMC after extraction, in order to save space. Ideally, the tegra_env.tbz2 file would be inside an SD card
2.2.2. Flash the SSD:
cd Linux_for_Tegra
sudo BOARDID=2888 BOARDSKU=0004 FAB=400 BOARDREV=K.0 ./tools/kernel_flash/l4t_initrd_flash.sh --flash-only -S 8GiB -c tools/kernel_flash/flash_l4t_external.xml --external-only --external-device nvme0n1p1 --direct nvme0n1 jetson-agx-xavier-devkit external
2.3. Partition the SSD
2.3.1. Install dependencies:
sudo apt update
sudo apt install cloud-guest-utils
sudo apt -y install dosfstools
2.3.2. Start parted:
sudo parted /dev/nvme0n1
2.3.3. Create free space to later enlarge the OS partition:
- In this case the starting point was calculated to be 65GB, refer to the next bullet point for details.
(parted) mkpart primary ext4 65GB 364GB
- The starting point was calculated like:
OSExtensionStart = (FinalSize - CurrentAPPSize) + APPEnd = (64GB-8GB)+9.2GB} = 65GB
- The APPEnd can be seen by doing:
(parted) print free
- In this case the output is the following, where the end of the APP partition is at 9.191 GB.
Number Start End Size File system Name Flags 17.4kB 20.5kB 3072B Free Space 2 20.5kB 67.1MB 67.1MB kernel msftdata 3 67.1MB 134MB 67.1MB kernel_b msftdata 4 134MB 135MB 459kB kernel-dtb msftdata 5 135MB 135MB 459kB kernel-dtb_b msftdata 6 135MB 219MB 83.9MB recovery msftdata 7 219MB 220MB 524kB recovery-dtb msftdata 8 220MB 534MB 315MB RECROOTFS msftdata 9 534MB 601MB 67.1MB fat32 esp boot, esp 10 601MB 601MB 18.4kB UDA msftdata 601MB 601MB 2048B Free Space 1 601MB 9191MB 8590MB ext4 APP msftdata 9191MB 1000GB 991GB Free Space
2.3.4. Make a partition with the rest of the free space:
(parted) mkpart primary ext4 364GB 1000GB
2.3.5. Quit parted:
(parted) quit
2.3.6. Create the filesystems for the new partitions:
sudo mkfs -t ext4 /dev/nvme0n1p11
sudo mkfs -t vfat /dev/nvme0n1p12
2.3.7. Enlarge the OS partition and filesystem to fill the free space created on step 3:
sudo growpart /dev/nvme0n1 1
sudo e2fsck -f /dev/nvme0n1p1
sudo resize2fs /dev/nvme0n1p1
2.3.8. Verify the SSD is formatted correctly:
sudo parted -l
- An output similar to the following one should be seen:
Number Start End Size File system Name Flags 2 20.5kB 67.1MB 67.1MB kernel msftdata 3 67.1MB 134MB 67.1MB kernel_b msftdata 4 134MB 135MB 459kB kernel-dtb msftdata 5 135MB 135MB 459kB kernel-dtb_b msftdata 6 135MB 219MB 83.9MB recovery msftdata 7 219MB 220MB 524kB recovery-dtb msftdata 8 220MB 534MB 315MB RECROOTFS msftdata 9 534MB 601MB 67.1MB fat32 esp boot, esp 10 601MB 601MB 18.4kB UDA msftdata 1 601MB 65.0GB 64.4GB ext4 APP msftdata 11 65.0GB 364GB 299GB ext4 primary 12 364GB 1000GB 636GB fat32 primary
2.3.9. Reboot.
- By default, the Jetson should now boot from SSD.
Important: The data partition (partition 2 in the HPI project context which is meant to hold Docker data) can also be encrypted at this stage as past of the SSD formatting. For this, follow section Encrypt data partition before rebooting the AGX.
3. Flash and create an Encrypted Image for the SSD
- The following instructions assume that an SSD NVMe card is already installed on the AGX module.
- The following instructions do not cover image and kernel compilation, but any image can be compiled and used normally.
- This section is covered on section ll
3.1 Create the JetPack environment
This is the JetPack environment that is going to live inside the eMMC.
3.1.1 Get the sources:
Follow section Get the JetPack sources
3.2 Configure the encypted partition
3.2.1. Modified the enc XML file to flash the encrypted APP partition. This XML file defines the partition table. You can do it by running:
$ sudo ./tools/kernel_flash/l4t_initrd_flash.sh --direct <extdev_on_host> \ -c <external-partition-layout> \ --external-device <extdev_on_target> \ [ -p <options> ] \ [ -S <rootfssize> ] \ <boardname> external
Instructions can be found in Linux_for_Tegra/tools/kernel_flash/>README_initrd_flash.txt README file, follow the Workflow 11: Manually generate a bootable external storage device.
3.2.2 Encrypted workaround:
A way to recover the NVIDIA-generated key is by modifying the Python script that generates it. The script can be found here: tools/disk_encryption/gen_luks_passphrase.py. To obtain the generated passphrase, save the key to a file by adding the following lines to the script:
# Generate passphrase if args.unique_pass: label_str = "luks-srv-passphrase-unique" else: label_str = "luks-srv-passphrase-generic" context_str = ''.join(str(c) for c in args.context_string) passphrase = nist_sp_800_108_with_CMAC(luks_key, context_str, label_str) print("%s" % passphrase.hex()) + f = open("PASS.txt", "w") + f.write("%s" % passphrase.hex()) + f.close() if __name__ == "__main__": main()
This will generate a file called PASS.txt inside the bootloader directory. In this file lives the passphrase that is going to be needed later on to decrypt the filesystem. Please be aware that this PASS.txt should not be included in the final JetPack generated environment, it's just meant to be saved for later use.
/$HOME/Linux_for_Tegra/bootloader$ ✵ >>> ls | grep PASS PASS.txt
3.2.3 Generate the encrypted key:
Go to the following location:
cd tools/disk_encryption/
Create the encrypted key that will be used in the next steps:
openssl rand -rand /dev/random -hex 16 > encrypted.key
Be aware of the path where this key is stored. DO NOT DELETE IT. It will be need it several times during this process.
- For more info on disk encryption visit:Developer Guide - Disk Encryption and the workflows in Linux_for_Tegra/tools/kernel_flash/README_initrd_flash.txt
3.2.4 Edit l4t_flash_from_kernel.sh: This script is located on /$HOME/Linux_for_Tegra/tools/kernel_flash. Add the following lines:
function get_dev_name_on_target { local disk_name= local device_name="$1" local part_num if [[ "${host_mode}" = "0" ]]; then echo "${device_name}" else disk_name=$(get_disk_name "$(basename "${device_name}")") + shopt -s extglob part_num=${device_name##${disk_name}} + part_num=${part_num##${part_num%%+([[:digit:]])}} + shopt -u extglob get_partition "${device_map["${disk_name}"]}" "${part_num}" fi }
3.2.5. Replace the nvsimg2img binary This file is located at /$HOME/Linux_for_Tegra/tools/kernel_flash/bin/. Download this file simg2img, and replace it for the old.
cd Downloads/ mv simg2img nvsimg2img mv nvsimg2img /$HOME/Linux_for_Tegra/tools/kernel_flash/bin/
3.2.6. Put the AGX into recovery mode.
3.2.7. Create the images:
- Note: The image size is specified with the
-S
flag. It can be smaller than 8GiB if a smaller filesystem is generated.
sudo ROOTFS_ENC=1 ./tools/kernel_flash/l4t_initrd_flash.sh --no-flash --external-device nvme0n1p1 -c ./tools/kernel_flash/flash_l4t_nvme_rootfs_enc.xml -p "-i encryption.key" --external-only -S 8GiB --direct nvme0n1 jetson-xavier external
Note: The flag "-i encryption.key" is the path to the recently created encrypted key, which should be: /$HOME/Linux_For_Tegra/tools/disk_ecnryption/encrypted.key
3.2.8. Delete the rootfs and unnecessary images:
sudo rm -rf rootfs
sudo rm -f bootloader/system_boot.*
sudo rm -f bootloader/system_root_encrypted.*
3.2.9. Create the tarball:
- Note: This might take a while.
cd ..
tar cjf tegra_env.tbz2 Linux_for_Tegra/ --verbose
3.4. Flash and format the SDD
- This section will explain how to flash the encrypted environment to the SSD from the Jetson platform.
- The next steps assume the JetPack environment tarball is already available in the Jetson.
- These steps are meant to be followed in the Jetson.
- The Jetson can be accessed through ssh if connected to a network (applies if the minimal FS was flashed).
3.4.1. Untar the JetPack environment tarball:
sudo tar xvjf tegra_env.tbz2 --verbose
- Note: Remove the tar file if it is copied to the eMMC after extraction to save space. Ideally, the tegra_env.tbz2 file would be inside an SD card.
3.4.2. Patch the XML partition table file with the right SSD disk dimensions:
cd Linux_for_Tegra
sed -i "s/num_sectors=\"122159104\"/"num_sectors="\"$(cat /sys/block/nvme0n1/size)\"/g" tools/kernel_flash/flash_l4t_nvme_rootfs_enc.xml
sed -i "s/sector_size=\"512\"/"sector_size="\"$(cat /sys/block/nvme0n1/queue/hw_sector_size)\"/g" tools/kernel_flash/flash_l4t_nvme_rootfs_enc.xml
3.4.3. Flash the SSD:
sudo ./tools/kernel_flash/l4t_initrd_flash.sh --flash-only --external-device nvme0n1p1 -c ./tools/kernel_flash/flash_l4t_nvme_rootfs_enc.xml --external-only -S 8GiB --direct nvme0n1 jetson-xavier external
3.5. Partition the SSD
3.5.1. Install dependencies:
sudo apt update
sudo apt install cloud-guest-utils
sudo apt -y install dosfstools
3.5.2. Start parted:
sudo parted /dev/nvme0n1
3.5.3. Create free space to later enlarge the OS partition:
- In this case the starting point was calculated to be 65GB, refer to the next bullet point for details.
(parted) mkpart primary ext4 65GB 364GB
- The starting point (65GB) was calculated like:
OSExtensionStart = (FinalSize - CurrentAPPSize) + APP_ENC_End = (64GB-8GB)+9.3GB = 65GB
- The APP_ENC_End can be seen by doing:
(parted) print free
- In this case the output is the following, where the end of the APP partition is at 9.225 GB.
Number Start End Size File system Name Flags 17,4kB 20,5kB 3072B Free Space 3 20,5kB 83,9MB 83,9MB recovery msftdata 4 83,9MB 84,4MB 524kB recovery-dtb msftdata 5 84,4MB 168MB 83,9MB kernel msftdata 6 168MB 252MB 83,9MB kernel_b msftdata 7 252MB 253MB 524kB kernel-dtb msftdata 8 253MB 253MB 524kB kernel-dtb_b msftdata 9 253MB 568MB 315MB RECROOTFS msftdata 10 568MB 635MB 67,1MB fat32 esp boot, esp 11 635MB 635MB 18,4kB UDA msftdata 635MB 635MB 2048B Free Space 1 635MB 1054MB 419MB ext4 APP msftdata 2 1054MB 9225MB 8171MB APP_ENC msftdata 9225MB 1000GB 991GB Free Space
3.5.4. Make a partition with the rest of the free space:
(parted) mkpart primary ext4 364GB 1000GB
3.5.5. Quit parted:
(parted) quit
3.5.6. Create the filesystems for the new partitions:
sudo mkfs -t ext4 /dev/nvme0n1p12
sudo mkfs -t vfat /dev/nvme0n1p13
3.5.7. Decrypt the APP_ENC partition, use the key generated in the flashing process:
sudo cryptsetup -v luksOpen /dev/nvme0n1p2 <target-name>
- target-name can be any name.
- The output should be something like the following:
Enter passphrase for /dev/nvme0n1p2: Key slot 0 unlocked. Command successful.
3.5.8. Extend the partition and the filesystem to fill the free space created on step 3:
sudo growpart /dev/nvme0n1 2
sudo cryptsetup resize <target-name>
sudo e2fsck -f /dev/mapper/<target-name>
sudo resize2fs /dev/mapper/<target-name>
Validate that the filesystem is really around 64GB by mounting it:
sudo mount /dev/mapper/<target-name> /mnt
df -h /mnt
- Then unmount:
sudo umount /mnt
- Another way to do this is to run
df -h /dev/mapper/<OS-given-target-name>
. You can verify which is the target name by runninglsblk
.
- These actions will ask again for the partition passphrase.
- Verify that the partition and the filesystem got extended by running lsblk
, in this example the target-name is hpi-encrypt:
nvme0n1 259:0 0 931,5G 0 disk ├─nvme0n1p1 259:24 0 400M 0 part ├─nvme0n1p2 259:25 0 59,6G 0 part │ └─hpi-encrypt 252:0 0 59,6G 0 crypt ├─nvme0n1p3 259:26 0 80M 0 part ├─nvme0n1p4 259:27 0 512K 0 part ├─nvme0n1p5 259:28 0 80M 0 part ├─nvme0n1p6 259:29 0 80M 0 part ├─nvme0n1p7 259:30 0 512K 0 part ├─nvme0n1p8 259:31 0 512K 0 part ├─nvme0n1p9 259:32 0 300M 0 part ├─nvme0n1p10 259:33 0 64M 0 part ├─nvme0n1p11 259:34 0 18K 0 part ├─nvme0n1p12 259:35 0 278,5G 0 part └─nvme0n1p13 259:36 0 592,5G 0 part
3.5.9. Close the encrypted partition:
sudo cryptsetup -v luksClose <target-name>
3.5.10. Verify the SSD is formatted correctly:
sudo parted -l
- An output similar to the following one should be seen:
Number Start End Size File system Name Flags 3 20,5kB 83,9MB 83,9MB recovery msftdata 4 83,9MB 84,4MB 524kB recovery-dtb msftdata 5 84,4MB 168MB 83,9MB kernel msftdata 6 168MB 252MB 83,9MB kernel_b msftdata 7 252MB 253MB 524kB kernel-dtb msftdata 8 253MB 253MB 524kB kernel-dtb_b msftdata 9 253MB 568MB 315MB RECROOTFS msftdata 10 568MB 635MB 67,1MB fat32 esp boot, esp 11 635MB 635MB 18,4kB UDA msftdata 1 635MB 1054MB 419MB ext4 APP msftdata 2 1054MB 65,0GB 63,9GB APP_ENC msftdata 12 65,0GB 364GB 299GB ext4 primary 13 364GB 1000GB 636GB fat32 primary
Important: The data partition can also be encrypted at this stage as past of the SSD formatting. For this, follow section Encrypt data partition before rebooting the platform.
3.5.11. Reboot.
- By default, the Jetson should now boot from SSD.
General procedures
This section aims to gather different procedures, with detailed steps, that were needed to the workflow of this wiki but maybe they were not wide explained.
1. Encrypt data partition
- The partition to encrypt use in these instructions is
/dev/nvme0n1p11
for example purposes.
1. Format the partition using cryptsetup
, it will ask you to create a passcode for the partition:
Important: that this will overwrite the current data.
sudo cryptsetup -y -v luksFormat /dev/nvme0n1p11
- Now, if you try to mount the partition it should fail:
sudo mount /dev/nvme0n1p11 /mnt
- The error log should look like:
mount: /mnt: unknown filesystem type 'crypto_LUKS'.
2. Configure a target to be able to access the partition:
- The target can have any name.
sudo cryptsetup -v luksOpen /dev/nvme0n1p11 <target-name>
- Now the partition is accessible through a sub partition. This can be validated by running:
lsblk
- The output should be something like the following (using hpidata as target name):
├─nvme0n1p9 259:9 0 64M 0 part ├─nvme0n1p10 259:10 0 18K 0 part ├─nvme0n1p11 259:11 0 278,5G 0 part │ └─hpdata 252:0 0 278,5G 0 crypt └─nvme0n1p12 259:12 0 592,5G 0 part
3. Create a filesystem using the target:
- The following command created an ext4 type filesystem.
sudo mkfs.ext4 /dev/mapper/<target-name>
4. Close the target:
sudo cryptsetup -v luksClose <target-name>
- If you do
lsblk
again, the target (sub partition) will be gone.
2. Access the encrypted partition
1. Configure a target to be able to access the partition:
- The target can have any name.
sudo cryptsetup -v luksOpen /dev/nvme0n1p11 <target-name>
2. Mount the target:
sudo mount -v /dev/mapper/<target-name> /mnt
- From this point, the data on the partition can be accessed through the mount point.
3. Unmount the target and close the partition:
sudo umount /mnt
sudo cryptsetup -v luksClose <target-name>
3. Add a Key File to Decrypt LUKS Partition
Important: LUKS only allows having 8 different keys, including the passphrase.
1. Generate a key a store it in a file. For example:
echo "Q2fQamleTgKoRM9luHiSRoerTojy9w0a" > luks_key.txt
2. Add the key to the LUKS partition. In order to do this you need to enter the passphrase initially set.
sudo cryptsetup luksAddKey /dev/nvme0n1p11 luks_key.txt
Note: If you want to only use the key file instead of a passphrase use the following command when formatting the partition (see Step 1 of the Encrypt data partition section):
sudo cryptsetup -y -v luksFormat /dev/nvme0n1p11 --key-file=luks_key.txt
3 Try to access the partition to test the key.
sudo cryptsetup -v luksOpen /dev/nvme0n1p11 <target-name> --key-file=luks_key.txt
- The output should be something like the following:
# Output Key slot 1 unlocked. Command successful.
4. Close the partition:
sudo cryptsetup -v luksClose <target-name>
4. Store the JetPack environment
Since the standard Ubuntu filesystem that comes by default with JetPack takes too much space and the JetPack environment might not fit, one of the two options below is recommended to be followed.
4.1 Flash the AGX eMMC with a minimal filesystem
- This method flashes a very minimal filesystem. It does not include a desktop GUI.
On the host computer used to flash the AGX's eMMC:
1. Follow subsection Create a minimal filesystem to create a minimal filesystem.
2. Flash the eMMC:
- Set the AGX to Force Recovery mode and connect it to the host computer, then execute the flash script.
sudo ./flash.sh jetson-xavier mmcblk0p1
3. Once the eMMC is flashed, connect it to a network using an ethernet cable and transfer the JetPack environment tarball:
rsync --progress tegra_env.tbz2 <username>@<Jetson-IP>:~
4.2 Use an SD card to hold the JetPack environment
- This method can be used if reflashing the eMMC is not desired. Just save the JetPack environment tarball into a (preferrably 16GB or larger) micro SD card and then insert it into the Jetson.
- On the Jetson, mount the SD card to get into its contents.
5. SSD partitioning
The following sections detail how to partition and delete partitions from the disk.
The following command can be run to have more information about the storage devices detected:
sudo parted -l
5.1 How to make partitions
1. Check de NVMe's device name:
lsblk -d -p | grep nvme | cut -d\ -f 1
- The output should something like the following:
/dev/nvme0n1
2. Start parted on the device disk:
sudo parted /dev/nvme0n1
3. Once on parted select the device by running select /dev/nvme0n1 + Enter
:
- The output should be the following:
(parted) select /dev/nvme0n1 Using /dev/nvme0n1
4. Make the disk label by running mklabel gpt
.
5. Make the desired partitions, for example to make 3 partitions run the following:
mkpart primary ext4 1MB 64GB
mkpart primary ext4 64GB 364GB
mkpart primary ext4 364GB 1024GB
Note: To check the free space of the disk (helpful to know how much space is left after making each partition) run print free
.
- The output should be something like the following:
Model: Samsung SSD 970 EVO Plus 1TB (nvme) Disk /dev/nvme0n1: 1000GB Sector size (logical/physical): 512B/512B Partition Table: gpt Disk Flags: Number Start End Size File system Name Flags 17.4kB 1049kB 1031kB Free Space 1 1049kB 64.0GB 64.0GB ext4 primary 2 64.0GB 364GB 300GB ext4 primary 364GB 1000GB 636GB Free Space
6. Quit parted by running quit
.
7. Build the filesystem for each partition, for example for the three partitions created:
sudo mkfs -t ext4 /dev/nvme0n1p1
sudo mkfs -t ext4 /dev/nvme0n1p2
sudo mkfs -t vfat /dev/nvme0n1p3
5.2 Mount a partition permanently
5.2.1 Encrypted LUKS partition
To always have a partition mounted on boot, follow the next instructions. In this section, the previously encrypted partition "nvme0n1p2" will help as an example.
First add the mapper information to the /etc/crypttab file.
sudo vim /etc/crypttab
Add the following information:
<target name> <source device> <key-file> <options>
Where:
- target name: describes the mapped device name. For example, if your device mapping is /dev/mapper/hpi, then hpi is the required target.
- source device: describes either the block special device or file that contains the encrypted data. This is specified using UUID=<uuid>, or LABEL=<label>, PARTUUID=<partuuid> or PARTLABEL=<partlabel>.
To find the UUID information, you can use:
lsblk -f /dev/nvme0n1p2
And the output should look like this one:
NAME FSTYPE LABEL UUID FSAVAIL FSUSE% MOUNTPOINT nvme0n1p2 crypto_LUKS 9c3b5881-a4f8-4a51-a785-b55597b458cb └─hpi ext4 dac3843f-2556-41fe-90c6-7f7efc0c508f 53.2G 4%
- key-file: describes the file to use as a key for decrypting the data of the source device. Note that the passphrase must not be followed by a newline character. On this case, I used the LUK key previously generated before creating the encrypted images on the host computer.
- options: describes the cryptsetup options associated with the encryption process. At minimum, the field should contain either the string luks respectively tcrypt or the cipher, hash and size options. Options are in the format: key=value [,key=value …].
Note: Consult man crypttab for more information.
The information that will be added should look like this:
hpi UUID="9c3b5881-a4f8-4a51-a785-b55597b458cb" /home/nvidia/Linux_for_Tegra/tools/disk_encryption/encrypted.key luks
Be aware that the UUID added above is the one that belongs to the nvme0n1p2 partition, NOT the one of the hpi target device.
Next, create a mount point.
sudo mkdir /mnt/capturemodes
Then, update the /etc/fstab file with device information in order to define how to mount the LUKS device. The entry in the /etc/fstab file should take the format;
<file system> <mount point> <type> <options> <dump> <pass>
Following the example, it should look like this:
/dev/mapper/hpi /mnt/capturemodes ext4 defaults 0 0
Verify using the mount command before rebooting the system. If all is working, you should see “successfully mounted” for your LUKS device.
$ mount -av / : ignored /mnt/capturemodes : successfully mounted
You can now reboot your system to confirm the same.
systemctl reboot
Once the reboot is done, check the mounting:
$ lsblk nvme0n1 259:0 0 931.5G 0 disk ├─nvme0n1p1 259:1 0 400M 0 part ├─nvme0n1p2 259:2 0 59.6G 0 part │ └─hpi 252:0 0 59.6G 0 crypt /mnt/capturemodes
Note: After turning on or rebooting the board, the serial console will ask for the passphrase:
Please enter passphrase for disk APP_ENC (hpi) on /mnt/capturemodes:
5.2.2. Mount a normal partition
Add a rule to the /etc/fstab file. For example, to have the second partition made on these examples be always mounted on /mnt/capturemodes add the following line:
/dev/nvme0n1p2 /mnt/capturemodes ext4 defaults 0 1
6. Delete partitions
1. Select the disk device using fdisk:
sudo fdisk /dev/nvme0n1
2. Make sure to have selected the right device by printing its information by pressing p + Enter
.
- The output should show the disk information:
Command (m for help): p Disk /dev/nvme0n1: 931.53 GiB, 1000204886016 bytes, 1953525168 sectors Disk model: Samsung SSD 970 EVO Plus 1TB Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disklabel type: gpt Disk identifier: 4B4A6BA5-6665-42A9-A0EB-DF76D474D831 Device Start End Sectors Size Type /dev/nvme0n1p1 40 33554471 33554432 16G Microsoft basic data /dev/nvme0n1p2 33554472 33685543 131072 64M Microsoft basic data /dev/nvme0n1p3 33685544 33816615 131072 64M Microsoft basic data /dev/nvme0n1p4 33816616 33817511 896 448K Microsoft basic data /dev/nvme0n1p5 33817512 33818407 896 448K Microsoft basic data /dev/nvme0n1p6 33818408 33982247 163840 80M Microsoft basic data /dev/nvme0n1p7 33982248 33983271 1024 512K Microsoft basic data /dev/nvme0n1p8 33983272 34597671 614400 300M Microsoft basic data /dev/nvme0n1p9 34597672 34728743 131072 64M EFI System /dev/nvme0n1p10 34728744 1953525134 1918796391 915G Microsoft basic data
3. To delete a partition, press d + Enter
, then <partition number to delete> + Enter
:
Command (m for help): d Partition number (1-10, default 10): 1 Partition 1 has been deleted
Note: If there is just one partition, it will be deleted immediately after d + Enter
.
4. Write the changes to the disk by pressing w + Enter
:
Command (m for help): w The partition table has been altered. Calling ioctl() to re-read partition table. Syncing disks.
7. Make Jetson boot from SSD - using JetPack tools and a host PC
Important: Make sure that an SSD is installed on the Jetson before going ahead with the next steps.
1. Make sure that the Jetson can boot from the eMMC. This is an obligatory requirement. The steps following this one assume the Jetson can boot from the eMMC and that a JetPack environment is already set up. To setup JetPack and flash the eMMC follow the instructions at Build and testing instructions.
2. Install the necessary dependencies on the host PC:
sudo apt install libxml2-utils simg2img network-manager abootimg sshpass device-tree-compiler
3. Stop the automount service (this command applies to Debian based systems):
systemctl stop udisks2.service
4. Move to the Linux_for_Tegra directory and set the Jetson to recovery mode.
cd <JetPack-directory>/Linux_for_Tegra
5. Flash the NVMe:
sudo ./tools/kernel_flash/l4t_initrd_flash.sh --external-device nvme0n1p1 -c ./tools/kernel_flash/flash_l4t_nvme.xml --external-only -S <APP-partition-size>GiB --showlogs jetson-xavier nvme0n1p1
- <APP-partition-size> corresponds to the size root (/) will take.
- For example for a 16GB root:
sudo ./tools/kernel_flash/l4t_initrd_flash.sh --external-device nvme0n1p1 -c ./tools/kernel_flash/flash_l4t_nvme.xml --external-only -S 16GiB --showlogs jetson-xavier nvme0n1p1
Note: The flashing process can take a long time (from ~30min to ~1h).
- After the flashing is done reboot the Jetson and it should boot from the SSD. If it does not, refer to the Change boot order section.
- To check where the system is booting from, the flag in the extlinux.conf file can be checked or by running
lsblk
and checking where/
is mounted:
- Cat the extlinux.conf file:
cat /boot/extlinux/extlinux.conf
- Look for the root flag, in this case we are booting from eMMC.
. . . APPEND ${cbootargs} root=/dev/mmcblk0p1
- Run lsblk
:
lsblk
- We can see that /
is mounted on mmcblk0p1 (eMMC):
nvidia@hpi-xavier:~$ lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT mmcblk0 179:0 0 29.1G 0 disk ├─mmcblk0p1 179:1 0 28G 0 part /
8. Change the boot order
The order in which the Jetson is going to try to boot from can be modified. By default, after installing an SSD, the boot order will be to try to boot from the SSD and then from eMMC. Modifying the boot order can be useful in cases where a boot from eMMC is needed to modify the SDD partitions, for example.
Important: A display, a mouse and keyboard are needed for this method.
1. Connect a display, mouse and keyboard to the Jetson and boot. When booting, press the F12 key repeatedly until a message saying "Press ESC for boot options" appears. When this appears, immediately press ESC
.
2. On the UEFI GUI, select the following:
Boot Maintenance Manager Boot Options Change Boot Order
3. Select the booting options (should be highlighted in black when selected) and press Enter.
4. A menu like the following will appear. To move the selected option up or down, use the +
and -
keyboard keys. Then press Enter
.

5. Hit ESC
until the main menu is reached. Once here, select Continue and press Enter
. The Jetson should boot from the selected device after this step.

After all these steps are done your Jetson should boot from the encrypted SSD