blob: 0cb080590739999012a488f6af09bef540c7879e [file] [log] [blame]
Roman Okhrimenko977b3752022-03-31 14:40:48 +03001"""MCUBoot Flash Map Converter (JSON to .h)
2Copyright (c) 2022 Infineon Technologies AG
3"""
4
5import sys
6import getopt
7import json
8
9# Supported Platforms
Dovhal Artem (CSUKR CSS ICW SW FW 1)f7a3d1b2022-04-01 15:07:37 +000010cm0pCore = {
11 'cortex-m0+': 'CM0P',
12 'cm0+': 'CM0P',
13 'm0+': 'CM0P',
14 'cortex-m0p': 'CM0P',
15 'cm0p': 'CM0P',
16 'm0p': 'CM0P',
17 'cortex-m0plus': 'CM0P',
18 'cm0plus': 'CM0P',
19 'm0plus': 'CM0P'
20}
21
22cm4Core = {
23 'cortex-m4': 'CM4',
24 'cm4': 'CM4',
25 'm4': 'CM4'
26}
27
28cm33Core = {
29 'cortex-m33': 'CM33',
30 'cm33': 'CM33',
31 'm33': 'CM33'
32}
33
34allCores_PSOC_06x = {**cm0pCore, **cm4Core}
35
36common_PSOC_061 = {
37 'flashAddr': 0x10000000,
38 'eraseSize': 0x200, # 512 bytes
39 'smifAddr': 0x18000000,
40 'smifSize': 0x8000000, # i.e., window size
41 'VTAlign': 0x400, # Vector Table alignment
42 'allCores': cm4Core,
43 'bootCore': 'Cortex-M4',
44 'appCore': 'Cortex-M4'
45}
46
47common_PSOC_06x = {
48 'flashAddr': 0x10000000,
49 'eraseSize': 0x200, # 512 bytes
50 'smifAddr': 0x18000000,
51 'smifSize': 0x8000000, # i.e., window size
52 'VTAlign': 0x400, # Vector Table alignment
53 'allCores': allCores_PSOC_06x,
54 'bootCore': 'Cortex-M0+',
55 'appCore': 'Cortex-M4'
56}
57
Roman Okhrimenko977b3752022-03-31 14:40:48 +030058platDict = {
Dovhal Artem (CSUKR CSS ICW SW FW 1)f7a3d1b2022-04-01 15:07:37 +000059 'PSOC_061_2M': {
Roman Okhrimenko977b3752022-03-31 14:40:48 +030060 'flashSize': 0x200000, # 2 MBytes
Dovhal Artem (CSUKR CSS ICW SW FW 1)f7a3d1b2022-04-01 15:07:37 +000061 **common_PSOC_061
62 },
63 'PSOC_061_1M': {
64 'flashSize': 0x100000, # 1 MByte
65 **common_PSOC_061
66 },
67 'PSOC_061_512K': {
68 'flashSize': 0x80000, # 512 KBytes
69 **common_PSOC_061
70 },
71
72 'PSOC_062_2M': {
73 'flashSize': 0x200000, # 2 MBytes
74 **common_PSOC_06x
Roman Okhrimenko977b3752022-03-31 14:40:48 +030075 },
76 'PSOC_062_1M': {
Roman Okhrimenko977b3752022-03-31 14:40:48 +030077 'flashSize': 0x100000, # 1 MByte
Dovhal Artem (CSUKR CSS ICW SW FW 1)f7a3d1b2022-04-01 15:07:37 +000078 **common_PSOC_06x
Roman Okhrimenko977b3752022-03-31 14:40:48 +030079 },
80 'PSOC_062_512K': {
Roman Okhrimenko977b3752022-03-31 14:40:48 +030081 'flashSize': 0x80000, # 512 KBytes
Dovhal Artem (CSUKR CSS ICW SW FW 1)f7a3d1b2022-04-01 15:07:37 +000082 **common_PSOC_06x
Roman Okhrimenko977b3752022-03-31 14:40:48 +030083 },
Dovhal Artem (CSUKR CSS ICW SW FW 1)f7a3d1b2022-04-01 15:07:37 +000084
85 'PSOC_063_1M': {
86 'flashSize': 0x100000, # 1 MByte
87 **common_PSOC_06x
88 },
89
Roman Okhrimenko977b3752022-03-31 14:40:48 +030090 'CYW20829': {
91 'flashSize': 0, # n/a
92 'smifAddr': 0x60000000,
Dovhal Artem (CSUKR CSS ICW SW FW 1)f7a3d1b2022-04-01 15:07:37 +000093 'smifSize': 0x8000000, # i.e., window size
94 'VTAlign': 0x200, # Vector Table alignment
95 'allCores': cm33Core,
96 'bootCore': 'Cortex-M33',
97 'appCore': 'Cortex-M33',
98 'bitsPerCnt': False
99 },
100
101
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300102}
103
104# Supported SPI Flash ICs
105flashDict = {
106 # Fudan
107 'FM25Q04': {
108 'flashSize': 0x80000, # 4 Mbits
109 'eraseSize': 0x1000, # 128 uniform sectors with 4K-byte each
110 },
111 'FM25W04': {
112 'flashSize': 0x80000, # 4 Mbits
113 'eraseSize': 0x1000, # 128 uniform sectors with 4K-byte each
114 },
115 'FM25Q08': {
116 'flashSize': 0x100000, # 8 Mbits
117 'eraseSize': 0x1000, # 256 uniform sectors with 4K-byte each
118 },
119 'FM25W08': {
120 'flashSize': 0x100000, # 8 Mbits
121 'eraseSize': 0x1000, # 256 uniform sectors with 4K-byte each
122 },
123 # Puya
124 'P25Q05H': {
125 'flashSize': 0x10000, # 512 Kbits
126 'eraseSize': 0x1000, # Uniform 4K-byte Sector Erase
127 },
128 'P25Q10H': {
129 'flashSize': 0x20000, # 1 Mbit
130 'eraseSize': 0x1000, # Uniform 4K-byte Sector Erase
131 },
132 'P25Q20H': {
133 'flashSize': 0x40000, # 2 Mbits
134 'eraseSize': 0x1000, # Uniform 4K-byte Sector Erase
135 },
136 'P25Q40H': {
137 'flashSize': 0x80000, # 4 Mbits
138 'eraseSize': 0x1000, # Uniform 4K-byte Sector Erase
139 },
140 # Infineon
141 'S25HS256T': {
142 'flashSize': 0x2000000, # 256 Mbits
143 'eraseSize': 0x40000, # Uniform Sector Architecture
144 },
145 'S25HS512T': {
146 'flashSize': 0x4000000, # 512 Mbits
147 'eraseSize': 0x40000, # Uniform Sector Architecture
148 },
149 'S25HS01GT': {
150 'flashSize': 0x8000000, # 1 Gbit
151 'eraseSize': 0x40000, # Uniform Sector Architecture
152 }
153}
154
155
156def is_overlap(fa1off, fa1size, fa2off, fa2size, align):
157 """Check if two flash areas on the same device overlap"""
158 mask = align - 1
159 assert align > 0 and (align & mask) == 0 # ensure align is a power of 2
160 fa1end = (fa1off + fa1size + mask) & ~mask
161 fa2end = (fa2off + fa2size + mask) & ~mask
162 fa1off = fa1off & ~mask
163 fa2off = fa2off & ~mask
164 return fa1off < fa2end and fa2off < fa1end
165
166
167def is_same_mem(fa1addr, fa2addr):
168 """Check if two addresses belong to the same memory"""
169 if fa1addr is None or fa2addr is None:
170 return False
171 mask = 0xFF000000
172 return (fa1addr & mask) == (fa2addr & mask)
173
174
175class CmdLineParams:
176 """Command line parameters"""
177
178 def __init__(self):
179 self.plat_id = ''
180 self.in_file = ''
181 self.out_file = ''
182 self.img_id = None
Dovhal Artem (CSUKR CSS ICW SW FW 1)f7a3d1b2022-04-01 15:07:37 +0000183 self.policy = None
184 self.set_core = False
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300185
186 usage = 'USAGE:\n' + sys.argv[0] + \
187 ''' -p <platform> -i <flash_map.json> -o <flash_map.h> -d <img_id>
188
189OPTIONS:
190-h --help Display the usage information
191-p --platform= Target (e.g., PSOC_062_512K)
192-i --ifile= JSON flash map file
193-o --ofile= C header file to be generated
Dovhal Artem (CSUKR CSS ICW SW FW 1)f7a3d1b2022-04-01 15:07:37 +0000194-d --img_id ID of application to build
195-c --policy Policy file in JSON format
196-m --core Detect and set Cortex-M CORE
197'''
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300198
199 try:
200 opts, unused = getopt.getopt(
Dovhal Artem (CSUKR CSS ICW SW FW 1)f7a3d1b2022-04-01 15:07:37 +0000201 sys.argv[1:], 'hi:o:p:d:c:m',
202 ['help', 'platform=', 'ifile=', 'ofile=', 'img_id=', 'policy=', 'core'])
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300203 if len(unused) > 0:
204 print(usage, file=sys.stderr)
205 sys.exit(1)
206 except getopt.GetoptError:
207 print(usage, file=sys.stderr)
208 sys.exit(1)
209
210 for opt, arg in opts:
211 if opt in ('-h', '--help'):
212 print(usage, file=sys.stderr)
213 sys.exit()
214 elif opt in ('-p', '--platform'):
215 self.plat_id = arg
216 elif opt in ('-i', '--ifile'):
217 self.in_file = arg
218 elif opt in ('-o', '--ofile'):
219 self.out_file = arg
220 elif opt in ('-d', '--img_id'):
221 self.img_id = arg
Dovhal Artem (CSUKR CSS ICW SW FW 1)f7a3d1b2022-04-01 15:07:37 +0000222 elif opt in ('-c', '--policy'):
223 self.policy = arg
224 elif opt in ('-m', '--core'):
225 self.set_core = True
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300226
227 if len(self.in_file) == 0 or len(self.out_file) == 0:
228 print(usage, file=sys.stderr)
229 sys.exit(1)
230
231
232class AreaList:
233 """List of flash areas"""
234
235 def __init__(self, plat, flash, use_overwrite):
236 self.plat = plat
237 self.flash = flash
238 self.use_overwrite = use_overwrite
239 self.areas = []
240 self.peers = {}
241 self.trailers = {}
242 self.internal_flash = False
243 self.external_flash = False
244 self.external_flash_xip = False
245
246 def get_min_erase_size(self):
247 """Calculate minimum erase block size for int./ext. Flash """
248 return self.plat['eraseSize'] if self.plat['flashSize'] > 0 \
249 else self.flash['eraseSize']
250
251 def get_img_trailer_size(self):
252 """Calculate image trailer size"""
253 return self.get_min_erase_size()
254
255 def process_int_area(self, title, fa_addr, fa_size,
256 img_trailer_size, shared_slot):
257 """Process internal flash area"""
258 fa_device_id = 'FLASH_DEVICE_INTERNAL_FLASH'
259 fa_off = fa_addr - self.plat['flashAddr']
260 if img_trailer_size is not None:
261 if self.use_overwrite:
262 if shared_slot:
263 print('Shared slot', title,
264 'is not supported in OVERWRITE mode',
265 file=sys.stderr)
266 sys.exit(7)
267 else:
268 # Check trailer alignment (start at the sector boundary)
269 align = (fa_off + fa_size - img_trailer_size) % \
270 self.plat['eraseSize']
271 if align != 0:
272 fa_addr += self.plat['eraseSize'] - align
273 if fa_addr + fa_size <= \
274 self.plat['flashAddr'] + self.plat['flashSize']:
275 print('Misaligned', title,
276 '- suggested address', hex(fa_addr),
277 file=sys.stderr)
278 else:
279 print('Misaligned', title, file=sys.stderr)
280 sys.exit(7)
281 else:
282 # Check alignment (flash area should start at the sector boundary)
283 if fa_off % self.plat['eraseSize'] != 0:
284 print('Misaligned', title, file=sys.stderr)
285 sys.exit(7)
286 slot_sectors = int((fa_off % self.plat['eraseSize'] +
287 fa_size + self.plat['eraseSize'] - 1) //
288 self.plat['eraseSize'])
289 return fa_device_id, fa_off, slot_sectors
290
291 def process_ext_area(self, title, fa_addr, fa_size,
292 img_trailer_size, shared_slot):
293 """Process external flash area"""
294 if self.flash is None:
295 print('Unspecified SPI Flash IC',
296 file=sys.stderr)
297 sys.exit(3)
298 if fa_addr + fa_size <= \
299 self.plat['smifAddr'] + self.flash['flashSize']:
300 flash_idx = 'CY_BOOT_EXTERNAL_DEVICE_INDEX'
301 fa_device_id = f'FLASH_DEVICE_EXTERNAL_FLASH({flash_idx})'
302 fa_off = fa_addr - self.plat['smifAddr']
303 else:
304 print('Misfitting', title, file=sys.stderr)
305 sys.exit(7)
306 if img_trailer_size is not None:
307 if self.use_overwrite:
308 if shared_slot:
309 print('Shared slot', title,
310 'is not supported in OVERWRITE mode',
311 file=sys.stderr)
312 sys.exit(7)
313 else:
314 # Check trailer alignment (start at the sector boundary)
315 align = (fa_off + fa_size - img_trailer_size) % \
316 self.flash['eraseSize']
317 if align != 0:
318 peer_addr = self.peers.get(fa_addr)
319 if shared_slot:
320 # Special case when using both int. and ext. memory
321 if self.plat['flashSize'] > 0 and \
322 align % self.plat['eraseSize'] == 0:
323 print('Note:', title, 'requires', align,
324 'padding bytes before trailer',
325 file=sys.stderr)
326 else:
327 print('Misaligned', title, file=sys.stderr)
328 sys.exit(7)
329 elif is_same_mem(fa_addr, peer_addr) and \
330 fa_addr % self.flash['eraseSize'] == \
331 peer_addr % self.flash['eraseSize']:
332 pass # postpone checking
333 else:
334 fa_addr += self.flash['eraseSize'] - align
335 if fa_addr + fa_size <= \
336 self.plat['smifAddr'] + self.flash['flashSize']:
337 print('Misaligned', title,
338 '- suggested address', hex(fa_addr),
339 file=sys.stderr)
340 else:
341 print('Misaligned', title, file=sys.stderr)
342 sys.exit(7)
343 else:
344 # Check alignment (flash area should start at the sector boundary)
345 if fa_off % self.flash['eraseSize'] != 0:
346 print('Misaligned', title, file=sys.stderr)
347 sys.exit(7)
348 slot_sectors = int((fa_off % self.flash['eraseSize'] +
349 fa_size + self.flash['eraseSize'] - 1) //
350 self.flash['eraseSize'])
351 self.external_flash = True
352 if self.flash['XIP']:
353 self.external_flash_xip = True
354 return fa_device_id, fa_off, slot_sectors
355
356 def chk_area(self, fa_addr, fa_size, peer_addr=None):
357 """Check area location (internal/external flash)"""
358 if peer_addr is not None:
359 self.peers[peer_addr] = fa_addr
360 fa_limit = fa_addr + fa_size
361 if self.plat['flashSize'] and \
362 fa_addr >= self.plat['flashAddr'] and \
363 fa_limit <= self.plat['flashAddr'] + self.plat['flashSize']:
364 # Internal flash
365 self.internal_flash = True
366
367 def add_area(self, title,
368 fa_id, fa_addr, fa_size,
369 img_trailer_size=None, shared_slot=False):
370 """Add flash area to AreaList.
371 Internal/external flash is detected by address.
372 Returns number of sectors in a slot"""
373 if fa_size == 0:
374 print('Empty', title, file=sys.stderr)
375 sys.exit(7)
376
377 fa_limit = fa_addr + fa_size
378 if self.plat['flashSize'] and \
379 fa_addr >= self.plat['flashAddr'] and \
380 fa_limit <= self.plat['flashAddr'] + self.plat['flashSize']:
381 # Internal flash
382 fa_device_id, fa_off, slot_sectors = self.process_int_area(
383 title, fa_addr, fa_size, img_trailer_size, shared_slot)
384 align = self.plat['eraseSize']
385 elif self.plat['smifSize'] and \
386 fa_addr >= self.plat['smifAddr'] and \
387 fa_limit <= self.plat['smifAddr'] + self.plat['smifSize']:
388 # External flash
389 fa_device_id, fa_off, slot_sectors = self.process_ext_area(
390 title, fa_addr, fa_size, img_trailer_size, shared_slot)
391 align = self.flash['eraseSize']
392 else:
393 print('Invalid', title, file=sys.stderr)
394 sys.exit(7)
395
396 if shared_slot:
397 assert img_trailer_size is not None
398 tr_addr = fa_addr + fa_size - img_trailer_size
399 tr_name = self.trailers.get(tr_addr)
400 if tr_name is not None:
401 print('Same trailer address for', title, 'and', tr_name,
402 file=sys.stderr)
403 sys.exit(7)
404 self.trailers[tr_addr] = title
405
406 # Ensure no flash areas on this device will overlap, except the
407 # shared slot
408 for area in self.areas:
409 if fa_device_id == area['fa_device_id']:
410 over = is_overlap(fa_off, fa_size,
411 area['fa_off'], area['fa_size'],
412 align)
413 if shared_slot and area['shared_slot']:
414 if not over: # images in shared slot should overlap
415 print(title, 'is not shared with', area['title'],
416 file=sys.stderr)
417 sys.exit(7)
418 elif over:
419 print(title, 'overlaps with', area['title'],
420 file=sys.stderr)
421 sys.exit(7)
422
423 self.areas.append({'title': title,
424 'shared_slot': shared_slot,
425 'fa_id': fa_id,
426 'fa_device_id': fa_device_id,
427 'fa_off': fa_off,
428 'fa_size': fa_size})
429 return slot_sectors
430
431 def generate_c_source(self, params):
432 """Generate C source"""
433 c_array = 'flash_areas'
434
435 try:
436 with open(params.out_file, "w", encoding='UTF-8') as out_f:
437 out_f.write('/* AUTO-GENERATED FILE, DO NOT EDIT.'
Dovhal Artem (CSUKR CSS ICW SW FW 1)f7a3d1b2022-04-01 15:07:37 +0000438 ' ALL CHANGES WILL BE LOST! */\n\n'
439 '#ifndef CY_FLASH_MAP_H\n#define CY_FLASH_MAP_H\n')
440 out_f.write(f'\n/* Platform: {params.plat_id} */\n')
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300441 out_f.write(f'\nstatic struct flash_area {c_array}[] = {{\n')
442 comma = len(self.areas)
443 area_count = 0
444 for area in self.areas:
445 comma -= 1
446 if area['fa_id'] is not None:
447 sss = ' /* Shared secondary slot */' \
448 if area['shared_slot'] else ''
449 out_f.writelines('\n'.join([
450 ' {' + sss,
451 f" .fa_id = {area['fa_id']},",
452 f" .fa_device_id = {area['fa_device_id']},",
453 f" .fa_off = {hex(area['fa_off'])}U,",
454 f" .fa_size = {hex(area['fa_size'])}U",
455 ' },' if comma else ' }', '']))
456 area_count += 1
457 out_f.write('};\n\n'
458 'struct flash_area *boot_area_descs[] = {\n')
459 for area_index in range(area_count):
460 out_f.write(f' &{c_array}[{area_index}U],\n')
Dovhal Artem (CSUKR CSS ICW SW FW 1)f7a3d1b2022-04-01 15:07:37 +0000461 out_f.write(' NULL\n};\n\n#endif /* CY_FLASH_MAP_H */\n')
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300462 except (FileNotFoundError, OSError):
463 print('Cannot create', params.out_file, file=sys.stderr)
464 sys.exit(4)
465
466
467def cvt_dec_or_hex(val, desc):
468 """Convert (hexa)decimal string to number"""
469 try:
470 return int(val, 0)
471 except ValueError:
472 print('Invalid value', val, 'for', desc, file=sys.stderr)
473 sys.exit(6)
474
475
476def get_val(obj, attr):
477 """Get JSON 'value'"""
478 obj = obj[attr]
479 try:
480 return cvt_dec_or_hex(obj['value'], obj['description'])
481 except KeyError as key:
482 print('Malformed JSON:', key,
483 'is missing in', "'" + attr + "'",
484 file=sys.stderr)
485 sys.exit(5)
486
487
488def get_bool(obj, attr, def_val=False):
Dovhal Artem (CSUKR CSS ICW SW FW 1)f7a3d1b2022-04-01 15:07:37 +0000489 """Get JSON boolean value (returns def_val if it is missing)"""
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300490 ret_val = def_val
491 obj = obj.get(attr)
492 if obj is not None:
493 try:
494 val = str(obj['value']).lower()
495 desc = obj['description']
496 if val == 'true':
497 ret_val = True
498 elif val == 'false':
499 ret_val = False
500 else:
501 print('Invalid value', val, 'for', desc, file=sys.stderr)
502 sys.exit(6)
503 except KeyError as key:
504 print('Malformed JSON:', key,
505 'is missing in', "'" + attr + "'",
506 file=sys.stderr)
507 sys.exit(5)
508 return ret_val
509
510
Dovhal Artem (CSUKR CSS ICW SW FW 1)f7a3d1b2022-04-01 15:07:37 +0000511def get_str(obj, attr, def_val=None):
512 """Get JSON string value (returns def_val if it is missing)"""
513 ret_val = def_val
514 obj = obj.get(attr)
515 if obj is not None:
516 try:
517 ret_val = str(obj['value'])
518 except KeyError as key:
519 print('Malformed JSON:', key,
520 'is missing in', "'" + attr + "'",
521 file=sys.stderr)
522 sys.exit(5)
523 return ret_val
524
525
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300526class AddrSize:
527 """Bootloader area"""
528
529 def __init__(self, bootloader, addr_name, size_name):
530 self.fa_addr = get_val(bootloader, addr_name)
531 self.fa_size = get_val(bootloader, size_name)
532
533
534def calc_status_size(boot_swap_status_row_sz, max_img_sectors,
535 img_number, scratch_flag=True):
536 """Estimate status size, see swap_status.h"""
537 boot_swap_status_cnt_sz = 4
538 boot_swap_status_crc_sz = 4
539 boot_swap_status_mgcrec_sz = 4
540 boot_swap_status_trailer_size = 64
541 boot_swap_status_payld_sz = \
542 boot_swap_status_row_sz - boot_swap_status_mgcrec_sz - \
543 boot_swap_status_cnt_sz - boot_swap_status_crc_sz
544 boot_swap_status_sect_rows_num = \
545 int((max_img_sectors - 1) //
546 boot_swap_status_payld_sz) + 1
547 boot_swap_status_trail_rows_num = \
548 int((boot_swap_status_trailer_size - 1) //
549 boot_swap_status_payld_sz) + 1
550 boot_swap_status_d_size = \
551 boot_swap_status_row_sz * \
552 (boot_swap_status_sect_rows_num + boot_swap_status_trail_rows_num)
553 boot_swap_status_mult = 2
554 boot_swap_status_size = boot_swap_status_mult * boot_swap_status_d_size
555 status_zone_cnt = 2 * img_number
556 if scratch_flag:
557 status_zone_cnt += 1
558 return boot_swap_status_size * status_zone_cnt
559
560
561def process_json(in_file):
562 """Process JSON"""
563 try:
564 with open(in_file, encoding='UTF-8') as in_f:
565 try:
566 flash_map = json.load(in_f)
567 except ValueError:
568 print('Cannot parse', in_file, file=sys.stderr)
569 sys.exit(4)
570 except (FileNotFoundError, OSError):
571 print('Cannot open', in_file, file=sys.stderr)
572 sys.exit(4)
573 flash = flash_map.get('external_flash')
574 if flash is not None:
575 flash = flash[0]
576 model = flash.get('model')
577 mode = flash.get('mode')
578 if model is not None:
579 try:
580 flash = flashDict[model]
581 except KeyError:
582 print('Supported SPI Flash ICs are:',
583 ', '.join(flashDict.keys()),
584 file=sys.stderr)
585 sys.exit(3)
586 else:
587 try:
588 flash = {'flashSize': cvt_dec_or_hex(flash['flash-size'],
589 'flash-size'),
590 'eraseSize': cvt_dec_or_hex(flash['erase-size'],
591 'erase-size')}
592 except KeyError as key:
593 print('Malformed JSON:', key,
594 "is missing in 'external_flash'",
595 file=sys.stderr)
596 sys.exit(3)
597 flash.update({'XIP': str(mode).upper() == 'XIP'})
598 return flash_map['boot_and_upgrade'], flash
599
600
601def process_images(area_list, boot_and_upgrade):
602 """Process images"""
603 app_count = 0
604 slot_sectors_max = 0
605 all_shared = get_bool(boot_and_upgrade['bootloader'], 'shared_slot')
606 any_shared = all_shared
Dovhal Artem (CSUKR CSS ICW SW FW 1)f7a3d1b2022-04-01 15:07:37 +0000607 app_core = None
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300608 apps_flash_map = [None, ]
609
610 for stage in range(2):
611 for app_index in range(1, 5):
612
613 app_flash_map = {}
614
615 try:
616 app_ident = f'application_{app_index}'
617 application = boot_and_upgrade[app_ident]
618 try:
619 primary_addr = get_val(application, 'address')
620 primary_size = get_val(application, 'size')
621 secondary_addr = get_val(application, 'upgrade_address')
622 secondary_size = get_val(application, 'upgrade_size')
623 except KeyError as key:
624 print('Malformed JSON:', key, 'is missing',
625 file=sys.stderr)
626 sys.exit(5)
627 if stage == 0:
628 if primary_size != secondary_size:
629 print('Primary and secondary slot sizes'
630 ' are different for', app_ident,
631 file=sys.stderr)
632 sys.exit(6)
633 area_list.chk_area(primary_addr, primary_size)
634 area_list.chk_area(secondary_addr, secondary_size,
635 primary_addr)
Dovhal Artem (CSUKR CSS ICW SW FW 1)f7a3d1b2022-04-01 15:07:37 +0000636 if application.get('core') is None:
637 if app_index == 1:
638 app_core = area_list.plat['appCore']
639 elif app_index > 1:
640 print('"core" makes sense only for the 1st app',
641 file=sys.stderr)
642 sys.exit(6)
643 else:
644 app_core = get_str(application, 'core',
645 area_list.plat['appCore'])
646 if app_index == 1:
647 app_core = area_list.plat['allCores'].get(app_core.lower())
648 if app_core is None:
649 print('Unknown "core"', file=sys.stderr)
650 sys.exit(6)
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300651 else:
652 slot_sectors_max = max(
653 slot_sectors_max,
654 area_list.add_area(
655 f'{app_ident} (primary slot)',
656 f'FLASH_AREA_IMG_{app_index}_PRIMARY',
657 primary_addr, primary_size,
658 area_list.get_img_trailer_size()))
659 shared_slot = get_bool(application, 'shared_slot', all_shared)
660 any_shared = any_shared or shared_slot
661 slot_sectors_max = max(
662 slot_sectors_max,
663 area_list.add_area(
664 f'{app_ident} (secondary slot)',
665 f'FLASH_AREA_IMG_{app_index}_SECONDARY',
666 secondary_addr, secondary_size,
667 area_list.get_img_trailer_size(),
668 shared_slot))
669
670 app_slot_prim = {"address": hex(primary_addr), "size": hex(primary_size)}
671 app_slot_sec = {"address": hex(secondary_addr), "size": hex(secondary_size)}
672
673 app_flash_map.update({"primary": app_slot_prim, "secondary": app_slot_sec})
674 apps_flash_map.append(app_flash_map)
675
676 app_count = app_index
677
678 except KeyError:
679 break
680 if app_count == 0:
681 print('Malformed JSON: no application(s) found',
682 file=sys.stderr)
683 sys.exit(5)
684
Dovhal Artem (CSUKR CSS ICW SW FW 1)f7a3d1b2022-04-01 15:07:37 +0000685 return app_core, app_count, slot_sectors_max, apps_flash_map, any_shared
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300686
687
688def main():
689 """Flash map converter"""
690 params = CmdLineParams()
691
692 try:
693 plat = platDict[params.plat_id]
694 except KeyError:
695 print('Supported platforms are:', ', '.join(platDict.keys()),
696 file=sys.stderr)
697 sys.exit(2)
698
699 try:
700 boot_and_upgrade, flash = process_json(params.in_file)
701 bootloader = boot_and_upgrade['bootloader']
702 boot = AddrSize(bootloader, 'address', 'size')
703 except KeyError as key:
704 print('Malformed JSON:', key, 'is missing',
705 file=sys.stderr)
706 sys.exit(5)
707
708 try:
709 scratch = AddrSize(bootloader, 'scratch_address', 'scratch_size')
710 except KeyError:
711 scratch = None
712
713 try:
714 swap_status = AddrSize(bootloader, 'status_address', 'status_size')
715 except KeyError:
716 swap_status = None
717
718 # Create flash areas
719 area_list = AreaList(plat, flash, scratch is None and swap_status is None)
720 area_list.add_area('bootloader', 'FLASH_AREA_BOOTLOADER',
721 boot.fa_addr, boot.fa_size)
722
723 # Service RAM app (optional)
724 service_app = boot_and_upgrade.get('service_app')
725 app_binary = None
726 input_params = None
727 app_desc = None
728 if service_app is not None:
729 if plat['flashSize'] > 0:
730 print('service_app is unsupported on this platform',
731 file=sys.stderr)
732 sys.exit(7)
733 try:
734 app_binary = AddrSize(service_app, 'address', 'size')
735 input_params = AddrSize(service_app, 'params_address', 'params_size')
736 app_desc = AddrSize(service_app, 'desc_address', 'desc_size')
737 if input_params.fa_addr != app_binary.fa_addr + app_binary.fa_size or \
738 app_desc.fa_addr != input_params.fa_addr + input_params.fa_size or \
739 app_desc.fa_size != 0x20:
740 print('Malformed service_app definition', file=sys.stderr)
741 sys.exit(7)
742 area_list.add_area('service_app', None, app_binary.fa_addr,
743 app_binary.fa_size + input_params.fa_size + app_desc.fa_size)
744 except KeyError as key:
745 print('Malformed JSON:', key, 'is missing',
746 file=sys.stderr)
747 sys.exit(5)
748
749 # Fill flash areas
Dovhal Artem (CSUKR CSS ICW SW FW 1)f7a3d1b2022-04-01 15:07:37 +0000750 app_core, app_count, slot_sectors_max, apps_flash_map, shared_slot = \
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300751 process_images(area_list, boot_and_upgrade)
752
Dovhal Artem (CSUKR CSS ICW SW FW 1)f7a3d1b2022-04-01 15:07:37 +0000753 cy_img_hdr_size = 0x400
754 app_start = int(apps_flash_map[1].get("primary").get("address"), 0) + cy_img_hdr_size
755
756 if app_start % plat['VTAlign'] != 0:
757 print('Starting address', apps_flash_map[1].get("primary").get("address"),
758 '+', hex(cy_img_hdr_size),
759 'must be aligned to', hex(plat['VTAlign']),
760 file=sys.stderr)
761 sys.exit(7)
762
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300763 slot_sectors_max = max(slot_sectors_max, 32)
764
765 if swap_status is not None:
766 status_size_min = calc_status_size(area_list.get_min_erase_size(),
767 slot_sectors_max,
768 app_count,
769 scratch is not None)
770
771 if swap_status.fa_size < status_size_min:
772 print('Insufficient swap status area - suggested size',
773 hex(status_size_min),
774 file=sys.stderr)
775 sys.exit(7)
776 area_list.add_area('swap status partition',
777 'FLASH_AREA_IMAGE_SWAP_STATUS',
778 swap_status.fa_addr, swap_status.fa_size)
779
780 if scratch is not None:
781 area_list.add_area('scratch area',
782 'FLASH_AREA_IMAGE_SCRATCH',
783 scratch.fa_addr, scratch.fa_size)
784
785 # Image id parameter is not used for MCUBootApp
786 if params.img_id is None:
787 area_list.generate_c_source(params)
788
789 # Report necessary values back to make
790 print('# AUTO-GENERATED FILE, DO NOT EDIT. ALL CHANGES WILL BE LOST!')
Dovhal Artem (CSUKR CSS ICW SW FW 1)f7a3d1b2022-04-01 15:07:37 +0000791 print('BOOTLOADER_SIZE :=', hex(boot.fa_size))
792 if params.set_core:
793 print('CORE :=', plat['allCores'][plat['bootCore'].lower()])
794 print('APP_CORE :=', app_core)
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300795
796 if params.img_id is not None:
Dovhal Artem (CSUKR CSS ICW SW FW 1)f7a3d1b2022-04-01 15:07:37 +0000797 primary_img_start = apps_flash_map[int(params.img_id)].get("primary").get("address")
798 secondary_img_start = apps_flash_map[int(params.img_id)].get("secondary").get("address")
799 slot_size = apps_flash_map[int(params.img_id)].get("primary").get("size")
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300800
801 print('PRIMARY_IMG_START := ' + primary_img_start)
802 print('SECONDARY_IMG_START := ' + secondary_img_start)
803 print('SLOT_SIZE := ' + slot_size)
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300804 else:
805 print('MCUBOOT_IMAGE_NUMBER :=', app_count)
806 print('MAX_IMG_SECTORS :=', slot_sectors_max)
807
808 if area_list.use_overwrite:
809 print('USE_OVERWRITE := 1')
810 if area_list.external_flash:
811 print('USE_EXTERNAL_FLASH := 1')
812 if area_list.external_flash_xip:
813 print('USE_XIP := 1')
814 if shared_slot:
815 print('USE_SHARED_SLOT := 1')
816 if service_app is not None:
817 print('PLATFORM_SERVICE_APP_OFFSET :=',
818 hex(app_binary.fa_addr - plat['smifAddr']))
819 print('PLATFORM_SERVICE_APP_INPUT_PARAMS_OFFSET :=',
820 hex(input_params.fa_addr - plat['smifAddr']))
821 print('PLATFORM_SERVICE_APP_DESC_OFFSET :=',
822 hex(app_desc.fa_addr - plat['smifAddr']))
823 print('USE_HW_ROLLBACK_PROT := 1')
824
825
826if __name__ == '__main__':
827 main()