blob: 3d609380d87e4dd63a940ac22486b98f81c2fe8d [file] [log] [blame]
Harrison Mutai19dc4f92024-05-10 16:54:29 +00001#!/usr/bin/env python3
2# type: ignore[attr-defined]
3
4#
5# Copyright (c) 2024, Arm Limited. All rights reserved.
6#
7# SPDX-License-Identifier: BSD-3-Clause
8#
9
10"""Module defining the Transfer List Compiler (TLC) command line interface."""
11
12from pathlib import Path
13
14import click
Harrison Mutai622b6072024-08-21 13:06:46 +000015import jinja2
Charlie Barehamd7a9efc2024-06-17 11:58:03 +010016import yaml
Harrison Mutai19dc4f92024-05-10 16:54:29 +000017
18from tlc.tl import *
19
20
21@click.group()
22@click.version_option()
23def cli():
24 pass
25
26
27@cli.command()
28@click.argument("filename", type=click.Path(dir_okay=False))
29@click.option(
30 "-s", "--size", default=0x1000, type=int, help="Maximum size of the Transfer List"
31)
32@click.option(
33 "--fdt",
34 type=click.Path(exists=True),
35 help="Path to flattened device tree (FDT).",
36)
37@click.option(
38 "--entry",
39 type=(int, click.Path(exists=True)),
40 multiple=True,
41 help="A tag ID and the corresponding path to a binary blob in the form <id> <path-to-blob>.",
42)
43@click.option(
44 "--flags",
45 default=TRANSFER_LIST_ENABLE_CHECKSUM,
46 show_default=True,
47 help="Settings for the TL's properties.",
48)
Charlie Barehamd7a9efc2024-06-17 11:58:03 +010049@click.option(
50 "--from-yaml",
51 type=click.Path(exists=True),
52 help="Create the transfer list from a YAML config file.",
53)
54def create(filename, size, fdt, entry, flags, from_yaml):
Harrison Mutai19dc4f92024-05-10 16:54:29 +000055 """Create a new Transfer List."""
Charlie Barehamd7a9efc2024-06-17 11:58:03 +010056 try:
57 if from_yaml:
58 with open(from_yaml, "r") as f:
59 config = yaml.safe_load(f)
Harrison Mutai19dc4f92024-05-10 16:54:29 +000060
Charlie Barehamd7a9efc2024-06-17 11:58:03 +010061 tl = TransferList.from_dict(config)
62 else:
63 tl = TransferList(size)
Harrison Mutai19dc4f92024-05-10 16:54:29 +000064
Charlie Barehamd7a9efc2024-06-17 11:58:03 +010065 entry = (*entry, (1, fdt)) if fdt else entry
66
67 for id, path in entry:
68 tl.add_transfer_entry_from_file(id, path)
Harrison Mutai19dc4f92024-05-10 16:54:29 +000069 except MemoryError as mem_excp:
70 raise MemoryError(
71 "TL max size exceeded, consider increasing with the option -s"
72 ) from mem_excp
73
74 tl.write_to_file(filename)
75
76
77@cli.command()
78@click.argument("filename", type=click.Path(exists=True, dir_okay=False))
79@click.option(
80 "--fdt-offset",
81 is_flag=True,
82 help="Returns the offset of FDT in the TL if it is present.",
83)
84@click.option(
85 "--header",
86 is_flag=True,
87 help="Print the Transfer List header.",
88)
89@click.option(
90 "--entries",
91 is_flag=True,
92 help="Print the Transfer List entries.",
93)
94def info(filename, fdt_offset, header, entries):
95 """Print the contents of an existing Transfer List.
96
97 This command allows you to extract the data stored in a binary blob
98 representing a transfer list (TL). The transfer list must comply with the
99 version of the firmware handoff specification supported by this tool.
100 """
101 tl = TransferList.fromfile(filename)
102
103 if fdt_offset:
104 return print(tl.get_entry_data_offset(1))
105
106 if header and entries or not (header or entries):
107 print(tl, sep="")
108 if tl.entries:
109 print("----", tl.get_transfer_entries_str(), sep="\n")
110 elif entries:
111 print(tl.get_transfer_entries_str())
112 elif header:
113 print(tl)
114
115
116@cli.command()
117@click.argument("filename", type=click.Path(exists=True, dir_okay=False))
118@click.option(
119 "--tags",
120 type=int,
121 multiple=True,
122 help="Tags to be removed from TL.",
123)
124def remove(filename, tags):
125 """Remove Transfer Entries with given tags.
126
127 Remove Transfer Entries with given tags from a Transfer List."""
128 tl = TransferList.fromfile(filename)
129
130 for tag in tags:
131 tl.remove_tag(tag)
132 tl.write_to_file(filename)
133
134
135@cli.command()
136@click.argument("filename", type=click.Path(exists=True, dir_okay=False))
137@click.option(
138 "--entry",
139 type=(int, click.Path(exists=True)),
140 multiple=True,
141 help="A tag ID and the corresponding path to a binary blob in the form <id> <path-to-blob>.",
142)
143def add(filename, entry):
144 """Update an existing Transfer List with given images."""
145 tl = TransferList.fromfile(filename)
146
147 for id, path in entry:
148 tl.add_transfer_entry_from_file(id, path)
149
150 tl.write_to_file(filename)
151
152
153@cli.command()
154@click.argument("filename", type=click.Path(exists=True, dir_okay=False))
155@click.option(
156 "-C", type=click.Path(exists=True), help="Output directory for extracted images."
157)
158def unpack(filename, c):
159 """Unpack images from a Transfer List."""
160 tl = TransferList.fromfile(filename)
161 pwd = Path(".") if not c else Path(c)
162
163 for i, te in enumerate(tl.entries):
164 with open(pwd / f"te_{i}_{te.id}.bin", "wb") as f:
165 f.write(te.data)
166
167
168@cli.command()
169@click.argument("filename", type=click.Path(exists=True, dir_okay=False))
Harrison Mutai622b6072024-08-21 13:06:46 +0000170@click.option(
171 "--output",
172 "-O",
173 type=click.Path(exists=False),
174 help="Output filename for the header",
175 default=Path("header.h"),
176)
177def gen_header(filename, output):
178 """Generate a header with common definitions."""
179 tl = TransferList.fromfile(filename)
180 tmp_keys = tl.__dict__
181 tmp_keys["header_guard"] = Path(output).name.replace(".", "_").upper()
182
183 dtb_te = tl.get_entry(1)
184
185 if dtb_te:
186 tmp_keys["dtb_offset"] = dtb_te.offset + dtb_te.hdr_size
187
188 env = jinja2.Environment(
189 loader=jinja2.PackageLoader("tlc", "templates"),
190 )
191 template = env.get_template("header.h.j2")
192 with open(output, "w") as f:
193 f.write(template.render(tmp_keys))
194
195
196@cli.command()
197@click.argument("filename", type=click.Path(exists=True, dir_okay=False))
Harrison Mutai19dc4f92024-05-10 16:54:29 +0000198def validate(filename):
199 """Validate the contents of an existing Transfer List."""
200 TransferList.fromfile(filename)
201 print("Valid TL!")