summaryrefslogtreecommitdiff
path: root/tools/sptool
diff options
context:
space:
mode:
authorJ-Alves <joao.alves@arm.com>2022-03-21 16:27:56 +0000
committerJ-Alves <joao.alves@arm.com>2022-05-04 15:36:56 +0100
commit2e82874cc9b7922e000dd4d7718e3153e347b1d7 (patch)
treee60d1995efa18eb03795bc6e34435eaec4500e1d /tools/sptool
parenta96a07bfb66b7d38fe3da824e8ba183967659008 (diff)
downloadarm-trusted-firmware-2e82874cc9b7922e000dd4d7718e3153e347b1d7.tar.gz
feat(sptool): python version of the sptool
To cope with the changes/design decisions in the implementation of boot protocol, from FF-A v1.1 specification in the S-EL2 SPM, we have changed the format of the sp pkg header. These changes need to be reflected in the sptool, used for packaging the SP binary, and the SP's FF-A manifest. Now the SP pkg can contain the boot information blob as defined by the FF-A specification. To cater for these changes, bring to the TF-A project an equivalent to the tool used in the Hafnium project. Signed-off-by: J-Alves <joao.alves@arm.com> Change-Id: I046f5d6e3c2ef0ba6c87f65302e127dedef34c28
Diffstat (limited to 'tools/sptool')
-rwxr-xr-xtools/sptool/sptool.py145
1 files changed, 145 insertions, 0 deletions
diff --git a/tools/sptool/sptool.py b/tools/sptool/sptool.py
new file mode 100755
index 000000000..ae7df92c1
--- /dev/null
+++ b/tools/sptool/sptool.py
@@ -0,0 +1,145 @@
+#!/usr/bin/python3
+# Copyright (c) 2022, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+
+#
+# Copyright 2022 The Hafnium Authors.
+#
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file or at
+# https://opensource.org/licenses/BSD-3-Clause.
+
+"""
+Script which generates a Secure Partition package.
+https://trustedfirmware-a.readthedocs.io/en/latest/components/secure-partition-manager.html#secure-partition-packages
+"""
+
+import argparse
+from collections import namedtuple
+import sys
+from shutil import copyfileobj
+import os
+
+HF_PAGE_SIZE = 0x1000 # bytes
+HEADER_ELEMENT_BYTES = 4 # bytes
+MANIFEST_IMAGE_SPLITTER=':'
+PM_OFFSET_DEFAULT = "0x1000"
+IMG_OFFSET_DEFAULT = "0x4000"
+
+def split_dtb_bin(i : str):
+ return i.split(MANIFEST_IMAGE_SPLITTER)
+
+def align_to_page(n):
+ return HF_PAGE_SIZE * \
+ (round(n / HF_PAGE_SIZE) + \
+ (1 if n % HF_PAGE_SIZE else 0))
+
+def to_bytes(value):
+ return int(value).to_bytes(HEADER_ELEMENT_BYTES, 'little')
+
+class SpPkg:
+ def __init__(self, pm_path : str, img_path : str, pm_offset: int,
+ img_offset: int):
+ if not os.path.isfile(pm_path) or not os.path.isfile(img_path):
+ raise Exception(f"Parameters should be path. \
+ manifest: {pm_path}; img: {img_path}")
+ self.pm_path = pm_path
+ self.img_path = img_path
+ self._SpPkgHeader = namedtuple("SpPkgHeader",
+ ("magic", "version",
+ "pm_offset", "pm_size",
+ "img_offset", "img_size"))
+
+ if pm_offset >= img_offset:
+ raise ValueError("pm_offset must be smaller than img_offset")
+
+ is_hfpage_aligned = lambda val : val % HF_PAGE_SIZE == 0
+ if not is_hfpage_aligned(pm_offset) or not is_hfpage_aligned(img_offset):
+ raise ValueError(f"Offsets provided need to be page aligned: pm-{pm_offset}, img-{img_offset}")
+
+ if img_offset - pm_offset < self.pm_size:
+ raise ValueError(f"pm_offset and img_offset do not fit the specified file:{pm_path})")
+
+ self.pm_offset = pm_offset
+ self.img_offset = img_offset
+
+ def __str__(self):
+ return \
+ f'''--SP package Info--
+ header:{self.header}
+ pm: {self.pm_path}
+ img: {self.img_path}
+ '''
+
+ @property
+ def magic(self):
+ return "SPKG".encode()
+
+ @property
+ def version(self):
+ return 0x2
+
+ @property
+ def pm_size(self):
+ return os.path.getsize(self.pm_path)
+
+ @property
+ def img_size(self):
+ return os.path.getsize(self.img_path)
+
+ @property
+ def header(self):
+ return self._SpPkgHeader(
+ self.magic,
+ self.version,
+ self.pm_offset,
+ self.pm_size,
+ self.img_offset,
+ self.img_size)
+
+ @property
+ def header_size(self):
+ return len(self._SpPkgHeader._fields)
+
+ def generate(self, f_out : str):
+ with open(f_out, "wb+") as output:
+ for h in self.header:
+ to_write = h if type(h) is bytes else to_bytes(h)
+ output.write(to_write)
+ output.seek(self.pm_offset)
+ with open(self.pm_path, "rb") as pm:
+ copyfileobj(pm, output)
+ output.seek(self.img_offset)
+ with open(self.img_path, "rb") as img:
+ copyfileobj(img, output)
+
+def Main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument("-i", required=True,
+ help="path to partition's image and manifest separated by a colon.")
+ parser.add_argument("--pm-offset", required=False, default=PM_OFFSET_DEFAULT,
+ help="set partitition manifest offset.")
+ parser.add_argument("--img-offset", required=False, default=IMG_OFFSET_DEFAULT,
+ help="set partition image offset.")
+ parser.add_argument("-o", required=True, help="set output file path.")
+ parser.add_argument("-v", required=False, action="store_true",
+ help="print package information.")
+ args = parser.parse_args()
+
+ if not os.path.exists(os.path.dirname(args.o)):
+ raise Exception("Provide a valid output file path!\n")
+
+ image_path, manifest_path = split_dtb_bin(args.i)
+ pm_offset = int(args.pm_offset, 0)
+ img_offset = int(args.img_offset, 0)
+ pkg = SpPkg(manifest_path, image_path, pm_offset, img_offset)
+ pkg.generate(args.o)
+
+ if args.v is True:
+ print(pkg)
+
+ return 0
+
+if __name__ == "__main__":
+ sys.exit(Main())