feat(tlc): add --align argument
Extended the command line interface to receive an alignment
argument.
TLC tool will align the data of the TEs accordingly.
Signed-off-by: J-Alves <joao.alves@arm.com>
Change-Id: I281b0b4c1851d58377bf6b31fcee03ee2f53367b
diff --git a/tools/tlc/tests/test_cli.py b/tools/tlc/tests/test_cli.py
index a5ef30e..ebe1f6a 100644
--- a/tools/tlc/tests/test_cli.py
+++ b/tools/tlc/tests/test_cli.py
@@ -17,6 +17,7 @@
import pytest
import yaml
from click.testing import CliRunner
+from conftest import generate_random_bytes
from tlc.cli import cli
from tlc.te import TransferEntry
@@ -32,6 +33,22 @@
assert TransferList.fromfile(test_file) is not None
+@pytest.mark.parametrize("align", [4, 6, 12, 13])
+def test_create_with_align(align, tlcrunner, tmpdir):
+ tl_file = tmpdir.join("tl.bin").strpath
+ tlcrunner.invoke(cli, ["create", "-s", "10000", "-a", align, tl_file])
+
+ blob = tmpdir.join("blob.bin")
+
+ blob.write_binary(generate_random_bytes(0x200))
+ tlcrunner.invoke(cli, ["add", "--entry", 1, blob.strpath, tl_file])
+
+ tl = TransferList.fromfile(tl_file)
+ te = tl.entries[-1]
+ assert tl.alignment == align
+ assert (te.offset + te.hdr_size) % (1 << align) == 0
+
+
def test_create_with_fdt(tmpdir):
runner = CliRunner()
fdt = tmpdir.join("fdt.dtb")
@@ -69,6 +86,20 @@
assert len(tl.entries) == len(tlc_entries)
+@pytest.mark.parametrize("align", [4, 6, 12, 13])
+def test_cli_add_entry_with_align(align, tlcrunner, tmpdir, tmptlstr):
+ blob = tmpdir.join("blob.bin")
+ blob.write_binary(bytes(0x100))
+
+ tlcrunner.invoke(cli, ["add", "--align", align, "--entry", 1, blob, tmptlstr])
+ tl = TransferList.fromfile(tmptlstr)
+ te = tl.entries[-1]
+
+ print(tl, *(te for te in tl.entries), sep="\n---------------\n")
+ assert (te.offset + te.hdr_size) % (1 << align) == 0
+ assert tl.alignment == align
+
+
def test_info(tlcrunner, tmptlstr, tmpfdt):
tlcrunner.invoke(cli, ["add", "--entry", "0", "/dev/null", tmptlstr])
tlcrunner.invoke(cli, ["add", "--fdt", tmpfdt.strpath, tmptlstr])
diff --git a/tools/tlc/tests/test_transfer_list.py b/tools/tlc/tests/test_transfer_list.py
index 54d93ec..6900b41 100644
--- a/tools/tlc/tests/test_transfer_list.py
+++ b/tools/tlc/tests/test_transfer_list.py
@@ -157,7 +157,7 @@
assert f.read(te.data_size) == te.data
-def test_write_multiple_tes_to_file(tmpdir, random_entries):
+def test_write_multiple_tes_to_file(tmpdir, random_entries, random_entry):
"""Check that we can create a TL with multiple TE's."""
test_file = tmpdir.join("test_tl_blob.bin")
tl = TransferList(0x4000)
@@ -166,6 +166,10 @@
for tag_id, data in _test_entries:
tl.add_transfer_entry(tag_id, data)
+ # Add a few entries with special alignment requirements
+ blob_id, blob = random_entry(0x200)
+ tl.add_transfer_entry(blob_id, blob, data_align=12)
+
tl.write_to_file(test_file)
with open(test_file, "rb") as f:
@@ -180,6 +184,13 @@
data_size = int.from_bytes(f.read(4), "little")
assert f.read(data_size) == data
+ f.seek(int(math.ceil(f.tell() / (1 << 12)) * (1 << 12)) - 8)
+ assert int.from_bytes(f.read(3), "little") == blob_id
+ assert int.from_bytes(f.read(1), "little") == TransferEntry.hdr_size
+ # Make sure the data in the TE matches the data in the original case
+ data_size = int.from_bytes(f.read(4), "little")
+ assert f.read(data_size) == blob
+
# padding is added to align TE's, make sure padding is added to the size of
# the TL by checking we don't overflow.
assert f.tell() <= tl.size
diff --git a/tools/tlc/tlc/cli.py b/tools/tlc/tlc/cli.py
index 3d60938..81bf6fb 100644
--- a/tools/tlc/tlc/cli.py
+++ b/tools/tlc/tlc/cli.py
@@ -27,6 +27,14 @@
@cli.command()
@click.argument("filename", type=click.Path(dir_okay=False))
@click.option(
+ "-a",
+ "--align",
+ type=int,
+ default=3,
+ show_default=True,
+ help="Set alignment in powers of 2 (e.g., -a 3 for 8 byte alignment).",
+)
+@click.option(
"-s", "--size", default=0x1000, type=int, help="Maximum size of the Transfer List"
)
@click.option(
@@ -51,7 +59,7 @@
type=click.Path(exists=True),
help="Create the transfer list from a YAML config file.",
)
-def create(filename, size, fdt, entry, flags, from_yaml):
+def create(filename, align, size, fdt, entry, flags, from_yaml):
"""Create a new Transfer List."""
try:
if from_yaml:
@@ -60,12 +68,12 @@
tl = TransferList.from_dict(config)
else:
- tl = TransferList(size)
+ tl = TransferList(size, alignment=align)
entry = (*entry, (1, fdt)) if fdt else entry
for id, path in entry:
- tl.add_transfer_entry_from_file(id, path)
+ tl.add_transfer_entry_from_file(id, path, data_align=align)
except MemoryError as mem_excp:
raise MemoryError(
"TL max size exceeded, consider increasing with the option -s"
@@ -133,19 +141,24 @@
@cli.command()
-@click.argument("filename", type=click.Path(exists=True, dir_okay=False))
+@click.option(
+ "-a",
+ "--align",
+ type=int,
+ help="Set alignment in powers of 2 (e.g., -a 3 for 8 byte alignment).",
+)
@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):
+@click.argument("filename", type=click.Path(exists=True, dir_okay=False))
+def add(align, entry, filename):
"""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.add_transfer_entry_from_file(id, path, data_align=align)
tl.write_to_file(filename)
diff --git a/tools/tlc/tlc/tl.py b/tools/tlc/tlc/tl.py
index 326b857..30e6d9e 100644
--- a/tools/tlc/tlc/tl.py
+++ b/tools/tlc/tlc/tl.py
@@ -86,11 +86,14 @@
granule = 8
def __init__(
- self, max_size: int = hdr_size, flags: int = TRANSFER_LIST_ENABLE_CHECKSUM
+ self,
+ max_size: int = hdr_size,
+ flags: int = TRANSFER_LIST_ENABLE_CHECKSUM,
+ alignment: int = 3,
) -> None:
assert max_size >= self.hdr_size
self.checksum: int = 0
- self.alignment: int = 3
+ self.alignment: int = alignment
self.size = self.hdr_size
self.total_size = max_size
self.flags = flags
@@ -163,10 +166,14 @@
# get settings from config and set defaults
max_size = config.get("max_size", 0x1000)
has_checksum = config.get("has_checksum", True)
+ align = config.get("alignment", None)
flags = TRANSFER_LIST_ENABLE_CHECKSUM if has_checksum else 0
- tl = cls(max_size, flags)
+ if align:
+ tl = cls(max_size, flags, alignment=align)
+ else:
+ tl = cls(max_size, flags)
for entry in config["entries"]:
tl.add_transfer_entry_from_dict(entry)
@@ -327,8 +334,12 @@
te_format = transfer_entry_formats[tag_id]
tag_name = te_format["tag_name"]
+ align = entry.get("alignment", None)
+
if "blob_file_path" in entry:
- return self.add_transfer_entry_from_file(tag_id, entry["blob_file_path"])
+ return self.add_transfer_entry_from_file(
+ tag_id, entry["blob_file_path"], data_align=align
+ )
elif tag_name == "tpm_event_log_table":
with open(entry["event_log"], "rb") as f:
event_log_data = f.read()
@@ -336,7 +347,7 @@
flags_bytes = entry["flags"].to_bytes(4, "little")
data = flags_bytes + event_log_data
- return self.add_transfer_entry(tag_id, data)
+ return self.add_transfer_entry(tag_id, data, data_align=align)
elif tag_name == "exec_ep_info":
return self.add_entry_point_info_transfer_entry(entry)
elif "format" in te_format and "fields" in te_format:
@@ -347,9 +358,11 @@
else:
raise ValueError(f"Invalid transfer entry {entry}.")
- def add_transfer_entry_from_file(self, tag_id: int, path: Path) -> TransferEntry:
+ def add_transfer_entry_from_file(
+ self, tag_id: int, path: Path, data_align: int = 0
+ ) -> TransferEntry:
with open(path, "rb") as f:
- return self.add_transfer_entry(tag_id, f.read())
+ return self.add_transfer_entry(tag_id, f.read(), data_align=data_align)
def write_to_file(self, file: Path) -> None:
"""Write the contents of the TL to a file."""