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 tempfile
|
||||||
import datetime
|
import datetime
|
||||||
import uuid
|
import uuid
|
||||||
|
import struct
|
||||||
|
import zlib
|
||||||
|
import hashlib
|
||||||
from shutil import rmtree
|
from shutil import rmtree
|
||||||
from os.path import join, exists, dirname, basename, abspath, normpath, splitext
|
from os.path import join, exists, dirname, basename, abspath, normpath, splitext
|
||||||
from os.path import relpath
|
from os.path import relpath
|
||||||
|
@ -33,7 +36,7 @@ from jinja2.environment import Environment
|
||||||
from .arm_pack_manager import Cache
|
from .arm_pack_manager import Cache
|
||||||
from .utils import (mkdir, run_cmd, run_cmd_ext, NotSupportedException,
|
from .utils import (mkdir, run_cmd, run_cmd_ext, NotSupportedException,
|
||||||
ToolException, InvalidReleaseTargetException,
|
ToolException, InvalidReleaseTargetException,
|
||||||
intelhex_offset)
|
intelhex_offset, integer)
|
||||||
from .paths import (MBED_CMSIS_PATH, MBED_TARGETS_PATH, MBED_LIBRARIES,
|
from .paths import (MBED_CMSIS_PATH, MBED_TARGETS_PATH, MBED_LIBRARIES,
|
||||||
MBED_HEADER, MBED_DRIVERS, MBED_PLATFORM, MBED_HAL,
|
MBED_HEADER, MBED_DRIVERS, MBED_PLATFORM, MBED_HAL,
|
||||||
MBED_CONFIG_FILE, MBED_LIBRARIES_DRIVERS,
|
MBED_CONFIG_FILE, MBED_LIBRARIES_DRIVERS,
|
||||||
|
@ -339,8 +342,68 @@ def prepare_toolchain(src_paths, build_dir, target, toolchain_name,
|
||||||
|
|
||||||
return toolchain
|
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'):
|
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:
|
Positional Arguments:
|
||||||
region_list - list of regions, which should contain filenames
|
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:
|
for region in region_list:
|
||||||
if region.active and not region.filename:
|
if region.active and not region.filename:
|
||||||
raise ToolException("Active region has no contents: No file found.")
|
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:
|
if region.filename:
|
||||||
print(" Filling region %s with %s" % (region.name, region.filename))
|
print(" Filling region %s with %s" % (region.name, region.filename))
|
||||||
part = intelhex_offset(region.filename, offset=region.start)
|
part = intelhex_offset(region.filename, offset=region.start)
|
||||||
|
|
|
@ -30,7 +30,7 @@ from jinja2 import FileSystemLoader, StrictUndefined
|
||||||
from jinja2.environment import Environment
|
from jinja2.environment import Environment
|
||||||
from jsonschema import Draft4Validator, RefResolver
|
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 ..arm_pack_manager import Cache
|
||||||
from ..targets import (CUMULATIVE_ATTRIBUTES, TARGET_MAP, generate_py_target,
|
from ..targets import (CUMULATIVE_ATTRIBUTES, TARGET_MAP, generate_py_target,
|
||||||
get_resolution_order, Target)
|
get_resolution_order, Target)
|
||||||
|
@ -41,8 +41,11 @@ except NameError:
|
||||||
unicode = str
|
unicode = str
|
||||||
PATH_OVERRIDES = set(["target.bootloader_img"])
|
PATH_OVERRIDES = set(["target.bootloader_img"])
|
||||||
BOOTLOADER_OVERRIDES = set(["target.bootloader_img", "target.restrict_size",
|
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"])
|
"target.mbed_app_start", "target.mbed_app_size"])
|
||||||
|
|
||||||
|
|
||||||
# Base class for all configuration exceptions
|
# Base class for all configuration exceptions
|
||||||
class ConfigException(Exception):
|
class ConfigException(Exception):
|
||||||
"""Config system only exception. Makes it easier to distinguish config
|
"""Config system only exception. Makes it easier to distinguish config
|
||||||
|
@ -579,6 +582,41 @@ class Config(object):
|
||||||
raise ConfigException(
|
raise ConfigException(
|
||||||
"Bootloader build requested but no bootlader configuration")
|
"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):
|
def _generate_bootloader_build(self, rom_start, rom_size):
|
||||||
start = rom_start
|
start = rom_start
|
||||||
rom_end = rom_start + rom_size
|
rom_end = rom_start + rom_size
|
||||||
|
@ -599,14 +637,34 @@ class Config(object):
|
||||||
yield Region("bootloader", rom_start, part_size, False,
|
yield Region("bootloader", rom_start, part_size, False,
|
||||||
filename)
|
filename)
|
||||||
start = rom_start + part_size
|
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:
|
if self.target.restrict_size is not None:
|
||||||
new_size = int(self.target.restrict_size, 0)
|
new_size = int(self.target.restrict_size, 0)
|
||||||
new_size = Config._align_floor(start + new_size, self.sectors) - start
|
new_size = Config._align_floor(start + new_size, self.sectors) - start
|
||||||
yield Region("application", start, new_size, True, None)
|
yield Region("application", start, new_size, True, None)
|
||||||
start += new_size
|
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,
|
yield Region("post_application", start, rom_end - start,
|
||||||
False, None)
|
False, None)
|
||||||
else:
|
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,
|
yield Region("application", start, rom_end - start,
|
||||||
True, None)
|
True, None)
|
||||||
if start > rom_start + rom_size:
|
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"
|
raise ToolException("File %s does not have a known binary file type"
|
||||||
% filename)
|
% filename)
|
||||||
return ih
|
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