Tests: Secure Partition package

Added template "partition_package" and respective script.

Change-Id: I87fbb28635ebe31f5cf1e61d0569f2782f19b40a
Signed-off-by: Olivier Deprez <olivier.deprez@arm.com>
Signed-off-by: J-Alves <joao.alves@arm.com>
diff --git a/build/image/generate_partition_image.py b/build/image/generate_partition_image.py
new file mode 100755
index 0000000..46fc36a
--- /dev/null
+++ b/build/image/generate_partition_image.py
@@ -0,0 +1,120 @@
+#!/usr/bin/env python3
+#
+# Copyright 2020 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
+import sys
+from shutil import copyfileobj
+import os
+
+HF_PAGE_SIZE = 0x1000
+HEADER_ELEMENT_BYTES = 4 # bytes
+HEADER_LEN = 6
+
+MANIFEST_IMAGE_SPLITTER=':'
+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(4, 'little')
+
+class sp_pkg_info:
+    def __init__(self, manifest_path : str, image_path : str, include_header = True):
+        if not os.path.isfile(manifest_path) or not os.path.isfile(image_path):
+            raise Exception(f"Parameters should be path.  \
+                              manifest: {manifest_path}; image: {image_path}")
+        self.manifest_path = manifest_path
+        self.image_path = image_path
+        self.include_header = include_header
+
+    def __str__(self):
+        return \
+        f'''-------------------SP package Info------------------------
+        header:{self.header}
+        manifest: {self.manifest_path}
+        image: {self.image_path}
+        '''
+
+    @property
+    def magic(self):
+        return "SPKG".encode()
+
+    @property
+    def version(self):
+        return 1
+
+    @property
+    def manifest_offset(self):
+        return self.header_size if self.include_header else 0
+
+    @property
+    def manifest_size(self):
+        return os.path.getsize(self.manifest_path)
+
+    @property
+    def image_offset(self):
+        return align_to_page(self.manifest_offset + self.manifest_size)
+
+    @property
+    def image_size(self):
+        return os.path.getsize(self.image_path)
+
+    @property
+    def header(self):
+        return [self.magic,
+                self.version,
+                self.manifest_offset,
+                self.manifest_size,
+                self.image_offset,
+                self.image_size]
+
+    @property
+    def header_size(self):
+        return (HEADER_ELEMENT_BYTES * HEADER_LEN)
+
+    def generate_package(self, f_out : str):
+        with open(f_out, "wb+") as output:
+            if self.include_header is True:
+                for h in self.header:
+                    to_write = h if type(h) is bytes else to_bytes(h)
+                    output.write(to_write)
+            with open(self.manifest_path, "rb") as manifest:
+                copyfileobj(manifest, output)
+            output.seek(self.image_offset, 0)
+            with open(self.image_path, "rb") as image:
+                copyfileobj(image, output)
+
+def Main():
+    parser = argparse.ArgumentParser()
+    parser.add_argument("-i", required=True,
+                        help="Add Secure Partition image and Manifest blob "
+                             "(specified in two paths) separated by a colon).")
+    parser.add_argument("-o", required=True, help="Set output file path.")
+    parser.add_argument("-n", required=False, action="store_true", default=False,
+                        help="Generate package without header.")
+    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)
+    pkg = sp_pkg_info(manifest_path, image_path, not args.n)
+    pkg.generate_package(args.o)
+
+    return 0
+
+if __name__ == "__main__":
+    sys.exit(Main())