wolfBoot/tools/scripts/mpfs_bootmode2.sh

149 lines
5.7 KiB
Bash
Executable File

#!/bin/bash
#
# PolarFire SoC boot mode 2 programming helper.
#
# Two jobs mpfsBootmodeProgrammer cannot do on its own:
#
# mpfs_bootmode2.sh [options] wolfboot.elf
# Program the User Boot Loader (the TARGET=mpfs250_ubl build) into sNVM
# and select boot mode 2 on a die the programmer does not list (the
# secure "S" parts, e.g. MPFS250TS, which an authenticated sNVM client
# needs). The programmer is run in --dryrun to produce the UBL image
# (its 60-byte header, SHA-256 and Intel hex) and the USK; the fpgenprog
# steps it logged are replayed in a project for the requested die.
#
# mpfs_bootmode2.sh --envm [options] wolfboot_envm_signed.elf
# Program the eNVM only (the signed wolfBoot and its manifest) and leave
# the boot mode and sNVM alone, i.e. update the eNVM wolfBoot under boot
# mode 2. The programmer always selects boot mode 1 when it programs
# eNVM, so its envm_client step is replayed without the boot-mode step.
#
# Boot mode 1 is restored with the programmer itself:
# java -jar mpfsBootmodeProgrammer.jar --bootmode 1 --die MPFS250T ... wolfboot.elf
#
# Options:
# --die DIE fpgenprog die (default MPFS250TS)
# --package PKG package (default FCG1152)
# --snvm-page N first sNVM page of the UBL (default 0)
# --usk KEY 12-byte hex USK, or 0 for a random one (default 0)
# --encrypt store the UBL as authenticated ciphertext
# --regenerate-smk also generate a new sNVM Master Key. The authenticated
# sNVM client the UBL lives in cannot be created on a device
# whose SMK has never been initialized, and the programmer
# never asks for one. A new SMK invalidates every existing
# authenticated or encrypted sNVM client on the device.
# --workdir DIR output directory (default: current directory)
# --dryrun generate everything, do not program
#
# Requires SC_INSTALL_DIR (SoftConsole) and FPGENPROG (Libero fpgenprog).
set -e
DIE=MPFS250TS
PACKAGE=FCG1152
SNVM_PAGE=0
USK=0
ENCRYPT=""
SMK=0
WORKDIR="$PWD"
DRYRUN=0
ENVM=0
while [ $# -gt 1 ]; do
case "$1" in
--die) DIE="$2"; shift 2 ;;
--package) PACKAGE="$2"; shift 2 ;;
--snvm-page) SNVM_PAGE="$2"; shift 2 ;;
--usk) USK="$2"; shift 2 ;;
--encrypt) ENCRYPT="--encrypt"; shift ;;
--regenerate-smk) SMK=1; shift ;;
--workdir) WORKDIR="$2"; shift 2 ;;
--dryrun) DRYRUN=1; shift ;;
--envm) ENVM=1; shift ;;
*) echo "unknown option: $1" >&2; exit 1 ;;
esac
done
ELF="${1:-}"
[ -n "$ELF" ] && [ -f "$ELF" ] || { echo "usage: $0 [--envm] [options] wolfboot.elf" >&2; exit 1; }
[ -n "${SC_INSTALL_DIR:-}" ] || { echo "SC_INSTALL_DIR is not set" >&2; exit 1; }
[ -x "${FPGENPROG:-}" ] || { echo "FPGENPROG is not an executable" >&2; exit 1; }
JAVA="$SC_INSTALL_DIR/eclipse/jre/bin/java"
JAR="$SC_INSTALL_DIR/extras/mpfs/mpfsBootmodeProgrammer.jar"
# The programmer knows the non-secure die names only; it is just generating
# the image here, so hand it the base die.
JAR_DIE="${DIE%S}"
mkdir -p "$WORKDIR"
WORKDIR="$(cd "$WORKDIR" && pwd)"
NAME="$(basename "$ELF" .elf)"
# The programmer takes the ELF relative to its working directory.
cmp -s "$ELF" "$WORKDIR/$NAME.elf" 2>/dev/null || cp "$ELF" "$WORKDIR/$NAME.elf"
if [ "$ENVM" = 1 ]; then
MODE=1
STEP=envm_client
GEN="$WORKDIR/bootmode1"
JAR_ARGS="--bootmode 1"
else
MODE=2
STEP=snvm_client
GEN="$WORKDIR/bootmode2"
JAR_ARGS="--bootmode 2 --snvm_page $SNVM_PAGE --usk $USK $ENCRYPT"
fi
PROJ="$WORKDIR/bootmode${MODE}_$DIE/fpgenprogProject"
LOG="$GEN/debugLog.txt"
echo "[1/3] generating the image with mpfsBootmodeProgrammer (dry run)"
# Boot mode 2 on a non-secure die fails at bitstream generation; the image
# and the USK are already written by then.
# shellcheck disable=SC2086
"$JAVA" -jar "$JAR" $JAR_ARGS --die "$JAR_DIE" --package "$PACKAGE" --dryrun \
--workdir "$WORKDIR" "$NAME.elf" > "$WORKDIR/bootmode${MODE}_jar.log" 2>&1 || true
[ -f "$LOG" ] && grep -q "fpgenprog $STEP " "$LOG" || {
echo "mpfsBootmodeProgrammer produced no image; see $WORKDIR/bootmode${MODE}_jar.log" >&2
exit 1
}
# The exact arguments the programmer used for a step, pointed at the new project.
cmd_args() {
grep -o "fpgenprog $1 [^\"]*" "$LOG" | tail -1 | sed "s/^fpgenprog $1 //" | \
sed "s|--location [^ ]*|--location $PROJ|"
}
CLIENT_ARGS="$(cmd_args $STEP)"
if [ "$SMK" = 1 ]; then
[ "$MODE" = 2 ] || { echo "--regenerate-smk applies to boot mode 2 only" >&2; exit 1; }
echo "note: generating a new sNVM Master Key; authenticated sNVM clients"
echo " already on this device will no longer authenticate"
CLIENT_ARGS="$CLIENT_ARGS --regenerate_smk"
fi
BOOT_INFO_ARGS=""
[ "$MODE" = 2 ] && BOOT_INFO_ARGS="$(cmd_args mss_boot_info)"
echo "[2/3] generating the bitstream for $DIE"
rm -rf "$PROJ"
mkdir -p "$(dirname "$PROJ")"
"$FPGENPROG" new_project --location "$PROJ" --target_die "$DIE" --target_package "$PACKAGE"
if [ -n "$BOOT_INFO_ARGS" ]; then
# shellcheck disable=SC2086
"$FPGENPROG" mss_boot_info $BOOT_INFO_ARGS
fi
# shellcheck disable=SC2086
"$FPGENPROG" $STEP $CLIENT_ARGS
"$FPGENPROG" generate_bitstream --location "$PROJ"
if [ "$MODE" = 2 ]; then
USKFILE="$(ls "$GEN"/"$NAME"-bm2-usk.txt 2>/dev/null | head -1)"
[ -n "$USKFILE" ] && echo "USK (keep it: a UBL update needs it): $USKFILE"
fi
if [ "$DRYRUN" = 1 ]; then
echo "[3/3] dry run: not programming"
exit 0
fi
echo "[3/3] programming"
"$FPGENPROG" run_action --location "$PROJ" --action PROGRAM
if [ "$MODE" = 2 ]; then
echo "done: boot mode 2, UBL in sNVM from page $SNVM_PAGE"
else
echo "done: eNVM programmed, boot mode unchanged"
fi