Build: Enhance handling of images

This change enhances the assembly and signing of images with scripting.
Macros that are needed for these processes are now extracted from
the flash_layout.h files with python scripts.
The built images are not modified.

Change-Id: Iba00bdd3217b302df8968ce2619e31a1bc961e42
Signed-off-by: Sverteczky, Marcell <marcell.sverteczky@arm.com>
diff --git a/bl2/ext/mcuboot/MCUBoot.cmake b/bl2/ext/mcuboot/MCUBoot.cmake
index 9770f99..f685121 100644
--- a/bl2/ext/mcuboot/MCUBoot.cmake
+++ b/bl2/ext/mcuboot/MCUBoot.cmake
@@ -64,16 +64,22 @@
 	set(FILE_TO_PREPROCESS ${CMAKE_BINARY_DIR}/image_macros_to_preprocess.c)
 	set(PREPROCESSED_FILE ${CMAKE_BINARY_DIR}/image_macros_preprocessed.c)
 	set(CONTENT_FOR_PREPROCESSING "#include \"${FLASH_LAYOUT}\"\n\n"
-		"/* Enumeration that is used by the assemble.py script for correct binary generation when nested macros are used */\n"
+		"/* Enumeration that is used by the assemble.py and imgtool.py scripts\n"
+		" * for correct binary generation when nested macros are used\n"
+		" */\n"
 		"enum image_attributes {\n"
 		"\tRE_SECURE_IMAGE_OFFSET = SECURE_IMAGE_OFFSET,\n"
 		"\tRE_SECURE_IMAGE_MAX_SIZE = SECURE_IMAGE_MAX_SIZE,\n"
 		"\tRE_NON_SECURE_IMAGE_OFFSET = NON_SECURE_IMAGE_OFFSET,\n"
-		"\tRE_NON_SECURE_IMAGE_MAX_SIZE = NON_SECURE_IMAGE_MAX_SIZE\n}\;"
+		"\tRE_NON_SECURE_IMAGE_MAX_SIZE = NON_SECURE_IMAGE_MAX_SIZE,\n"
+		"#ifdef IMAGE_LOAD_ADDRESS\n"
+		"\tRE_IMAGE_LOAD_ADDRESS = IMAGE_LOAD_ADDRESS,\n"
+		"#endif\n"
+		"\tRE_SIGN_BIN_SIZE = SIGN_BIN_SIZE\n}\;"
 	)
 
 	#Create a file that will be preprocessed later in order to be able to handle nested macros
-	#in the flash_layout.h file for certain macros
+	#in header files for certain macros
 	file(WRITE ${FILE_TO_PREPROCESS} ${CONTENT_FOR_PREPROCESSING})
 
 	#Preprocess the .c file that contains the image related macros
@@ -86,7 +92,7 @@
 						POST_BUILD
 						#Create concatenated binary image from the two binary file
 						COMMAND ${PYTHON_EXECUTABLE} ${MCUBOOT_DIR}/scripts/assemble.py
-						ARGS -l ${PREPROCESSED_FILE}
+						ARGS --layout ${PREPROCESSED_FILE}
 							 -s $<TARGET_FILE_DIR:${_MY_PARAMS_S_BIN}>/${_MY_PARAMS_S_BIN}.bin
 							 -n $<TARGET_FILE_DIR:${_MY_PARAMS_NS_BIN}>/${_MY_PARAMS_NS_BIN}.bin
 							 -o ${CMAKE_BINARY_DIR}/${_MY_PARAMS_FULL_BIN}.bin
@@ -94,13 +100,12 @@
 						#Sign concatenated binary image with default public key in mcuboot folder
 						COMMAND ${PYTHON_EXECUTABLE} ${MCUBOOT_DIR}/scripts/imgtool.py
 						ARGS sign
-							 --layout ${FLASH_LAYOUT}
+							 --layout ${PREPROCESSED_FILE}
 							 -k ${KEY_FILE}
 							 --align 1
 							 -v ${IMAGE_VERSION}
 							 ${ADD_SECURITY_COUNTER}
 							 -H 0x400
-							 --pad ${SIGN_BIN_SIZE}
 							 ${CMAKE_BINARY_DIR}/${_MY_PARAMS_FULL_BIN}.bin
 							 ${CMAKE_BINARY_DIR}/${_MY_PARAMS_SIGN_BIN}.bin)
 
diff --git a/bl2/ext/mcuboot/scripts/assemble.py b/bl2/ext/mcuboot/scripts/assemble.py
index f446f90..5a75424 100644
--- a/bl2/ext/mcuboot/scripts/assemble.py
+++ b/bl2/ext/mcuboot/scripts/assemble.py
@@ -25,26 +25,10 @@
 import re
 import os
 import shutil
+import macro_parser
 
-offset_re = re.compile(r"^\s*RE_([0-9A-Z_]+)_IMAGE_OFFSET\s*=\s*(((0x)?[0-9a-fA-F]+)\s*([\+\-]\s*((0x)?[0-9a-fA-F]+)\s*)*)")
-size_re = re.compile(r"^\s*RE_([0-9A-Z_]+)_IMAGE_MAX_SIZE\s*=\s*(((0x)?[0-9a-fA-F]+)\s*([\+\-]\s*((0x)?[0-9a-fA-F]+)\s*)*)")
-
-#Simple parser that takes a string and evaluates an expression from it.
-#The expression might contain additions and subtractions amongst numbers that are
-#written in decimal or hexadecimal form.
-def parse_and_sum(text):
-    nums = re.findall(r'[0x\d]+|[\d]+', text)
-    for i in range(len(nums)):
-        nums[i] = int(nums[i], 0)
-    ops = re.findall(r'\+|\-', text)
-    sum = nums[0]
-    for i in range(len(ops)):
-        if ops[i] == '+':
-            sum += nums[i+1]
-        else:
-            sum -= nums[i+1]
-    return sum
-
+offset_re = re.compile(r"^\s*RE_([0-9A-Z_]+)_IMAGE_OFFSET\s*=\s*(.*)")
+size_re = re.compile(r"^\s*RE_([0-9A-Z_]+)_IMAGE_MAX_SIZE\s*=\s*(.*)")
 
 class Assembly():
     def __init__(self, layout_path, output):
@@ -61,20 +45,8 @@
         offsets = {}
         sizes = {}
 
-        if os.path.isabs(self.layout_path):
-            configFile = self.layout_path
-        else:
-            scriptsDir = os.path.dirname(os.path.abspath(__file__))
-            configFile = os.path.join(scriptsDir, self.layout_path)
-
-        with open(configFile, 'r') as fd:
-            for line in fd:
-                m = offset_re.match(line)
-                if m is not None:
-                    offsets[m.group(1)] = parse_and_sum(m.group(2))
-                m = size_re.match(line)
-                if m is not None:
-                    sizes[m.group(1)] = parse_and_sum(m.group(2))
+        offsets = macro_parser.evaluate_macro(self.layout_path, offset_re, 1, 2)
+        sizes = macro_parser.evaluate_macro(self.layout_path, size_re, 1, 2)
 
         if 'SECURE' not in offsets:
             raise Exception("Image config does not have secure partition")
@@ -103,7 +75,7 @@
     parser = argparse.ArgumentParser()
 
     parser.add_argument('-l', '--layout', required=True,
-            help='Location of the memory layout file')
+            help='Location of the file that contains preprocessed macros')
     parser.add_argument('-s', '--secure', required=True,
             help='Unsigned secure image')
     parser.add_argument('-n', '--non_secure',
diff --git a/bl2/ext/mcuboot/scripts/imgtool.py b/bl2/ext/mcuboot/scripts/imgtool.py
index 43d7d15..b226faf 100644
--- a/bl2/ext/mcuboot/scripts/imgtool.py
+++ b/bl2/ext/mcuboot/scripts/imgtool.py
@@ -23,28 +23,10 @@
 from imgtool_lib import image
 from imgtool_lib import version
 import sys
+import macro_parser
 
-def find_load_address(args):
-    load_address_re = re.compile(r"^#define\sIMAGE_LOAD_ADDRESS\s+(0x[0-9a-fA-F]+)")
-
-    if os.path.isabs(args.layout):
-            configFile = args.layout
-    else:
-        scriptsDir = os.path.dirname(os.path.abspath(__file__))
-        configFile = os.path.join(scriptsDir, args.layout)
-
-    ramLoadAddress = None
-    with open(configFile, 'r') as flash_layout_file:
-        for line in flash_layout_file:
-            m = load_address_re.match(line)
-            if m is not None:
-                ramLoadAddress = int(m.group(1), 0)
-                print("**[INFO]** Writing load address from the macro in "
-                      "flash_layout.h to the image header.. "
-                       + hex(ramLoadAddress)
-                       + " (dec. " + str(ramLoadAddress) + ")")
-                break
-    return ramLoadAddress
+sign_bin_size_re = re.compile(r"^\s*RE_SIGN_BIN_SIZE\s*=\s*(.*)")
+image_load_address_re = re.compile(r"^\s*RE_IMAGE_LOAD_ADDRESS\s*=\s*(.*)")
 
 # Returns the last version number if present, or None if not
 def get_last_version(path):
@@ -118,17 +100,19 @@
                                  + (version_num.minor << 16)
                                  + version_num.revision)
 
+    pad_size = macro_parser.evaluate_macro(args.layout, sign_bin_size_re, 0, 1)
     img = image.Image.load(args.infile,
                            version=version_num,
                            header_size=args.header_size,
                            security_cnt=args.security_counter,
                            included_header=args.included_header,
-                           pad=args.pad)
+                           pad=pad_size)
     key = keys.load(args.key) if args.key else None
-    img.sign(key, find_load_address(args))
+    ram_load_address = macro_parser.evaluate_macro(args.layout, image_load_address_re, 0, 1)
+    img.sign(key, ram_load_address)
 
-    if args.pad:
-        img.pad_to(args.pad, args.align)
+    if pad_size:
+        img.pad_to(pad_size, args.align)
 
     img.save(args.outfile)
 
@@ -164,8 +148,8 @@
     getpub.add_argument('-l', '--lang', metavar='lang', default='c')
 
     sign = subs.add_parser('sign', help='Sign an image with a private key')
-    sign.add_argument('--layout', required=True,
-                      help='Location of the memory layout file')
+    sign.add_argument('-l', '--layout', required=True,
+                      help='Location of the file that contains preprocessed macros')
     sign.add_argument('-k', '--key', metavar='filename')
     sign.add_argument("--align", type=alignment_value, required=True)
     sign.add_argument("-v", "--version", type=version.decode_version,
@@ -175,8 +159,6 @@
     sign.add_argument("-H", "--header-size", type=intparse, required=True)
     sign.add_argument("--included-header", default=False, action='store_true',
                       help='Image has gap for header')
-    sign.add_argument("--pad", type=intparse,
-                      help='Pad image to this many bytes, adding trailer magic')
     sign.add_argument("--rsa-pkcs1-15",
                       help='Use old PKCS#1 v1.5 signature algorithm',
                       default=False, action='store_true')
diff --git a/bl2/ext/mcuboot/scripts/macro_parser.py b/bl2/ext/mcuboot/scripts/macro_parser.py
new file mode 100644
index 0000000..3f7feb6
--- /dev/null
+++ b/bl2/ext/mcuboot/scripts/macro_parser.py
@@ -0,0 +1,70 @@
+#! /usr/bin/env python3

+#

+# -----------------------------------------------------------------------------

+# Copyright (c) 2019, Arm Limited. All rights reserved.

+#

+# SPDX-License-Identifier: BSD-3-Clause

+#

+# -----------------------------------------------------------------------------

+

+

+import re

+import os

+

+expression_re = re.compile(r"[(]?(([(]?(((0x)[0-9a-fA-F]+)|([0-9]+))[)]?)\s*([\+\-]\s*([(]?(((0x)[0-9a-fA-F]+)|([0-9]+))[)]?)\s*)*)[)]?")

+

+# Simple parser that takes a string and evaluates an expression from it.

+# The expression might contain additions and subtractions amongst numbers that

+# are written in decimal or hexadecimal form.

+# The parses can process expressions in which the parentheses does not change

+# the sign of the following number or numbers in an expression.

+# Thus the parser can process the following expression: (x + y)

+# However it will not calculate the correct sum for the expression below:

+# (x - (y + z))

+def parse_and_sum(text):

+    m = expression_re.match(text)

+    if m is None:

+        msg = "The script was probably invoked manually"

+        msg += " with having certain macros nested in flash_layouts.h.\n"

+        msg += "Please revisit the flash_layout.h file and hardcode values"

+        msg += " for the (NON-)SECURE_IMAGE_OFFSET and"

+        msg += " (NON-)SECURE_IMAGE_MAX_SIZE macros"

+        raise Exception(msg)

+

+    nums = re.findall(r'(0x[A-Fa-f0-9]+)|[\d]+', m.group(0))

+    for i in range(len(nums)):

+        nums[i] = int(nums[i], 0)

+    ops = re.findall(r'\+|\-', m.group(0))

+    sum = nums[0]

+    for i in range(len(ops)):

+        if ops[i] == '+':

+            sum += nums[i+1]

+        else:

+            sum -= nums[i+1]

+    return sum

+

+

+# Opens a file that contains the macro of interest, then finds the macro with

+# a regular expression, parses the expression that is defined for the given

+# macro. Lastly it evaluates the expression with the parse_and_sum function

+def evaluate_macro(file, regexp, matchGroupKey, matchGroupData):

+    regexp_compiled = re.compile(regexp)

+

+    if os.path.isabs(file):

+        configFile = file

+    else:

+        scriptsDir = os.path.dirname(os.path.abspath(__file__))

+        configFile = os.path.join(scriptsDir, file)

+

+    macroValue = {}

+    with open(configFile, 'r') as macros_preprocessed_file:

+        for line in macros_preprocessed_file:

+            m = regexp_compiled.match(line)

+            if m is not None:

+                macroValue[m.group(matchGroupKey)] = \

+                parse_and_sum(m.group(matchGroupData))

+

+    if (matchGroupKey == 0 and not macroValue):

+        macroValue["None"] = None

+

+    return list(macroValue.values())[0] if (matchGroupKey == 0) else macroValue

diff --git a/platform/ext/Mps2AN519.cmake b/platform/ext/Mps2AN519.cmake
index 9206a6a..8f09654 100644
--- a/platform/ext/Mps2AN519.cmake
+++ b/platform/ext/Mps2AN519.cmake
@@ -34,7 +34,6 @@
 endif()
 set (FLASH_LAYOUT          "${PLATFORM_DIR}/target/mps2/an519/partition/flash_layout.h")
 set (PLATFORM_LINK_INCLUDES "${PLATFORM_DIR}/target/mps2/an519/partition/")
-set (SIGN_BIN_SIZE         0x100000)
 
 if (BL2)
   set (BL2_LINKER_CONFIG ${BL2_SCATTER_FILE_NAME})
diff --git a/platform/ext/Mps2AN521.cmake b/platform/ext/Mps2AN521.cmake
index 7c5c970..8b1f4ea 100644
--- a/platform/ext/Mps2AN521.cmake
+++ b/platform/ext/Mps2AN521.cmake
@@ -35,7 +35,6 @@
 endif()
 set (FLASH_LAYOUT           "${PLATFORM_DIR}/target/mps2/an521/partition/flash_layout.h")
 set (PLATFORM_LINK_INCLUDES "${PLATFORM_DIR}/target/mps2/an521/partition/")
-set (SIGN_BIN_SIZE          0x100000)
 
 if (BL2)
   set (BL2_LINKER_CONFIG ${BL2_SCATTER_FILE_NAME})
diff --git a/platform/ext/Mps3AN524.cmake b/platform/ext/Mps3AN524.cmake
index 94fdef4..419c9bc 100644
--- a/platform/ext/Mps3AN524.cmake
+++ b/platform/ext/Mps3AN524.cmake
@@ -42,7 +42,6 @@
 endif()
 set (FLASH_LAYOUT "${AN524_DIR}/partition/flash_layout.h")
 set (PLATFORM_LINK_INCLUDES "${AN524_DIR}/partition/")
-set (SIGN_BIN_SIZE 0x80000)
 
 if (BL2)
     set (BL2_LINKER_CONFIG ${BL2_SCATTER_FILE_NAME})
diff --git a/platform/ext/musca_a.cmake b/platform/ext/musca_a.cmake
index 7433f44..8813780 100644
--- a/platform/ext/musca_a.cmake
+++ b/platform/ext/musca_a.cmake
@@ -34,7 +34,6 @@
 endif()
 set (FLASH_LAYOUT          "${PLATFORM_DIR}/target/musca_a/partition/flash_layout.h")
 set (PLATFORM_LINK_INCLUDES "${PLATFORM_DIR}/target/musca_a/partition")
-set (SIGN_BIN_SIZE         0x100000)
 
 if (BL2)
   set (BL2_LINKER_CONFIG ${BL2_SCATTER_FILE_NAME})
diff --git a/platform/ext/musca_b1.cmake b/platform/ext/musca_b1.cmake
index 7d3f5c2..77b51f6 100644
--- a/platform/ext/musca_b1.cmake
+++ b/platform/ext/musca_b1.cmake
@@ -34,7 +34,6 @@
 endif()
 set(FLASH_LAYOUT           "${PLATFORM_DIR}/target/musca_b1/partition/flash_layout.h")
 set(PLATFORM_LINK_INCLUDES "${PLATFORM_DIR}/target/musca_b1/partition")
-set(SIGN_BIN_SIZE          0xC0000)
 
 if (BL2)
     set(BL2_LINKER_CONFIG ${BL2_SCATTER_FILE_NAME})
diff --git a/platform/ext/target/mps2/an519/partition/flash_layout.h b/platform/ext/target/mps2/an519/partition/flash_layout.h
index 13fd8c8..4dc96fd 100644
--- a/platform/ext/target/mps2/an519/partition/flash_layout.h
+++ b/platform/ext/target/mps2/an519/partition/flash_layout.h
@@ -48,6 +48,8 @@
  * above.
  */
 #define FLASH_PARTITION_SIZE            (0x80000)    /* 512 kB */
+#define SIGN_BIN_SIZE                   (FLASH_PARTITION_SIZE + \
+                                        FLASH_PARTITION_SIZE)
 
 /* Sector size of the flash hardware; same as FLASH0_SECTOR_SIZE */
 #define FLASH_AREA_IMAGE_SECTOR_SIZE    (0x1000)     /* 4 kB */
diff --git a/platform/ext/target/mps2/an521/partition/flash_layout.h b/platform/ext/target/mps2/an521/partition/flash_layout.h
index 2aff59b..c9c56e9 100644
--- a/platform/ext/target/mps2/an521/partition/flash_layout.h
+++ b/platform/ext/target/mps2/an521/partition/flash_layout.h
@@ -48,6 +48,8 @@
  * above.
  */
 #define FLASH_PARTITION_SIZE            (0x80000)    /* 512 kB */
+#define SIGN_BIN_SIZE                   (FLASH_PARTITION_SIZE + \
+                                        FLASH_PARTITION_SIZE)
 
 /* Sector size of the flash hardware; same as FLASH0_SECTOR_SIZE */
 #define FLASH_AREA_IMAGE_SECTOR_SIZE    (0x1000)     /* 4 kB */
diff --git a/platform/ext/target/mps3/an524/partition/flash_layout.h b/platform/ext/target/mps3/an524/partition/flash_layout.h
index 6c9739b..d854bc0 100644
--- a/platform/ext/target/mps3/an524/partition/flash_layout.h
+++ b/platform/ext/target/mps3/an524/partition/flash_layout.h
@@ -67,6 +67,8 @@
 
 #define FLASH_AREA_S_IMAGE_SIZE         0x40000     /* 256 KB */
 #define FLASH_AREA_NS_IMAGE_SIZE        0x40000     /* 256 KB */
+#define SIGN_BIN_SIZE                   (FLASH_AREA_S_IMAGE_SIZE + \
+                                        FLASH_AREA_NS_IMAGE_SIZE)
 
 #define FLASH_AREA_IMAGE_SLOT_SIZE      (FLASH_AREA_S_IMAGE_SIZE + \
                                          FLASH_AREA_NS_IMAGE_SIZE)
diff --git a/platform/ext/target/musca_a/partition/flash_layout.h b/platform/ext/target/musca_a/partition/flash_layout.h
index 1bda7fe..744ecbd 100644
--- a/platform/ext/target/musca_a/partition/flash_layout.h
+++ b/platform/ext/target/musca_a/partition/flash_layout.h
@@ -51,6 +51,8 @@
  * above.
  */
 #define FLASH_PARTITION_SIZE            (0x80000) /* 512KB */
+#define SIGN_BIN_SIZE                   (FLASH_PARTITION_SIZE + \
+                                        FLASH_PARTITION_SIZE)
 
 /* Sector size of the flash hardware */
 #define FLASH_AREA_IMAGE_SECTOR_SIZE    (0x1000)   /* 4KB */
diff --git a/platform/ext/target/musca_b1/partition/flash_layout.h b/platform/ext/target/musca_b1/partition/flash_layout.h
index c03ade0..31b5dd7 100644
--- a/platform/ext/target/musca_b1/partition/flash_layout.h
+++ b/platform/ext/target/musca_b1/partition/flash_layout.h
@@ -50,6 +50,8 @@
 #define FLASH_NS_PARTITION_SIZE         (0x80000) /* NS partition: 512 KB */
 #define FLASH_PARTITION_SIZE            (FLASH_S_PARTITION_SIZE + \
                                          FLASH_NS_PARTITION_SIZE)
+#define SIGN_BIN_SIZE                   (FLASH_S_PARTITION_SIZE + \
+                                         FLASH_NS_PARTITION_SIZE)
 
 /* Sector size of the flash hardware */
 #define FLASH_AREA_IMAGE_SECTOR_SIZE    (0x1000)   /* 4KB */