#!/bin/sh

# Raspberry Pi4 boot EEPROM updater.

set -e

script_dir=$(cd "$(dirname "$0")" && pwd)

if [ -f /etc/default/rpi-eeprom-update ]; then
   . /etc/default/rpi-eeprom-update
fi

LOCAL_MODE=0
if [ -n "$FIRMWARE_ROOT" ]; then
   # Provided by environment
   true
elif [ -d /lib/firmware/raspberrypi/bootloader ]; then
   # Default firmware root exists
   FIRMWARE_ROOT=/lib/firmware/raspberrypi/bootloader
else
   # Work from local git checkout
   LOCAL_MODE=1
   FIRMWARE_ROOT="${script_dir}/firmware"
fi

# May be used to select beta or stable releases instead of the default critical updates.
FIRMWARE_RELEASE_STATUS=${FIRMWARE_RELEASE_STATUS:-critical}
FIRMWARE_IMAGE_DIR=${FIRMWARE_IMAGE_DIR:-${FIRMWARE_ROOT}/${FIRMWARE_RELEASE_STATUS}}
FIRMWARE_BACKUP_DIR=${FIRMWARE_BACKUP_DIR:-/var/lib/raspberrypi/bootloader/backup}
ENABLE_VL805_UPDATES=${ENABLE_VL805_UPDATES:-1}
USE_FLASHROM=${USE_FLASHROM:-0}
RECOVERY_BIN=${RECOVERY_BIN:-${FIRMWARE_ROOT}/${FIRMWARE_RELEASE_STATUS}/recovery.bin}
BOOTFS=${BOOTFS:-/boot}
VCMAILBOX=${VCMAILBOX:-/opt/vc/bin/vcmailbox}

EXIT_SUCCESS=0
EXIT_UPDATE_REQUIRED=1
EXIT_FAILED=2
EXIT_EEPROM_FROZEN=3
# Reserved
# EXIT_PREVIOUS_UPDATE_FAILED=4

OVERWRITE_CONFIG=0
# Maximum safe SPI speed for EEPROM access 16000, slower is ok.
SPI_SPEED=16000
# Timestamp for first release which doesn't have a timestamp field
BOOTLOADER_FIRST_VERSION=1557513636
EEPROM_SIZE=524288
BOARD_INFO=
BOARD_REVISION=
BOARD_TYPE=

# Newer board revisions embed the VLI firmware in the bootloader EEPROM and
# there is no way to separately update the VLI firmware. Consequently,
# standalone vl805 update files do not trigger automatic updates.
# Recovery.bin and the the SPI bootloader ignore vl805.bin files on boards
# without a dedicate VL805 EEPROM.
HAVE_VL805_EEPROM=0

# Simple bootloader which is able to load start.elf in the event of a power
# cut. This runs SDRAM at low speed and may have reduced functionality but
# should be enough to run flashrom again.

TMP_EEPROM_IMAGE=""
TMP_BOOTFS_MNT=""

VL805_CURRENT_VERSION=
VL805_UPDATE_VERSION=

# The update actions selected by the version check
ACTION_UPDATE_BOOTLOADER=0
ACTION_UPDATE_VL805=0

cleanup() {
   if [ -f "${TMP_EEPROM_IMAGE}" ]; then
      rm -f "${TMP_EEPROM_IMAGE}"
   fi
   if [ -f "${TMP_EEPROM_CONFIG}" ]; then
      rm -f "${TMP_EEPROM_CONFIG}"
   fi
   if [ -f "${NEW_EEPROM_CONFIG}" ]; then
      rm -f "${NEW_EEPROM_CONFIG}"
   fi
   if [ -d "${TMP_BOOTFS_MNT}" ]; then
      umount "${TMP_BOOTFS_MNT}"
      rmdir "${TMP_BOOTFS_MNT}"
   fi
   TMP_BOOTFS_MNT=
   TMP_EEPROM_IMAGE=
   TMP_EEPROM_CONFIG=
   NEW_EEPROM_CONFIG=
}
trap cleanup EXIT

die() {
   echo "$@" >&2
   exit ${EXIT_FAILED}
}

prepareImage()
{
   [ -f "${BOOTLOADER_UPDATE_IMAGE}" ] || die "EEPROM image \'${BOOTLOADER_UPDATE_IMAGE}\' not found"
   TMP_EEPROM_IMAGE="$(mktemp)"
   TMP_EEPROM_CONFIG="$(mktemp)"
   NEW_EEPROM_CONFIG="$(mktemp)"

   mkdir -p "${FIRMWARE_BACKUP_DIR}"

   # Backup the configuration of the currently loaded bootloader
   vcgencmd bootloader_config > "${TMP_EEPROM_CONFIG}"
   backup="${FIRMWARE_BACKUP_DIR}/pieeprom-backup-$(date +%Y%m%d-%H%M%S).conf"
   cp -f "${TMP_EEPROM_CONFIG}" "${backup}"

   if [ -x "${EEPROM_CONFIG_HOOK}" ]; then
      echo "Running EEPROM config hook ${EEPROM_CONFIG_HOOK}"
      if ! "${EEPROM_CONFIG_HOOK}" -u "${BOOTLOADER_UPDATE_IMAGE}" < "${TMP_EEPROM_CONFIG}" > "${NEW_EEPROM_CONFIG}"; then
         echo "EEPROM config hook \"${EEPROM_CONFIG_HOOK}\"  failed. Using original configuration"
         cp -f "${TMP_EEPROM_CONFIG}" "${NEW_EEPROM_CONFIG}"
      fi
   else
      cp -f "${TMP_EEPROM_CONFIG}" "${NEW_EEPROM_CONFIG}"
   fi

   if [ "$(wc -l "${NEW_EEPROM_CONFIG}" | awk '{print $1}')" -lt 3 ]; then
      # Don't propagate empty EEPROM config files and also prevent the initial
      # bootloader config with WAKE_ON_GPIO=0 propgating to newer versions by
      # accident.
      OVERWRITE_CONFIG=1
   fi

   cp -f "${BOOTLOADER_UPDATE_IMAGE}" "${TMP_EEPROM_IMAGE}"

   if [ "${OVERWRITE_CONFIG}" = 0 ]; then
      "${script_dir}/rpi-eeprom-config" \
         --out "${TMP_EEPROM_IMAGE}" \
         --config "${NEW_EEPROM_CONFIG}" "${BOOTLOADER_UPDATE_IMAGE}"
   fi
}

applyRecoveryUpdate()
{
   [ -n "${BOOTLOADER_UPDATE_IMAGE}" ] || [ -n "${VL805_UPDATE_IMAGE}" ] || die "No update images specified"

   findBootFS

   # A '.sig' file is created so that recovery.bin can check that the
   # EEPROM image has not been created (e.g. SD card corruption).
   # The .sig file format is currently just a SHA256 in ASCII hex. In future,
   # if an actual public key signature is required then that plus any other
   # data would be appended after the SHA256 signature.
   if [ -n "${BOOTLOADER_UPDATE_IMAGE}" ]; then
        [ -f "${BOOTLOADER_UPDATE_IMAGE}" ] || die "${BOOTLOADER_UPDATE_IMAGE} not found"

        TMP_EEPROM_IMAGE="$(mktemp)"
        prepareImage
        # If recovery.bin encounters pieeprom.upd then it will select it in
        # preference to pieeprom.bin. The .upd file also causes recovery.bin
        # to rename itself to recovery.000 and reboot if the update is successful.
        # The rename causes the ROM to ignore this file and use the newly flashed
        # EEPROM image instead.
        sha256sum "${TMP_EEPROM_IMAGE}" | awk '{print $1}' > "${BOOTFS}/pieeprom.sig" \
                || die "Failed to create ${BOOTFS}/pieeprom.sig"

        cp -f "${TMP_EEPROM_IMAGE}" "${BOOTFS}/pieeprom.upd" \
                || die "Failed to copy ${TMP_EEPROM_IMAGE} to ${BOOTFS}"
   fi

   if [ -n "${VL805_UPDATE_IMAGE}" ]; then
        sha256sum "${VL805_UPDATE_IMAGE}" | awk '{print $1}' > "${BOOTFS}/vl805.sig" \
                || die "Failed to create ${BOOTFS}/vl805.sig"
        cp -f "${VL805_UPDATE_IMAGE}" "${BOOTFS}/vl805.bin"
   fi

   cp -f "${RECOVERY_BIN}" "${BOOTFS}/recovery.bin" \
      || die "Failed to copy ${RECOVERY_BIN} to ${BOOTFS}"
}

applyUpdate() {
   checksums_file="/var/lib/dpkg/info/rpi-eeprom.md5sums"

   [ "$(id -u)" = "0" ] || die "* Must be run as root - try 'sudo rpi-eeprom-update'"

   if [ "${IGNORE_DPKG_CHECKSUMS}" = 0 ] && [ -f "${checksums_file}" ]; then
      (
         cd /
         if ! md5sum -c "${checksums_file}" > /dev/null 2>&1; then
            md5sum -c "${checksums_file}"
            die "rpi-eeprom checksums failed - try reinstalling this package"
         fi
      )
   fi

   if [ "${USE_FLASHROM}" = 0 ]; then
      applyRecoveryUpdate
      return
   fi

   if [ -f "${BOOTLOADER_UPDATE_IMAGE}" ]; then
      echo "WARNING: USE_FLASHROM is deprecated."
      # Bootloader EEPROM chip-select is muxed with audio pin so disable audio
      # LDO first to avoid sending noise to analog audio.
      "${VCMAILBOX}" 0x00030056 4 4 0 > /dev/null || true
      dtparam audio=off

      # Switch the SPI pins to boot EEPROM
      dtoverlay spi-gpio40-45
      modprobe spidev
      modprobe spi-bcm2835

      prepareImage "${BOOTLOADER_UPDATE_IMAGE}"

      echo "Applying bootloader update ${BOOTLOADER_UPDATE_IMAGE}"
      flashrom -p "linux_spi:dev=/dev/spidev0.0,spispeed=${SPI_SPEED}" -w "${TMP_EEPROM_IMAGE}" || die "flashrom EEPROM update failed"

      dtparam -R spi-gpio40-45
      dtparam audio=on
      ${VCMAILBOX} 0x00030056 4 4 1 > /dev/null || true
   fi

   if [ -f "${VL805_UPDATE_IMAGE}" ]; then
      echo "Applying VL805 image ${VL805_UPDATE_IMAGE}"
      vl805 -w "${VL805_UPDATE_IMAGE}"
   fi

   echo "Applying bootloader update ${BOOTLOADER_UPDATE_IMAGE}"
}

# Use the version reported by the loaded EEPROM instead of attempting to retrieve
# this via flashrom to avoid unnecessary audio glitches.
BOOTLOADER_CURRENT_VERSION=
getBootloaderCurrentVersion() {
   if vcgencmd bootloader_version | grep -q timestamp; then
      BOOTLOADER_CURRENT_VERSION=$(vcgencmd bootloader_version | grep timestamp | awk '{print $2}')
      if [ "${BOOTLOADER_CURRENT_VERSION}" = "0" ]; then
         # If a timestamp of zero is returned then it's new firmware but an
         # old bootloader. Assume bootloader v0
         BOOTLOADER_CURRENT_VERSION="${BOOTLOADER_FIRST_VERSION}"
      fi
   else
      # New bootloader / old firmware ? Try to parse the date
      BOOTLOADER_CURRENT_VERSION=$(date -u +%s --date "$(vcgencmd bootloader_version | head -n1)" 2>/dev/null || true)
   fi

   # Failed to parse the version. Default to the initial production release.
   if [ -z "${BOOTLOADER_CURRENT_VERSION}" ]; then
      BOOTLOADER_CURRENT_VERSION="${BOOTLOADER_FIRST_VERSION}"
   fi
}

# Find latest applicable update version
BOOTLOADER_UPDATE_IMAGE=""
BOOTLOADER_UPDATE_VERSION=0
getBootloaderUpdateVersion() {
   BOOTLOADER_UPDATE_VERSION=0
   match=".*/pieeprom-[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9].bin"
   latest="$(find "${FIRMWARE_IMAGE_DIR}" -maxdepth 1 -type f -size "${EEPROM_SIZE}c" -regex "${match}" | sort -r | head -n1)"
   if [ -f "${latest}" ]; then
      BOOTLOADER_UPDATE_VERSION=$(strings "${latest}" | grep BUILD_TIMESTAMP | sed 's/.*=//g')
      BOOTLOADER_UPDATE_IMAGE="${latest}"
   fi
}

checkDependencies() {
   BOARD_INFO="$(sed -n '/^Revision/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo)"
   if [ $(((0x$BOARD_INFO >> 23) & 1)) -ne 0 ] && [ $(((0x$BOARD_INFO >> 12) & 15)) -eq 3 ]; then
      echo "BCM2711 detected"
   else
      # Not a BCM2711, no EEPROMs to update.
      exit ${EXIT_SUCCESS}
   fi

   BOARD_TYPE=$(((0x$BOARD_INFO >> 4) & 0xff))
   BOARD_REVISION=$((0x$BOARD_INFO & 0xf))

   if [ ${BOARD_TYPE} -eq 17 ] && [ ${BOARD_REVISION} -lt 4 ]; then
      echo "Dedicated VL805 EEPROM detected"
      HAVE_VL805_EEPROM=1
   else
      echo "VL805 firmware in bootloader EEPROM"
      HAVE_VL805_EEPROM=0
   fi

   if ! command -v vcgencmd  > /dev/null; then
      die "vcgencmd not found. On Debian, try installing the libraspberrypi-bin package."
   fi

   if [ ! -d "${FIRMWARE_IMAGE_DIR}" ]; then
      die "EEPROM updates directory ${FIRMWARE_IMAGE_DIR} not found."
   fi

   # If a board revision specific firmware directory is defined then use that
   # in preference to the generic directory.
   if [ -d "${FIRMWARE_IMAGE_DIR}-${BOARD_INFO}" ]; then
      FIRMWARE_IMAGE_DIR="${FIRMWARE_IMAGE_DIR}-${BOARD_INFO}"
   fi

   if vcgencmd bootloader_config | grep -qi "Command not registered"; then
      die "vcgencmd: 'bootloader_config' command not supported. Please update VC firmware and reboot."
   fi

   if ! command -v sha256sum > /dev/null; then
      die "sha256sum not found. On Debian, try installing the coreutilities package"
   fi

   if ! command -v flashrom  > /dev/null && [ "${USE_FLASHROM}" = 1 ]; then
      die "flashrom not found. On Debian, try installing the flashrom package."
   fi

   if [ ! -x "${VCMAILBOX}" ] && [ "${USE_FLASHROM}" = 1 ]; then
      die "vcmailbox not found. On Debian, try installing the libraspberrypi-bin package."
   fi

   if ! command -v dtparam > /dev/null && [ "${USE_FLASHROM}" = 1 ]; then
      die "dtparam not found. On Debian, try installing the libraspberrypi-bin package."
   fi

   if ! command -v dtoverlay > /dev/null && [ "${USE_FLASHROM}" = 1 ]; then
      die "dtoverlay not found. On Debian, try installing the libraspberrypi-bin package."
   fi

   if [ "${USE_FLASHROM}" = 0 ] && [ ! -f "${RECOVERY_BIN}" ]; then
      die "${RECOVERY_BIN} not found."
   fi
}

usage() {
cat <<EOF
rpi-eeprom-update [options]... [FILE]

Bootloader EEPROM update tool for the Raspberry Pi 4.

Checks whether the Raspberry Pi 4 bootloader and the VL805 USB controller
EEPROMs are up-to-date and optionally updates the EEPROMs at the next reboot.

The default update mechanism writes recovery.bin and the EEPROM update
image(s) (pieeprom.upd and vl805.bin) to the boot partition.
The SHA256 hash of the corresponding images are written to pieeprom.sig
and/or vl805.sig. This guards against file system corruption which could
cause the EEPROM to be flashed with an invalid image. This is not a
security check.

At the next reboot the ROM runs recovery.bin which updates EEPROM(s).
If the update was successful recovery.bin renames itself to recovery.000
to prevent it from running a second time then resets the system.
The system should then boot normally.

If /boot does not correspond to the boot partition and this
is not a NOOBS system, then the mount point for BOOTFS should be defined
in /etc/default/rpi-eeprom-update by defining the BOOTFS variable.

A backup of the current EEPROM config file is written to ${FIRMWARE_BACKUP_DIR}
before applying the update.

Unless the -d flag is specified, the current bootloader configuration is
retained.

Options:
   -a Automatically install bootloader and USB (VLI) EEPROM updates.
   -A Specify which type of EEPROM to automatically update (vl805 or bootloader)
   -d Use the default bootloader config, or if a file is specified using the -f
      flag use the config in that file. This option only applies when a
      bootloader EEPROM update is needed; if the bootloader EEPROM is up-to-date
      then its config will not be changed.
   -f Install the given file instead of the latest applicable update
      Ignores the FREEZE_VERSION flag in bootloader and is intended for manual
      firmware updates.
   -h Display help text and exit
   -i Ignore package checksums - for rpi-eeprom developers.
   -j Write status information using JSON notation
   -m Write status information to the given file when run without -a or -f
   -r Removes temporary EEPROM update files from the boot partition.
   -u Install the specified VL805 (USB EEPROM) image file.

Environment:
Environment variables should be defined in /etc/default/rpi-eeprom-update

EEPROM_CONFIG_HOOK

Specifies the path of an optional script which post-processes the
configuration file before it is applied to the new image. The modified
output must contain at least 3 lines and should contain WAKE_ON_GPIO
and POWER_OFF_ON_HALT settings.

USE_FLASHROM

USE_FLASHROM is deprecated and there is no support for this. The muxing
of the SPI pins causes too many issues for this to ever be reliable.

The flashrom update mechanism may be enabled by setting USE_FLASHROM=1. This
also selects the vl805 tool instead of using recovery.bin to perform the
update. This may be desirable if an immediate update is required or if an
SD card is not present.
However, this not recommended because the SPI pins are muxed with audio and other
device drivers may be using SPI (e.g. HATs). This is also not safe in the
event of a power failure during the update of the EEPROM.
Changing the VL805 firmware whilst USB devices are attached may also cause
those devices to stop working until after the system is reboot.

FIRMWARE_RELEASE_STATUS

Specifies the release status of the firmware to apply. The default is 'critical'.

Before selecting a firmware release directory this script checks whether there
is a board revision specific variant e.g. critical-c03111. If present then the
board-revision specific version is used in preference.

Release status:

critical: The latest production release plus important security or hardware compatibility bug fixes.

stable: Contains new features that have already undergone some beta testing.
These are candidates for new production releases.

beta: New features, bug fixes for development/test purposes. Use at your own
risk!

As far as rpi-eeprom-update is concerned FIRMWARE_RELEASE_STATUS is just
the subdirectory mapping under ${FIRMWARE_ROOT}. Therefore, custom release
directories are supported by creating the relevant directory and changing
the FIRMWARE_RELEASE_STATUS environment variable.

Examples:
To extract the configuration file from an EEPROM image:
   rpi-eeprom-config pieeprom.bin --out bootconf.txt

To update the configuration file in an EEPROM image:
   rpi-eeprom-config pieeprom.bin --config bootconf.txt --out pieeprom-new.bin

To flash the new image:
   sudo rpi-eeprom-update -d -f ./pieeprom-new.bin

The syntax is the same as config.txt See online documentation for the list of parameters.

The official documentation for the Raspberry Pi bootloader EEPROM is available at
https://www.raspberrypi.org/documentation/hardware/raspberrypi/booteeprom.md

EOF
  exit ${EXIT_SUCCESS}
}

printVersions()
{
   if [ "${ACTION_UPDATE_BOOTLOADER}" = 1 ]; then
      echo "BOOTLOADER: update required"
   else
      echo "BOOTLOADER: up-to-date"
   fi

   echo "CURRENT: $(date -u "-d@${BOOTLOADER_CURRENT_VERSION}") (${BOOTLOADER_CURRENT_VERSION})"
   echo " LATEST: $(date -u "-d@${BOOTLOADER_UPDATE_VERSION}") (${BOOTLOADER_UPDATE_VERSION})"
   echo " FW DIR: ${FIRMWARE_IMAGE_DIR}"

   if [ "${ACTION_UPDATE_VL805}" = 1 ]; then
      echo "VL805: update required"
   else
      if [ "$(id -u)" = "0" ]; then
         echo "VL805: up-to-date"
      else
         echo "VL805: version unknown. Try sudo rpi-eeprom-update"
      fi
   fi

   echo "CURRENT: ${VL805_CURRENT_VERSION}"
   echo " LATEST: ${VL805_UPDATE_VERSION}"
}

findBootFS()
{
   # recovery.bin is loaded by the ROM from the boot partition, this is normally
   # ${BOOTFS} but on NOOBS this is /dev/mmcblk0p1 with volume label RECOVERY
   # If ${BOOTFS} is not writable OR is not on /dev/mmcblk0 then error because the ROM
   # can only load recovery.bin from the on-board SD-CARD slot or the EEPROM.

   if blkid | grep -qE "/dev/mmcblk0p1.*LABEL_FATBOOT.*RECOVERY.*TYPE.*vfat"; then
      TMP_BOOTFS_MNT="$(mktemp -d)"
      mount /dev/mmcblk0p1 "${TMP_BOOTFS_MNT}"
      BOOTFS="${TMP_BOOTFS_MNT}"
   fi

   # If BOOTFS is not a directory or doesn't contain any .elf files then
   # it's probably not the boot partition.
   [ -d "${BOOTFS}" ] || die "BOOTFS: \"${BOOTFS}\" is not a directory"
   if [ "$(find "${BOOTFS}/" -name "*.elf" | wc -l)" -gt 0 ]; then
      echo "BOOTFS ${BOOTFS}"
   else
      echo "WARNING: BOOTFS: \"${BOOTFS}\" contains no .elf files. Please check boot directory"
   fi
}

getVL805CurrentVersion()
{
   # The version number is obtained by examing a section of PCI config
   # space which is only accessible as root. If the command is not run as
   # root then treat the version as unknown and skip VLI updates.
   VL805_CURRENT_VERSION=""
   if [ "$(id -u)" = "0" ]; then
      if command -v lspci >/dev/null; then
         vlver="$(lspci -d 1106:3483 -xxx | awk '/^50:/ { print "VL805 FW version: " $5 $4 $3 $2 }')"
      else
         vlver="$(vl805 | grep "VL805 FW version")"
      fi
      if [ -n "${vlver}" ]; then
         VL805_CURRENT_VERSION="${vlver#*: }"
      fi
   fi
}

getVL805UpdateVersion()
{
   # The VL805 version number is an eight character hex string. Select the
   # largest number for the newest version.
   # The vl805.latest version is retained for backwards compatibility with
   # thirdparty scripts (are there any?) but it not used by this script and
   # is deprecated.
   VL805_UPDATE_VERSION=""
   match='.*/vl805-.*.bin'
   ver=$(find "${FIRMWARE_IMAGE_DIR}" -maxdepth 1 -type f -follow -regex "${match}" | sed 's/.*\/vl805-\([0-9a-f]*\)\.bin/\1/' | sort -r | head -n1)
   if [ -f "${FIRMWARE_IMAGE_DIR}/vl805-${ver}.bin" ]; then
      VL805_UPDATE_VERSION="${ver}"
      VL805_UPDATE_IMAGE="${FIRMWARE_IMAGE_DIR}/vl805-${ver}.bin"
   fi
}

# Retrieve the version information and determine whether newer
# versions are available.
lookupVersionInfo()
{
   getBootloaderCurrentVersion
   getBootloaderUpdateVersion

   getVL805CurrentVersion

   if [ "${BOOTLOADER_UPDATE_VERSION}" -gt "${BOOTLOADER_CURRENT_VERSION}" ]; then
      ACTION_UPDATE_BOOTLOADER=1
   else
      BOOTLOADER_UPDATE_IMAGE=""
   fi

   if [ "${HAVE_VL805_EEPROM}" = 1 ]; then
      getVL805UpdateVersion
      if [ -n "${VL805_CURRENT_VERSION}" ] && [ -n "${VL805_UPDATE_VERSION}" ]; then
         if [ "$((0x${VL805_CURRENT_VERSION}))" -lt "$((0x${VL805_UPDATE_VERSION}))" ];  then
            ACTION_UPDATE_VL805=1
         else
            VL805_UPDATE_IMAGE=""
         fi
      fi
   else
      VL805_UPDATE_VERSION="${VL805_CURRENT_VERSION}"
      ACTION_UPDATE_VL805=0
   fi
}

checkAndApply()
{
   lookupVersionInfo
   removePreviousUpdates

   # Restrict the automatic updates to the EEPROM types selected by the -A option.
   if [ "${AUTO_UPDATE_VL805}" != 1 ]; then
      ACTION_UPDATE_VL805=0
      VL805_UPDATE_IMAGE=""
   fi
   if [ "${AUTO_UPDATE_BOOTLOADER}" != 1 ]; then
      ACTION_UPDATE_BOOTLOADER=0
      BOOTLOADER_UPDATE_IMAGE=""
   fi

   if [ "${ACTION_UPDATE_BOOTLOADER}" = 1 ] || [ "${ACTION_UPDATE_VL805}" = 1 ]; then
      echo "*** INSTALLING EEPROM UPDATES ***"
      printVersions
      applyUpdate
      echo "EEPROM updates pending. Please reboot to apply the update."
   else
      printVersions
   fi
}

fileUpdate()
{
   removePreviousUpdates
   echo "*** INSTALLING ${BOOTLOADER_UPDATE_IMAGE} ${VL805_UPDATE_IMAGE} ***"

   if [ -n "${BOOTLOADER_UPDATE_IMAGE}" ]; then
      [ -f "${BOOTLOADER_UPDATE_IMAGE}" ] || die "Bootloader image \"${BOOTLOADER_UPDATE_IMAGE}\" not found"
   fi

   if [ -n "${VL805_UPDATE_IMAGE}" ]; then
      [ -f "${VL805_UPDATE_IMAGE}" ] || die "VL805 image \"${VL805_UPDATE_IMAGE}\" not found"
   fi

   applyUpdate
   echo "EEPROM update pending. Please reboot to apply the update."
}

removePreviousUpdates()
{
   if [ "$(id -u)" = "0" ]; then
      findBootFS

      # Remove any stale recovery.bin files or EEPROM images
      # N.B. recovery.bin is normally ignored by the ROM if is not a valid
      # executable but it's best to not have the file at all.
      rm -f "${BOOTFS}/recovery.bin"
      rm -f "${BOOTFS}/pieeprom.bin" "${BOOTFS}/pieeprom.upd" "${BOOTFS}/pieeprom.sig"
      rm -f "${BOOTFS}/vl805.bin" "${BOOTFS}/vl805.sig"
      # Case insensitive for FAT bootfs
      find "${BOOTFS}" -maxdepth 1 -type f -follow -iname "recovery.*" -regex '.*\.[0-9][0-9][0-9]$' -exec rm -f {} \;
   fi
}

checkVersion()
{
   lookupVersionInfo

   if [ "${BOOTLOADER_UPDATE_VERSION}" -gt "${BOOTLOADER_CURRENT_VERSION}" ]; then
      echo "*** UPDATE REQUIRED ***"
      printVersions
      write_status_info "EXIT_UPDATE_REQUIRED"
      exit ${EXIT_UPDATE_REQUIRED}
   else
      printVersions
      write_status_info "EXIT_SUCCESS"
      exit ${EXIT_SUCCESS}
   fi
}

write_status_info()
{
   [ -z "${MACHINE_OUTPUT}" ] && return 0

   exit_code="${1:-EXIT_FAILED}"
   bootloader_cur="${BOOTLOADER_CURRENT_VERSION:-0}"
   bootloader_new="${BOOTLOADER_UPDATE_VERSION:-0}"
   vl805_cur="${VL805_CURRENT_VERSION}"
   vl805_new="${VL805_UPDATE_VERSION}"

    if [ "${JSON_OUTPUT}" = "no" ]; then
      [ "${HAVE_VL805_EEPROM}" = "0" ] && vl805_eeprom="no" || vl805_eeprom="yes"
      cat > "${MACHINE_OUTPUT}" <<EOF
EXITCODE="${exit_code}"
BOOTLOADER_CURRENT=${bootloader_cur}
BOOTLOADER_LATEST=${bootloader_new}
VL805_CURRENT="${vl805_cur}"
VL805_LATEST="${vl805_new}"
VL805_EEPROM="${vl805_eeprom}"
EOF
   else
      [ "${HAVE_VL805_EEPROM}" = "0" ] && vl805_eeprom="false" || vl805_eeprom="true"
      cat > "${MACHINE_OUTPUT}" <<EOF
{
  "EXITCODE": "${exit_code}",
  "BOOTLOADER_CURRENT": ${bootloader_cur},
  "BOOTLOADER_LATEST": ${bootloader_new},
  "VL805_CURRENT": "${vl805_cur}",
  "VL805_LATEST": "${vl805_new}",
  "VL805_EEPROM": ${vl805_eeprom}
}
EOF
   fi
   return 0
}

AUTO_UPDATE_BOOTLOADER=0
AUTO_UPDATE_VL805=0
MACHINE_OUTPUT=""
JSON_OUTPUT="no"
IGNORE_DPKG_CHECKSUMS=$LOCAL_MODE

while getopts A:adhif:m:ju:r option; do
   case "${option}" in
   A)
      if [ "${OPTARG}" = "bootloader" ]; then
         AUTO_UPDATE_BOOTLOADER=1
      elif [ "${OPTARG}" = "vl805" ]; then
         AUTO_UPDATE_VL805=1
      else
         die "Unknown update mode: ${OPTARG}"
      fi
      ;;
   a) AUTO_UPDATE_BOOTLOADER=1
      AUTO_UPDATE_VL805=1
      ;;
   d) OVERWRITE_CONFIG=1
      ;;
   f) BOOTLOADER_UPDATE_IMAGE="${OPTARG}"
      ;;
   i) IGNORE_DPKG_CHECKSUMS=1
      ;;
   j) JSON_OUTPUT="yes"
      ;;
   m) MACHINE_OUTPUT="${OPTARG}"
      ;;
   h) usage
      ;;
   r) [ "$(id -u)" = "0" ] || die "* Must be run as root - try 'sudo rpi-eeprom-update -r'"
      echo "Removing temporary files from previous EEPROM update"
      removePreviousUpdates
      exit 0
      ;;
   u) VL805_UPDATE_IMAGE="${OPTARG}"
      ;;
   *) echo "Unknown argument \"${option}\""
      usage
      ;;
   esac
done

checkDependencies
if [ "${AUTO_UPDATE_BOOTLOADER}" = 1 ] || [ "${AUTO_UPDATE_VL805}" = 1 ]; then
   if vcgencmd bootloader_config | grep FREEZE_VERSION=1; then
      echo "EEPROM version is frozen. Skipping update"
      exit ${EXIT_EEPROM_FROZEN}
   else
      checkAndApply
   fi
elif [ -n "${BOOTLOADER_UPDATE_IMAGE}" ] || [ -n "${VL805_UPDATE_IMAGE}" ]; then
   fileUpdate
else
   checkVersion
fi
