mirror of
https://github.com/raspberrypi/rpi-update.git
synced 2026-01-20 21:13:38 +08:00
rpi-update: Add support for updating the bootloader EEPROM (#24)
* Download the latest EEPROM release to the local /lib/firmware/raspberrypi/bootloader directory * Update the rpi-eeprom tools * Remove the old eeprom_version check * Check bootloader commits as well as firwmware commits * SKIP_BOOTLOADER default to 1 for now until fully tested * Update recovery.bin if the bootloader revision has changed.
This commit is contained in:
223
rpi-update
223
rpi-update
@@ -15,6 +15,10 @@ REPO_URI=${REPO_URI:-"https://github.com/raspberrypi/rpi-firmware"}
|
||||
REPO_API_URI=${REPO_URI/github.com/api.github.com\/repos}
|
||||
REPO_CONTENT_URI=${REPO_URI/github.com/raw.githubusercontent.com}
|
||||
|
||||
BOOTLOADER_REPO_URI=${BOOTLOADER_REPO_URI:-"https://github.com/raspberrypi/rpi-eeprom"}
|
||||
BOOTLOADER_REPO_API_URI=${BOOTLOADER_REPO_URI/github.com/api.github.com\/repos}
|
||||
BOOTLOADER_REPO_CONTENT_URI=${BOOTLOADER_REPO_URI/github.com/raw.githubusercontent.com}
|
||||
|
||||
UPDATE_SELF=${UPDATE_SELF:-1}
|
||||
UPDATE_REPO_URI="https://github.com/raspberrypi/rpi-update"
|
||||
UPDATE_REPO_CONTENT_URI=${UPDATE_REPO_URI/github.com/raw.githubusercontent.com}
|
||||
@@ -55,6 +59,7 @@ else
|
||||
fi
|
||||
WORK_PATH=${WORK_PATH:-"${ROOT_PATH}/root"}
|
||||
SKIP_KERNEL=${SKIP_KERNEL:-}
|
||||
SKIP_BOOTLOADER=${SKIP_BOOTLOADER:-1}
|
||||
SKIP_FIRMWARE=${SKIP_FIRMWARE:-0}
|
||||
SKIP_SDK=${SKIP_SDK:-0}
|
||||
SKIP_VCLIBS=${SKIP_VCLIBS:-0}
|
||||
@@ -79,6 +84,8 @@ FW_MODPATH="${ROOT_PATH}/lib/modules"
|
||||
FW_REV_IN=${1:-""}
|
||||
FW_REVFILE="${FW_PATH}/.firmware_revision"
|
||||
SELFUPDATE_SCRIPT="${WORK_PATH}/.updateScript.sh"
|
||||
BOOTLOADER_REV_IN=${2:-""}
|
||||
BOOTLOADER_REVFILE="${FW_PATH}/.bootloader_revision"
|
||||
|
||||
[ "${RPI_UPDATE_UNSUPPORTED}" -ne 0 ] && echo -e "You appear to be trying to update firmware on an incompatible distribution. To force update, run the following:\nsudo -E RPI_UPDATE_UNSUPPORTED=0 rpi-update" && exit 1
|
||||
|
||||
@@ -138,7 +145,7 @@ function update_self() {
|
||||
cat > "${SELFUPDATE_SCRIPT}" << EOF
|
||||
if mv "${_tempFileName}" "$0"; then
|
||||
rm -- "\$0"
|
||||
exec env UPDATE_SELF=0 /bin/bash "$0" "${FW_REV_IN}"
|
||||
exec env UPDATE_SELF=0 /bin/bash "$0" "${FW_REV_IN}" "${BOOTLOADER_REV_IN}"
|
||||
else
|
||||
echo " !!! Failed!"
|
||||
fi
|
||||
@@ -233,70 +240,91 @@ function update_sdk {
|
||||
fi
|
||||
}
|
||||
|
||||
# Check if the bootloader is older than the latest critical release. An old
|
||||
# bootloader shouldn't block rpi-update so just inform the user that bootloader
|
||||
# is out of date.
|
||||
function check_eeprom_version {
|
||||
local CURRENT_VERSION=""
|
||||
local FIRST_VERSION=1557513636
|
||||
# MIN VERSION for Sep 10 2019 EEPROM
|
||||
local MIN_VERSION=1568112110
|
||||
local HAVE_BOOTLOADER_EEPROM=0
|
||||
function download_bootloader_tools {
|
||||
for tool in rpi-eeprom-update rpi-eeprom-config rpi-eeprom-digest; do
|
||||
temp="$(mktemp)"
|
||||
if ! eval curl -fs ${CURL_OPTIONS} "${BOOTLOADER_REPO_CONTENT_URI}/${BOOTLOADER_REV}/${tool}" --output "${temp}"; then
|
||||
echo " !!! Failed to download ${tool}"
|
||||
rm -f "${temp}"
|
||||
exit 1
|
||||
fi
|
||||
mv "${temp}" "/usr/bin/${tool}"
|
||||
chmod a+rx "/usr/bin/${tool}"
|
||||
done
|
||||
}
|
||||
|
||||
# Skip EEPROM check if vcgencmd is missing because it won't be possible to
|
||||
# check the version.
|
||||
if ! command -v vcgencmd > /dev/null; then
|
||||
return
|
||||
function download_bootloader_images {
|
||||
bcm_chip=$1
|
||||
latest_eeprom=$(eval curl -fs ${CURL_OPTIONS} ${BOOTLOADER_REPO_API_URI}/git/trees/${BOOTLOADER_REV}?recursive=1 | grep "firmware-${bcm_chip}/latest/pieeprom" | sed 's/.*\(pieeprom.*\)".*/\1/' | sort -r | head -n1)
|
||||
if [[ -n "${latest_eeprom}" ]]; then
|
||||
fw_path="/lib/firmware/raspberrypi/bootloader-${bcm_chip}/latest"
|
||||
if [[ ! -d "${fw_path}" ]]; then
|
||||
echo "Path ${fw_path} not found. Please install the rpi-eeprom package first"
|
||||
exit 1
|
||||
fi
|
||||
if [[ "${BOOTLOADER_REV_IN}" != "master" ]]; then
|
||||
echo "Non default bootloader revision specified (${BOOTLOADER_REV_IN}) deleting local bootloader binaries in ${fw_path}"
|
||||
rm -rf "${fw_path}"
|
||||
mkdir -p "${fw_path}"
|
||||
fi
|
||||
if [[ ! -f "${fw_path}/${latest_eeprom}" ]]; then
|
||||
eeprom_temp="$(mktemp)"
|
||||
if ! eval curl -fs ${CURL_OPTIONS} "${BOOTLOADER_REPO_CONTENT_URI}/${BOOTLOADER_REV}/firmware-${bcm_chip}/latest/${latest_eeprom}" --output "${eeprom_temp}"; then
|
||||
echo " !!! Failed to download firmware-${bcm_chip}/${latest_eeprom}"
|
||||
rm -rf "${eeprom_temp}"
|
||||
exit 1
|
||||
fi
|
||||
mv "${eeprom_temp}" "${fw_path}/${latest_eeprom}"
|
||||
chmod a+r "${fw_path}/${latest_eeprom}"
|
||||
fi
|
||||
|
||||
rev=
|
||||
if [ -f /proc/cpuinfo ]; then
|
||||
rev="$(sed -n '/^Revision/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo)"
|
||||
# Always download the latest recovery.bin if bootloader_rev has changed.
|
||||
recovery_temp="$(mktemp)"
|
||||
if ! eval curl -fs ${CURL_OPTIONS} "${BOOTLOADER_REPO_CONTENT_URI}/${BOOTLOADER_REV}/firmware-${bcm_chip}/latest/recovery.bin" --output "${recovery_temp}"; then
|
||||
echo " !!! Failed to download ${bcm_chip}/recovery.bin"
|
||||
rm -rf "${recovery_temp}"
|
||||
exit 1
|
||||
fi
|
||||
mv "${recovery_temp}" "${fw_path}/recovery.bin"
|
||||
chmod a+r "${fw_path}/recovery.bin"
|
||||
fi
|
||||
}
|
||||
|
||||
if [ -n $rev ] && [ $(((0x$rev >> 23) & 1)) -ne 0 ] && [ $(((0x$rev >> 12) & 15)) -eq 3 ]; then
|
||||
HAVE_BOOTLOADER_EEPROM=1
|
||||
fi
|
||||
function download_bootloader {
|
||||
if [[ ${SKIP_BOOTLOADER} -eq 0 ]]; then
|
||||
echo "Downloading bootloader tools"
|
||||
download_bootloader_tools
|
||||
|
||||
if [ "${HAVE_BOOTLOADER_EEPROM}" != 1 ]; then
|
||||
return
|
||||
echo "Downloading bootloader images"
|
||||
if grep -q "bcm2711" /proc/device-tree/compatible; then
|
||||
download_bootloader_images 2711
|
||||
fi
|
||||
if grep -q "bcm2712" /proc/device-tree/compatible; then
|
||||
download_bootloader_images 2712
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# vcgencmd doesn't return non-zero for unknown commands.
|
||||
if vcgencmd bootloader_config | grep -qi "Command not registered"; then
|
||||
# Firmware is too old to return the bootloader config
|
||||
return
|
||||
function update_bootloader {
|
||||
if [[ ${SKIP_BOOTLOADER} -eq 0 ]]; then
|
||||
sed /etc/default/rpi-eeprom-update -i -e "s/^FIRMWARE_RELEASE_STATUS.*/FIRMWARE_RELEASE_STATUS=\"latest\"/"
|
||||
if [[ "${BOOTLOADER_REV_IN}" != "master" ]]; then
|
||||
# Use latest according to rpi-eeprom git hash
|
||||
echo "Using latest bootloader from rpi-eeprom ${BOOTLOADER_REV_IN}"
|
||||
config_temp="$(mktemp)"
|
||||
if ! rpi-eeprom-config > "${config_temp}"; then
|
||||
echo "Failed to read current bootloader config"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# If FREEZE_VERSION is specified then assume that the user doesn't want
|
||||
# an EEPROM update so skip the check.
|
||||
if vcgencmd bootloader_config | grep -q FREEZE_VERSION=1; then
|
||||
return
|
||||
if ! rpi-eeprom-config -a "${config_temp}"; then
|
||||
echo "Failed to update bootloader - rpi-eeprom-rev ${BOOTLOADER_REV_IN}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if vcgencmd bootloader_version | grep -q timestamp; then
|
||||
CURRENT_VERSION=$(vcgencmd bootloader_version | grep timestamp | awk '{print $2}')
|
||||
if [ "${CURRENT_VERSION}" = "0" ]; then
|
||||
# If a timestamp of zero is returned then it's new firmware but an
|
||||
# old bootloader. Assume bootloader v0
|
||||
CURRENT_VERSION="${FIRST_VERSION}"
|
||||
fi
|
||||
elif vcgencmd bootloader_version | grep -qi "unknown"; then
|
||||
return
|
||||
rm -f "${config_temp}"
|
||||
else
|
||||
# New bootloader / old firmware ? Try to parse the date
|
||||
CURRENT_VERSION=$(date -u +%s --date "$(vcgencmd bootloader_version | head -n1)")
|
||||
# Update if newer
|
||||
rpi-eeprom-update -a
|
||||
fi
|
||||
|
||||
# Failed to parse the version. Default to the initial production release.
|
||||
if [ -z "${CURRENT_VERSION}" ]; then
|
||||
CURRENT_VERSION="${FIRST_VERSION}"
|
||||
fi
|
||||
|
||||
if [ "${CURRENT_VERSION}" -lt "${MIN_VERSION}" ]; then
|
||||
echo "A newer bootloader EEPROM version is available."
|
||||
echo "On Debian, try: sudo apt update; sudo apt install rpi-eeprom"
|
||||
echo "then reboot to install the new bootloader"
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -316,8 +344,8 @@ function show_notice {
|
||||
if ${NOTICE_HASH_EXISTS}; then
|
||||
local NOTICE=$(echo "${FULL_NOTICE}" | tail -n+2)
|
||||
local NEW_HASH=${FW_REV}
|
||||
local LOCAL_lt_NOTICE=$(compare_hashes "${LOCAL_HASH}" lt "${NOTICE_HASH}")
|
||||
local NEW_ge_NOTICE=$(compare_hashes "${NEW_HASH}" ge "${NOTICE_HASH}")
|
||||
local LOCAL_lt_NOTICE=$(compare_hashes "${REPO_API_URI}" "${LOCAL_HASH}" lt "${NOTICE_HASH}")
|
||||
local NEW_ge_NOTICE=$(compare_hashes "${REPO_API_URI}" "${NEW_HASH}" ge "${NOTICE_HASH}")
|
||||
if ! ${LOCAL_lt_NOTICE} && ! ${NEW_ge_NOTICE}; then
|
||||
return
|
||||
fi
|
||||
@@ -455,6 +483,7 @@ function finalise {
|
||||
fi
|
||||
echo " *** Storing current firmware revision"
|
||||
echo "${FW_REV}" > "${FW_REVFILE}"
|
||||
echo "${BOOTLOADER_REV}" > "${BOOTLOADER_REVFILE}"
|
||||
}
|
||||
|
||||
function do_backup {
|
||||
@@ -509,13 +538,14 @@ function do_update {
|
||||
check_partition 256
|
||||
fi
|
||||
check_initramfs
|
||||
check_eeprom_version
|
||||
show_notice
|
||||
download_bootloader
|
||||
download_rev
|
||||
if [[ -f "${FW_REPOLOCAL}/pre-install" ]]; then
|
||||
echo " *** Running pre-install script"
|
||||
source "${FW_REPOLOCAL}/pre-install"
|
||||
fi
|
||||
update_bootloader
|
||||
update_firmware
|
||||
update_modules
|
||||
update_vc_libs
|
||||
@@ -624,14 +654,14 @@ function noobs_fix {
|
||||
}
|
||||
|
||||
function get_hash_date {
|
||||
local COMMITS_URI=${REPO_API_URI}/commits/$1
|
||||
local COMMITS_URI=${1}/commits/$2
|
||||
eval curl ${CURL_OPTIONS_API} -s ${CURL_OPTIONS} "${COMMITS_URI}" | grep "date" | head -1 | awk -F\" '{print $4}'
|
||||
}
|
||||
|
||||
function compare_hashes {
|
||||
local DATE1=$(get_hash_date "$1")
|
||||
local DATE2=$(get_hash_date "$3")
|
||||
if [ $(date -d "${DATE1}" +%s) -$2 $(date -d "${DATE2}" +%s) ]; then
|
||||
local DATE1=$(get_hash_date "${1}" "$2")
|
||||
local DATE2=$(get_hash_date "${1}" "$4")
|
||||
if [ $(date -d "${DATE1}" +%s) -$3 $(date -d "${DATE2}" +%s) ]; then
|
||||
echo true
|
||||
else
|
||||
echo false
|
||||
@@ -640,10 +670,16 @@ function compare_hashes {
|
||||
|
||||
function get_long_hash {
|
||||
# ask github for long version hash
|
||||
local COMMITS_URI=${REPO_API_URI}/commits/$1
|
||||
local COMMITS_URI=${1}/commits/$2
|
||||
eval curl ${CURL_OPTIONS_API} -s ${CURL_OPTIONS} "${COMMITS_URI}" | awk 'BEGIN {hash=""} { if (hash == "" && $1 == "\"sha\":") {hash=substr($2, 2, 40);} } END {print hash}'
|
||||
}
|
||||
|
||||
function print_diffs {
|
||||
local diff_uri="$1"
|
||||
SEPARATOR="======================================================"
|
||||
eval curl ${CURL_OPTIONS_API} -s ${CURL_OPTIONS} "${diff_uri}" | awk -v SEPARATOR="${SEPARATOR}" -F\" ' { if ($2 == "commits") {commits=1} if (commits && $2 == "message") {print SEPARATOR "\nCommit: " $4} }' | sed 's/\\n\\n/\nCommit:\ /g'
|
||||
}
|
||||
|
||||
|
||||
if [[ ${EUID} -ne 0 ]]; then
|
||||
echo " !!! This tool must be run as root"
|
||||
@@ -688,15 +724,28 @@ if [[ "${FW_REV_IN}" == "" ]]; then
|
||||
FW_REV_IN=${BRANCH}
|
||||
fi
|
||||
|
||||
if [[ "${BOOTLOADER_REV_IN}" == "" ]]; then
|
||||
BOOTLOADER_REV_IN=${BRANCH}
|
||||
fi
|
||||
|
||||
ARTIFACT=""
|
||||
BUILD=""
|
||||
FW_REV=""
|
||||
if [[ ${FW_REV_IN} != http* ]] && [[ ! -f ${FW_REV_IN} ]]; then
|
||||
FW_REV=$(get_long_hash "${FW_REV_IN}")
|
||||
FW_REV=$(get_long_hash "${REPO_API_URI}" "${FW_REV_IN}")
|
||||
fi
|
||||
|
||||
echo FW_REV:$FW_REV
|
||||
|
||||
BOOTLOADER_REV=""
|
||||
BOOTLOADER_LOCAL_HASH=""
|
||||
if [[ ${SKIP_BOOTLOADER} -eq 0 ]]; then
|
||||
if [[ ${BOOTLOADER_REV_IN} != http* ]] && [[ ! -f ${BOOTLOADER_REV_IN} ]]; then
|
||||
BOOTLOADER_REV=$(get_long_hash "${BOOTLOADER_REPO_API_URI}" "${BOOTLOADER_REV_IN}")
|
||||
fi
|
||||
echo BOOTLOADER_REV:$BOOTLOADER_REV
|
||||
fi
|
||||
|
||||
if [[ "${FW_REV}" == "" ]]; then
|
||||
if [[ ${FW_REV_IN} != http* ]] && [[ ! -f ${FW_REV_IN} ]]; then
|
||||
IFS=':' read ARTIFACT BUILD <<<${FW_REV_IN}
|
||||
@@ -735,23 +784,59 @@ if [[ ! -f "${FW_REVFILE}" ]]; then
|
||||
else
|
||||
if [[ "${ARTIFACT}" != "" ]]; then
|
||||
LOCAL_HASH=$(cat "${FW_REVFILE}")
|
||||
if [[ "${SKIP_BOOTLOADER}" -eq 0 ]]; then
|
||||
BOOTLOADER_LOCAL_HASH=$(cat "${BOOTLOADER_REVFILE}")
|
||||
fi
|
||||
else
|
||||
LOCAL_HASH=$(get_long_hash "$(cat "${FW_REVFILE}")")
|
||||
LOCAL_HASH=$(get_long_hash ${REPO_API_URI} "$(cat "${FW_REVFILE}")")
|
||||
if [[ "${SKIP_BOOTLOADER}" -eq 0 ]]; then
|
||||
if [[ ! -f "${BOOTLOADER_REVFILE}" ]]; then
|
||||
BOOTLOADER_LOCAL_HASH=0
|
||||
else
|
||||
BOOTLOADER_LOCAL_HASH=$(get_long_hash "${BOOTLOADER_REPO_API_URI}" "$(cat "${BOOTLOADER_REVFILE}")")
|
||||
fi
|
||||
if [[ "${LOCAL_HASH}" == "${FW_REV}" ]]; then
|
||||
echo " *** Your firmware is already up to date (delete ${FW_REVFILE} to force an update anyway)"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "${LOCAL_HASH}" == "${FW_REV}" && "${BOOTLOADER_LOCAL_HASH}" == "${BOOTLOADER_REV}" ]] ; then
|
||||
echo " *** Your firmware is already up to date (delete ${FW_REVFILE} and ${BOOTLOADER_REVFILE} to force an update anyway)"
|
||||
exit 0
|
||||
else
|
||||
if [[ "${LOCAL_HASH}" == "${FW_REV}" ]]; then
|
||||
# Skip other components if only the bootloader has changed
|
||||
SKIP_FIRMWARE=1
|
||||
SKIP_KERNEL=1
|
||||
SKIP_VCLIBS=1
|
||||
SKIP_SDK=1
|
||||
SKIP_DOWNLOAD=1
|
||||
ARTIFACT=""
|
||||
elif [[ "${BOOTLOADER_LOCAL_HASH}" == "${BOOTLOADER_REV}" ]] ; then
|
||||
SKIP_BOOTLOADER=1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ ${JUST_CHECK} -ne 0 ]]; then
|
||||
if $(compare_hashes "${LOCAL_HASH}" lt "${FW_REV}"); then
|
||||
if $(compare_hashes "${REPO_API_URI}" "${LOCAL_HASH}" lt "${FW_REV}"); then
|
||||
echo " *** Firmware update required. New commits available:"
|
||||
DIFF_URI=${REPO_API_URI}/compare/${LOCAL_HASH}...${FW_REV}
|
||||
else
|
||||
print_diffs "${DIFF_URI}"
|
||||
elif $(compare_hashes "${REPO_API_URI}" "${LOCAL_HASH}" gt "${FW_REV}"); then
|
||||
echo " *** Firmware downgrade requested. Commits to drop:"
|
||||
DIFF_URI=${REPO_API_URI}/compare/${FW_REV}...${LOCAL_HASH}
|
||||
print_diffs "${DIFF_URI}"
|
||||
fi
|
||||
|
||||
if [[ ${SKIP_BOOTLOADER} -eq 0 ]]; then
|
||||
if $(compare_hashes "${BOOTLOADER_REPO_API_URI}" "${BOOTLOADER_LOCAL_HASH}" lt "${BOOTLOADER_REV}"); then
|
||||
echo " *** Bootloader update required. New commits available:"
|
||||
DIFF_URI=${BOOTLOADER_REPO_API_URI}/compare/${BOOTLOADER_LOCAL_HASH}...${BOOTLOADER_REV}
|
||||
print_diffs "${DIFF_URI}"
|
||||
elif $(compare_hashes "${BOOTLOADER_REPO_API_URI}" "${BOOTLOADER_LOCAL_HASH}" gt "${BOOTLOADER_REV}"); then
|
||||
echo " *** Bootloader downgrade requested. Commits to drop:"
|
||||
DIFF_URI=${BOOTLOADER_REPO_API_URI}/compare/${BOOTLOADER_REV}...${BOOTLOADER_LOCAL_HASH}
|
||||
print_diffs "${DIFF_URI}"
|
||||
fi
|
||||
fi
|
||||
SEPARATOR="======================================================"
|
||||
eval curl ${CURL_OPTIONS_API} -s ${CURL_OPTIONS} "${DIFF_URI}" | awk -v SEPARATOR="${SEPARATOR}" -F\" ' { if ($2 == "commits") {commits=1} if (commits && $2 == "message") {print SEPARATOR "\nCommit: " $4} }' | sed 's/\\n\\n/\nCommit:\ /g'
|
||||
exit 2
|
||||
fi
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user