Infineon: Switch to 1.9.0 code base, add xmc7000 family support, refactor memory layer
diff --git a/scripts/assemble.py b/scripts/assemble.py
index 0f39fcc..05f9793 100755
--- a/scripts/assemble.py
+++ b/scripts/assemble.py
@@ -26,6 +26,7 @@
 import re
 import os
 import os.path
+import pickle
 import sys
 
 def same_keys(a, b):
@@ -95,13 +96,12 @@
             ofd.write(ibuf)
 
 def find_board_name(bootdir):
-    suffix = ".dts.pre.tmp"
-
-    for _, _, files in os.walk(os.path.join(bootdir, "zephyr")):
-        for filename in files:
-            if filename.endswith(suffix):
-                return filename[:-len(suffix)]
-
+    dot_config = os.path.join(bootdir, "zephyr", ".config")
+    with open(dot_config, "r") as f:
+        for line in f:
+            if line.startswith("CONFIG_BOARD="):
+                return line.split("=", 1)[1].strip('"')
+    raise Exception("Expected CONFIG_BOARD line in {}".format(dot_config))
 
 def main():
     parser = argparse.ArgumentParser()
@@ -132,10 +132,10 @@
 
     board = find_board_name(args.bootdir)
 
-    dts_path = os.path.join(args.bootdir, "zephyr", board + ".dts.pre.tmp")
-
-    edt = devicetree.edtlib.EDT(dts_path, [os.path.join(zephyr_base, "dts", "bindings")],
-            warn_reg_unit_address_mismatch=False)
+    edt_pickle = os.path.join(args.bootdir, "zephyr", "edt.pickle")
+    with open(edt_pickle, 'rb') as f:
+        edt = pickle.load(f)
+        assert isinstance(edt, devicetree.edtlib.EDT)
 
     output = Assembly(args.output, args.bootdir, edt)
 
diff --git a/scripts/imgtool.nix b/scripts/imgtool.nix
index 9ac41bc..ea9ba8b 100644
--- a/scripts/imgtool.nix
+++ b/scripts/imgtool.nix
@@ -20,7 +20,7 @@
       python37.pkgs.cryptography
       python37.pkgs.intelhex
       python37.pkgs.setuptools
-      python37.pkgs.cbor
+      python37.pkgs.cbor2
     ]
   );
 in
diff --git a/scripts/imgtool/__init__.py b/scripts/imgtool/__init__.py
index ca43b8d..a7f5978 100644
--- a/scripts/imgtool/__init__.py
+++ b/scripts/imgtool/__init__.py
@@ -14,4 +14,4 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-imgtool_version = "1.8.0"
+imgtool_version = "1.9.0"
diff --git a/scripts/imgtool/boot_record.py b/scripts/imgtool/boot_record.py
index ac433aa..8ab2f60 100644
--- a/scripts/imgtool/boot_record.py
+++ b/scripts/imgtool/boot_record.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2019, Arm Limited.
+# Copyright (c) 2019-2021, Arm Limited.
 # Copyright (c) 2020, Linaro Limited
 #
 # SPDX-License-Identifier: Apache-2.0
@@ -16,8 +16,11 @@
 # limitations under the License.
 
 from enum import Enum
-import cbor
 
+try:
+    from cbor2 import dumps
+except ImportError:
+    from cbor import dumps
 
 class SwComponent(int, Enum):
     """
@@ -46,4 +49,4 @@
     #       list because later it will be modified by the bootloader.
     properties[SwComponent.MEASUREMENT_VALUE] = sw_measurement_value
 
-    return cbor.dumps(properties)
+    return dumps(properties)
diff --git a/scripts/imgtool/image.py b/scripts/imgtool/image.py
index 2a5eb59..7109446 100644
--- a/scripts/imgtool/image.py
+++ b/scripts/imgtool/image.py
@@ -43,7 +43,7 @@
 BIN_EXT = "bin"
 INTEL_HEX_EXT = "hex"
 DEFAULT_MAX_SECTORS = 128
-MAX_ALIGN = 8
+DEFAULT_MAX_ALIGN = 8
 DEP_IMAGES_KEY = "images"
 DEP_VERSIONS_KEY = "versions"
 MAX_SW_TYPE_LENGTH = 12  # Bytes
@@ -81,12 +81,6 @@
 TLV_INFO_MAGIC = 0x6907
 TLV_PROT_INFO_MAGIC = 0x6908
 
-boot_magic = bytes([
-    0x77, 0xc2, 0x95, 0xf3,
-    0x60, 0xd2, 0xef, 0x7f,
-    0x35, 0x52, 0x50, 0x0f,
-    0x2c, 0xb6, 0x79, 0x80, ])
-
 STRUCT_ENDIAN_DICT = {
         'little': '<',
         'big':    '>'
@@ -98,6 +92,9 @@
                     INVALID_SIGNATURE
                     """)
 
+def align_up(num, align):
+    assert (align & (align - 1) == 0) and align != 0
+    return (num + (align - 1)) & ~(align - 1)
 
 class TLV():
     def __init__(self, endian, magic=TLV_INFO_MAGIC):
@@ -135,7 +132,7 @@
                  slot_size=0, max_sectors=DEFAULT_MAX_SECTORS,
                  overwrite_only=False, endian="little", load_addr=0,
                  rom_fixed=None, erased_val=None, save_enctlv=False,
-                 security_counter=None):
+                 security_counter=None, max_align=None):
 
         if load_addr and rom_fixed:
             raise click.UsageError("Can not set rom_fixed and load_addr at the same time")
@@ -161,6 +158,22 @@
         self.hkdf_salt = None
         self.hkdf_len = 48
         self.enc_nonce = bytes([0] * 16)
+        self.max_align = max(DEFAULT_MAX_ALIGN, align) if max_align is None else int(max_align)
+
+        if self.max_align == DEFAULT_MAX_ALIGN:
+            self.boot_magic = bytes([
+                0x77, 0xc2, 0x95, 0xf3,
+                0x60, 0xd2, 0xef, 0x7f,
+                0x35, 0x52, 0x50, 0x0f,
+                0x2c, 0xb6, 0x79, 0x80, ])
+        else:
+            align_lsb = self.max_align & 0x00ff
+            align_msb = (self.max_align & 0xff00) >> 8
+            self.boot_magic = bytes([
+                align_lsb, align_msb, 0x2d, 0xe1,
+                0x5d, 0x29, 0x41, 0x0b,
+                0x8d, 0x77, 0x67, 0x9c,
+                0x11, 0x0f, 0x1f, 0x8a, ])
 
         if security_counter == 'auto':
             # Security counter has not been explicitly provided,
@@ -233,11 +246,16 @@
                                                   self.enctlv_len)
                 trailer_addr = (self.base_addr + self.slot_size) - trailer_size
                 padding = bytearray([self.erased_val] *
-                                    (trailer_size - len(boot_magic)))
+                                    (trailer_size - len(self.boot_magic)))
                 if self.confirm and not self.overwrite_only:
-                    padding[-MAX_ALIGN] = 0x01  # image_ok = 0x01
-                padding += boot_magic
-                h.puts(trailer_addr, bytes(padding))
+                    magic_size = 16
+                    magic_align_size = align_up(magic_size, self.max_align)
+                    image_ok_idx = -(magic_align_size + self.max_align)
+                    flag = bytearray([self.erased_val] * magic_align_size)
+                    flag[0] = 0x01 # image_ok = 0x01
+                    h.puts(trailer_addr + image_ok_idx, bytes(flag))
+                h.puts(trailer_addr + (trailer_size - len(self.boot_magic)),
+                       bytes(self.boot_magic))
             h.tofile(path, 'hex')
         else:
             if self.pad:
@@ -297,7 +315,7 @@
         return cipherkey, ciphermac, pubk
 
     def create(self, key, public_key_format, enckey, dependencies=None,
-               sw_type=None, custom_tlvs=None, encrypt_keylen=128, use_random_iv=False):
+               sw_type=None, custom_tlvs=None, encrypt_keylen=128, clear=False, use_random_iv=False):
         self.enckey = enckey
 
         if use_random_iv:
@@ -470,13 +488,14 @@
                 else:
                     tlv.add('ENCX25519', enctlv)
 
-            nonce = self.enc_nonce
-            cipher = Cipher(algorithms.AES(plainkey), modes.CTR(nonce),
-                            backend=default_backend())
-            encryptor = cipher.encryptor()
-            img = bytes(self.payload[self.header_size:])
-            self.payload[self.header_size:] = \
-                encryptor.update(img) + encryptor.finalize()
+            if not clear:
+                nonce = self.enc_nonce
+                cipher = Cipher(algorithms.AES(plainkey), modes.CTR(nonce),
+                                backend=default_backend())
+                encryptor = cipher.encryptor()
+                img = bytes(self.payload[self.header_size:])
+                self.payload[self.header_size:] = \
+                    encryptor.update(img) + encryptor.finalize()
 
         self.payload += prot_tlv.get()
         self.payload += tlv.get()
@@ -531,10 +550,11 @@
                       save_enctlv, enctlv_len):
         # NOTE: should already be checked by the argument parser
         magic_size = 16
+        magic_align_size = align_up(magic_size, self.max_align)
         if overwrite_only:
-            return MAX_ALIGN * 2 + magic_size
+            return self.max_align * 2 + magic_align_size
         else:
-            if write_size not in set([1, 2, 4, 8]):
+            if write_size not in set([1, 2, 4, 8, 16, 32]):
                 raise click.BadParameter("Invalid alignment: {}".format(
                     write_size))
             m = DEFAULT_MAX_SECTORS if max_sectors is None else max_sectors
@@ -542,12 +562,12 @@
             if enckey is not None:
                 if save_enctlv:
                     # TLV saved by the bootloader is aligned
-                    keylen = (int((enctlv_len - 1) / MAX_ALIGN) + 1) * MAX_ALIGN
+                    keylen = align_up(enctlv_len, self.max_align)
                 else:
-                    keylen = 16
+                    keylen = align_up(16, self.max_align)
                 trailer += keylen * 2  # encryption keys
-            trailer += MAX_ALIGN * 4  # image_ok/copy_done/swap_info/swap_size
-            trailer += magic_size
+            trailer += self.max_align * 4  # image_ok/copy_done/swap_info/swap_size
+            trailer += magic_align_size
             return trailer
 
     def pad_to(self, size):
@@ -557,10 +577,13 @@
                                    self.save_enctlv, self.enctlv_len)
         padding = size - (len(self.payload) + tsize)
         pbytes = bytearray([self.erased_val] * padding)
-        pbytes += bytearray([self.erased_val] * (tsize - len(boot_magic)))
+        pbytes += bytearray([self.erased_val] * (tsize - len(self.boot_magic)))
+        pbytes += self.boot_magic
         if self.confirm and not self.overwrite_only:
-            pbytes[-MAX_ALIGN] = 0x01  # image_ok = 0x01
-        pbytes += boot_magic
+            magic_size = 16
+            magic_align_size = align_up(magic_size, self.max_align)
+            image_ok_idx = -(magic_align_size + self.max_align)
+            pbytes[image_ok_idx] = 0x01  # image_ok = 0x01
         self.payload += pbytes
 
     @staticmethod
diff --git a/scripts/imgtool/main.py b/scripts/imgtool/main.py
index 941c096..b3b4f59 100755
--- a/scripts/imgtool/main.py
+++ b/scripts/imgtool/main.py
@@ -254,6 +254,10 @@
               type=click.Choice(['128','256']),
               help='When encrypting the image using AES, select a 128 bit or '
                    '256 bit key len.')
+@click.option('-c', '--clear', required=False, is_flag=True, default=False,
+              help='Output a non-encrypted image with encryption capabilities,'
+                   'so it can be installed in the primary slot, and encrypted '
+                   'when swapped to the secondary.')
 @click.option('-e', '--endian', type=click.Choice(['little', 'big']),
               default='little', help="Select little or big endian")
 @click.option('--overwrite-only', default=False, is_flag=True,
@@ -288,8 +292,13 @@
               help='Specify the value of security counter. Use the `auto` '
               'keyword to automatically generate it from the image version.')
 @click.option('-v', '--version', callback=validate_version,  required=True)
-@click.option('--align', type=click.Choice(['1', '2', '4', '8']),
+@click.option('--align', type=click.Choice(['1', '2', '4', '8', '16', '32']),
               required=True)
+@click.option('--max-align', type=click.Choice(['8', '16', '32']),
+              required=False,
+              help='Maximum flash alignment. Set if flash alignment of the '
+              'primary and secondary slot differ and any of them is larger '
+              'than 8.')
 @click.option('--public-key-format', type=click.Choice(['hash', 'full']),
               default='hash', help='In what format to add the public key to '
               'the image manifest: full key or hash of the key.')
@@ -304,7 +313,7 @@
          pad_header, slot_size, pad, confirm, max_sectors, overwrite_only,
          endian, encrypt_keylen, encrypt, infile, outfile, dependencies,
          load_addr, hex_addr, erased_val, save_enctlv, security_counter,
-         boot_record, custom_tlv, rom_fixed, use_random_iv):
+         boot_record, custom_tlv, rom_fixed, max_align, clear, use_random_iv):
 
     if confirm:
         # Confirmed but non-padded images don't make much sense, because
@@ -316,7 +325,7 @@
                       max_sectors=max_sectors, overwrite_only=overwrite_only,
                       endian=endian, load_addr=load_addr, rom_fixed=rom_fixed,
                       erased_val=erased_val, save_enctlv=save_enctlv,
-                      security_counter=security_counter)
+                      security_counter=security_counter, max_align=max_align)
     img.load(infile)
     key = load_key(key) if key else None
     enckey = load_key(encrypt) if encrypt else None
@@ -351,7 +360,7 @@
             custom_tlvs[tag] = value.encode('utf-8')
 
     img.create(key, public_key_format, enckey, dependencies, boot_record,
-               custom_tlvs, int(encrypt_keylen), use_random_iv=use_random_iv)
+               custom_tlvs, int(encrypt_keylen), clear, use_random_iv=use_random_iv)
     img.save(outfile, hex_addr)
 
 
diff --git a/scripts/requirements.txt b/scripts/requirements.txt
index 9481e2c..2446928 100644
--- a/scripts/requirements.txt
+++ b/scripts/requirements.txt
@@ -1,4 +1,4 @@
 cryptography>=2.6
 intelhex
 click
-cbor>=1.0.0
+cbor2
diff --git a/scripts/setup.py b/scripts/setup.py
index a228ea3..692cfb7 100644
--- a/scripts/setup.py
+++ b/scripts/setup.py
@@ -17,7 +17,7 @@
         'cryptography>=2.4.2',
         'intelhex>=2.2.1',
         'click',
-        'cbor>=1.0.0',
+        'cbor2',
     ],
     entry_points={
         "console_scripts": ["imgtool=imgtool.main:imgtool"]