TX2 L4T 32.1 Automatic Booting

With the new version of L4T, on first boot the user is prompted to provide information such as locale, username/password, and network settings. Has anyone been successful in finding a way to automate these parameters?

Looking into it some, it appears that ubiquity is being used for the install process, is it possible to use preseeding to automate the responses, and if so does anyone have any pointers for this process?

I don’t know the specific files, but all of those can be edited in the rootfs prior to flash and the flashed system will retain those settings. For example, I add my host PC’s public keys and what I flash takes public key login without any edits every time I flash. Similar for network setup.

You might have to research each of those settings one by one and see what file changes create those. One example to start with is “/etc/timezone”. Once a timezone is set, then this file is either a symbolic link pointing to another location, or else it is a custom file. Simply copy the linked location there, or else a custom edited version (it’s plain text so it is easy to read and edit).

NOTE: I copy my version of timezone to my “Linux_for_Tegra/rootfs/etc/” host PC directory before flashing.

Has anyone been successful yet in modifying the rootfs so that it does not require going through the menus on first boot?

I haven’t looked, but I do know there is a “first boot” package on many Linux distributions. Are you aware of cloning? You could simply answer the first boot questions on a device, and then clone…followed by using the clone during any flash. You would have to be careful to not also clone passwords and certain network settings if you are using this for production. Instructions for cloning will depend on which release you are using (see “head -n 1 /etc/nv_tegra_release”).

If you happen to know what files on the “Linux_for_Tegra/rootfs/” directory need editing, then you can simply edit those ahead of time. For the most part these files would be no different on a Jetson than on a desktop PC.

There is a way, which requires “manual” flashing:

  1. Extract Jetson_Linux_R32.1.0_aarch64.tbz2
  2. Extract Tegra_Linux_Sample-Root-Filesystem_R32.1.0_aarch64.tbz2 inside Linux_for_Tegra/rootfs (dirs extracted in a previous steps), as root
    sudo tar jxvf Tegra_Linux_Sample-Root-Filesystem_R32.1.0_aarch64.tbz2 -C rootfs
  3. Prevent OEM setup on frist boot:
    cat << EOF | sudo tee -a rootfs/etc/systemd/system/default.target
  4. Either inject root password:
    JETSONROOTPWD=$(openssl passwd -1 -salt Salz supersecretpwd)
    sudo sed -i "s|^\(root\:\)\*\(\:.*\)|\1${JETSONROOTPWD}\2|" rootfs/etc/shadow

    OR Generate normal user in rootfs:

    sudo apt install qemu-user-static
    sudo cp /usr/bin/qemu-aarch64-static rootfs/usr/bin/
    sudo chroot rootfs qemu-aarch64-static /bin/bash
    adduser nvidia
    adduser nvidia sudo
    sed -i 's|^%sudo.*|%sudo\tALL=NOPASSWD: ALL|' /etc/sudoers
    rm rootfs/usr/bin/qemu-aarch64-static
  5. Finally, flash the board with:
    sudo ./apply_binaries.sh
    sudo ./flash.sh jetson-tx2 mmcblk0p1

Here is my take on headless installation - it’s a simple patch for rootfs:

--- rootfs/lib/systemd/system/oem-config.service.orig   2019-03-20 15:51:52.548161197 +0100
+++ rootfs/lib/systemd/system/oem-config.service        2019-04-01 10:31:10.362212768 +0200
@@ -26,6 +26,9 @@
            automatic-oem-config) automatic=--automatic ;;      \
        esac;                                                   \
     done;                                                      \
+    debconf-set-selections /preseed.cfg;                       \
+    rm /usr/lib/ubiquity/plugins/nvlicense.py;                 \
+    automatic=--automatic;                                     \
     exec oem-config-firstboot $debug $automatic'
--- /dev/null   2019-03-28 22:44:34.130262723 +0100
+++ rootfs/preseed.cfg  2019-04-01 15:34:31.161111825 +0200
@@ -0,0 +1,10 @@
+d-i debian-installer/locale string en_US.UTF-8
+d-i keyboard-configuration/xkb-keymap select us
+d-i keyboard-configuration/layoutcode string us
+d-i keyboard-configuration/variantcode string
+d-i time/zone string UTC
+d-i passwd/username string nvidia
+d-i passwd/user-fullname string nvidia
+d-i passwd/user-password password nvidia
+d-i passwd/user-password-again password nvidia
+d-i oem-config/late_command string rm /preseed.cfg

Apply it after running ./apply_binaries.sh

Cool! But wouldn’t preseed.cfg will stay on rootfs after flash, exposing the password in clear text? Perhaps an encrypted password would be a better idea? Like:

# printf "r00tme" | mkpasswd -s -m md5

# or encrypted using an MD5 hash.
d-i passwd/user-password-crypted password $1$CHp7HkQW$Z2ZTY5cZMurbwbqU1zaS.1

The password in my example preseed file isn’t secret, so in this particular case it doesn’t matter. Basically default config has the same security as no password, so if you need any, you need to set the password either using passwd command after the install, or using your suggestion. It is indeed not advisable to store the real password in clear-text, even if file is rm’ed afterwards (see oem-config/late_command). Did you test your way of setting the password?


I tried to use a preseed file for configuring the default oem image, but they seem to fail when there is no screen enabled (screen disabled within the device tree). I have verified that when I modify my device tree and the screen is enabled the preseed file works and the installation completes. Any ideas how can I go around this issue. I have access to a serial terminal only. Thanks in advance.



Works fine for me with TX2 and the following DTS patch disabling HDMI:

--- hardware/nvidia/platform/t18x/quill/kernel-dts/tegra186-quill-p3310-1000-a00-00-base.dts.orig       2019-03-11 07:29:12.000000000 +0100        
+++ hardware/nvidia/platform/t18x/quill/kernel-dts/tegra186-quill-p3310-1000-a00-00-base.dts    2019-03-20 10:55:41.665497161 +0100
@@ -304,7 +304,7 @@
                        status = "okay";
                        nvidia,active-panel = <&sor1_hdmi_display>;
                        hdmi-display {
-                               status = "okay";
+                               status = "disabled";
                        dp-display {
                                status = "disabled";

I haven’t tried the above, but here is some extra info on the process: