mirror of
https://github.com/raspberrypi/rpi-eeprom.git
synced 2026-01-20 21:13:36 +08:00
rpi-eeprom-update: Add the option to use flashrom for updates on Raspberry Pi 5
On Raspberry Pi 5 there are dedicated pins for the bootloader SPI EEPROM. This makes it possible to do immediate updates via flashrom. The "current" EEPROM config is the EEPROM config at boot rather than what has just been written to the SPI flash because this is consistent with current behaviour. To use flashrom instead of recovery.bin for bootloader updates set RPI_EEPROM_USE_FLASHROM=1 in /etc/defaults/rpi-eeprom-update BCM2711 On CM4, Pi4, CM4-S, Pi400 config.txt must be modified to disable the analog audio driver which shares the GPIO pins used by the bootloader EEPROM. dtparam=spi=on dtoverlay=audremap dtoverlay=spi-gpio40-45
This commit is contained in:
@@ -109,7 +109,7 @@ def exit_error(msg):
|
||||
sys.stderr.write("ERROR: %s\n" % msg)
|
||||
sys.exit(1)
|
||||
|
||||
def shell_cmd(args):
|
||||
def shell_cmd(args, timeout=5, echo=False):
|
||||
"""
|
||||
Executes a shell command waits for completion returning STDOUT. If an
|
||||
error occurs then exit and output the subprocess stdout, stderr messages
|
||||
@@ -117,9 +117,14 @@ def shell_cmd(args):
|
||||
"""
|
||||
start = time.time()
|
||||
arg_str = ' '.join(args)
|
||||
result = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
bufsize = 0 if echo else -1
|
||||
result = subprocess.Popen(args, bufsize=bufsize, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
|
||||
while time.time() - start < 5:
|
||||
while time.time() - start < timeout:
|
||||
if echo:
|
||||
s = result.stdout.read(80).decode('utf-8')
|
||||
if s != "":
|
||||
sys.stdout.write(s)
|
||||
if result.poll() is not None:
|
||||
break
|
||||
|
||||
@@ -128,8 +133,8 @@ def shell_cmd(args):
|
||||
|
||||
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:
|
||||
(arg_str, result.returncode, result.stdout.read().decode('utf-8'), result.stderr.read().decode('utf-8')))
|
||||
elif not echo:
|
||||
return result.stdout.read().decode('utf-8')
|
||||
|
||||
def get_latest_eeprom():
|
||||
@@ -170,8 +175,10 @@ def apply_update(config, eeprom=None, config_src=None):
|
||||
# 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)
|
||||
|
||||
# If flashrom is used then the command will not return until the EEPROM
|
||||
# has been updated so use a larger timeout.
|
||||
shell_cmd(args, timeout=20, echo=True)
|
||||
|
||||
def edit_config(eeprom=None):
|
||||
"""
|
||||
@@ -377,6 +384,15 @@ class BootloaderImage(object):
|
||||
% (src_filename, len(src_bytes), MAX_FILE_SIZE))
|
||||
self.update(src_bytes, dst_filename)
|
||||
|
||||
def set_timestamp(self, timestamp):
|
||||
"""
|
||||
Sets the self-update timestamp in an EEPROM image file. This is useful when
|
||||
using flashrom to write to SPI flash instead of using the bootloader self-update mode.
|
||||
"""
|
||||
ts = int(timestamp)
|
||||
struct.pack_into('<L', self._bytes, len(self._bytes) - 4, ts)
|
||||
struct.pack_into('<L', self._bytes, len(self._bytes) - 8, ~ts & 0xffffffff)
|
||||
|
||||
def write(self):
|
||||
"""
|
||||
Writes the updated EEPROM image to stdout or the specified output file.
|
||||
@@ -498,6 +514,7 @@ See 'rpi-eeprom-update -h' for more information about the available EEPROM image
|
||||
parser.add_argument('-d', '--digest', help='Signed boot only. The name of the .sig file generated by rpi-eeprom-dgst for config.txt ', required=False)
|
||||
parser.add_argument('-p', '--pubkey', help='Signed boot only. The name of the RSA public key file to store in the EEPROM', required=False)
|
||||
parser.add_argument('-x', '--extract', action='store_true', default=False, help='Extract the modifiable files (boot.conf, pubkey, signature)', required=False)
|
||||
parser.add_argument('-t', '--timestamp', help='Set the timestamp in the EEPROM image file', required=False)
|
||||
parser.add_argument('eeprom', nargs='?', help='Name of EEPROM file to use as input')
|
||||
args = parser.parse_args()
|
||||
|
||||
@@ -518,6 +535,8 @@ See 'rpi-eeprom-update -h' for more information about the available EEPROM image
|
||||
apply_update(args.apply, args.eeprom, args.apply)
|
||||
elif args.eeprom is not None:
|
||||
image = BootloaderImage(args.eeprom, args.out)
|
||||
if args.timestamp is not None:
|
||||
image.set_timestamp(args.timestamp)
|
||||
if args.config is not None:
|
||||
if not os.path.exists(args.config):
|
||||
exit_error("config file '%s' not found" % args.config)
|
||||
@@ -527,6 +546,8 @@ See 'rpi-eeprom-update -h' for more information about the available EEPROM image
|
||||
if args.pubkey is not None:
|
||||
image.update_key(args.pubkey, PUBKEY_BIN)
|
||||
image.write()
|
||||
elif args.config is None and args.timestamp is not None:
|
||||
image.write()
|
||||
else:
|
||||
image.read()
|
||||
elif args.config is None and args.eeprom is None:
|
||||
|
||||
Reference in New Issue
Block a user