From 49a2a4f22eec755b8c0377b20a5ecbfee089643e Mon Sep 17 00:00:00 2001 From: tim Date: Sun, 17 Jan 2021 16:43:49 +0000 Subject: [PATCH] pieeprom-2021-01-16: Update to latest release for BCM2711 XHCI boot --- recovery/boot.conf | 9 +++++++++ recovery/bootcode4.bin | Bin 98208 -> 0 bytes recovery/pieeprom-2021-01-16.bin | Bin 0 -> 524288 bytes recovery/pieeprom.bin | Bin 524288 -> 0 bytes recovery/pieeprom.original.bin | 1 + recovery/pieeprom.sig | 3 ++- recovery/rpi-eeprom-config | 347 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ recovery/update-pieeprom.sh | 15 +++++++++++++++ win32/rpiboot_setup.exe | Bin 8427005 -> 0 bytes 9 files changed, 374 insertions(+), 1 deletion(-) create mode 100644 recovery/boot.conf create mode 100644 recovery/pieeprom-2021-01-16.bin create mode 120000 recovery/pieeprom.original.bin create mode 100755 recovery/rpi-eeprom-config create mode 100755 recovery/update-pieeprom.sh diff --git a/recovery/boot.conf b/recovery/boot.conf new file mode 100644 index 0000000..8988878 --- /dev/null +++ b/recovery/boot.conf @@ -0,0 +1,9 @@ +[all] +BOOT_UART=0 +WAKE_ON_GPIO=1 +POWER_OFF_ON_HALT=0 +# Disable bootloader updates from USB MSD & network. +ENABLE_SELF_UPDATE=0 +# SD, PCIe USB MSD, BCM2711 USB MSD, LOOP +BOOT_ORDER=0xf541 + diff --git a/recovery/bootcode4.bin b/recovery/bootcode4.bin index 3a4d201..a5864e2 100644 Binary files a/recovery/bootcode4.bin and b/recovery/bootcode4.bin differ diff --git a/recovery/pieeprom-2021-01-16.bin b/recovery/pieeprom-2021-01-16.bin new file mode 100644 index 0000000..72ca170 Binary files /dev/null and b/recovery/pieeprom-2021-01-16.bin differ diff --git a/recovery/pieeprom.bin b/recovery/pieeprom.bin index 9ad8bbf..8400558 100644 Binary files a/recovery/pieeprom.bin and b/recovery/pieeprom.bin differ diff --git a/recovery/pieeprom.original.bin b/recovery/pieeprom.original.bin new file mode 120000 index 0000000..ac1540f --- /dev/null +++ b/recovery/pieeprom.original.bin @@ -0,0 +1 @@ +pieeprom-2021-01-16.bin \ No newline at end of file diff --git a/recovery/pieeprom.sig b/recovery/pieeprom.sig index 464bf01..b8486c2 100644 --- a/recovery/pieeprom.sig +++ b/recovery/pieeprom.sig @@ -1 +1,2 @@ -14362fccbe836696bffea7e3b6eeb1b52c29fe9361a2851d08cd11869b43cb91 +4fe4dee06b4401da28cec09c9bae1ab76b7994525f4e5c36a06adb9a2ffb5429 +ts: 1610965456 diff --git a/recovery/rpi-eeprom-config b/recovery/rpi-eeprom-config new file mode 100755 index 0000000..7a5f632 --- /dev/null +++ b/recovery/rpi-eeprom-config @@ -0,0 +1,347 @@ +#!/usr/bin/env python + +""" +rpi-eeprom-config +""" + +import argparse +import atexit +import os +import subprocess +import struct +import sys +import tempfile +import time + +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 +# but the following mask can be used to test for section headers and skip +# unknown data. +# +# The last 4KB of the EEPROM image is reserved for internal use by the +# bootloader and may be overwritten during the update process. +MAGIC = 0x55aaf00f +MAGIC_MASK = 0xfffff00f +FILE_MAGIC = 0x55aaf11f # id for modifiable file, currently only bootconf.txt +FILE_HDR_LEN = 20 +FILENAME_LEN = 12 +TEMP_DIR = None + +def exit_handler(): + """ + Delete any temporary files. + """ + if TEMP_DIR is not None and os.path.exists(TEMP_DIR): + tmp_image = os.path.join(TEMP_DIR, 'pieeprom.upd') + if os.path.exists(tmp_image): + os.remove(tmp_image) + tmp_conf = os.path.join(TEMP_DIR, 'boot.conf') + if os.path.exists(tmp_conf): + os.remove(tmp_conf) + os.rmdir(TEMP_DIR) + +def create_tempdir(): + global TEMP_DIR + if TEMP_DIR is None: + TEMP_DIR = tempfile.mkdtemp() + +def exit_error(msg): + """ + Trapped a fatal error, output message to stderr and exit with non-zero + return code. + """ + sys.stderr.write("ERROR: %s\n" % msg) + sys.exit(1) + +def shell_cmd(args): + """ + Executes a shell command waits for completion returning STDOUT. If an + error occurs then exit and output the subprocess stdout, stderr messages + for debug. + """ + start = time.time() + arg_str = ' '.join(args) + result = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + + while time.time() - start < 5: + if result.poll() is not None: + break + + if result.poll() is None: + exit_error("%s timeout" % arg_str) + + if result.returncode != 0: + exit_error("%s failed: %d\n %s\n %s\n" % + (arg_str, result.returncode, result.stdout.read(), result.stderr.read())) + else: + return result.stdout.read().decode('utf-8') + +def get_latest_eeprom(): + """ + Returns the path of the latest EEPROM image file if it exists. + """ + latest = shell_cmd(['rpi-eeprom-update', '-l']).rstrip() + if not os.path.exists(latest): + exit_error("EEPROM image '%s' not found" % latest) + return latest + +def apply_update(config, eeprom=None, config_src=None): + """ + Applies the config file to the latest available EEPROM image and spawns + rpi-eeprom-update to schedule the update at the next reboot. + """ + if eeprom is not None: + eeprom_image = eeprom + else: + eeprom_image = get_latest_eeprom() + create_tempdir() + tmp_update = os.path.join(TEMP_DIR, 'pieeprom.upd') + image = BootloaderImage(eeprom_image, tmp_update) + image.write(config) + config_str = open(config).read() + if config_src is None: + config_src = '' + sys.stdout.write("Updating bootloader EEPROM\n image: %s\nconfig_src: %s\nconfig: %s\n%s\n%s\n%s\n" % + (eeprom_image, config_src, config, '#' * 80, config_str, '#' * 80)) + + sys.stdout.write("\n*** To cancel this update run 'sudo rpi-eeprom-update -r' ***\n\n") + + # Ignore APT package checksums so that this doesn't fail when used + # with EEPROMs with configs delivered outside of APT. + # The checksums are really just a safety check for automatic updates. + args = ['rpi-eeprom-update', '-d', '-i', '-f', tmp_update] + resp = shell_cmd(args) + sys.stdout.write(resp) + +def edit_config(eeprom=None): + """ + Implements something like 'git commit' for editing EEPROM configs. + """ + # Default to nano if $EDITOR is not defined. + editor = 'nano' + if 'EDITOR' in os.environ: + editor = os.environ['EDITOR'] + + config_src = '' + # If there is a pending update then use the configuration from + # that in order to support incremental updates. Otherwise, + # use the current EEPROM configuration. + bootfs = shell_cmd(['rpi-eeprom-update', '-b']).rstrip() + pending = os.path.join(bootfs, 'pieeprom.upd') + if os.path.exists(pending): + config_src = pending + image = BootloaderImage(pending) + current_config = image.get_config().decode('utf-8') + else: + config_src = 'vcgencmd bootloader_config' + current_config = read_current_config() + + create_tempdir() + tmp_conf = os.path.join(TEMP_DIR, 'boot.conf') + out = open(tmp_conf, 'w') + out.write(current_config) + out.close() + cmd = "\'%s\' \'%s\'" % (editor, tmp_conf) + result = os.system(cmd) + if result != 0: + exit_error("Aborting update because \'%s\' exited with code %d." % (cmd, result)) + + new_config = open(tmp_conf, 'r').read() + if len(new_config.splitlines()) < 2: + exit_error("Aborting update because \'%s\' appears to be empty." % tmp_conf) + apply_update(tmp_conf, eeprom, config_src) + +def read_current_config(): + """ + Reads the configuration used by the current bootloader. + """ + return shell_cmd(['vcgencmd', 'bootloader_config']) + +class BootloaderImage(object): + def __init__(self, filename, output=None): + """ + Instantiates a Bootloader image writer with a source eeprom (filename) + and optionally an output filename. + """ + self._filename = filename + try: + self._bytes = bytearray(open(filename, 'rb').read()) + except IOError as err: + exit_error("Failed to read \'%s\'\n%s\n" % (filename, str(err))) + self._out = None + if output is not None: + self._out = open(output, 'wb') + + if len(self._bytes) != IMAGE_SIZE: + exit_error("%s: Expected size %d bytes actual size %d bytes" % + (filename, IMAGE_SIZE, len(self._bytes))) + + def find_config(self): + offset = 0 + magic = 0 + while offset < IMAGE_SIZE: + magic, length = struct.unpack_from('>LL', self._bytes, offset) + if (magic & MAGIC_MASK) != MAGIC: + raise Exception('EEPROM is corrupted') + + if magic == FILE_MAGIC: # Found a file + name = self._bytes[offset + 8: offset + FILE_HDR_LEN] + if name.decode('utf-8') == 'bootconf.txt': + return (offset, length) + + offset += 8 + length # length + type + offset = (offset + 7) & ~7 + + raise Exception('EEPROM parse error: Bootloader config not found') + + def write(self, new_config): + hdr_offset, length = self.find_config() + new_config_bytes = open(new_config, 'rb').read() + new_len = len(new_config_bytes) + FILENAME_LEN + 4 + 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') + + struct.pack_into('>L', self._bytes, hdr_offset + 4, new_len) + struct.pack_into(("%ds" % len(new_config_bytes)), self._bytes, + hdr_offset + 4 + FILE_HDR_LEN, new_config_bytes) + + # If the new config is smaller than the old config then set any old + # data which is now unused to all ones (erase value) + pad_start = hdr_offset + 4 + FILE_HDR_LEN + len(new_config_bytes) + pad = 0 + while pad < (length - len(new_config_bytes)): + struct.pack_into('B', self._bytes, pad_start + pad, 0xff) + pad = pad + 1 + + if self._out is not None: + self._out.write(self._bytes) + self._out.close() + else: + if hasattr(sys.stdout, 'buffer'): + sys.stdout.buffer.write(self._bytes) + else: + sys.stdout.write(self._bytes) + + def get_config(self): + hdr_offset, length = self.find_config() + offset = hdr_offset + 4 + FILE_HDR_LEN + config_bytes = self._bytes[offset:offset+length-FILENAME_LEN-4] + return config_bytes + + def read(self): + config_bytes = self.get_config() + if self._out is not None: + self._out.write(config_bytes) + self._out.close() + else: + if hasattr(sys.stdout, 'buffer'): + sys.stdout.buffer.write(config_bytes) + else: + sys.stdout.write(config_bytes) + +def main(): + """ + Utility for reading and writing the configuration file in the + Raspberry Pi 4 bootloader EEPROM image. + """ + description = """\ +Bootloader EEPROM configuration tool for the Raspberry Pi 4. +Operating modes: + +1. Outputs the current bootloader configuration to STDOUT if no arguments are + specified OR the given output file if --out is specified. + + rpi-eeprom-config [--out boot.conf] + +2. Extracts the configuration file from the given 'eeprom' file and outputs + the result to STDOUT or the output file if --output is specified. + + rpi-eeprom-config pieeprom.bin [--out boot.conf] + +3. Writes a new EEPROM image replacing the configuration file with the contents + of the file specified by --config. + + rpi-eeprom-config --config boot.conf --out newimage.bin pieeprom.bin + + The new image file can be installed via rpi-eeprom-update + rpi-eeprom-update -d -f newimage.bin + +4. Applies a given config file to an EEPROM image and invokes rpi-eeprom-update + to schedule an update of the bootloader when the system is rebooted. + + Since this command launches rpi-eeprom-update to schedule the EEPROM update + it must be run as root. + + sudo rpi-eeprom-config --apply boot.conf [pieeprom.bin] + + If the 'eeprom' argument is not specified then the latest available image + is selected by calling 'rpi-eeprom-update -l'. + +5. The '--edit' parameter behaves the same as '--apply' except that instead of + applying a predefined configuration file a text editor is launched with the + contents of the current EEPROM configuration. + + Since this command launches rpi-eeprom-update to schedule the EEPROM update + it must be run as root. + + The configuration file will be taken from: + * The cached bootloader configuration 'vcgencmd bootloader_config' + * The current pending update - typically /boot/pieeprom.upd + + sudo -E rpi-eeprom-config --edit [pieeprom.bin] + + To cancel the pending update run 'sudo rpi-eeprom-update -r' + + The default text editor is nano and may be overridden by setting the 'EDITOR' + environment variable and passing '-E' to 'sudo' to preserve the environment. + +See 'rpi-eeprom-update -h' for more information about the available EEPROM +images. +""" + parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter, + description=description) + + parser.add_argument('-a', '--apply', required=False, + help='Updates the bootloader to the given config plus latest available EEPROM release.') + parser.add_argument('-c', '--config', help='Name of bootloader configuration file', required=False) + parser.add_argument('-e', '--edit', action='store_true', default=False, help='Edit the current EEPROM config') + parser.add_argument('-o', '--out', help='Name of output file', required=False) + parser.add_argument('eeprom', nargs='?', help='Name of EEPROM file to use as input') + args = parser.parse_args() + + + if (args.edit or args.apply is not None) and os.getuid() != 0: + exit_error("--edit/--apply must be run as root") + + if args.edit: + edit_config(args.eeprom) + elif args.apply is not None: + if not os.path.exists(args.apply): + exit_error("config file '%s' not found" % args.apply) + apply_update(args.apply, args.eeprom, args.apply) + elif args.eeprom is not None: + image = BootloaderImage(args.eeprom, args.out) + if args.config is not None: + if not os.path.exists(args.config): + exit_error("config file '%s' not found" % args.config) + image.write(args.config) + else: + image.read() + elif args.config is None and args.eeprom is None: + current_config = read_current_config() + if args.out is not None: + open(args.out, 'w').write(current_config) + else: + sys.stdout.write(current_config) + +if __name__ == '__main__': + atexit.register(exit_handler) + main() diff --git a/recovery/update-pieeprom.sh b/recovery/update-pieeprom.sh new file mode 100755 index 0000000..ab56464 --- /dev/null +++ b/recovery/update-pieeprom.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +# Utility to update the EEPROM image (pieeprom.bin) and signature +# (pieeprom.sig) with a new EEPROM config. +# +# pieeprom.original.bin - The source EEPROM from rpi-eeprom repo +# boot.conf - The bootloader config file to apply. + +set -e + +script_dir="$(cd "$(dirname "$0")" && pwd)" + +${script_dir}/rpi-eeprom-config --config ${script_dir}/boot.conf --out ${script_dir}/pieeprom.bin ${script_dir}/pieeprom.original.bin +sha256sum ${script_dir}/pieeprom.bin | awk '{print $1}' > ${script_dir}/pieeprom.sig +echo "ts: $(date -u +%s)" >> "${script_dir}/pieeprom.sig" diff --git a/win32/rpiboot_setup.exe b/win32/rpiboot_setup.exe index bab43c0..9b4cd27 100755 Binary files a/win32/rpiboot_setup.exe and b/win32/rpiboot_setup.exe differ -- libgit2 0.21.4