blob: e574e59daaa5f08ad384f4a2ec868fe3c6de954d [file] [log] [blame]
#!/usr/bin/env python3
# type: ignore[attr-defined]
#
# Copyright (c) 2024, Arm Limited. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
"""Module defining the Transfer List Compiler (TLC) command line interface."""
from pathlib import Path
import click
from tlc.tl import *
@click.group()
@click.version_option()
def cli():
pass
@cli.command()
@click.argument("filename", type=click.Path(dir_okay=False))
@click.option(
"-s", "--size", default=0x1000, type=int, help="Maximum size of the Transfer List"
)
@click.option(
"--fdt",
type=click.Path(exists=True),
help="Path to flattened device tree (FDT).",
)
@click.option(
"--entry",
type=(int, click.Path(exists=True)),
multiple=True,
help="A tag ID and the corresponding path to a binary blob in the form <id> <path-to-blob>.",
)
@click.option(
"--flags",
default=TRANSFER_LIST_ENABLE_CHECKSUM,
show_default=True,
help="Settings for the TL's properties.",
)
def create(filename, size, fdt, entry, flags):
"""Create a new Transfer List."""
tl = TransferList(size)
entry = (*entry, (1, fdt)) if fdt else entry
try:
for id, path in entry:
tl.add_transfer_entry_from_file(id, path)
except MemoryError as mem_excp:
raise MemoryError(
"TL max size exceeded, consider increasing with the option -s"
) from mem_excp
tl.write_to_file(filename)
@cli.command()
@click.argument("filename", type=click.Path(exists=True, dir_okay=False))
@click.option(
"--fdt-offset",
is_flag=True,
help="Returns the offset of FDT in the TL if it is present.",
)
@click.option(
"--header",
is_flag=True,
help="Print the Transfer List header.",
)
@click.option(
"--entries",
is_flag=True,
help="Print the Transfer List entries.",
)
def info(filename, fdt_offset, header, entries):
"""Print the contents of an existing Transfer List.
This command allows you to extract the data stored in a binary blob
representing a transfer list (TL). The transfer list must comply with the
version of the firmware handoff specification supported by this tool.
"""
tl = TransferList.fromfile(filename)
if fdt_offset:
return print(tl.get_entry_data_offset(1))
if header and entries or not (header or entries):
print(tl, sep="")
if tl.entries:
print("----", tl.get_transfer_entries_str(), sep="\n")
elif entries:
print(tl.get_transfer_entries_str())
elif header:
print(tl)
@cli.command()
@click.argument("filename", type=click.Path(exists=True, dir_okay=False))
@click.option(
"--tags",
type=int,
multiple=True,
help="Tags to be removed from TL.",
)
def remove(filename, tags):
"""Remove Transfer Entries with given tags.
Remove Transfer Entries with given tags from a Transfer List."""
tl = TransferList.fromfile(filename)
for tag in tags:
tl.remove_tag(tag)
tl.write_to_file(filename)
@cli.command()
@click.argument("filename", type=click.Path(exists=True, dir_okay=False))
@click.option(
"--entry",
type=(int, click.Path(exists=True)),
multiple=True,
help="A tag ID and the corresponding path to a binary blob in the form <id> <path-to-blob>.",
)
def add(filename, entry):
"""Update an existing Transfer List with given images."""
tl = TransferList.fromfile(filename)
for id, path in entry:
tl.add_transfer_entry_from_file(id, path)
tl.write_to_file(filename)
@cli.command()
@click.argument("filename", type=click.Path(exists=True, dir_okay=False))
@click.option(
"-C", type=click.Path(exists=True), help="Output directory for extracted images."
)
def unpack(filename, c):
"""Unpack images from a Transfer List."""
tl = TransferList.fromfile(filename)
pwd = Path(".") if not c else Path(c)
for i, te in enumerate(tl.entries):
with open(pwd / f"te_{i}_{te.id}.bin", "wb") as f:
f.write(te.data)
@cli.command()
@click.argument("filename", type=click.Path(exists=True, dir_okay=False))
def validate(filename):
"""Validate the contents of an existing Transfer List."""
TransferList.fromfile(filename)
print("Valid TL!")