mirror of
https://github.com/raspberrypi/rpi-eeprom.git
synced 2026-01-20 21:13:36 +08:00
The current help text for rpi-eeprom-config are unclear. This PR changes them so that the help text matches what the tool does and what each parameter specifies. The man page, automatically derived from the help text, is also fixed.
114 lines
4.2 KiB
Python
Executable File
114 lines
4.2 KiB
Python
Executable File
#!/usr/bin/python
|
|
|
|
# rpi-eeprom-config
|
|
# Utility for reading and writing the configuration file in the
|
|
# Raspberry Pi4 bootloader EEPROM image.
|
|
|
|
import argparse
|
|
import struct
|
|
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
|
|
# but the following mask can be used to test for section headers and skip
|
|
# unknown data.
|
|
MAGIC = 0x55aaf00f
|
|
MAGIC_MASK = 0xfffff00f
|
|
FILE_MAGIC = 0x55aaf11f # id for modifiable file, currently only bootconf.txt
|
|
FILE_HDR_LEN = 20
|
|
FILENAME_LEN = 12
|
|
|
|
class BootloaderImage(object):
|
|
def __init__(self, filename, output):
|
|
self._filename = filename
|
|
self._bytes = bytearray(open(filename, 'rb').read())
|
|
self._out = None
|
|
if output is not None:
|
|
self._out = open(output, 'wb')
|
|
|
|
if len(self._bytes) != IMAGE_SIZE:
|
|
raise Exception("%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 += 4 + length
|
|
offset += 8 - (offset % 8) # Pad
|
|
|
|
raise Exception('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 read(self):
|
|
hdr_offset, length = self.find_config()
|
|
offset = hdr_offset + 4 + FILE_HDR_LEN
|
|
config_bytes = self._bytes[offset:offset+length-FILENAME_LEN-4]
|
|
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():
|
|
parser = argparse.ArgumentParser('RPI EEPROM config tool')
|
|
parser.add_argument('--config', help='Insert new bootloader config into EEPROM image. CONFIG specifies the file containing the new config.')
|
|
parser.add_argument('--out', help='Extract current bootloader config from EEPROM image. OUT specifies the file to put the config into.')
|
|
parser.add_argument('eeprom', help='Name of EEPROM image file (e.g. pieeprom.bin)')
|
|
args = parser.parse_args()
|
|
|
|
image = BootloaderImage(args.eeprom, args.out)
|
|
if args.config is not None:
|
|
image.write(args.config)
|
|
else:
|
|
image.read()
|
|
|
|
if __name__ == '__main__':
|
|
main()
|