Merge pull request #5950 from theotherjimmy/header-config

Reserve and Render header in managed BL mode
pull/6251/head
Anna Bridge 2018-03-01 16:25:18 +00:00 committed by GitHub
commit 8f5b857747
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 137 additions and 3 deletions

View File

@ -20,6 +20,9 @@ import re
import tempfile
import datetime
import uuid
import struct
import zlib
import hashlib
from shutil import rmtree
from os.path import join, exists, dirname, basename, abspath, normpath, splitext
from os.path import relpath
@ -33,7 +36,7 @@ from jinja2.environment import Environment
from .arm_pack_manager import Cache
from .utils import (mkdir, run_cmd, run_cmd_ext, NotSupportedException,
ToolException, InvalidReleaseTargetException,
intelhex_offset)
intelhex_offset, integer)
from .paths import (MBED_CMSIS_PATH, MBED_TARGETS_PATH, MBED_LIBRARIES,
MBED_HEADER, MBED_DRIVERS, MBED_PLATFORM, MBED_HAL,
MBED_CONFIG_FILE, MBED_LIBRARIES_DRIVERS,
@ -339,8 +342,68 @@ def prepare_toolchain(src_paths, build_dir, target, toolchain_name,
return toolchain
def _printihex(ihex):
import pprint
pprint.PrettyPrinter().pprint(ihex.todict())
def _real_region_size(region):
try:
part = intelhex_offset(region.filename, offset=region.start)
return (part.maxaddr() - part.minaddr()) + 1
except AttributeError:
return region.size
def _fill_header(region_list, current_region):
"""Fill an application header region
This is done it three steps:
* Fill the whole region with zeros
* Fill const, timestamp and size entries with their data
* Fill the digests using this header as the header region
"""
region_dict = {r.name: r for r in region_list}
header = IntelHex()
header.puts(current_region.start, b'\x00' * current_region.size)
start = current_region.start
for member in current_region.filename:
_, type, subtype, data = member
member_size = Config.header_member_size(member)
if type == "const":
fmt = {
"8le": ">B", "16le": "<H", "32le": "<L", "64le": "<Q",
"8be": "<B", "16be": ">H", "32be": ">L", "64be": ">Q"
}[subtype]
header.puts(start, struct.pack(fmt, integer(data, 0)))
elif type == "timestamp":
fmt = {"32le": "<L", "64le": "<Q",
"32be": ">L", "64be": ">Q"}[subtype]
header.puts(start, struct.pack(fmt, time()))
elif type == "size":
fmt = {"32le": "<L", "64le": "<Q",
"32be": ">L", "64be": ">Q"}[subtype]
size = sum(_real_region_size(region_dict[r]) for r in data)
header.puts(start, struct.pack(fmt, size))
elif type == "digest":
if data == "header":
ih = header[:start]
else:
ih = intelhex_offset(region_dict[data].filename, offset=region_dict[data].start)
if subtype.startswith("CRCITT32"):
fmt = {"CRCITT32be": ">l", "CRCITT32le": "<l"}[subtype]
header.puts(start, struct.pack(fmt, zlib.crc32(ih.tobinarray())))
elif subtype.startswith("SHA"):
if subtype == "SHA256":
hash = hashlib.sha256()
elif subtype == "SHA512":
hash = hashlib.sha512()
hash.update(ih.tobinarray())
header.puts(start, hash.digest())
start += Config.header_member_size(member)
return header
def merge_region_list(region_list, destination, padding=b'\xFF'):
"""Merege the region_list into a single image
"""Merge the region_list into a single image
Positional Arguments:
region_list - list of regions, which should contain filenames
@ -355,6 +418,11 @@ def merge_region_list(region_list, destination, padding=b'\xFF'):
for region in region_list:
if region.active and not region.filename:
raise ToolException("Active region has no contents: No file found.")
if isinstance(region.filename, list):
header_basename, _ = splitext(destination)
header_filename = header_basename + "_header.hex"
_fill_header(region_list, region).tofile(header_filename, format='hex')
region = region._replace(filename=header_filename)
if region.filename:
print(" Filling region %s with %s" % (region.name, region.filename))
part = intelhex_offset(region.filename, offset=region.start)

View File

@ -30,7 +30,7 @@ from jinja2 import FileSystemLoader, StrictUndefined
from jinja2.environment import Environment
from jsonschema import Draft4Validator, RefResolver
from ..utils import json_file_to_dict, intelhex_offset
from ..utils import json_file_to_dict, intelhex_offset, integer
from ..arm_pack_manager import Cache
from ..targets import (CUMULATIVE_ATTRIBUTES, TARGET_MAP, generate_py_target,
get_resolution_order, Target)
@ -41,8 +41,11 @@ except NameError:
unicode = str
PATH_OVERRIDES = set(["target.bootloader_img"])
BOOTLOADER_OVERRIDES = set(["target.bootloader_img", "target.restrict_size",
"target.header_format", "target.header_offset",
"target.app_offset",
"target.mbed_app_start", "target.mbed_app_size"])
# Base class for all configuration exceptions
class ConfigException(Exception):
"""Config system only exception. Makes it easier to distinguish config
@ -579,6 +582,41 @@ class Config(object):
raise ConfigException(
"Bootloader build requested but no bootlader configuration")
@staticmethod
def header_member_size(member):
_, _, subtype, _ = member
try:
return int(subtype[:-2]) // 8
except:
if subtype.startswith("CRCITT32"):
return 32 // 8
elif subtype == "SHA256":
return 256 // 8
elif subtype == "SHA512":
return 512 // 8
else:
raise ValueError("target.header_format: subtype %s is not "
"understood" % subtype)
@staticmethod
def _header_size(format):
return sum(Config.header_member_size(m) for m in format)
def _make_header_region(self, start, header_format, offset=None):
size = self._header_size(header_format)
region = Region("header", start, size, False, None)
start += size
start = ((start + 7) // 8) * 8
return (start, region)
@staticmethod
def _assign_new_offset(rom_start, start, new_offset, region_name):
newstart = rom_start + integer(new_offset, 0)
if newstart < start:
raise ConfigException(
"Can not place % region inside previous region" % region_name)
return newstart
def _generate_bootloader_build(self, rom_start, rom_size):
start = rom_start
rom_end = rom_start + rom_size
@ -599,14 +637,34 @@ class Config(object):
yield Region("bootloader", rom_start, part_size, False,
filename)
start = rom_start + part_size
if self.target.header_format:
if self.target.header_offset:
start = self._assign_new_offset(
rom_start, start, self.target.header_offset, "header")
start, region = self._make_header_region(
start, self.target.header_format)
yield region._replace(filename=self.target.header_format)
if self.target.restrict_size is not None:
new_size = int(self.target.restrict_size, 0)
new_size = Config._align_floor(start + new_size, self.sectors) - start
yield Region("application", start, new_size, True, None)
start += new_size
if self.target.header_format:
if self.target.header_offset:
start = self._assign_new_offset(
rom_start, start, self.target.header_offset, "header")
start, region = self._make_header_region(
start, self.target.header_format)
yield region
if self.target.app_offset:
start = self._assign_new_offset(
rom_start, start, self.target.app_offset, "application")
yield Region("post_application", start, rom_end - start,
False, None)
else:
if self.target.app_offset:
start = self._assign_new_offset(
rom_start, start, self.target.app_offset, "application")
yield Region("application", start, rom_end - start,
True, None)
if start > rom_start + rom_size:

View File

@ -520,3 +520,11 @@ def intelhex_offset(filename, offset):
raise ToolException("File %s does not have a known binary file type"
% filename)
return ih
def integer(maybe_string, base):
"""Make an integer of a number or a string"""
if isinstance(maybe_string, int):
return maybe_string
else:
return int(maybe_string, base)