Skip to content

Instantly share code, notes, and snippets.

@FrankWu100
Created April 8, 2021 07:15
Show Gist options
  • Save FrankWu100/b691280a89dca466c8c2439ecf479984 to your computer and use it in GitHub Desktop.
Save FrankWu100/b691280a89dca466c8c2439ecf479984 to your computer and use it in GitHub Desktop.
TX2 massflash 32.4
************************************************************************
Linux for Tegra
Massflash
README
************************************************************************
The NVIDIA Tegra Linux Package provides ``massflash'' tools to flash
multiple Jetson devices simultaneously. This document describes detailed
procedure of ``massflashing''.
The massflashing tool generates ``massflash blob'' in trusted environment.
The massflash blob is portable, encrypted, and signed binary firmware and
tool files, which are used to flash one or more Jetson devices simultaneously
in insecure place such as factory floor without revealing any SBK or PKC key
files in human readable form.
========================================================================
Building the Massflash Blob in Trusted Environment
========================================================================
There are 2 methods to build the massflash blob: ONLINE and OFFLINE.
The ONLINE method requires the target Jetson device attached to the host
and the OFFLINE method requires knowledge of actual specification of
target device.
Building the Massflash Blob with ONLINE method
----------------------------------------------
Building the massflash blob with ONLINE method requires:
- Set up a X86 Linux host as the ``signing host'' in safe location.
See ``L4T_quick_start_guide.txt'' for detailed host setup.
- If and only if secureboot is required, take extra steps:
See ``Installing the L4T Secureboot Package'' in README_secureboot.txt
to install secureboot package.
See ``Generating the RSA Key Pair'' in README_secureboot.txt
to generate the RSA Key-pair.
See ``Preparing the DK(KEK)/SBK/ODM Fuses'' in README_secureboot.txt
to prepare the DK(KEK)/SBK/ODM keys.
To generate the massflash blob with ONLINE method:
- Enter the command `cd Linux_for_Tegra`.
- connect one target Jetson device, and put it into RCM mode.
- sudo ./nvmassflashgen.sh [<secureboot options>] <device name> mmcblk0p1
See ``Signing and Flashing Boot Files in two steps'' in
README_secureboot.txt for details of <secureboot options>.
Examples for ONLINE massflash blob generation method:
To generate clear massflash blob:
sudo ./nvmassflashgen.sh <device name> mmcblk0p1
To generate PKC signed massflash blob:
sudo ./nvmassflashgen.sh -x <TegraID> -y PKC -u <PKC keyfile> <device name> mmcblk0p1
Where `<device_name>` is one of supported jetson devices:
jetson-xavier-nx-devkit-emmc, jetson-nano-devkit-emmc,
jetson-agx-xavier-devkit, jetson-agx-xavier-devkit-8gb,
jetson-tx2-devkit, jetson-tx2-devkit-tx2i, jetson-tx2-devkit-4gb, and
jetson-tx1-devkit.
NOTE: nvmassflashgen.sh generates massflash images named as:
mfi_<device_name>.tbz2 for clear massflash blob,
mfi_<device_name>_signed.tbz2 for PKC signed massflash blob,
mfi_<device_name>_encrypt_signed.tbz2 for SBK+PKC massflash blob.
NOTE: SBKPKC is supported only in OFFLINE mode by jetson-tx2-devkit,
jetson-tx2-devkit-4gb, jetson-tx2-devkit-tx2i,
jetson-agx-xavier-devkit, jetson-agx-xavier-devkit-8gb, and
jetson-xavier-nx-devkit-emmc.
NOTE: For detailed information about <key.pem>, <SBK file>, and
<KEK file>, see README_secureboot.txt
Building the Massflash Blob with OFFLINE method
-----------------------------------------------
Building the massflash blob with OFFLINE method requires:
Same as ONLINE method. See ``Building the Massflash Blob with ONLINE
method'' above.
To generate the massflash blob with OFFLINE method:
- Enter the command `cd Linux_for_Tegra`.
- No actual jetson device attachment is necessary.
- Just add ``BOARDID=<boardid> BOARDSKU=<sku> FAB=<fab> [BOARDREV=<rev>]
FUSELEVEL=fuselevel_production'' in front of
``./nvmassflashgen.sh'' as in ONLINE method:
sudo BOARDID=<boardid> BOARDSKU=<sku> FAB=<fab> [BOARDREV=<rev>] \
FUSELEVEL=fuselevel_production \
./nvmassflashgen.sh [<secureboot options>] <device name> mmcblk0p1
See ``Signing and Flashing Boot Files in two steps'' in
README_secureboot.txt for details of <secureboot options>.
Where actual values are:
BOARDID BOARDSKU FAB BOARDREV
--------------------------------+--------+---------+----+---------
jetson-xavier-nx-devkit-emmc 3668 0001 100 N/A
jetson-nano-devkit-emmc 3448 0002 200 N/A
jetson-agx-xavier-devkit (16GB) 2888 0001 400 H.0
jetson-agx-xavier-devkit (32GB) 2888 0004 400 K.0
jetson-agx-xavier-devkit-8gb 2888 0006 400 B.0
jetson-tx2-devkit 3310 1000 B02 N/A
jetson-tx2-devkit-tx2i 3489 0000 300 A.0
jetson-tx2-devkit-4gb 3489 0888 300 F.0
jetson-tx1-devkit 2180 0000 400 N/A
--------------------------------+--------+---------+----+---------
NOTE: Only jetson-agx-xavier-devkit and jetson-agx-xavier-devkit-8gb
require ``BOARDREV'' argument.
NOTE: jetson-agx-xavier-devkit 16GB(SKU1) and 32GB(SKU4) are using
same configuration. Only differences are BOARDSKU and BOARDREV.
NOTE: All input and output are exactly same as ONLINE method.
Examples for OFFLINE massflash blob generation method:
To generate jetson-tx1-devkit clear massflash blob:
sudo BOARDID=2180 BOARDSKU=0000 FAB=400 FUSELEVEL=fuselevel_production \
./nvmassflashgen.sh jetson-tx1-devkit mmcblk0p1
To generate jetson-tx2-devkit-4gb clear massflash blob:
sudo BOARDID=3489 BOARDSKU=0888 FAB=300 FUSELEVEL=fuselevel_production \
./nvmassflashgen.sh jetson-tx2-devkit-4gb mmcblk0p1
To generate jetson-agx-xavier-devkit (32GB) clear massflash blob:
sudo BOARDID=2888 BOARDSKU=0004 FAB=400 BOARDREV=K.0 \
FUSELEVEL=fuselevel_production \
./nvmassflashgen.sh jetson-agx-xavier-devkit mmcblk0p1
To generate jetson-agx-xavier-devkit-8gb clear massflash blob:
sudo BOARDID=2888 BOARDSKU=0006 FAB=400 BOARDREV=B.0 \
FUSELEVEL=fuselevel_production \
./nvmassflashgen.sh jetson-agx-xavier-devkit-8gb mmcblk0p1
To generate jetson-tx2-devkit-tx2i clear massflash blob:
sudo BOARDID=3489 BOARDSKU=0000 FAB=300 FUSELEVEL=fuselevel_production \
./nvmassflashgen.sh jetson-tx2-devkit-tx2i mmcblk0p1
To generate jetson-tx2-devkit PKC signed massflash blob:
sudo BOARDID=3310 BOARDSKU=1000 FAB=B02 FUSELEVEL=fuselevel_production \
./nvmassflashgen.sh -x 0x18 -y PKC -u <pkc_keyfile> \
jetson-tx2-devkit mmcblk0p1
To generate jetson-agx-xavier-devkit (16GB) SBK encrypted + PKC signed massflash blob:
sudo BOARDID=2888 BOARDSKU=0001 FAB=400 BOARDREV=H.0 \
FUSELEVEL=fuselevel_production ./nvmassflashgen.sh -x 0x19 -y SBKPKC \
-u <pkc_keyfile> -v <sbk_keyfile> jetson-agx-xavier-devkit mmcblk0p1
To generate jetson-nano-devkit-emmc PKC signed massflash blob:
sudo BOARDID=3448 BOARDSKU=0002 FAB=200 FUSELEVEL=fuselevel_production \
./nvmassflashgen.sh -x 0x21 -y PKC -u <pkc_keyfile> \
jetson-nano-devkit-emmc mmcblk0p1
To generate jetson-xavier-nx-devkit-emmc SBK encrypted PKC signed massflash blob:
sudo BOARDID=3668 BOARDSKU=0001 FAB=100 BOARDREV=H.0 \
FUSELEVEL=fuselevel_production ./nvmassflashgen.sh -x 0x19 -y SBKPKC \
-u <pkc_keyfile> -v <sbk_keyfile> jetson-xavier-nx-devkit-emmc mmcblk0p1
========================================================================
Flashing the Massflash Blob in Untrusted Environment
========================================================================
Flashing the massflash blob in untrusted environment requires:
- Set up one or more X86 Linux host as the ``flashing host''.
The flashing hosts do not require any L4T BSP installation.
- Use the following procedure to flash one or more jetson devices
simultaneously.
- Following procedure must be performed on each flashing hosts.
1. Download mfi_<jetson_device>[[_encrypt]_signed].tbz2
Example:
ubuntu@ahost:~$ scp loginname@<master host ipaddr>:Linux_for_Tegra/mfi_jetson_tx1_signed.tbz2
loginname@<master host ipaddr?'s password:
mfi_jetson_tx1_signed.tbz2 100% 1024KB 1.0MB/s 00:00
2. Untar mfi_<jetson_device>[[_encrypt]_signed].tbz2 image:
Example:
- tar xvjf mfi_jetson_tx1_signed.tbz2
3. Change directory to the massflash blob directory.
Example:
- cd mfi_jetson_tx1_signed
4. Flash multiple TX1s simultaneously:
- Connect the Jetson devices to the flashing hosts.
(Make sure all devices are in exactly the same hardware revision as
prepared in ``Building Massflash Blob'' section above: Especially
SKU, FAB, BOARDREV, etc... )
- Put all of connected Jetsons into RCM mode.
- Enter: `sudo ./nvmflash.sh [--showlogs]`
NOTE: nvmflash.sh saves all massflashing logs in mfilogs
directory in mfi_<jetson_device>[[_encrypt]_signed].
Each log name has following format:
``<hostname>_<timestamp>_<pid>_flash_<USB_path>.log''
NOTE: This procedure can be repeated and all the boards flashed
with same massflash blob have exactly same L4T firmware version.
NOTE: The final performance (i.e. how many simultaneous flashing
each flashing host can take) is solely depending on USB
configuration of each flashing host.
#!/bin/bash
# Copyright (c) 2018-2020, NVIDIA CORPORATION. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# * Neither the name of NVIDIA CORPORATION nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
hdrsize=$((LINENO - 2));
hdrtxt=`head -n ${hdrsize} $0`;
fdlock=200;
set -o pipefail;
set -o errtrace;
shopt -s extglob;
curdir=$(cd `dirname $0` && pwd);
nargs=$#;
nargs=$(($nargs-1));
ext_target_board=${!nargs};
if [ ! -r ${ext_target_board}.conf ]; then
echo "Error: Invalid target board - ${ext_target_board}.";
exit 1;
fi
LDK_DIR=`readlink -f "${curdir}"`;
source ${ext_target_board}.conf;
BLDIR="bootloader";
FLASHCMD="flashcmd.txt";
MFGENCMD="mfgencmd.txt";
mfidir="mfi_${ext_target_board}";
gen_aflash_sh_v1()
{
local aflash_txt=`cat << EOF
usbarg="--instance \\\$1";
cidarg="--chip AFARG_CHIPID";
rcmarg="--rcm AFARG_RCMARG";
bctarg="--bct AFARG_BCTARG";
dlbctarg="--download bct AFARG_DLBCTARG";
wrbctarg="--write BCT AFARG_WRBCTARG";
ebtarg="--download ebt AFARG_EBTARG 0 0"; # type file [loadaddr entry]
rp1arg="--download rp1 AFARG_RP1ARG 0 0"; # type file [loadaddr entry]
pttarg="--pt AFARG_PTTARG.bin";
bfsarg="--updatebfsinfo AFARG_PTTARG.bin";
storagefile="\\\$\\\$_storage_info.bin";
chkerr()
{
if [ \\\$? -ne 0 ]; then
echo "*** Error: \\\$1 failed.";
rm -f \\\${storagefile};
exit 1;
fi;
echo "*** \\\$1 succeeded.";
}
execmd ()
{
local banner="\\\$1";
local cmd="\\\$2";
local nochk="\\\$3";
echo; echo "*** \\\${banner}";
echo "\\\${cmd}";
if [ "\\\${nochk}" != "" ]; then
\\\${cmd};
return;
fi;
\\\${cmd};
chkerr "\\\${banner}";
}
curdir=\\\$(cd \\\`dirname \\\$0\\\` && pwd);
pushd \\\${curdir} > /dev/null 2>&1;
banner="Updating BFS information on BCT";
cmd="\\\${curdir}/tegrabct \\\${bctarg} \\\${cidarg} \\\${bfsarg}";
execmd "\\\${banner}" "\\\${cmd}";
banner="Boot Rom communication";
cmd="\\\${curdir}/tegrarcm \\\${usbarg} \\\${cidarg} \\\${rcmarg}";
execmd "\\\${banner}" "\\\${cmd}";
banner="Sending BCTs";
cmd="\\\${curdir}/tegrarcm \\\${usbarg} \\\${dlbctarg}";
execmd "\\\${banner}" "\\\${cmd}";
banner="Sending bootloader and pre-requisite binaries";
cmd="\\\${curdir}/tegrarcm \\\${usbarg} \\\${ebtarg} \\\${rp1arg}";
execmd "\\\${banner}" "\\\${cmd}";
banner="Booting Recovery";
cmd="\\\${curdir}/tegrarcm \\\${usbarg} --boot recovery";
execmd "\\\${banner}" "\\\${cmd}";
banner="Retrieving storage infomation";
cmd="\\\${curdir}/tegradevflash \\\${usbarg} ";
cmd+="--oem platformdetails storage \\\${storagefile}";
execmd "\\\${banner}" "\\\${cmd}";
banner="Flashing the device";
cmd="\\\${curdir}/tegradevflash \\\${usbarg} \\\${pttarg} ";
cmd+="--storageinfo \\\${storagefile} --create";
execmd "\\\${banner}" "\\\${cmd}";
banner="Writing the BCT";
cmd="\\\${curdir}/tegradevflash \\\${usbarg} \\\${wrbctarg}";
execmd "\\\${banner}" "\\\${cmd}";
banner="Rebooting the device";
cmd="\\\${curdir}/tegradevflash \\\${usbarg} --reboot coldboot";
execmd "\\\${banner}" "\\\${cmd}";
rm -f \\\${storagefile};
popd > /dev/null 2>&1;
exit 0;
EOF`;
echo "${hdrtxt}" > nvaflash.sh;
echo "${aflash_txt}" >> nvaflash.sh;
chmod +x nvaflash.sh;
local conv="";
conv+="-e s/AFARG_RCMARG/${rcmarg}/g ";
conv+="-e s/AFARG_BCTARG/${bctarg}/g ";
conv+="-e s/AFARG_DLBCTARG/${dlbctarg}/g ";
conv+="-e s/AFARG_WRBCTARG/${wrbctarg}/g ";
conv+="-e s/AFARG_EBTARG/${ebtarg}/g ";
conv+="-e s/AFARG_RP1ARG/${rp1arg}/g ";
conv+="-e s/AFARG_PTTARG/${pttarg}/g ";
sed -i ${conv} nvaflash.sh;
if [ $? -ne 0 ]; then
echo "Error: Setting up nvaflash.sh";
exit 1;
fi;
fc=`cat nvaflash.sh | sed -e s/AFARG_CHIPID/"${cidarg}"/g`;
echo "${fc}" > nvaflash.sh;
}
gen_aflash_sh_v2()
{
local aflash_txt=`cat << EOF
usbarg="--instance \\\$1";
cidarg="--chip AFARG_CHIPID";
rcmarg="--rcm AFARG_RCMARG";
rcmsfarg="AFARG_RCMSFARG";
pttarg="--pt AFARG_PTTARG.bin";
storagefile="storage_info.bin";
dlbrbctarg="--download bct_bootrom AFARG_DLBRBCTARG";
wrbrbctarg="--write BCT AFARG_WRBRBCTARG";
mb1bctarg="AFARG_DLMB1BCTARG";
dlmb1bctarg="--download bct_mb1 AFARG_DLMB1BCTARG";
wrmb1bctarg="--write MB1_BCT AFARG_WRMB1BCTARG";
wrmb1bctbarg="--write MB1_BCT_b AFARG_WRMB1BCTARG";
membctarg="AFARG_MEMBCTARG";
dlmembctarg="--download bct_mem AFARG_DLMEMBCTARG";
wrmembctarg="--write MEM_BCT AFARG_WRMEMBCTARG";
wrmembctbarg="--write MEM_BCT_b AFARG_WRMEMBCTARG";
memcbctarg="AFARG_MEMCBCTARG";
chkerr()
{
if [ \\\$? -ne 0 ]; then
echo "*** Error: \\\$1 failed.";
exit 1;
fi;
echo "*** \\\$1 succeeded.";
}
execmd ()
{
local banner="\\\$1";
local cmd="\\\$2";
local nochk="\\\$3";
echo; echo "*** \\\${banner}";
echo "\\\${cmd}";
if [ "\\\${nochk}" != "" ]; then
\\\${cmd};
return;
fi;
\\\${cmd};
chkerr "\\\${banner}";
}
curdir=\\\$(cd \\\`dirname \\\$0\\\` && pwd);
pushd \\\${curdir} > /dev/null 2>&1;
banner="Boot Rom communication";
cmd="\\\${curdir}/tegrarcm_v2 \\\${usbarg} \\\${cidarg} ";
if [ "\\\${rcmsfarg}" != "" ]; then
cmd+="--rcm \\\${rcmsfarg} ";
fi;
cmd+="\\\${rcmarg} ";
execmd "\\\${banner}" "\\\${cmd}";
# SBK+PKC has the worst BL state transition delay up to 2 sec
sleep 2;
banner="Checking applet";
cmd="\\\${curdir}/tegrarcm_v2 \\\${usbarg} --isapplet";
execmd "\\\${banner}" "\\\${cmd}";
banner="Sending BCTs";
cmd="\\\${curdir}/tegrarcm_v2 \\\${usbarg} \\\${dlbrbctarg} ";
if [ "\\\${mb1bctarg}" != "" ]; then
cmd+="\\\${dlmb1bctarg} ";
fi;
if [ "\\\${membctarg}" != "" ]; then
cmd+="\\\${dlmembctarg}";
fi;
execmd "\\\${banner}" "\\\${cmd}";
banner="Sending bootloader and pre-requisite binaries";
cmd="\\\${curdir}/tegrarcm_v2 \\\${usbarg} --download blob blob.bin";
execmd "\\\${banner}" "\\\${cmd}";
banner="Booting Recovery";
cmd="\\\${curdir}/tegrarcm_v2 \\\${usbarg} --boot recovery";
execmd "\\\${banner}" "\\\${cmd}";
banner="Checking applet";
cmd="\\\${curdir}/tegrarcm_v2 \\\${usbarg} --isapplet";
execmd "\\\${banner}" "\\\${cmd}" "1";
sleep 3;
banner="Checking CPU bootloader";
cmd="\\\${curdir}/tegradevflash_v2 \\\${usbarg} --iscpubl";
execmd "\\\${banner}" "\\\${cmd}";
exec ${fdlock}>aflash.lock;
flock ${fdlock};
if [ \\\$(ls -1 mbr_* gpt_* 2>&1 | wc -l) != "4" ]; then
banner="Retrieving storage infomation";
cmd="\\\${curdir}/tegradevflash_v2 \\\${usbarg} ";
cmd+="--oem platformdetails storage \\\${storagefile}";
execmd "\\\${banner}" "\\\${cmd}";
banner="Generating GPT";
cmd="\\\${curdir}/tegraparser_v2 --storageinfo \\\${storagefile} ";
cmd+="--generategpt \\\${pttarg}";
execmd "\\\${banner}" "\\\${cmd}";
fi;
flock -u ${fdlock};
banner="Flashing the device";
cmd="\\\${curdir}/tegradevflash_v2 \\\${usbarg} \\\${pttarg} --create";
execmd "\\\${banner}" "\\\${cmd}";
banner="Writing the BR BCT";
cmd="\\\${curdir}/tegradevflash_v2 \\\${usbarg} \\\${wrbrbctarg}";
execmd "\\\${banner}" "\\\${cmd}";
if [ "\\\${mb1bctarg}" != "" ]; then
banner="Writing coldboot MB1 BCT";
cmd="\\\${curdir}/tegradevflash_v2 \\\${usbarg} \\\${wrmb1bctarg}";
execmd "\\\${banner}" "\\\${cmd}";
banner="Writing coldboot MB1_B BCT";
cmd="\\\${curdir}/tegradevflash_v2 \\\${usbarg} \\\${wrmb1bctbarg}";
execmd "\\\${banner}" "\\\${cmd}";
fi;
if [ "\\\${membctarg}" != "" ]; then
banner="Writing the MEM BCT";
cmd="\\\${curdir}/tegradevflash_v2 \\\${usbarg} \\\${wrmembctarg}";
execmd "\\\${banner}" "\\\${cmd}";
banner="Writing the MEM BCT B";
cmd="\\\${curdir}/tegradevflash_v2 \\\${usbarg} \\\${wrmembctbarg}";
execmd "\\\${banner}" "\\\${cmd}";
fi;
banner="Rebooting the device";
cmd="\\\${curdir}/tegradevflash_v2 \\\${usbarg} --reboot coldboot";
execmd "\\\${banner}" "\\\${cmd}";
popd > /dev/null 2>&1;
exit 0;
EOF`;
echo "${hdrtxt}" > nvaflash.sh;
echo "${aflash_txt}" >> nvaflash.sh;
chmod +x nvaflash.sh;
local conv="";
conv+="-e s/AFARG_RCMSFARG/${rcmsfarg}/g ";
conv+="-e s/AFARG_RCMARG/${rcmarg}/g ";
conv+="-e s/AFARG_PTTARG/${pttarg}/g ";
conv+="-e s/AFARG_DLBRBCTARG/${dlbrbctarg}/g ";
conv+="-e s/AFARG_WRBRBCTARG/${dlbrbctarg}/g ";
conv+="-e s/AFARG_DLMB1BCTARG/${dlmb1bctarg}/g ";
conv+="-e s/AFARG_WRMB1BCTARG/${wrmb1bctarg}/g ";
conv+="-e s/AFARG_MEMBCTARG/${membctarg}/g ";
conv+="-e s/AFARG_DLMEMBCTARG/${dlmembctarg}/g ";
conv+="-e s/AFARG_WRMEMBCTARG/${wrmembctarg}/g ";
conv+="-e s/AFARG_MEMCBCTARG/${memcbctarg}/g ";
sed -i ${conv} nvaflash.sh;
if [ $? -ne 0 ]; then
echo "Error: Setting up nvaflash.sh";
exit 1;
fi;
fc=`cat nvaflash.sh | sed -e s/AFARG_CHIPID/"${cidarg}"/g`;
echo "${fc}" > nvaflash.sh;
}
gen_aflash_sh()
{
local tfv=$1;
case ${tfv} in
1) gen_aflash_sh_v1; ;;
2) gen_aflash_sh_v2; ;;
*) echo "Error: Unknown tegraflash version"; exit 1; ;;
esac;
}
gen_mflash_sh()
{
local mflash_txt=`cat << EOF
curdir=\\\$(cd \\\`dirname \\\$0\\\` && pwd);
showlogs=0;
if [ "\\\$1" = "--showlogs" ]; then
showlogs=1;
fi;
# Find devices to flash
devpaths=(\\\$(find /sys/bus/usb/devices/usb*/ \\\\
-name devnum -print0 | {
found=()
while read -r -d "" fn_devnum; do
dir="\\\$(dirname "\\\${fn_devnum}")"
vendor="\\\$(cat "\\\${dir}/idVendor")"
if [ "\\\${vendor}" != "0955" ]; then
continue
fi
product="\\\$(cat "\\\${dir}/idProduct")"
case "\\\${product}" in
"7721") ;;
"7f21") ;;
"7018") ;;
"7c18") ;;
"7121") ;;
"7019") ;;
"7e19") ;;
"7418") ;;
*)
continue
;;
esac
fn_busnum="\\\${dir}/busnum"
if [ ! -f "\\\${fn_busnum}" ]; then
continue
fi
fn_devpath="\\\${dir}/devpath"
if [ ! -f "\\\${fn_devpath}" ]; then
continue
fi
busnum="\\\$(cat "\\\${fn_busnum}")"
devpath="\\\$(cat "\\\${fn_devpath}")"
found+=("\\\${busnum}-\\\${devpath}")
done
echo "\\\${found[@]}"
}))
# Exit if no devices to flash
if [ \\\${#devpaths[@]} -eq 0 ]; then
echo "No devices to flash"
exit 1
fi
# Create a folder for saving log
mkdir -p mfilogs;
pid="\\\$\\\$"
ts=\\\`date +%Y%m%d-%H%M%S\\\`;
# Clear old gpt crufts
rm -f mbr_* gpt_*;
# Flash all devices in background
flash_pids=()
for devpath in "\\\${devpaths[@]}"; do
fn_log="mfilogs/\\\${ts}_\\\${pid}_flash_\\\${devpath}.log"
cmd="\\\${curdir}/nvaflash.sh \\\${devpath}";
\\\${cmd} > "\\\${fn_log}" 2>&1 &
flash_pid="\\\$!";
flash_pids+=("\\\${flash_pid}")
echo "Start flashing device: \\\${devpath}, PID: \\\${flash_pid}";
if [ \\\${showlogs} -eq 1 ]; then
gnome-terminal -e "tail -f \\\${fn_log}" -t \\\${fn_log} > /dev/null 2>&1 &
fi;
done
# Wait until all flash processes done
failure=0
while true; do
running=0
if [ \\\${showlogs} -ne 1 ]; then
echo -n "Ongoing processes:"
fi;
new_flash_pids=()
for flash_pid in "\\\${flash_pids[@]}"; do
if [ -e "/proc/\\\${flash_pid}" ]; then
if [ \\\${showlogs} -ne 1 ]; then
echo -n " \\\${flash_pid}"
fi;
running=\\\$((\\\${running} + 1))
new_flash_pids+=("\\\${flash_pid}")
else
wait "\\\${flash_pid}" || failure=1
fi
done
if [ \\\${showlogs} -ne 1 ]; then
echo
fi;
if [ \\\${running} -eq 0 ]; then
break
fi
flash_pids=("\\\${new_flash_pids[@]}")
sleep 5
done
if [ \\\${failure} -ne 0 ]; then
echo "Flash complete (WITH FAILURES)";
exit 1
fi
echo "Flash complete (SUCCESS)"
EOF`;
echo "${hdrtxt}" > nvmflash.sh;
echo "${mflash_txt}" >> nvmflash.sh;
chmod +x nvmflash.sh;
}
getidx()
{
local i;
local f="$1";
local s="$2";
shift; shift;
local a=($@);
for (( i=0; i<${#a[@]}; i++ )); do
if [ "$f" != "${a[$i]}" ]; then
continue;
fi;
i=$(( i+1 ));
if [ "${s}" != "" ]; then
if [ "$s" != ${a[$i]} ]; then
continue;
fi;
i=$(( i+1 ));
fi;
return $i;
done;
echo "Error: $f $s not found";
exit 1;
}
chkidx()
{
local i;
local f="$1";
shift;
local a=($@);
for (( i=0; i<${#a[@]}; i++ )); do
if [ "$f" != "${a[$i]}" ]; then
continue;
fi;
return 0;
done;
return 1;
}
chext ()
{
local i;
local var="$1";
local fname=`basename "$2"`;
local OIFS=${IFS};
IFS='.';
na=($fname);
IFS=${OIFS};
local nasize=${#na[@]};
if [ $nasize -lt 2 ]; then
echo "Error: invalid file name: ${fname}";
exit 1;
fi;
na[$((nasize-1))]=${3};
local newname="";
for (( i=0; i < ${nasize}; i++ )); do
newname+="${na[$i]}";
if [ $i -lt $((nasize-1)) ]; then
newname+=".";
fi;
done;
eval "${var}=${newname}";
}
gen_param()
{
local tf_v=1;
local len;
local binsidx;
local a=`echo "$1" | sed -e s/\"//g -e s/\;//g`;
local OIFS=${IFS};
IFS=' ';
a=($a);
IFS=$OIFS;
blobxmltxt="";
getidx "--bl" "" "${a[@]}";
ebtarg="${a[$?]}";
getidx "--chip" "" "${a[@]}";
cidarg="${a[$?]}";
len=$(expr length "${cidarg}");
if [ ${len} -le 4 ]; then
tgid="${cidarg}";
if [ "${CHIPMAJOR}" != "" ]; then
cidarg="${cidarg} ${CHIPMAJOR}";
else
local addchipmajor="true";
local relfile="${LDK_DIR}/rootfs/etc/nv_tegra_release";
if [ -f "${relfile}" ]; then
rel=`head -n 1 "${relfile}"`;
rel=`echo "${rel}" | awk -F ' ' '{print $2}'`;
if [ "${rel}" \< "R32" ]; then
addchipmajor="false";
fi;
fi;
if [ "${addchipmajor}" = "true" ]; then
cidarg="${cidarg} 0";
fi;
fi;
else
tgid=`echo "${cidarg}" | awk -F ' ' '{print $1}'`;
fi;
if [ "${tgid}" != "0x21" ]; then
tf_v=2;
fi;
getidx "--applet" "" "${a[@]}";
rcmarg="${a[$?]}";
if [ "${rcmarg}" = "nvtboot_recovery.bin" -o \
"${rcmarg}" = "mb1_recovery_prod.bin" -o \
"${rcmarg}" = "mb1_t194_prod.bin" ]; then
rcmarg="rcm_list_signed.xml";
fi;
getidx "--cfg" "" "${a[@]}";
pttarg="${a[$?]}";
chkidx "--bins" "${a[@]}";
if [ $? -eq 0 ]; then
getidx "--bins" "" "${a[@]}";
binsidx=$?;
else
chkidx "--bin" "${a[@]}";
if [ $? -eq 0 ]; then
getidx "--bin" "" "${a[@]}";
binsidx=$?;
fi;
fi;
if [ ${tf_v} -eq 1 ]; then
# Tegraflash V1
# BCT params
getidx "--bct" "" "${a[@]}";
local bctfilename="${a[$?]}";
chext bctfilename ${bctfilename} "bct";
bctarg="${bctfilename}";
dlbctarg="${bctfilename}";
wrbctarg="${bctfilename}";
# BIN params
getidx "--bldtb" "" "${a[@]}";
rp1arg="${a[$?]}";
bfsarg="${pttarg}";
return ${tf_v};
fi;
# Tegraflash V2
# BCT params
chkidx "--bct" "${a[@]}";
if [ $? -eq 0 ]; then
getidx "--bct" "" "${a[@]}";
bctarg="${a[$?]}";
dlbrbctarg="${bctarg}";
else
dlbrbctarg="br_bct_BR.bct";
fi;
wrbrbctarg="${dlbrbctarg}";
chkidx "--applet_softfuse" "${a[@]}";
if [ $? -eq 0 ]; then
getidx "--applet_softfuse" "" "${a[@]}";
rcmsfarg="${a[$?]}";
fi;
chkidx "--mb1_bct" "${a[@]}";
if [ $? -eq 0 ]; then
getidx "--mb1_bct" "" "${a[@]}";
mb1bctarg="${a[$?]}";
dlmb1bctarg="${mb1bctarg}";
else
dlmb1bctarg="mb1_bct_MB1_sigheader.bct";
chkidx "--key" "${a[@]}";
if [ $? -eq 0 ]; then
dlmb1bctarg+=".signed";
else
dlmb1bctarg+=".encrypt";
fi;
fi;
chkidx "--mb1_cold_boot_bct" "${a[@]}";
if [ $? -eq 0 ]; then
getidx "--mb1_cold_boot_bct" "" "${a[@]}";
mb1cbctarg="${a[$?]}";
wrmb1bctarg="${mb1cbctarg}";
else
wrmb1bctarg="mb1_cold_boot_bct_MB1_sigheader.bct";
getidx "--cmd" "" "${a[@]}";
if [[ ${a[$?]} =~ secureflash ]]; then
if [ "${sbkpkc}" = "true" ]; then
wrmb1bctarg+=".encrypt";
fi;
wrmb1bctarg+=".signed";
else
wrmb1bctarg+=".encrypt";
fi;
fi;
if [ "${tgid}" = "0x19" ]; then
chkidx "--mem_bct" "${a[@]}";
if [ $? -eq 0 ]; then
getidx "--mem_bct" "" "${a[@]}";
membctarg="${a[$?]}";
dlmembctarg="${membctarg}";
else
dlmembctarg="mem_rcm_sigheader.bct";
getidx "--cmd" "" "${a[@]}";
if [[ ${a[$?]} =~ secureflash ]]; then
dlmembctarg+=".signed";
else
dlmembctarg+=".encrypt";
fi;
if [ "${tgid}" = "0x19" ]; then
membctarg="${dlmembctarg}";
fi;
fi;
chkidx "--mem_bct_cold_boot" "${a[@]}";
if [ $? -eq 0 ]; then
getidx "--mem_bct_cold_boot" "" "${a[@]}";
memcbctarg="${a[$?]}";
wrmembctarg="${memcbctarg}";
else
wrmembctarg="mem_coldboot_sigheader.bct";
getidx "--cmd" "" "${a[@]}";
if [[ ${a[$?]} =~ secureflash ]]; then
wrmembctarg+=".signed";
else
wrmembctarg+=".encrypt";
fi;
fi;
fi;
# BIN params
blobxmltxt+="<file_list mode=\"blob\">";
blobxmltxt+="<!--Auto generated by tegraflash.py-->";
blobfiles="";
# The first entry is EBT binary.
if [ "${bctarg}" != "" -a "${mb1bctarg}" != "" ]; then
blobxmltxt+="<file name=\"";
blobxmltxt+="${ebtarg}\" ";
blobfiles+="${ebtarg} ";
blobxmltxt+="type=\"bootloader\" />";
for (( i=${binsidx}; i<${#a[@]}; i++ )); do
if [[ ${a[$i]} =~ ^\-\- ]]; then
break;
fi;
blobxmltxt+="<file name=\"";
blobxmltxt+="${a[$((i+1))]}\" ";
blobfiles+="${a[$((i+1))]} ";
blobxmltxt+="type=\"${a[$i]}\" />";
i=$((i+1));
done;
else
local na=`echo "${ebtarg}" | cut -d'.' -f1`;
local suf=`echo "${ebtarg}" | cut -d'.' -f2`;
blobxmltxt+="<file name=\"";
blobxmltxt+="${na}_sigheader.${suf}.encrypt\" ";
blobfiles+="${na}_sigheader.${suf}.encrypt ";
blobxmltxt+="type=\"bootloader\" />";
for (( i=${binsidx}; i<${#a[@]}; i++ )); do
if [ "${a[$i]}" = "kernel" -o \
"${a[$i]}" = "kernel_dtb" ]; then
i=$((i+1));
continue;
fi;
if [[ ${a[$i]} =~ ^\-\- ]]; then
break;
fi;
na=`echo "${a[$((i+1))]}" | cut -d'.' -f1`;
suf=`echo "${a[$((i+1))]}" | cut -d'.' -f2`;
blobxmltxt+="<file name=\"";
blobxmltxt+="${na}_sigheader.${suf}.encrypt\" ";
blobfiles+="${na}_sigheader.${suf}.encrypt ";
blobxmltxt+="type=\"${a[$i]}\" />";
i=$((i+1));
done;
fi;
blobxmltxt+="</file_list>";
return ${tf_v};
}
clean_mfd()
{
rm -f *.sh *.sb *.hash *.sig *.txt *.tmp *.func *.raw;
local i;
local lst=`ls -1`;
local a=($lst);
for (( i=0; i<${#a[@]}; i++ )); do
if [ -L "${a[$i]}" ]; then
rm -f "${a[$i]}";
cp -f "../${a[$i]}" "${a[$i]}";
fi;
done;
}
findadev()
{
local devpaths=($(find /sys/bus/usb/devices/usb*/ -name devnum -print0 | {
local fn_devnum;
local found=();
while read -r -d "" fn_devnum; do
local dir="$(dirname "${fn_devnum}")";
local vendor="$(cat "${dir}/idVendor")";
if [ "${vendor}" != "0955" ]; then
continue
fi;
local product="$(cat "${dir}/idProduct")";
case "${product}" in
"7721") ;;
"7f21") ;;
"7018") ;;
"7c18") ;;
"7121") ;;
"7019") ;;
"7e19") ;;
"7418") ;;
*) continue ;;
esac
local fn_busnum="${dir}/busnum";
if [ ! -f "${fn_busnum}" ]; then
continue;
fi;
local fn_devpath="${dir}/devpath";
if [ ! -f "${fn_devpath}" ]; then
continue;
fi;
local busnum="$(cat "${fn_busnum}")";
local devpath="$(cat "${fn_devpath}")";
found+=("${busnum}-${devpath}");
done;
echo "${found[@]}";
}))
echo "${#devpaths[@]} Jetson devices in RCM mode. USB: ${devpaths[@]}";
return "${#devpaths[@]}";
}
create_signdir ()
{
local i;
local v;
local f;
local tfv=$2;
local l=(\
"ebtarg" \
"bctarg" \
"rp1arg" \
"rcmarg" \
"pttarg" \
);
if [ "$1" = "" ]; then
echo "Error: Null sign directory name.";
exit 1;
fi;
rm -rf "$1";
mkdir "$1";
pushd "$1" > /dev/null 2>&1;
for (( i=0; i<${#l[@]}; i++ )); do
v=${l[$i]};
if [ ${tfv} -gt 1 -a "${!v}" = "" ]; then
continue;
fi;
if [ ! -f ../${!v} ]; then
echo "Error: ../${!v} does not exist";
exit 1;
fi;
echo -n "copying ${!v} ... ";
cp -f ../${!v} .;
if [ $? -eq 0 ]; then
echo "succeeded."
else
echo "failed."
exit 1;
fi;
if [ "${v}" = "pttarg" ]; then
if [ ${tfv} -gt 1 ]; then
if [ ! -f "../${!v}.bin" ] || \
[ "${sbkpkc}" = "true" ] || \
[ "${pkc}" = "true" ]; then
#
# SBK/PKC still has stale file names
# in secureflash.xml.bin. So, the binary
# secureflash.xml.bin must be recreated
# from secureflash.xml.
#
pushd .. > /dev/null 2>&1;
cp -f ${!v} ${!v}.tmp;
./tegraparser_v2 --pt ${!v}.tmp;
popd > /dev/null 2>&1;
fi;
fi;
echo -n "copying ${!v}.bin ... ";
cp -f ../${!v}.bin .;
if [ $? -eq 0 ]; then
echo "succeeded."
else
echo "failed."
exit 1;
fi;
fi;
done;
local lst=`grep "filename>" ${pttarg} | sed -e s/\<filename\>// -e s?\</filename\>?? -e s?\</partition\>??`;
local a=($lst);
for (( i=0; i<${#a[@]}; i++ )); do
if [ -f "${a[$i]}" ]; then
continue;
fi;
#
# clear && PKC generates mbr & gpt, but SBK+PKC
# does not generate mbr & gpt. However, both mbr & gpt
# are re-generated by nvaflash.sh during actual flashing time.
# So, no need to copy.
#
if [[ "${a[$i]}" =~ ^mbr_ ]] || [[ "${a[$i]}" =~ ^gpt_ ]]; then
continue;
fi;
if [ ! -f "../${a[$i]}" ]; then
echo "Error: ${a[$i]} does not exist.";
exit 1;
fi;
echo -n "copying ${a[$i]} ... ";
cp ../${a[$i]} .;
if [ $? -eq 0 ]; then
echo "succeeded."
else
echo "failed."
exit 1;
fi;
done;
if [ "${blobfiles}" != "" ]; then
for f in ${blobfiles} ; do
if [ -f ${f} ]; then
continue;
fi;
echo -n "copying ${f} ... ";
cp ../${f} .;
if [ $? -eq 0 ]; then
echo "succeeded."
else
echo "failed."
exit 1;
fi;
done;
fi;
if [ ${tfv} = 2 -a "${tgid}" = "0x19" ]; then
local q="mem_rcm_sigheader.bct.signed";
if [ -f ../${q} ]; then
echo -n "copying ${q} ... ";
cp ../${q} .;
if [ $? -eq 0 ]; then
echo "succeeded."
else
echo "failed."
exit 1;
fi;
fi;
fi;
popd > /dev/null 2>&1;
}
fill_mfidir ()
{
local i;
local l;
local tf_v1=(\
"nvmflash.sh" \
"nvaflash.sh" \
"tegrarcm" \
"tegrabct" \
"tegradevflash" \
);
local tf_v2=(\
"nvmflash.sh" \
"nvaflash.sh" \
"tegrarcm_v2" \
"tegrabct_v2" \
"tegradevflash_v2" \
"tegrahost_v2" \
"tegraparser_v2" \
);
local opt=(\
"${rcmsfarg}" \
"emmc_bootblob_ver.txt" \
"qspi_bootblob_ver.txt" \
"${mb1bctarg}" \
"${mb1cbctarg}" \
"${memcbctarg}" \
"${membctarg}" \
);
if [ $1 -eq 2 ]; then
l=( ${tf_v2[@]} );
else
l=( ${tf_v1[@]} );
fi;
if [ "$2" = "" ]; then
echo "Error: Null MFI directory.";
exit 1;
fi;
if [ ! -d "$2" ]; then
echo "Error: MFI directory ($2) does not exists.";
exit 1;
fi;
pushd "$2" > /dev/null 2>&1;
clean_mfd;
local lst=`ls -1`;
local a=($lst);
for (( i=0; i<${#a[@]}; i++ )); do
if [ -L "${a[$i]}" ]; then
rm -f "${a[$i]}";
echo -n "copying ${a[$i]} ... ";
cp -f "../${a[$i]}" .;
if [ $? -eq 0 ]; then
echo "succeeded."
else
echo "failed."
exit 1;
fi;
fi;
done;
for (( i=0; i<${#l[@]}; i++ )); do
if [ ! -f ${l[$i]} ]; then
echo -n "copying ${l[$i]} ... ";
cp -f ../${l[$i]} .;
if [ $? -eq 0 ]; then
echo "succeeded."
else
echo "failed."
exit 1;
fi;
fi;
done;
for (( i=0; i<${#opt[@]}; i++ )); do
if [ "${opt[$i]}" = "" ]; then
continue;
fi;
if [ ! -f ${opt[$i]} -a -f ../${opt[$i]} ]; then
echo -n "copying ${opt[$i]} ... ";
cp -f ../${opt[$i]} .;
if [ $? -eq 0 ]; then
echo "succeeded."
else
echo "failed."
exit 1;
fi;
fi;
done;
if [ "${blobxmltxt}" != "" ]; then
local tid=`echo "${cidarg}" | cut -d' ' -f1`;
echo "${blobxmltxt}" > blob.xml;
./tegrahost_v2 --chip ${tid} --generateblob blob.xml blob.bin;
fi;
popd > /dev/null 2>&1;
}
if [[ "$@" =~ -u ]]; then
pkc="true";
if [[ "$@" =~ -v ]]; then
sbkpkc="true";
fi;
fi;
cat << EOF
================================================================================
|| Generate Massflash Image in the master host: ||
|| Requires the Jetson connected in RCM mode. ||
================================================================================
EOF
ndev=0;
if [ "${BOARDID}" = "" -o "${BOARDSKU}" = "" -o \
"${FAB}" = "" -o "${FUSELEVEL}" = "" ]; then
findadev;
ndev=$?;
if [ $ndev -ne 1 ]; then
if [ $ndev -gt 1 ]; then
echo "*** Too many Jetson devices found.";
else
echo "*** Error: No Jetson device found.";
fi;
echo "Connect 1 Jetson in RCM mode and rerun $0 $@";
exit 1;
fi;
else
echo "Generating massflash command without Jetson device connected:";
echo " BOARDID=${BOARDID} BOARDSKU=${BOARDSKU} FAB=${FAB} BOARDREV=${BOARDREV} FUSELEVEL=${FUSELEVEL}";
fi;
cat << EOF
+-------------------------------------------------------------------------------
| Step 1: Generate Command File
+-------------------------------------------------------------------------------
EOF
rm -f ${BLDIR}/flash.xml.tmp; # Remove old cruft
BOARDID=${BOARDID} BOARDSKU=${BOARDSKU} FAB=${FAB} BOARDREV=${BOARDREV} FUSELEVEL=${FUSELEVEL} ${curdir}/flash.sh --no-flash $@
if [ $? -ne 0 ]; then
echo "*** ERROR: ${FLASHCMD} generation failed.";
exit 1;
fi;
if [ ! -f "${BLDIR}/${FLASHCMD}" ]; then
echo "*** Error: command file generation failed.";
exit 1;
fi;
cmd=`cat ${BLDIR}/${FLASHCMD}`;
gen_param "${cmd}";
tfvers=$?;
pushd ${BLDIR} > /dev/null 2>&1;
if [[ ${cmd} =~ secureflash ]]; then
cat << EOF
+-------------------------------------------------------------------------------
| Step 2: Extract Signed Binaries
+-------------------------------------------------------------------------------
EOF
if [[ ${ebtarg} =~ encrypt.signed$ ]]; then
mfidir="${mfidir}_encrypt_signed";
else
mfidir="${mfidir}_signed";
fi;
signdir="mfitmp";
create_signdir "${signdir}" ${tfvers};
else
cat << EOF
+-------------------------------------------------------------------------------
| Step 2: Sign Binaries
+-------------------------------------------------------------------------------
EOF
cmdconv="-e s/flash\;// -e s/reboot/sign/";
cmd=`echo "${cmd}" | sed ${cmdconv}`;
echo "${cmd} --keep --skipuid" > ${MFGENCMD};
cat ${MFGENCMD};
bash ${MFGENCMD} 2>&1 | tee mfi.log;
if [ $? -ne 0 ]; then
echo "Error: Signing binaries failed.";
exit 1;
fi;
tok=`grep "Keep temporary directory" mfi.log`;
if [ "${tok}" = "" ]; then
echo "Error: signing binaries failed.";
exit 1;
fi;
signdir=`echo "${tok}" | awk -F ' ' '{print $4}'`;
signdir=`basename ${signdir}`;
fi;
cat << EOF
+-------------------------------------------------------------------------------
| Step 3: Generate Mass-flash scripts
+-------------------------------------------------------------------------------
EOF
rm -rf ${mfidir};
mv ${signdir} ${mfidir};
gen_mflash_sh;
gen_aflash_sh ${tfvers};
cat << EOF
+-------------------------------------------------------------------------------
| Step 4: Generate Mass-flash image tarball
+-------------------------------------------------------------------------------
EOF
fill_mfidir ${tfvers} "${mfidir}";
mfitarball="${mfidir}.tbz2";
tar cvjf ../${mfitarball} ${mfidir};
popd > /dev/null 2>&1;
echo "\
********************************************************************************
*** Mass Flashing tarball ${mfitarball} is ready.
********************************************************************************
1. Download ${mfitarball} to each flashing hosts.
2. Untar ${mfitarball}. ( tar xvjf ${mfitarball} )
3. cd ${mfidir}
4. Connect Jetson boards(${ext_target_board} only) and put them in RCM mode.
5. ./nvmflash.sh
";
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment