Allow embedding multiple firmware binaries into SD images (!1739)

This allows embedding multiple firmware binaries into SD images.
Firmware images for most devices that require this functionality consist
mainly of u-boot, but some devices (e.g. librem5) have multiple firmware
images that need to be embedded in the SD image created by pmbootstrap.

This functionality uses two new deviceinfo parameters:
    - deviceinfo_sd_embed_firmware: a comma-separated list of
      binary:offset (where binary is under /usr/share/firmware)
    - deviceinfo_sd_embed_firmware_step_size: The number of bytes for
      each increment of the offset specified in the
      deviceinfo_sd_embed_firmware (typically 1024 or 2048)

deviceinfo_write_uboot_spl has been obsoleted by these new parameters.
This commit is contained in:
Clayton Craft 2019-01-08 21:42:37 -08:00 committed by Oliver Smith
parent accff27dc3
commit 644083c0f7
No known key found for this signature in database
GPG key ID: 5AE7F5513E0885CB
2 changed files with 68 additions and 14 deletions

View file

@ -250,7 +250,6 @@ deviceinfo_attributes = [
"flash_heimdall_partition_initfs",
"flash_heimdall_partition_system",
"generate_legacy_uboot_initfs",
"write_uboot_spl",
"kernel_cmdline",
"generate_bootimg",
"bootimg_qcdt",
@ -264,6 +263,8 @@ deviceinfo_attributes = [
"flash_fastboot_vendor_id",
"flash_sparse",
"rootfs_image_sector_size",
"sd_embed_firmware",
"sd_embed_firmware_step_size",
# weston
"weston_pixman_type",

View file

@ -286,22 +286,75 @@ def setup_hostname(args):
pmb.chroot.root(args, ["sed", "-i", "-e", regex, "/etc/hosts"], suffix)
def write_uboot_spl(args):
if args.deviceinfo["write_uboot_spl"]:
logging.info("Writing the u-boot spl to the SD card with 8KB offset")
def embed_firmware(args):
"""
This method will embed firmware, located at /usr/share, that are specified
by the "sd_embed_firmware" deviceinfo parameter into the SD card image
(e.g. u-boot). Binaries that would overwrite the first partition are not
accepted, and if multiple binaries are specified then they will be checked
for collisions with each other.
"""
if not args.deviceinfo["sd_embed_firmware"]:
return
spl_file = os.path.join("/usr/share/u-boot/", args.deviceinfo["write_uboot_spl"])
spl_size = os.path.getsize(args.work + "/chroot_rootfs_" + args.device + spl_file)
step = 1024
if args.deviceinfo["sd_embed_firmware_step_size"]:
try:
step = int(args.deviceinfo["sd_embed_firmware_step_size"])
except ValueError:
raise RuntimeError("Value for "
"deviceinfo_sd_embed_firmware_step_size "
"is not valid: {}".format(step))
# First partition is at 2048 sectors, spl offset is at 8K
spl_max_size = (2048 * 512) - (8 * 1024)
device_rootfs = mount_device_rootfs(args)
binaries = args.deviceinfo["sd_embed_firmware"].split(",")
if spl_size > spl_max_size:
raise RuntimeError("U-boot SPL image is too big {}B > {}B".format(spl_size, spl_max_size))
# Perform three checks prior to writing binaries to disk: 1) that binaries
# exist, 2) that binaries do not extend into the first partition, 3) that
# binaries do not overlap eachother
binary_ranges = {}
binary_list = []
for binary_offset in binaries:
binary, offset = binary_offset.split(':')
try:
offset = int(offset)
except ValueError:
raise RuntimeError("Value for firmware binary offset is "
"not valid: {}".format(offset))
binary_path = os.path.join(args.work, "chroot_rootfs_" +
args.device, "usr/share", binary)
if not os.path.exists(binary_path):
raise RuntimeError("The following firmware binary does not "
"exist in the device rootfs: "
"{}".format("/usr/share/" + binary))
# Insure that embedding the firmware will not overrun the
# first partition
max_size = (2048 * 512) - (offset * step)
binary_size = os.path.getsize(binary_path)
if binary_size > max_size:
raise RuntimeError("The firmware is too big to embed in the "
"disk image {}B > {}B".format(binary_size,
max_size))
# Insure that the firmware does not conflict with any other firmware
# that will be embedded
binary_start = offset * step
binary_end = binary_start + binary_size
for start, end in binary_ranges.items():
if ((binary_start >= start and binary_start <= end) or
(binary_end >= start and binary_end <= end)):
raise RuntimeError("The firmware overlaps with at least one "
"other firmware image: {}".format(binary))
binary_ranges[binary_start] = binary_end
binary_list.append((binary, offset))
device_rootfs = mount_device_rootfs(args)
filename = os.path.join(device_rootfs, spl_file.lstrip("/"))
pmb.chroot.root(args, ["dd", "if=" + filename, "of=/dev/install", "bs=1024", "seek=8"])
# Write binaries to disk
for binary, offset in binary_list:
binary_file = os.path.join("/usr/share", binary)
logging.info("Embed firmware {} in the SD card image at offset {} with"
" step size {}".format(binary, offset, step))
filename = os.path.join(device_rootfs, binary_file.lstrip("/"))
pmb.chroot.root(args, ["dd", "if=" + filename, "of=/dev/install",
"bs=" + str(step), "seek=" + str(offset)])
def install_system_image(args):
@ -332,7 +385,7 @@ def install_system_image(args):
create_home_from_skel(args)
configure_apk(args)
copy_ssh_keys(args)
write_uboot_spl(args)
embed_firmware(args)
pmb.chroot.shutdown(args, True)
# Convert rootfs to sparse using img2simg