mirror of https://github.com/ARMmbed/mbed-os.git
Merge pull request #5950 from theotherjimmy/header-config
Reserve and Render header in managed BL modepull/6251/head
commit
8f5b857747
|
@ -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)
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue