diff --git a/firmware/critical/pieeprom-2019-05-10.bin b/firmware/beta/pieeprom-2019-10-08.bin similarity index 71% rename from firmware/critical/pieeprom-2019-05-10.bin rename to firmware/beta/pieeprom-2019-10-08.bin index c0f6caf..368b2ad 100644 Binary files a/firmware/critical/pieeprom-2019-05-10.bin and b/firmware/beta/pieeprom-2019-10-08.bin differ diff --git a/firmware/beta/pieeprom-2019-10-16.bin b/firmware/beta/pieeprom-2019-10-16.bin new file mode 100644 index 0000000..1c8925d Binary files /dev/null and b/firmware/beta/pieeprom-2019-10-16.bin differ diff --git a/firmware/beta/recovery.bin b/firmware/beta/recovery.bin new file mode 100644 index 0000000..6d0378e Binary files /dev/null and b/firmware/beta/recovery.bin differ diff --git a/firmware/beta/vl805-00013701.bin b/firmware/beta/vl805-00013701.bin new file mode 100644 index 0000000..23230a3 Binary files /dev/null and b/firmware/beta/vl805-00013701.bin differ diff --git a/firmware/beta/vl805-000137ab.bin b/firmware/beta/vl805-000137ab.bin new file mode 100644 index 0000000..8874e54 Binary files /dev/null and b/firmware/beta/vl805-000137ab.bin differ diff --git a/firmware/beta/vl805.latest b/firmware/beta/vl805.latest new file mode 100644 index 0000000..00b6cc4 --- /dev/null +++ b/firmware/beta/vl805.latest @@ -0,0 +1 @@ +000137ab diff --git a/firmware/recovery.bin b/firmware/critical/recovery.bin similarity index 100% rename from firmware/recovery.bin rename to firmware/critical/recovery.bin diff --git a/firmware/raspberry_pi4_network_boot_beta.md b/firmware/raspberry_pi4_network_boot_beta.md index 97c2f10..8e680ab 100644 --- a/firmware/raspberry_pi4_network_boot_beta.md +++ b/firmware/raspberry_pi4_network_boot_beta.md @@ -127,3 +127,14 @@ Optional dotted decimal ip address (e.g. 192.169.1.99) for the TFTP server which This maybe useful on home networks because tftpd-hpa can be used instead of dnsmasq where broadband router is the DHCP server. Default: "" +### TFTP_PREFIX (since 2019-10-08) +Configure the TFTP prefix string to probe +* 0 - The serial number +* 1 - The value of TFTP_PREFIX_STR +* 2 - The mac-address separated by dashes (lower case) +Default: 0 + +### TFTP_PREFIX_STR (since 2019-10-08) +The prefix string to use with TFTP_PREFIX=1 - up to 127 characters. +Default: "" + diff --git a/firmware/release-notes.md b/firmware/release-notes.md index 202e93a..2e587e5 100644 --- a/firmware/release-notes.md +++ b/firmware/release-notes.md @@ -1,5 +1,26 @@ # Raspberry Pi4 bootloader EEPROM release notes +## 2019-10-17 - rpi-eeprom-update + recovery.bin + * New beta recovery.bin which can update the VLI EEPROM before + start.elf is loaded. This is the recommended and default method + because no USB devices will be in use at this stage. + * Extend the USE_FLASHROM configuration to use the vl805 tool + to program the VL805 directly. + * Generate SHA256 checksums in .sig files for the bootloader and + and VL805 images. This is required by the new recovery.bin to + guard against corrupted files being flashed to the EEPROM(s). + * Various variable renames to distinguish between the bootloader + and the VL805 images. + +## 2019-10-16 - Git 18472066 (BETA) + * Ignore trailing characters when parsing in PXE boot menu option. + * Improve error handling with unformatted sd-cards. +## 2019-10-08 - Git 26dd3686c (BETA) + * TFTP now uses RFC2348 blksize option to get 1024 byte blocks if the server supports it. + * Fix DHCP handling of SI_ADDR + * TFTP_PREFIX and TFTP_PREFIX_STR options for mac-address or string literal prefix. + * Improved support for standard capacity and SDv1 cards. + ## 2019-09-25 - Git 4d9824321 (BETA) * Increase TFTP timeout to 30s as default & bootconf.txt * Fix intermittent boot freeze/slowdown issue after loading start.elf diff --git a/rpi-eeprom-config b/rpi-eeprom-config index 993793f..ac34921 100755 --- a/rpi-eeprom-config +++ b/rpi-eeprom-config @@ -10,6 +10,8 @@ import sys IMAGE_SIZE = 512 * 1024 +MAX_BOOTCONF_SIZE = 2024 + # Each section starts with a magic number followed by a 32 bit offset to the # next section (big-endian). # The number, order and size of the sections depends on the bootloader version @@ -55,8 +57,9 @@ class BootloaderImage(object): hdr_offset, length = self.find_config() new_config_bytes = open(new_config, 'rb').read() new_len = len(new_config_bytes) + FILENAME_LEN + 4 - if new_len > length and new_len > 1024: - raise Exception('Config is too large') + if len(new_config_bytes) > MAX_BOOTCONF_SIZE: + raise Exception("Config is too large (%d bytes). The maximum size is %d bytes." + % (len(new_config_bytes), MAX_BOOTCONF_SIZE)) if hdr_offset + len(new_config_bytes) + FILE_HDR_LEN > IMAGE_SIZE: raise Exception('EEPROM image size exceeded') diff --git a/rpi-eeprom-update b/rpi-eeprom-update index 76a261f..6dad164 100755 --- a/rpi-eeprom-update +++ b/rpi-eeprom-update @@ -16,8 +16,9 @@ FIRMWARE_ROOT=${FIRMWARE_ROOT:-/lib/firmware/raspberrypi/bootloader} 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}/recovery.bin} +RECOVERY_BIN=${RECOVERY_BIN:-${FIRMWARE_ROOT}/${FIRMWARE_RELEASE_STATUS}/recovery.bin} BOOTFS=${BOOTFS:-/boot} EXIT_SUCCESS=0 @@ -31,7 +32,7 @@ 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 -FIRST_VERSION=1557513636 +BOOTLOADER_FIRST_VERSION=1557513636 EEPROM_SIZE=524288 # Simple bootloader which is able to load start.elf in the event of a power @@ -41,6 +42,13 @@ EEPROM_SIZE=524288 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}" @@ -65,9 +73,7 @@ die() { prepareImage() { - eeprom_image="$1" - - [ -f "${eeprom_image}" ] || die "EEPROM image \'${eeprom_image}\' not found" + [ -f "${BOOTLOADER_UPDATE_IMAGE}" ] || die "EEPROM image \'${BOOTLOADER_UPDATE_IMAGE}\' not found" TMP_EEPROM_IMAGE="$(mktemp)" TMP_EEPROM_CONFIG="$(mktemp)" @@ -85,98 +91,122 @@ prepareImage() OVERWRITE_CONFIG=1 fi - cp -f "${eeprom_image}" "${TMP_EEPROM_IMAGE}" + cp -f "${BOOTLOADER_UPDATE_IMAGE}" "${TMP_EEPROM_IMAGE}" if [ "${OVERWRITE_CONFIG}" = 0 ]; then "${script_dir}/rpi-eeprom-config" \ --out "${TMP_EEPROM_IMAGE}" \ - --config "${TMP_EEPROM_CONFIG}" "${eeprom_image}" + --config "${TMP_EEPROM_CONFIG}" "${BOOTLOADER_UPDATE_IMAGE}" fi } applyRecoveryUpdate() { - eeprom_image="$1" - [ -f "${eeprom_image}" ] || die "${eeprom_image} not found" - TMP_EEPROM_IMAGE="$(mktemp)" + [ -n "${BOOTLOADER_UPDATE_IMAGE}" ] || [ -n "${VL805_UPDATE_IMAGE}" ] || die "No update images specified" findBootFS - prepareImage "${eeprom_image}" - # 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. - cp -f "${TMP_EEPROM_IMAGE}" "${BOOTFS}/pieeprom.upd" \ - || die "Failed to copy ${TMP_EEPROM_IMAGE} to ${BOOTFS}" + # 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() { - eeprom_image="$1" - [ "$(id -u)" = "0" ] || die "* Must be run as root - try 'sudo rpi-eeprom-update'" if [ "${USE_FLASHROM}" = 0 ]; then - applyRecoveryUpdate "${eeprom_image}" + applyRecoveryUpdate return fi - # Bootloader EEPROM chip-select is muxed with audio pin so disable audio - # LDO first to avoid sending noise to analog audio. - /opt/vc/bin/vcmailbox 0x00030056 4 4 0 > /dev/null || true - dtparam audio=off + if [ -f "${BOOTLOADER_UPDATE_IMAGE}" ]; then + # Bootloader EEPROM chip-select is muxed with audio pin so disable audio + # LDO first to avoid sending noise to analog audio. + /opt/vc/bin/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 + # Switch the SPI pins to boot EEPROM + dtoverlay spi-gpio40-45 + modprobe spidev + modprobe spi-bcm2835 - prepareImage "${eeprom_image}" + prepareImage "${BOOTLOADER_UPDATE_IMAGE}" - echo "Applying update ${eeprom_image}" - flashrom -p "linux_spi:dev=/dev/spidev0.0,spispeed=${SPI_SPEED}" -w "${TMP_EEPROM_IMAGE}" || die "flashrom EEPROM update failed" + echo "Applying bootloaer 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 - /opt/vc/bin/vcmailbox 0x00030056 4 4 1 > /dev/null || true + dtparam -R spi-gpio40-45 + dtparam audio=on + /opt/vc/bin/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. -CURRENT_VERSION= -getCurrentVersion() { +BOOTLOADER_CURRENT_VERSION= +getBootloaderCurrentVersion() { if vcgencmd bootloader_version | grep -q timestamp; then - CURRENT_VERSION=$(vcgencmd bootloader_version | grep timestamp | awk '{print $2}') - if [ "${CURRENT_VERSION}" = "0" ]; 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 - CURRENT_VERSION="${FIRST_VERSION}" + BOOTLOADER_CURRENT_VERSION="${BOOTLOADER_FIRST_VERSION}" fi else # New bootloader / old firmware ? Try to parse the date - CURRENT_VERSION=$(date -u +%s --date "$(vcgencmd bootloader_version | head -n1)") + 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 "${CURRENT_VERSION}" ]; then - CURRENT_VERSION="${FIRST_VERSION}" + if [ -z "${BOOTLOADER_CURRENT_VERSION}" ]; then + BOOTLOADER_CURRENT_VERSION="${BOOTLOADER_FIRST_VERSION}" fi } # Find latest applicable update version -UPDATE_IMAGE="" -UPDATE_VERSION=0 -getUpdateVersion() { - UPDATE_VERSION=0 +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 - UPDATE_VERSION=$(strings "${latest}" | grep BUILD_TIMESTAMP | sed 's/.*=//g') - UPDATE_IMAGE="${latest}" + BOOTLOADER_UPDATE_VERSION=$(strings "${latest}" | grep BUILD_TIMESTAMP | sed 's/.*=//g') + BOOTLOADER_UPDATE_IMAGE="${latest}" fi } @@ -192,12 +222,20 @@ checkDependencies() { die "Bootloader updates directory ${FIRMWARE_IMAGE_DIR} not found." fi + if ! command -v vl805 -h > /dev/null 2>&1; then + die "vl805 command not found" + fi + if vcgencmd bootloader_config | grep -qi "Command not registered"; then - die "vcgencmd: 'bootloader_config' command not supported. Please update VC firmware" + die "vcgencmd: 'bootloader_config' command not supported. Please update VC firmware and reboot." fi - if ! flashrom --version > /dev/null 2>&1; then - [ "${USE_FLASHROM}" = 0 ] || die "flashrom not found." + if ! command -v sha256sum > /dev/null 2>&1; then + die "sha256sum not found. On Debian, try installing the coreutilities package" + fi + + if ! command -v flashrom > /dev/null 2>&1; then + [ "${USE_FLASHROM}" = 0 ] || die "flashrom not found. On Debian, try installing the flashrom package." fi if [ "${USE_FLASHROM}" = 0 ]; then @@ -208,18 +246,24 @@ checkDependencies() { usage() { cat < "${MACHINE_OUTPUT}" < "${MACHINE_OUTPUT}" <&2 + exit 1 +} + +FIRMWARE_DIR="${script_dir}/../firmware" +CONFIG="/etc/default/rpi-eeprom-update" + +[ "$(id -u)" = "0" ] || die "$0 Must be run as root - try 'sudo $0 [-b]'" + +cp -rfv "${FIRMWARE_DIR}"/* /lib/firmware/raspberrypi/bootloader +cp -fv "${script_dir}/../rpi-eeprom-config" /usr/bin +cp -fv "${script_dir}/../rpi-eeprom-update" /usr/bin +cp -fv "${script_dir}/../vl805" /usr/bin + +cp -fv "${script_dir}/../rpi-eeprom-update-default" /etc/default/rpi-eeprom-update + +if [ "$1" = "-b" ]; then + sed -i -e 's/^FIRMWARE_RELEASE_STATUS=.*/FIRMWARE_RELEASE_STATUS=beta/' "${CONFIG}" +fi diff --git a/test/test-rpi-eeprom-config b/test/test-rpi-eeprom-config index 9d72068..f56975a 100755 --- a/test/test-rpi-eeprom-config +++ b/test/test-rpi-eeprom-config @@ -107,6 +107,40 @@ check_update() fi } +# Verify that rpi-eeprom-config will apply and 2024 byte configuration file correctly. +check_conf_size_large() +{ + echo "check maximum config file size" + image="${script_dir}/$1" + conf="bootconf-2024.txt" + + expected_md5="$(md5sum "${conf}" | awk '{print $1}')" + + TMP_EEPROM="$(mktemp)" + "${script_dir}/../rpi-eeprom-config" \ + "${image}" \ + --config "${conf}" \ + --out "${TMP_EEPROM}" + + actual_md5="$("${script_dir}/../rpi-eeprom-config" "${TMP_EEPROM}" | md5sum | awk '{print $1}')" + [ "${actual_md5}" = "${expected_md5}" ] || die "EEPROM check large config: checksum mismatch" +} + +# Verify that rpi-eeprom-config will reject files exceeding 2024 bytes +check_conf_size_too_large() +{ + echo "check config file which exceeds the maximum size" + image="${script_dir}/$1" + conf="bootconf-2025.txt" + + expected_md5="$(md5sum "${conf}" | awk '{print $1}')" + + TMP_EEPROM="$(mktemp)" + if "${script_dir}/../rpi-eeprom-config" "${image}" --config "${conf}" --out "${TMP_EEPROM}" > /dev/null 2>&1; then + die "$config should have been rejected" + fi +} + check_loopback "../firmware/critical/pieeprom-2019-05-10.bin" "bootconf-2019-05-10.txt" cleanup @@ -118,3 +152,9 @@ cleanup check_reduce_size "../firmware/critical/pieeprom-2019-05-10.bin" "bootconf-2019-05-10.txt" cleanup + +check_conf_size_large "../firmware/critical/pieeprom-2019-05-10.bin" +cleanup + +check_conf_size_too_large "../firmware/critical/pieeprom-2019-05-10.bin" +cleanup diff --git a/vl805 b/vl805 new file mode 100755 index 0000000..d646de3 Binary files /dev/null and b/vl805 differ