Skip to content

Commit 8f5b857

Browse files
authored
Merge pull request #5950 from theotherjimmy/header-config
Reserve and Render header in managed BL mode
2 parents ae788f7 + 9f99330 commit 8f5b857

File tree

3 files changed

+137
-3
lines changed

3 files changed

+137
-3
lines changed

tools/build_api.py

Lines changed: 70 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020
import tempfile
2121
import datetime
2222
import uuid
23+
import struct
24+
import zlib
25+
import hashlib
2326
from shutil import rmtree
2427
from os.path import join, exists, dirname, basename, abspath, normpath, splitext
2528
from os.path import relpath
@@ -33,7 +36,7 @@
3336
from .arm_pack_manager import Cache
3437
from .utils import (mkdir, run_cmd, run_cmd_ext, NotSupportedException,
3538
ToolException, InvalidReleaseTargetException,
36-
intelhex_offset)
39+
intelhex_offset, integer)
3740
from .paths import (MBED_CMSIS_PATH, MBED_TARGETS_PATH, MBED_LIBRARIES,
3841
MBED_HEADER, MBED_DRIVERS, MBED_PLATFORM, MBED_HAL,
3942
MBED_CONFIG_FILE, MBED_LIBRARIES_DRIVERS,
@@ -339,8 +342,68 @@ def prepare_toolchain(src_paths, build_dir, target, toolchain_name,
339342

340343
return toolchain
341344

345+
def _printihex(ihex):
346+
import pprint
347+
pprint.PrettyPrinter().pprint(ihex.todict())
348+
349+
def _real_region_size(region):
350+
try:
351+
part = intelhex_offset(region.filename, offset=region.start)
352+
return (part.maxaddr() - part.minaddr()) + 1
353+
except AttributeError:
354+
return region.size
355+
356+
357+
def _fill_header(region_list, current_region):
358+
"""Fill an application header region
359+
360+
This is done it three steps:
361+
* Fill the whole region with zeros
362+
* Fill const, timestamp and size entries with their data
363+
* Fill the digests using this header as the header region
364+
"""
365+
region_dict = {r.name: r for r in region_list}
366+
header = IntelHex()
367+
header.puts(current_region.start, b'\x00' * current_region.size)
368+
start = current_region.start
369+
for member in current_region.filename:
370+
_, type, subtype, data = member
371+
member_size = Config.header_member_size(member)
372+
if type == "const":
373+
fmt = {
374+
"8le": ">B", "16le": "<H", "32le": "<L", "64le": "<Q",
375+
"8be": "<B", "16be": ">H", "32be": ">L", "64be": ">Q"
376+
}[subtype]
377+
header.puts(start, struct.pack(fmt, integer(data, 0)))
378+
elif type == "timestamp":
379+
fmt = {"32le": "<L", "64le": "<Q",
380+
"32be": ">L", "64be": ">Q"}[subtype]
381+
header.puts(start, struct.pack(fmt, time()))
382+
elif type == "size":
383+
fmt = {"32le": "<L", "64le": "<Q",
384+
"32be": ">L", "64be": ">Q"}[subtype]
385+
size = sum(_real_region_size(region_dict[r]) for r in data)
386+
header.puts(start, struct.pack(fmt, size))
387+
elif type == "digest":
388+
if data == "header":
389+
ih = header[:start]
390+
else:
391+
ih = intelhex_offset(region_dict[data].filename, offset=region_dict[data].start)
392+
if subtype.startswith("CRCITT32"):
393+
fmt = {"CRCITT32be": ">l", "CRCITT32le": "<l"}[subtype]
394+
header.puts(start, struct.pack(fmt, zlib.crc32(ih.tobinarray())))
395+
elif subtype.startswith("SHA"):
396+
if subtype == "SHA256":
397+
hash = hashlib.sha256()
398+
elif subtype == "SHA512":
399+
hash = hashlib.sha512()
400+
hash.update(ih.tobinarray())
401+
header.puts(start, hash.digest())
402+
start += Config.header_member_size(member)
403+
return header
404+
342405
def merge_region_list(region_list, destination, padding=b'\xFF'):
343-
"""Merege the region_list into a single image
406+
"""Merge the region_list into a single image
344407
345408
Positional Arguments:
346409
region_list - list of regions, which should contain filenames
@@ -355,6 +418,11 @@ def merge_region_list(region_list, destination, padding=b'\xFF'):
355418
for region in region_list:
356419
if region.active and not region.filename:
357420
raise ToolException("Active region has no contents: No file found.")
421+
if isinstance(region.filename, list):
422+
header_basename, _ = splitext(destination)
423+
header_filename = header_basename + "_header.hex"
424+
_fill_header(region_list, region).tofile(header_filename, format='hex')
425+
region = region._replace(filename=header_filename)
358426
if region.filename:
359427
print(" Filling region %s with %s" % (region.name, region.filename))
360428
part = intelhex_offset(region.filename, offset=region.start)

tools/config/__init__.py

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
from jinja2.environment import Environment
3131
from jsonschema import Draft4Validator, RefResolver
3232

33-
from ..utils import json_file_to_dict, intelhex_offset
33+
from ..utils import json_file_to_dict, intelhex_offset, integer
3434
from ..arm_pack_manager import Cache
3535
from ..targets import (CUMULATIVE_ATTRIBUTES, TARGET_MAP, generate_py_target,
3636
get_resolution_order, Target)
@@ -41,8 +41,11 @@
4141
unicode = str
4242
PATH_OVERRIDES = set(["target.bootloader_img"])
4343
BOOTLOADER_OVERRIDES = set(["target.bootloader_img", "target.restrict_size",
44+
"target.header_format", "target.header_offset",
45+
"target.app_offset",
4446
"target.mbed_app_start", "target.mbed_app_size"])
4547

48+
4649
# Base class for all configuration exceptions
4750
class ConfigException(Exception):
4851
"""Config system only exception. Makes it easier to distinguish config
@@ -579,6 +582,41 @@ def regions(self):
579582
raise ConfigException(
580583
"Bootloader build requested but no bootlader configuration")
581584

585+
@staticmethod
586+
def header_member_size(member):
587+
_, _, subtype, _ = member
588+
try:
589+
return int(subtype[:-2]) // 8
590+
except:
591+
if subtype.startswith("CRCITT32"):
592+
return 32 // 8
593+
elif subtype == "SHA256":
594+
return 256 // 8
595+
elif subtype == "SHA512":
596+
return 512 // 8
597+
else:
598+
raise ValueError("target.header_format: subtype %s is not "
599+
"understood" % subtype)
600+
601+
@staticmethod
602+
def _header_size(format):
603+
return sum(Config.header_member_size(m) for m in format)
604+
605+
def _make_header_region(self, start, header_format, offset=None):
606+
size = self._header_size(header_format)
607+
region = Region("header", start, size, False, None)
608+
start += size
609+
start = ((start + 7) // 8) * 8
610+
return (start, region)
611+
612+
@staticmethod
613+
def _assign_new_offset(rom_start, start, new_offset, region_name):
614+
newstart = rom_start + integer(new_offset, 0)
615+
if newstart < start:
616+
raise ConfigException(
617+
"Can not place % region inside previous region" % region_name)
618+
return newstart
619+
582620
def _generate_bootloader_build(self, rom_start, rom_size):
583621
start = rom_start
584622
rom_end = rom_start + rom_size
@@ -599,14 +637,34 @@ def _generate_bootloader_build(self, rom_start, rom_size):
599637
yield Region("bootloader", rom_start, part_size, False,
600638
filename)
601639
start = rom_start + part_size
640+
if self.target.header_format:
641+
if self.target.header_offset:
642+
start = self._assign_new_offset(
643+
rom_start, start, self.target.header_offset, "header")
644+
start, region = self._make_header_region(
645+
start, self.target.header_format)
646+
yield region._replace(filename=self.target.header_format)
602647
if self.target.restrict_size is not None:
603648
new_size = int(self.target.restrict_size, 0)
604649
new_size = Config._align_floor(start + new_size, self.sectors) - start
605650
yield Region("application", start, new_size, True, None)
606651
start += new_size
652+
if self.target.header_format:
653+
if self.target.header_offset:
654+
start = self._assign_new_offset(
655+
rom_start, start, self.target.header_offset, "header")
656+
start, region = self._make_header_region(
657+
start, self.target.header_format)
658+
yield region
659+
if self.target.app_offset:
660+
start = self._assign_new_offset(
661+
rom_start, start, self.target.app_offset, "application")
607662
yield Region("post_application", start, rom_end - start,
608663
False, None)
609664
else:
665+
if self.target.app_offset:
666+
start = self._assign_new_offset(
667+
rom_start, start, self.target.app_offset, "application")
610668
yield Region("application", start, rom_end - start,
611669
True, None)
612670
if start > rom_start + rom_size:

tools/utils.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -520,3 +520,11 @@ def intelhex_offset(filename, offset):
520520
raise ToolException("File %s does not have a known binary file type"
521521
% filename)
522522
return ih
523+
524+
525+
def integer(maybe_string, base):
526+
"""Make an integer of a number or a string"""
527+
if isinstance(maybe_string, int):
528+
return maybe_string
529+
else:
530+
return int(maybe_string, base)

0 commit comments

Comments
 (0)