refactor: change format of sp pkg

Hafnium supports 1-to-1 mapping of PAs to IPAs. According to the boot
protocol from FF-A v1.1 EAC0 spec, the boot information blob should be
provided in a continuous memory segment.
In order to simplify Hafnium's memory operations at boot stage, the SP
Package has been refactored to allocate space for the boot information
blob.
The change made to 'manifest.c' and to test SPs configuration is to
prevent this change from breaking the tests. The SP package
initialization in hafnium is revised in a subsequent patch.

Change-Id: I1d0a0b0aad3e305b3a33cd2bde55fc1f096586ca
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
deleted file mode 100755
index 46fc36a..0000000
--- a/build/image/generate_partition_image.py
+++ /dev/null
@@ -1,120 +0,0 @@
-#!/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())
diff --git a/build/image/image.gni b/build/image/image.gni
index 50ca799..5b1ac1b 100644
--- a/build/image/image.gni
+++ b/build/image/image.gni
@@ -364,7 +364,7 @@
 
   action(target_name) {
     forward_variables_from(invoker, [ "testonly" ])
-    script = "//build/image/generate_partition_image.py"
+    script = "//build/image/sptool.py"
 
     output_package = "${base_out_dir}/${invoker.output}"
 
@@ -386,6 +386,13 @@
       ]
     }
 
+    args += [
+      "--pm-offset",
+      "${invoker.pm_offset}",
+      "--img-offset",
+      "${invoker.img_offset}",
+    ]
+
     outputs = [
       output_package,
     ]
diff --git a/build/image/sptool.py b/build/image/sptool.py
new file mode 100755
index 0000000..949bd99
--- /dev/null
+++ b/build/image/sptool.py
@@ -0,0 +1,141 @@
+#!/usr/bin/env python3
+#
+# 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())
diff --git a/inc/hf/manifest.h b/inc/hf/manifest.h
index 91f07ad..553f99c 100644
--- a/inc/hf/manifest.h
+++ b/inc/hf/manifest.h
@@ -19,7 +19,7 @@
 #define MANIFEST_INVALID_ID UINT32_MAX
 
 #define SP_PKG_HEADER_MAGIC (0x474b5053)
-#define SP_PKG_HEADER_VERSION (0x1)
+#define SP_PKG_HEADER_VERSION (0x2)
 
 #define SP_RTX_BUF_NAME_SIZE 10
 
diff --git a/src/manifest.c b/src/manifest.c
index b514472..502d412 100644
--- a/src/manifest.c
+++ b/src/manifest.c
@@ -797,14 +797,9 @@
 		goto exit_unmap;
 	}
 
-	/* Expect DTB to immediately follow header */
-	if (sp_pkg->pm_offset != sizeof(struct sp_pkg_header)) {
-		dlog_error("Invalid package manifest offset.\n");
-		goto exit_unmap;
-	}
+	/* TODO: Do not map 2 pages. */
+	sp_header_dtb_size = align_up(sp_pkg->pm_size, 2 * PAGE_SIZE);
 
-	sp_header_dtb_size = align_up(
-		sp_pkg->pm_size + sizeof(struct sp_pkg_header), PAGE_SIZE);
 	if ((vm_id != HF_PRIMARY_VM_ID) &&
 	    (sp_header_dtb_size >= vm->secondary.mem_size)) {
 		dlog_error("Invalid package header or DT size.\n");
diff --git a/test/vmapi/ffa_secure_partition_only/BUILD.gn b/test/vmapi/ffa_secure_partition_only/BUILD.gn
index 7a4aadc..e7529e2 100644
--- a/test/vmapi/ffa_secure_partition_only/BUILD.gn
+++ b/test/vmapi/ffa_secure_partition_only/BUILD.gn
@@ -28,6 +28,8 @@
 
 partition_package("ffa_secure_partition_only_test_package") {
   testonly = true
+  pm_offset = "0x1000"
+  img_offset = "0x2000"
   files = [ [
         "partition-manifest.dtb",
         "secure_partition_test_vm.bin",
diff --git a/test/vmapi/ffa_secure_partition_only/partition-manifest.dts b/test/vmapi/ffa_secure_partition_only/partition-manifest.dts
index ab4fe89..e27a107 100644
--- a/test/vmapi/ffa_secure_partition_only/partition-manifest.dts
+++ b/test/vmapi/ffa_secure_partition_only/partition-manifest.dts
@@ -19,7 +19,7 @@
 	exception-level = <2>; /* S-EL1 */
 	execution-state = <0>; /* AARCH64 */
 	load-address = <0x6280000>;
-	entrypoint-offset = <0x1000>;
+	entrypoint-offset = <0x2000>;
 	xlat-granule = <0>; /* 4KiB */
 	messaging-method = <0>; /* Direct messaging only */
 
diff --git a/test/vmapi/ffa_secure_partitions/BUILD.gn b/test/vmapi/ffa_secure_partitions/BUILD.gn
index b012326..d34e21f 100644
--- a/test/vmapi/ffa_secure_partitions/BUILD.gn
+++ b/test/vmapi/ffa_secure_partitions/BUILD.gn
@@ -54,6 +54,8 @@
 
 partition_package("service_sp_second_package") {
   testonly = true
+  pm_offset = "0x1000"
+  img_offset = "0x2000"
   files = [ [
         "partition_manifest_service_sp_second.dtb",
         "secure_partitions_services.bin",
@@ -65,6 +67,8 @@
 
 partition_package("service_sp_first_package") {
   testonly = true
+  pm_offset = "0x1000"
+  img_offset = "0x2000"
   files = [ [
         "partition_manifest_service_sp_first.dtb",
         "secure_partitions_services.bin",
@@ -81,6 +85,8 @@
 
 partition_package("vm_primary_test_package") {
   testonly = true
+  pm_offset = "0x1000"
+  img_offset = "0x2000"
   files = [ [
         "partition_manifest_nwd_primary.dtb",
         "vm_primary.bin",
@@ -106,6 +112,8 @@
 
 partition_package("service_sp_second_el0_package") {
   testonly = true
+  pm_offset = "0x1000"
+  img_offset = "0x2000"
   files = [ [
         "partition_manifest_service_sp_second_el0.dtb",
         "sel0_partition.bin",
diff --git a/test/vmapi/ffa_secure_partitions/partition_manifest_nwd_primary.dts b/test/vmapi/ffa_secure_partitions/partition_manifest_nwd_primary.dts
index a5ebc77..2434ca5 100644
--- a/test/vmapi/ffa_secure_partitions/partition_manifest_nwd_primary.dts
+++ b/test/vmapi/ffa_secure_partitions/partition_manifest_nwd_primary.dts
@@ -19,7 +19,7 @@
 	exception-level = <0>; /* EL1 */
 	execution-state = <0>; /* AARCH64 */
 	load-address = <0x90000000>;
-	entrypoint-offset = <0x1000>;
+	entrypoint-offset = <0x2000>;
 	xlat-granule = <0>; /* 4KiB */
 	messaging-method = <0x3>; /* Supports sending/receiving direct requests. */
 	notification-support; /* Receipt of notifications. */
diff --git a/test/vmapi/ffa_secure_partitions/partition_manifest_service_sp_first.dts b/test/vmapi/ffa_secure_partitions/partition_manifest_service_sp_first.dts
index bc1cb01..0dade1b 100644
--- a/test/vmapi/ffa_secure_partitions/partition_manifest_service_sp_first.dts
+++ b/test/vmapi/ffa_secure_partitions/partition_manifest_service_sp_first.dts
@@ -19,7 +19,7 @@
 	exception-level = <2>; /* S-EL1 */
 	execution-state = <0>; /* AARCH64 */
 	load-address = <0x6480000>;
-	entrypoint-offset = <0x1000>;
+	entrypoint-offset = <0x2000>;
 	xlat-granule = <0>; /* 4KiB */
 	messaging-method = <0x3>; /* Supports sending/receiving direct requests. */
 	boot-order = <1>;
diff --git a/test/vmapi/ffa_secure_partitions/partition_manifest_service_sp_second.dts b/test/vmapi/ffa_secure_partitions/partition_manifest_service_sp_second.dts
index 1b2cefa..5e33df3 100644
--- a/test/vmapi/ffa_secure_partitions/partition_manifest_service_sp_second.dts
+++ b/test/vmapi/ffa_secure_partitions/partition_manifest_service_sp_second.dts
@@ -19,7 +19,7 @@
 	exception-level = <2>; /* S-EL1 */
 	execution-state = <0>; /* AARCH64 */
 	load-address = <0x6380000>;
-	entrypoint-offset = <0x1000>;
+	entrypoint-offset = <0x2000>;
 	xlat-granule = <0>; /* 4KiB */
 	messaging-method = <0x3>; /* Supports sending/receiving direct requests. */
 	boot-order = <4>;
diff --git a/test/vmapi/ffa_secure_partitions/partition_manifest_service_sp_second_el0.dts b/test/vmapi/ffa_secure_partitions/partition_manifest_service_sp_second_el0.dts
index 98fef8b..f19bffe 100644
--- a/test/vmapi/ffa_secure_partitions/partition_manifest_service_sp_second_el0.dts
+++ b/test/vmapi/ffa_secure_partitions/partition_manifest_service_sp_second_el0.dts
@@ -19,7 +19,7 @@
   exception-level = <1>; /* S-EL0 */
   execution-state = <0>; /* AARCH64 */
   load-address = <0x6290000>;
-  entrypoint-offset = <0x1000>;
+  entrypoint-offset = <0x2000>;
   xlat-granule = <0>; /* 4KiB */
   messaging-method = <0x3>; /* Direct messaging only */
   boot-order = <4>;
diff --git a/test/vmapi/primary_only_ffa/BUILD.gn b/test/vmapi/primary_only_ffa/BUILD.gn
index 12e0b60..1989840 100644
--- a/test/vmapi/primary_only_ffa/BUILD.gn
+++ b/test/vmapi/primary_only_ffa/BUILD.gn
@@ -28,6 +28,8 @@
 
 partition_package("primary_only_ffa_test_package") {
   testonly = true
+  pm_offset = "0x1000"
+  img_offset = "0x2000"
   files = [ [
         "partition-manifest.dtb",
         "primary_only_test_vm.bin",