Infineon: Add cyw20829 platform, shared slot feature, json memory map, psoc6 xip

Based in 1.8.0 release of MCUBoot library

This commit adds CYW20829 Infineon platform support with following capabilities:
1. Overwrite and swap upgrade mode support
2. Multi-image with up to 4 images
3. Hardware security counter is supported for CYW20829 platform

Add XIP support for PSOC6 platform - place BOOT slot in external memory and execute it in place using SMIF in XIP mode

and some new features for Infineon devices.

1. Shared upgrade slot feature - use one shared area for upgrade slots of multiple images
2. Memory map defined using JSON file - define memory regions for bootloader and user app in conventional way using JSON file
diff --git a/boot/cypress/scripts/flashmap.py b/boot/cypress/scripts/flashmap.py
new file mode 100644
index 0000000..339e4c5
--- /dev/null
+++ b/boot/cypress/scripts/flashmap.py
@@ -0,0 +1,710 @@
+"""MCUBoot Flash Map Converter (JSON to .h)
+Copyright (c) 2022 Infineon Technologies AG
+"""
+
+import sys
+import getopt
+import json
+
+# Supported Platforms
+platDict = {
+    'PSOC_062_2M': {
+        'flashAddr': 0x10000000,
+        'flashSize': 0x200000,  # 2 MBytes
+        'eraseSize': 0x200,  # 512 bytes
+        'smifAddr': 0x18000000,
+        'smifSize': 0x8000000  # i.e., window size
+    },
+    'PSOC_062_1M': {
+        'flashAddr': 0x10000000,
+        'flashSize': 0x100000,  # 1 MByte
+        'eraseSize': 0x200,  # 512 bytes
+        'smifAddr': 0x18000000,
+        'smifSize': 0x8000000  # i.e., window size
+    },
+    'PSOC_062_512K': {
+        'flashAddr': 0x10000000,
+        'flashSize': 0x80000,  # 512 KBytes
+        'eraseSize': 0x200,  # 512 bytes
+        'smifAddr': 0x18000000,
+        'smifSize': 0x8000000  # i.e., window size
+    },
+    'CYW20829': {
+        'flashSize': 0,  # n/a
+        'smifAddr': 0x60000000,
+        'smifSize': 0x8000000  # i.e., window size
+    }
+}
+
+# Supported SPI Flash ICs
+flashDict = {
+    # Fudan
+    'FM25Q04': {
+        'flashSize': 0x80000,  # 4 Mbits
+        'eraseSize': 0x1000,  # 128 uniform sectors with 4K-byte each
+    },
+    'FM25W04': {
+        'flashSize': 0x80000,  # 4 Mbits
+        'eraseSize': 0x1000,  # 128 uniform sectors with 4K-byte each
+    },
+    'FM25Q08': {
+        'flashSize': 0x100000,  # 8 Mbits
+        'eraseSize': 0x1000,  # 256 uniform sectors with 4K-byte each
+    },
+    'FM25W08': {
+        'flashSize': 0x100000,  # 8 Mbits
+        'eraseSize': 0x1000,  # 256 uniform sectors with 4K-byte each
+    },
+    # Puya
+    'P25Q05H': {
+        'flashSize': 0x10000,  # 512 Kbits
+        'eraseSize': 0x1000,  # Uniform 4K-byte Sector Erase
+    },
+    'P25Q10H': {
+        'flashSize': 0x20000,  # 1 Mbit
+        'eraseSize': 0x1000,  # Uniform 4K-byte Sector Erase
+    },
+    'P25Q20H': {
+        'flashSize': 0x40000,  # 2 Mbits
+        'eraseSize': 0x1000,  # Uniform 4K-byte Sector Erase
+    },
+    'P25Q40H': {
+        'flashSize': 0x80000,  # 4 Mbits
+        'eraseSize': 0x1000,  # Uniform 4K-byte Sector Erase
+    },
+    # Infineon
+    'S25HS256T': {
+        'flashSize': 0x2000000,  # 256 Mbits
+        'eraseSize': 0x40000,  # Uniform Sector Architecture
+    },
+    'S25HS512T': {
+        'flashSize': 0x4000000,  # 512 Mbits
+        'eraseSize': 0x40000,  # Uniform Sector Architecture
+    },
+    'S25HS01GT': {
+        'flashSize': 0x8000000,  # 1 Gbit
+        'eraseSize': 0x40000,  # Uniform Sector Architecture
+    }
+}
+
+
+def is_overlap(fa1off, fa1size, fa2off, fa2size, align):
+    """Check if two flash areas on the same device overlap"""
+    mask = align - 1
+    assert align > 0 and (align & mask) == 0  # ensure align is a power of 2
+    fa1end = (fa1off + fa1size + mask) & ~mask
+    fa2end = (fa2off + fa2size + mask) & ~mask
+    fa1off = fa1off & ~mask
+    fa2off = fa2off & ~mask
+    return fa1off < fa2end and fa2off < fa1end
+
+
+def is_same_mem(fa1addr, fa2addr):
+    """Check if two addresses belong to the same memory"""
+    if fa1addr is None or fa2addr is None:
+        return False
+    mask = 0xFF000000
+    return (fa1addr & mask) == (fa2addr & mask)
+
+
+class CmdLineParams:
+    """Command line parameters"""
+
+    def __init__(self):
+        self.plat_id = ''
+        self.in_file = ''
+        self.out_file = ''
+        self.img_id = None
+
+        usage = 'USAGE:\n' + sys.argv[0] + \
+                ''' -p <platform> -i <flash_map.json> -o <flash_map.h> -d <img_id>
+
+OPTIONS:
+-h  --help       Display the usage information
+-p  --platform=  Target (e.g., PSOC_062_512K)
+-i  --ifile=     JSON flash map file
+-o  --ofile=     C header file to be generated
+-d  --img_id     ID of application to build'''
+
+        try:
+            opts, unused = getopt.getopt(
+                sys.argv[1:], 'hi:o:p:d:',
+                ['help', 'platform=', 'ifile=', 'ofile=', 'img_id='])
+            if len(unused) > 0:
+                print(usage, file=sys.stderr)
+                sys.exit(1)
+        except getopt.GetoptError:
+            print(usage, file=sys.stderr)
+            sys.exit(1)
+
+        for opt, arg in opts:
+            if opt in ('-h', '--help'):
+                print(usage, file=sys.stderr)
+                sys.exit()
+            elif opt in ('-p', '--platform'):
+                self.plat_id = arg
+            elif opt in ('-i', '--ifile'):
+                self.in_file = arg
+            elif opt in ('-o', '--ofile'):
+                self.out_file = arg
+            elif opt in ('-d', '--img_id'):
+                self.img_id = arg
+
+        if len(self.in_file) == 0 or len(self.out_file) == 0:
+            print(usage, file=sys.stderr)
+            sys.exit(1)
+
+
+class AreaList:
+    """List of flash areas"""
+
+    def __init__(self, plat, flash, use_overwrite):
+        self.plat = plat
+        self.flash = flash
+        self.use_overwrite = use_overwrite
+        self.areas = []
+        self.peers = {}
+        self.trailers = {}
+        self.internal_flash = False
+        self.external_flash = False
+        self.external_flash_xip = False
+
+    def get_min_erase_size(self):
+        """Calculate minimum erase block size for int./ext. Flash """
+        return self.plat['eraseSize'] if self.plat['flashSize'] > 0 \
+            else self.flash['eraseSize']
+
+    def get_img_trailer_size(self):
+        """Calculate image trailer size"""
+        return self.get_min_erase_size()
+
+    def process_int_area(self, title, fa_addr, fa_size,
+                         img_trailer_size, shared_slot):
+        """Process internal flash area"""
+        fa_device_id = 'FLASH_DEVICE_INTERNAL_FLASH'
+        fa_off = fa_addr - self.plat['flashAddr']
+        if img_trailer_size is not None:
+            if self.use_overwrite:
+                if shared_slot:
+                    print('Shared slot', title,
+                          'is not supported in OVERWRITE mode',
+                          file=sys.stderr)
+                    sys.exit(7)
+            else:
+                # Check trailer alignment (start at the sector boundary)
+                align = (fa_off + fa_size - img_trailer_size) % \
+                        self.plat['eraseSize']
+                if align != 0:
+                    fa_addr += self.plat['eraseSize'] - align
+                    if fa_addr + fa_size <= \
+                            self.plat['flashAddr'] + self.plat['flashSize']:
+                        print('Misaligned', title,
+                              '- suggested address', hex(fa_addr),
+                              file=sys.stderr)
+                    else:
+                        print('Misaligned', title, file=sys.stderr)
+                    sys.exit(7)
+        else:
+            # Check alignment (flash area should start at the sector boundary)
+            if fa_off % self.plat['eraseSize'] != 0:
+                print('Misaligned', title, file=sys.stderr)
+                sys.exit(7)
+        slot_sectors = int((fa_off % self.plat['eraseSize'] +
+                            fa_size + self.plat['eraseSize'] - 1) //
+                           self.plat['eraseSize'])
+        return fa_device_id, fa_off, slot_sectors
+
+    def process_ext_area(self, title, fa_addr, fa_size,
+                         img_trailer_size, shared_slot):
+        """Process external flash area"""
+        if self.flash is None:
+            print('Unspecified SPI Flash IC',
+                  file=sys.stderr)
+            sys.exit(3)
+        if fa_addr + fa_size <= \
+                self.plat['smifAddr'] + self.flash['flashSize']:
+            flash_idx = 'CY_BOOT_EXTERNAL_DEVICE_INDEX'
+            fa_device_id = f'FLASH_DEVICE_EXTERNAL_FLASH({flash_idx})'
+            fa_off = fa_addr - self.plat['smifAddr']
+        else:
+            print('Misfitting', title, file=sys.stderr)
+            sys.exit(7)
+        if img_trailer_size is not None:
+            if self.use_overwrite:
+                if shared_slot:
+                    print('Shared slot', title,
+                          'is not supported in OVERWRITE mode',
+                          file=sys.stderr)
+                    sys.exit(7)
+            else:
+                # Check trailer alignment (start at the sector boundary)
+                align = (fa_off + fa_size - img_trailer_size) % \
+                        self.flash['eraseSize']
+                if align != 0:
+                    peer_addr = self.peers.get(fa_addr)
+                    if shared_slot:
+                        # Special case when using both int. and ext. memory
+                        if self.plat['flashSize'] > 0 and \
+                                align % self.plat['eraseSize'] == 0:
+                            print('Note:', title, 'requires', align,
+                                  'padding bytes before trailer',
+                                  file=sys.stderr)
+                        else:
+                            print('Misaligned', title, file=sys.stderr)
+                            sys.exit(7)
+                    elif is_same_mem(fa_addr, peer_addr) and \
+                            fa_addr % self.flash['eraseSize'] == \
+                            peer_addr % self.flash['eraseSize']:
+                        pass  # postpone checking
+                    else:
+                        fa_addr += self.flash['eraseSize'] - align
+                        if fa_addr + fa_size <= \
+                                self.plat['smifAddr'] + self.flash['flashSize']:
+                            print('Misaligned', title,
+                                  '- suggested address', hex(fa_addr),
+                                  file=sys.stderr)
+                        else:
+                            print('Misaligned', title, file=sys.stderr)
+                        sys.exit(7)
+        else:
+            # Check alignment (flash area should start at the sector boundary)
+            if fa_off % self.flash['eraseSize'] != 0:
+                print('Misaligned', title, file=sys.stderr)
+                sys.exit(7)
+        slot_sectors = int((fa_off % self.flash['eraseSize'] +
+                            fa_size + self.flash['eraseSize'] - 1) //
+                           self.flash['eraseSize'])
+        self.external_flash = True
+        if self.flash['XIP']:
+            self.external_flash_xip = True
+        return fa_device_id, fa_off, slot_sectors
+
+    def chk_area(self, fa_addr, fa_size, peer_addr=None):
+        """Check area location (internal/external flash)"""
+        if peer_addr is not None:
+            self.peers[peer_addr] = fa_addr
+        fa_limit = fa_addr + fa_size
+        if self.plat['flashSize'] and \
+                fa_addr >= self.plat['flashAddr'] and \
+                fa_limit <= self.plat['flashAddr'] + self.plat['flashSize']:
+            # Internal flash
+            self.internal_flash = True
+
+    def add_area(self, title,
+                 fa_id, fa_addr, fa_size,
+                 img_trailer_size=None, shared_slot=False):
+        """Add flash area to AreaList.
+        Internal/external flash is detected by address.
+        Returns number of sectors in a slot"""
+        if fa_size == 0:
+            print('Empty', title, file=sys.stderr)
+            sys.exit(7)
+
+        fa_limit = fa_addr + fa_size
+        if self.plat['flashSize'] and \
+                fa_addr >= self.plat['flashAddr'] and \
+                fa_limit <= self.plat['flashAddr'] + self.plat['flashSize']:
+            # Internal flash
+            fa_device_id, fa_off, slot_sectors = self.process_int_area(
+                title, fa_addr, fa_size, img_trailer_size, shared_slot)
+            align = self.plat['eraseSize']
+        elif self.plat['smifSize'] and \
+                fa_addr >= self.plat['smifAddr'] and \
+                fa_limit <= self.plat['smifAddr'] + self.plat['smifSize']:
+            # External flash
+            fa_device_id, fa_off, slot_sectors = self.process_ext_area(
+                title, fa_addr, fa_size, img_trailer_size, shared_slot)
+            align = self.flash['eraseSize']
+        else:
+            print('Invalid', title, file=sys.stderr)
+            sys.exit(7)
+
+        if shared_slot:
+            assert img_trailer_size is not None
+            tr_addr = fa_addr + fa_size - img_trailer_size
+            tr_name = self.trailers.get(tr_addr)
+            if tr_name is not None:
+                print('Same trailer address for', title, 'and', tr_name,
+                      file=sys.stderr)
+                sys.exit(7)
+            self.trailers[tr_addr] = title
+
+        # Ensure no flash areas on this device will overlap, except the
+        # shared slot
+        for area in self.areas:
+            if fa_device_id == area['fa_device_id']:
+                over = is_overlap(fa_off, fa_size,
+                                  area['fa_off'], area['fa_size'],
+                                  align)
+                if shared_slot and area['shared_slot']:
+                    if not over:  # images in shared slot should overlap
+                        print(title, 'is not shared with', area['title'],
+                              file=sys.stderr)
+                        sys.exit(7)
+                elif over:
+                    print(title, 'overlaps with', area['title'],
+                          file=sys.stderr)
+                    sys.exit(7)
+
+        self.areas.append({'title': title,
+                           'shared_slot': shared_slot,
+                           'fa_id': fa_id,
+                           'fa_device_id': fa_device_id,
+                           'fa_off': fa_off,
+                           'fa_size': fa_size})
+        return slot_sectors
+
+    def generate_c_source(self, params):
+        """Generate C source"""
+        c_array = 'flash_areas'
+
+        try:
+            with open(params.out_file, "w", encoding='UTF-8') as out_f:
+                out_f.write('/* AUTO-GENERATED FILE, DO NOT EDIT.'
+                            ' ALL CHANGES WILL BE LOST! */\n')
+                out_f.write(f'/* Platform: {params.plat_id} */\n')
+                out_f.write(f'\nstatic struct flash_area {c_array}[] = {{\n')
+                comma = len(self.areas)
+                area_count = 0
+                for area in self.areas:
+                    comma -= 1
+                    if area['fa_id'] is not None:
+                        sss = ' /* Shared secondary slot */' \
+                            if area['shared_slot'] else ''
+                        out_f.writelines('\n'.join([
+                            '    {' + sss,
+                            f"        .fa_id        = {area['fa_id']},",
+                            f"        .fa_device_id = {area['fa_device_id']},",
+                            f"        .fa_off       = {hex(area['fa_off'])}U,",
+                            f"        .fa_size      = {hex(area['fa_size'])}U",
+                            '    },' if comma else '    }', '']))
+                        area_count += 1
+                out_f.write('};\n\n'
+                            'struct flash_area *boot_area_descs[] = {\n')
+                for area_index in range(area_count):
+                    out_f.write(f'    &{c_array}[{area_index}U],\n')
+                out_f.write('    NULL\n};\n')
+        except (FileNotFoundError, OSError):
+            print('Cannot create', params.out_file, file=sys.stderr)
+            sys.exit(4)
+
+
+def cvt_dec_or_hex(val, desc):
+    """Convert (hexa)decimal string to number"""
+    try:
+        return int(val, 0)
+    except ValueError:
+        print('Invalid value', val, 'for', desc, file=sys.stderr)
+        sys.exit(6)
+
+
+def get_val(obj, attr):
+    """Get JSON 'value'"""
+    obj = obj[attr]
+    try:
+        return cvt_dec_or_hex(obj['value'], obj['description'])
+    except KeyError as key:
+        print('Malformed JSON:', key,
+              'is missing in', "'" + attr + "'",
+              file=sys.stderr)
+        sys.exit(5)
+
+
+def get_bool(obj, attr, def_val=False):
+    """Get JSON boolean value (returns def_val if it missing)"""
+    ret_val = def_val
+    obj = obj.get(attr)
+    if obj is not None:
+        try:
+            val = str(obj['value']).lower()
+            desc = obj['description']
+            if val == 'true':
+                ret_val = True
+            elif val == 'false':
+                ret_val = False
+            else:
+                print('Invalid value', val, 'for', desc, file=sys.stderr)
+                sys.exit(6)
+        except KeyError as key:
+            print('Malformed JSON:', key,
+                  'is missing in', "'" + attr + "'",
+                  file=sys.stderr)
+            sys.exit(5)
+    return ret_val
+
+
+class AddrSize:
+    """Bootloader area"""
+
+    def __init__(self, bootloader, addr_name, size_name):
+        self.fa_addr = get_val(bootloader, addr_name)
+        self.fa_size = get_val(bootloader, size_name)
+
+
+def calc_status_size(boot_swap_status_row_sz, max_img_sectors,
+                     img_number, scratch_flag=True):
+    """Estimate status size, see swap_status.h"""
+    boot_swap_status_cnt_sz = 4
+    boot_swap_status_crc_sz = 4
+    boot_swap_status_mgcrec_sz = 4
+    boot_swap_status_trailer_size = 64
+    boot_swap_status_payld_sz = \
+        boot_swap_status_row_sz - boot_swap_status_mgcrec_sz - \
+        boot_swap_status_cnt_sz - boot_swap_status_crc_sz
+    boot_swap_status_sect_rows_num = \
+        int((max_img_sectors - 1) //
+            boot_swap_status_payld_sz) + 1
+    boot_swap_status_trail_rows_num = \
+        int((boot_swap_status_trailer_size - 1) //
+            boot_swap_status_payld_sz) + 1
+    boot_swap_status_d_size = \
+        boot_swap_status_row_sz * \
+        (boot_swap_status_sect_rows_num + boot_swap_status_trail_rows_num)
+    boot_swap_status_mult = 2
+    boot_swap_status_size = boot_swap_status_mult * boot_swap_status_d_size
+    status_zone_cnt = 2 * img_number
+    if scratch_flag:
+        status_zone_cnt += 1
+    return boot_swap_status_size * status_zone_cnt
+
+
+def process_json(in_file):
+    """Process JSON"""
+    try:
+        with open(in_file, encoding='UTF-8') as in_f:
+            try:
+                flash_map = json.load(in_f)
+            except ValueError:
+                print('Cannot parse', in_file, file=sys.stderr)
+                sys.exit(4)
+    except (FileNotFoundError, OSError):
+        print('Cannot open', in_file, file=sys.stderr)
+        sys.exit(4)
+    flash = flash_map.get('external_flash')
+    if flash is not None:
+        flash = flash[0]
+        model = flash.get('model')
+        mode = flash.get('mode')
+        if model is not None:
+            try:
+                flash = flashDict[model]
+            except KeyError:
+                print('Supported SPI Flash ICs are:',
+                      ', '.join(flashDict.keys()),
+                      file=sys.stderr)
+                sys.exit(3)
+        else:
+            try:
+                flash = {'flashSize': cvt_dec_or_hex(flash['flash-size'],
+                                                     'flash-size'),
+                         'eraseSize': cvt_dec_or_hex(flash['erase-size'],
+                                                     'erase-size')}
+            except KeyError as key:
+                print('Malformed JSON:', key,
+                      "is missing in 'external_flash'",
+                      file=sys.stderr)
+                sys.exit(3)
+        flash.update({'XIP': str(mode).upper() == 'XIP'})
+    return flash_map['boot_and_upgrade'], flash
+
+
+def process_images(area_list, boot_and_upgrade):
+    """Process images"""
+    app_count = 0
+    slot_sectors_max = 0
+    all_shared = get_bool(boot_and_upgrade['bootloader'], 'shared_slot')
+    any_shared = all_shared
+
+    apps_flash_map = [None, ]
+
+    for stage in range(2):
+        for app_index in range(1, 5):
+
+            app_flash_map = {}
+
+            try:
+                app_ident = f'application_{app_index}'
+                application = boot_and_upgrade[app_ident]
+                try:
+                    primary_addr = get_val(application, 'address')
+                    primary_size = get_val(application, 'size')
+                    secondary_addr = get_val(application, 'upgrade_address')
+                    secondary_size = get_val(application, 'upgrade_size')
+                except KeyError as key:
+                    print('Malformed JSON:', key, 'is missing',
+                          file=sys.stderr)
+                    sys.exit(5)
+                if stage == 0:
+                    if primary_size != secondary_size:
+                        print('Primary and secondary slot sizes'
+                              ' are different for', app_ident,
+                              file=sys.stderr)
+                        sys.exit(6)
+                    area_list.chk_area(primary_addr, primary_size)
+                    area_list.chk_area(secondary_addr, secondary_size,
+                                       primary_addr)
+                else:
+                    slot_sectors_max = max(
+                        slot_sectors_max,
+                        area_list.add_area(
+                            f'{app_ident} (primary slot)',
+                            f'FLASH_AREA_IMG_{app_index}_PRIMARY',
+                            primary_addr, primary_size,
+                            area_list.get_img_trailer_size()))
+                    shared_slot = get_bool(application, 'shared_slot', all_shared)
+                    any_shared = any_shared or shared_slot
+                    slot_sectors_max = max(
+                        slot_sectors_max,
+                        area_list.add_area(
+                            f'{app_ident} (secondary slot)',
+                            f'FLASH_AREA_IMG_{app_index}_SECONDARY',
+                            secondary_addr, secondary_size,
+                            area_list.get_img_trailer_size(),
+                            shared_slot))
+
+                    app_slot_prim = {"address": hex(primary_addr), "size": hex(primary_size)}
+                    app_slot_sec = {"address": hex(secondary_addr), "size": hex(secondary_size)}
+
+                    app_flash_map.update({"primary": app_slot_prim, "secondary": app_slot_sec})
+                    apps_flash_map.append(app_flash_map)
+
+                app_count = app_index
+
+            except KeyError:
+                break
+        if app_count == 0:
+            print('Malformed JSON: no application(s) found',
+                  file=sys.stderr)
+            sys.exit(5)
+
+    return app_count, slot_sectors_max, apps_flash_map, any_shared
+
+
+def main():
+    """Flash map converter"""
+    params = CmdLineParams()
+
+    try:
+        plat = platDict[params.plat_id]
+    except KeyError:
+        print('Supported platforms are:', ', '.join(platDict.keys()),
+              file=sys.stderr)
+        sys.exit(2)
+
+    try:
+        boot_and_upgrade, flash = process_json(params.in_file)
+        bootloader = boot_and_upgrade['bootloader']
+        boot = AddrSize(bootloader, 'address', 'size')
+    except KeyError as key:
+        print('Malformed JSON:', key, 'is missing',
+              file=sys.stderr)
+        sys.exit(5)
+
+    try:
+        scratch = AddrSize(bootloader, 'scratch_address', 'scratch_size')
+    except KeyError:
+        scratch = None
+
+    try:
+        swap_status = AddrSize(bootloader, 'status_address', 'status_size')
+    except KeyError:
+        swap_status = None
+
+    # Create flash areas
+    area_list = AreaList(plat, flash, scratch is None and swap_status is None)
+    area_list.add_area('bootloader', 'FLASH_AREA_BOOTLOADER',
+                       boot.fa_addr, boot.fa_size)
+
+    # Service RAM app (optional)
+    service_app = boot_and_upgrade.get('service_app')
+    app_binary = None
+    input_params = None
+    app_desc = None
+    if service_app is not None:
+        if plat['flashSize'] > 0:
+            print('service_app is unsupported on this platform',
+                  file=sys.stderr)
+            sys.exit(7)
+        try:
+            app_binary = AddrSize(service_app, 'address', 'size')
+            input_params = AddrSize(service_app, 'params_address', 'params_size')
+            app_desc = AddrSize(service_app, 'desc_address', 'desc_size')
+            if input_params.fa_addr != app_binary.fa_addr + app_binary.fa_size or \
+                    app_desc.fa_addr != input_params.fa_addr + input_params.fa_size or \
+                    app_desc.fa_size != 0x20:
+                print('Malformed service_app definition', file=sys.stderr)
+                sys.exit(7)
+            area_list.add_area('service_app', None, app_binary.fa_addr,
+                               app_binary.fa_size + input_params.fa_size + app_desc.fa_size)
+        except KeyError as key:
+            print('Malformed JSON:', key, 'is missing',
+                  file=sys.stderr)
+            sys.exit(5)
+
+    # Fill flash areas
+    app_count, slot_sectors_max, apps_flash_map, shared_slot = \
+        process_images(area_list, boot_and_upgrade)
+
+    slot_sectors_max = max(slot_sectors_max, 32)
+
+    if swap_status is not None:
+        status_size_min = calc_status_size(area_list.get_min_erase_size(),
+                                           slot_sectors_max,
+                                           app_count,
+                                           scratch is not None)
+
+        if swap_status.fa_size < status_size_min:
+            print('Insufficient swap status area - suggested size',
+                  hex(status_size_min),
+                  file=sys.stderr)
+            sys.exit(7)
+        area_list.add_area('swap status partition',
+                           'FLASH_AREA_IMAGE_SWAP_STATUS',
+                           swap_status.fa_addr, swap_status.fa_size)
+
+    if scratch is not None:
+        area_list.add_area('scratch area',
+                           'FLASH_AREA_IMAGE_SCRATCH',
+                           scratch.fa_addr, scratch.fa_size)
+
+    # Image id parameter is not used for MCUBootApp
+    if params.img_id is None:
+        area_list.generate_c_source(params)
+
+    # Report necessary values back to make
+    print('# AUTO-GENERATED FILE, DO NOT EDIT. ALL CHANGES WILL BE LOST!')
+
+    if params.img_id is not None:
+        primary_img_start = (apps_flash_map[int(params.img_id)].get("primary")).get("address")
+        secondary_img_start = (apps_flash_map[int(params.img_id)].get("secondary")).get("address")
+        bootloader_size = (bootloader.get("size")).get("value")
+        slot_size = (apps_flash_map[int(params.img_id)].get("primary")).get("size")
+
+        print('PRIMARY_IMG_START := ' + primary_img_start)
+        print('SECONDARY_IMG_START := ' + secondary_img_start)
+        print('SLOT_SIZE := ' + slot_size)
+        print('BOOTLOADER_SIZE := ' + bootloader_size)
+    else:
+        print('MCUBOOT_IMAGE_NUMBER :=', app_count)
+        print('MAX_IMG_SECTORS :=', slot_sectors_max)
+
+    if area_list.use_overwrite:
+        print('USE_OVERWRITE := 1')
+    if area_list.external_flash:
+        print('USE_EXTERNAL_FLASH := 1')
+        if area_list.external_flash_xip:
+            print('USE_XIP := 1')
+    if shared_slot:
+        print('USE_SHARED_SLOT := 1')
+    if service_app is not None:
+        print('PLATFORM_SERVICE_APP_OFFSET :=',
+              hex(app_binary.fa_addr - plat['smifAddr']))
+        print('PLATFORM_SERVICE_APP_INPUT_PARAMS_OFFSET :=',
+              hex(input_params.fa_addr - plat['smifAddr']))
+        print('PLATFORM_SERVICE_APP_DESC_OFFSET :=',
+              hex(app_desc.fa_addr - plat['smifAddr']))
+        print('USE_HW_ROLLBACK_PROT := 1')
+
+
+if __name__ == '__main__':
+    main()