Permalink
Cannot retrieve contributors at this time
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
ota-bootloader-abstraction/scripts/mcuboot/flashmap.py
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
882 lines (799 sloc)
34.1 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"""MCUBoot Flash Map Converter (JSON to .h) | |
Copyright (c) 2022 Infineon Technologies AG | |
""" | |
import sys | |
import getopt | |
import json | |
# Supported Platforms | |
allCores_PSOC_06x = { | |
# Cortex-M0+ | |
'cortex-m0+': 'CM0P', | |
'cm0+': 'CM0P', | |
'm0+': 'CM0P', | |
'cortex-m0p': 'CM0P', | |
'cm0p': 'CM0P', | |
'm0p': 'CM0P', | |
'cortex-m0plus': 'CM0P', | |
'cm0plus': 'CM0P', | |
'm0plus': 'CM0P', | |
# Cortex-M4 | |
'cortex-m4': 'CM4', | |
'cm4': 'CM4', | |
'm4': 'CM4' | |
} | |
platDict = { | |
'PSOC_063_1M': { | |
'flashAddr': 0x10000000, | |
'flashSize': 0x100000, # 1 MByte | |
'eraseSize': 0x200, # 512 bytes | |
'VTAlign': 0x400, # Vector Table alignment | |
'allCores': allCores_PSOC_06x, | |
'appCore': 'Cortex-M4' | |
}, | |
'PSOC_062_2M': { | |
'flashAddr': 0x10000000, | |
'flashSize': 0x200000, # 2 MBytes | |
'eraseSize': 0x200, # 512 bytes | |
'smifAddr': 0x18000000, | |
'smifSize': 0x8000000, # i.e., window size | |
'VTAlign': 0x400, # Vector Table alignment | |
'allCores': allCores_PSOC_06x, | |
'appCore': 'Cortex-M4' | |
}, | |
'PSOC_062_1M': { | |
'flashAddr': 0x10000000, | |
'flashSize': 0x100000, # 1 MByte | |
'eraseSize': 0x200, # 512 bytes | |
'smifAddr': 0x18000000, | |
'smifSize': 0x8000000, # i.e., window size | |
'VTAlign': 0x400, # Vector Table alignment | |
'allCores': allCores_PSOC_06x, | |
'appCore': 'Cortex-M4' | |
}, | |
'PSOC_062_512K': { | |
'flashAddr': 0x10000000, | |
'flashSize': 0x80000, # 512 KBytes | |
'eraseSize': 0x200, # 512 bytes | |
'smifAddr': 0x18000000, | |
'smifSize': 0x8000000, # i.e., window size | |
'VTAlign': 0x400, # Vector Table alignment | |
'allCores': allCores_PSOC_06x, | |
'appCore': 'Cortex-M4' | |
}, | |
'CYW20829': { | |
'flashSize': 0, # n/a | |
'smifAddr': 0x60000000, | |
'smifSize': 0x8000000, # i.e., window size | |
'VTAlign': 0x200, # Vector Table alignment | |
'allCores': { | |
'cortex-m33': 'CM33', | |
'cm33': 'CM33', | |
'm33': 'CM33' | |
}, | |
'appCore': 'Cortex-M33' | |
}, | |
'CYW89829': { | |
'flashSize': 0, # n/a | |
'smifAddr': 0x60000000, | |
'smifSize': 0x8000000, # i.e., window size | |
'VTAlign': 0x200, # Vector Table alignment | |
'allCores': { | |
'cortex-m33': 'CM33', | |
'cm33': 'CM33', | |
'm33': 'CM33' | |
}, | |
'appCore': 'Cortex-M33' | |
}, | |
'EXPLORER': { | |
'flashSize': 0, # n/a | |
'smifAddr': 0x60000000, | |
'smifSize': 0x8000000, # i.e., window size | |
'VTAlign': 0x200 # Vector Table alignment | |
} | |
} | |
# 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 | |
}, | |
'S25FL512S': { | |
'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 | |
# [stde] For ota-update library usage, we do not need output 'c' file, just flashmap.mk | |
# [stde] which is piped from strdout to flashmap.mk | |
# if len(self.in_file) == 0 or len(self.out_file) == 0: | |
if len(self.in_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) | |
# [stde] More interesting output | |
if self.plat['flashSize']: | |
if fa_addr < self.plat['flashAddr']: | |
print(' addr < start of flash ! (' + str(hex(fa_addr)) + ' < ' + str(hex(self.plat['flashAddr'])) + ')', file=sys.stderr) | |
if fa_limit > (self.plat['flashAddr'] + self.plat['flashSize']): | |
print(' addr + size > end of flash ! (' + str(hex(fa_limit)) + ' > ' + str(hex(self.plat['flashAddr'] + self.plat['flashSize'])) + ')', file=sys.stderr) | |
if self.plat['smifSize']: | |
if fa_addr < self.plat['smifAddr']: | |
print(' addr < start of flash ! (' + str(hex(fa_addr)) + ' < ' + str(hex(self.plat['smifAddr'])) + ')', file=sys.stderr) | |
if fa_limit > (self.plat['smifAddr'] + self.plat['flashSize']): | |
print(' addr + size > end of flash ! (' + str(hex(fa_limit)) + ' > ' + str(hex(self.plat['smifAddr'] + self.plat['smifSize'])) + ')', file=sys.stderr) | |
# [stde] End of more interesting output | |
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("#ifndef CY_FLASH_MAP_H\n") | |
out_f.write("#define CY_FLASH_MAP_H\n\n") | |
if self.plat.get('bitsPerCnt'): | |
out_f.write('#ifdef NEED_FLASH_MAP\n') | |
out_f.write(f'static 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') | |
if self.plat.get('bitsPerCnt'): | |
out_f.write('#endif /* NEED_FLASH_MAP */\n') | |
out_f.close() | |
# inserted here to fix misra 'header guard' | |
list_counters = process_policy_20829(params.policy) | |
if list_counters is not None: | |
form_max_counter_array(list_counters, params.out_file) | |
with open(params.out_file, "a", encoding='UTF-8') as out_f: | |
out_f.write("#endif /* CY_FLASH_MAP_H */\n") | |
else: | |
out_f.write("#endif /* CY_FLASH_MAP_H */\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 is 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 | |
def get_str(obj, attr, def_val=None): | |
"""Get JSON string value (returns def_val if it is missing)""" | |
ret_val = def_val | |
obj = obj.get(attr) | |
if obj is not None: | |
try: | |
ret_val = str(obj['value']) | |
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 | |
app_core = None | |
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) | |
if application.get('core') is None: | |
if app_index == 1: | |
app_core = area_list.plat['appCore'] | |
elif app_index > 1: | |
print('"core" makes sense only for the 1st app', | |
file=sys.stderr) | |
sys.exit(6) | |
else: | |
app_core = get_str(application, 'core', | |
area_list.plat['appCore']) | |
if app_index == 1: | |
app_core = area_list.plat['allCores'].get(app_core.lower()) | |
if app_core is None: | |
print('Unknown "core"', file=sys.stderr) | |
sys.exit(6) | |
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_core, 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_core, app_count, slot_sectors_max, apps_flash_map, shared_slot = \ | |
process_images(area_list, boot_and_upgrade) | |
cy_img_hdr_size = 0x400 | |
app_start = int(apps_flash_map[1].get("primary").get("address"), 0) + cy_img_hdr_size | |
if app_start % plat['VTAlign'] != 0: | |
print('Starting address', apps_flash_map[1].get("primary").get("address"), | |
'+', hex(cy_img_hdr_size), | |
'must be aligned to', hex(plat['VTAlign']), | |
file=sys.stderr) | |
sys.exit(7) | |
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) | |
# [stde] Moved this printf above the call to generate_c_source | |
# [stde] generate_c_source() now outputs flash area names and values | |
# [stde] to both cy_flash_map.h and stdout, which is captured for flashmap.mk | |
# Report necessary values back to make | |
print('# AUTO-GENERATED FILE, DO NOT EDIT. ALL CHANGES WILL BE LOST!') | |
# Image id parameter is not used for MCUBootApp | |
if params.img_id is None: | |
# [stde] we do not need the .c file for ota-update, just flashmap.mk | |
if len(params.out_file) != 0: | |
area_list.generate_c_source(params) | |
# [stde] Start of modifications | |
# [stde] Output the DEFINES and the values to match flashmap.mk | |
# out_f.writelines("\n") | |
comma = len(area_list.areas) | |
area_count = 0 | |
for area in area_list.areas: | |
comma -= 1 | |
if area['fa_id'] is not None: | |
print(str(area['fa_id']) + "_DEV_ID :=" + area['fa_device_id'] ) | |
print(str(area['fa_id']) + "_START :=" + str.format("{:#08x}",(area['fa_off'])) ) | |
print(str(area['fa_id']) + "_SIZE :=" + str.format("{:#08x}",(area['fa_size'])) ) | |
area_count += 1 | |
# [stde] End of modifications | |
else: | |
# [stde] Start of modifications | |
# [stde] Output the DEFINES and the values to match flashmap.mk | |
# out_f.writelines("\n") | |
comma = len(area_list.areas) | |
area_count = 0 | |
for area in area_list.areas: | |
comma -= 1 | |
if area['fa_id'] is not None: | |
print(str(area['fa_id']) + "_DEV_ID :=" + area['fa_device_id'] ) | |
print(str(area['fa_id']) + "_START :=" + str.format("{:#08x}",(area['fa_off'])) ) | |
print(str(area['fa_id']) + "_SIZE :=" + str.format("{:#08x}",(area['fa_size'])) ) | |
area_count += 1 | |
# [stde] End of modifications | |
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) | |
# [stde] added "MCUBOOT_" for ota-update Makefile | |
print('MCUBOOT_MAX_IMG_SECTORS :=', slot_sectors_max) | |
print('APP_CORE :=', app_core) | |
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() |