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/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