Merge pull request #10113 from theotherjimmy/use-ns-rom-in-bl

Use secure/non-secure rom for bl modes
pull/10086/head
Martin Kojtal 2019-03-15 21:19:54 +01:00 committed by GitHub
commit 35e30e1b70
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 305 additions and 131 deletions

View File

@ -18,15 +18,11 @@ from __future__ import print_function, division, absolute_import
from copy import deepcopy from copy import deepcopy
from six import moves from six import moves
import json
import six
import os import os
import re import re
from os.path import dirname, abspath, exists, join, isabs from os.path import dirname, abspath, exists, join, isabs
import sys
from collections import namedtuple from collections import namedtuple
from os.path import splitext, relpath from os.path import relpath
from intelhex import IntelHex
from jinja2 import FileSystemLoader, StrictUndefined 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
@ -77,19 +73,21 @@ ALLOWED_FEATURES = [
] ]
# List of all possible ram memories that can be available for a target # List of all possible ram memories that can be available for a target
RAM_ALL_MEMORIES = ['IRAM1', 'IRAM2', 'IRAM3', 'IRAM4', 'SRAM_OC', \ RAM_ALL_MEMORIES = ['IRAM1', 'IRAM2', 'IRAM3', 'IRAM4', 'SRAM_OC',
'SRAM_ITC', 'SRAM_DTC', 'SRAM_UPPER', 'SRAM_LOWER', \ 'SRAM_ITC', 'SRAM_DTC', 'SRAM_UPPER', 'SRAM_LOWER',
'SRAM'] 'SRAM']
# List of all possible rom memories that can be available for a target # List of all possible rom memories that can be available for a target
ROM_ALL_MEMORIES = ['IROM1', 'PROGRAM_FLASH', 'IROM2'] ROM_ALL_MEMORIES = ['IROM1', 'PROGRAM_FLASH', 'IROM2']
# 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
errors""" errors"""
pass pass
class UndefinedParameter(ConfigException): class UndefinedParameter(ConfigException):
def __init__(self, param, name, kind, label): def __init__(self, param, name, kind, label):
self.param = param self.param = param
@ -103,6 +101,7 @@ class UndefinedParameter(ConfigException):
ConfigParameter.get_display_name(self.name, self.kind, self.label), ConfigParameter.get_display_name(self.name, self.kind, self.label),
) )
class ConfigParameter(object): class ConfigParameter(object):
"""This class keeps information about a single configuration parameter""" """This class keeps information about a single configuration parameter"""
@ -121,13 +120,13 @@ class ConfigParameter(object):
allow_prefix=False) allow_prefix=False)
self.defined_by = self.get_display_name(unit_name, unit_kind) self.defined_by = self.get_display_name(unit_name, unit_kind)
self.set_value(data.get("value", None), unit_name, unit_kind) self.set_value(data.get("value", None), unit_name, unit_kind)
self.value_min = data.get("value_min") self.value_min = data.get("value_min")
self.value_max = data.get("value_max") self.value_max = data.get("value_max")
self.accepted_values = data.get("accepted_values") self.accepted_values = data.get("accepted_values")
self.help_text = data.get("help", None) self.help_text = data.get("help", None)
self.required = data.get("required", False) self.required = data.get("required", False)
self.conflicts = data.get("conflicts", []) self.conflicts = data.get("conflicts", [])
self.macro_name = data.get("macro_name", "MBED_CONF_%s" % self.macro_name = data.get("macro_name", "MBED_CONF_%s" %
self.sanitize(self.name.upper())) self.sanitize(self.name.upper()))
self.config_errors = [] self.config_errors = []
@ -148,7 +147,8 @@ class ConfigParameter(object):
allow_prefix - True to allow the original name to have a prefix, False allow_prefix - True to allow the original name to have a prefix, False
otherwise otherwise
""" """
if name.find('.') == -1: # the name is not prefixed # the name is not prefixed
if name.find('.') == -1:
if unit_kind == "target": if unit_kind == "target":
prefix = "target." prefix = "target."
elif unit_kind == "application": elif unit_kind == "application":
@ -172,8 +172,10 @@ class ConfigParameter(object):
unit_name, unit_kind, label))) unit_name, unit_kind, label)))
prefix = temp[0] prefix = temp[0]
# Check if the given parameter prefix matches the expected prefix # Check if the given parameter prefix matches the expected prefix
if (unit_kind == "library" and prefix not in [unit_name, "target"]) or \ if (
(unit_kind == "target" and prefix != "target"): (unit_kind == "library" and prefix not in [unit_name, "target"]) or
(unit_kind == "target" and prefix != "target")
):
raise ConfigException( raise ConfigException(
"Invalid prefix '%s' for parameter name '%s' in '%s'" % "Invalid prefix '%s' for parameter name '%s' in '%s'" %
(prefix, name, ConfigParameter.get_display_name( (prefix, name, ConfigParameter.get_display_name(
@ -197,8 +199,11 @@ class ConfigParameter(object):
return "target:" + unit_name return "target:" + unit_name
elif unit_kind == "application": elif unit_kind == "application":
return "application%s" % ("[%s]" % label if label else "") return "application%s" % ("[%s]" % label if label else "")
else: # library else: # library
return "library:%s%s" % (unit_name, "[%s]" % label if label else "") return "library:%s%s" % (
unit_name,
"[%s]" % label if label else ""
)
@staticmethod @staticmethod
def sanitize(name): def sanitize(name):
@ -258,6 +263,7 @@ class ConfigParameter(object):
desc += " Conflicts with %s" % ", ".join(self.conflicts) desc += " Conflicts with %s" % ", ".join(self.conflicts)
return desc return desc
class ConfigMacro(object): class ConfigMacro(object):
""" A representation of a configuration macro. It handles both macros """ A representation of a configuration macro. It handles both macros
without a value (MACRO) and with a value (MACRO=VALUE) without a value (MACRO) and with a value (MACRO=VALUE)
@ -271,7 +277,9 @@ class ConfigMacro(object):
unit_kind - the type of macro this is unit_kind - the type of macro this is
""" """
self.name = name self.name = name
self.defined_by = ConfigParameter.get_display_name(unit_name, unit_kind) self.defined_by = ConfigParameter.get_display_name(
unit_name, unit_kind
)
if name.find("=") != -1: if name.find("=") != -1:
tmp = name.split("=") tmp = name.split("=")
if len(tmp) != 2: if len(tmp) != 2:
@ -283,6 +291,7 @@ class ConfigMacro(object):
self.macro_name = name self.macro_name = name
self.macro_value = None self.macro_value = None
class ConfigCumulativeOverride(object): class ConfigCumulativeOverride(object):
"""Representation of overrides for cumulative attributes""" """Representation of overrides for cumulative attributes"""
def __init__(self, name, additions=None, removals=None, strict=False): def __init__(self, name, additions=None, removals=None, strict=False):
@ -327,8 +336,8 @@ class ConfigCumulativeOverride(object):
"""Extend the list of override additions. """Extend the list of override additions.
Positional arguments: Positional arguments:
overrides - a list of a names that, when the override is evaluated, will overrides - a list of a names that, when the override is evaluated,
be added to the list will be added to the list
""" """
for override in overrides: for override in overrides:
if override in self.removals or \ if override in self.removals or \
@ -414,6 +423,7 @@ def _process_macros(mlist, macros, unit_name, unit_kind):
Region = namedtuple("Region", "name start size active filename") Region = namedtuple("Region", "name start size active filename")
RamRegion = namedtuple("RamRegion", "name start size active") RamRegion = namedtuple("RamRegion", "name start size active")
class Config(object): class Config(object):
"""'Config' implements the mbed configuration mechanism""" """'Config' implements the mbed configuration mechanism"""
@ -432,9 +442,13 @@ class Config(object):
full_path = os.path.join(directory, cls.__mbed_app_config_name) full_path = os.path.join(directory, cls.__mbed_app_config_name)
if os.path.isfile(full_path): if os.path.isfile(full_path):
if app_config_location is not None: if app_config_location is not None:
raise ConfigException("Duplicate '%s' file in '%s' and '%s'" raise ConfigException(
% (cls.__mbed_app_config_name, "Duplicate '{}' file in '{}' and '{}'".format(
cls.app_config_location, full_path)) cls.__mbed_app_config_name,
cls.app_config_location,
full_path
)
)
else: else:
app_config_location = full_path app_config_location = full_path
return app_config_location return app_config_location
@ -445,7 +459,7 @@ class Config(object):
else: else:
return "in {} element {}: {}".format( return "in {} element {}: {}".format(
path, ".".join(p for p in error.absolute_path), path, ".".join(p for p in error.absolute_path),
error.message.replace('u\'','\'')) error.message.replace('u\'', '\''))
def __init__(self, tgt, top_level_dirs=None, app_config=None): def __init__(self, tgt, top_level_dirs=None, app_config=None):
"""Construct a mbed configuration """Construct a mbed configuration
@ -470,20 +484,26 @@ class Config(object):
if self.app_config_location is None and top_level_dirs: if self.app_config_location is None and top_level_dirs:
self.app_config_location = self.find_app_config(top_level_dirs) self.app_config_location = self.find_app_config(top_level_dirs)
try: try:
self.app_config_data = json_file_to_dict(self.app_config_location) \ if self.app_config_location:
if self.app_config_location else {} self.app_config_data = json_file_to_dict(
except ValueError as exc: self.app_config_location
)
else:
self.app_config_data = {}
except ValueError:
self.app_config_data = {} self.app_config_data = {}
config_errors.append( config_errors.append(
ConfigException("Could not parse mbed app configuration from %s" ConfigException(
% self.app_config_location)) "Could not parse mbed app configuration from %s"
% self.app_config_location
)
)
if self.app_config_location is not None: if self.app_config_location is not None:
# Validate the format of the JSON file based on schema_app.json # Validate the format of the JSON file based on schema_app.json
schema_root = os.path.dirname(os.path.abspath(__file__)) schema_root = os.path.dirname(os.path.abspath(__file__))
schema_path = os.path.join(schema_root, "schema_app.json") schema_path = os.path.join(schema_root, "schema_app.json")
schema = json_file_to_dict(schema_path) schema = json_file_to_dict(schema_path)
url = moves.urllib.request.pathname2url(schema_path) url = moves.urllib.request.pathname2url(schema_path)
uri = moves.urllib_parse.urljoin("file://", url) uri = moves.urllib_parse.urljoin("file://", url)
@ -523,7 +543,7 @@ class Config(object):
dirname(self.target._from_file), dirname(self.target._from_file),
getattr(self.target, attr) getattr(self.target, attr)
) )
setattr( self.target, attr, new_path) setattr(self.target, attr, new_path)
self.cumulative_overrides = {key: ConfigCumulativeOverride(key) self.cumulative_overrides = {key: ConfigCumulativeOverride(key)
for key in CUMULATIVE_ATTRIBUTES} for key in CUMULATIVE_ATTRIBUTES}
@ -572,7 +592,9 @@ class Config(object):
if "requires" in self.app_config_data: if "requires" in self.app_config_data:
if cfg["name"] not in self.app_config_data["requires"]: if cfg["name"] not in self.app_config_data["requires"]:
continue continue
self.app_config_data["requires"].extend(cfg.get("requires", [])) self.app_config_data["requires"].extend(
cfg.get("requires", [])
)
self.processed_configs[full_path] = True self.processed_configs[full_path] = True
@ -582,9 +604,13 @@ class Config(object):
# name, exit with error # name, exit with error
if cfg["name"] in self.lib_config_data: if cfg["name"] in self.lib_config_data:
raise ConfigException( raise ConfigException(
"Library name '%s' is not unique (defined in '%s' and '%s')" "Library name '{}' is not unique "
% (cfg["name"], full_path, "(defined in '{}' and '{}')".format(
self.lib_config_data[cfg["name"]]["__config_path"])) cfg["name"],
full_path,
self.lib_config_data[cfg["name"]]["__config_path"]
)
)
self.lib_config_data[cfg["name"]] = cfg self.lib_config_data[cfg["name"]] = cfg
@property @property
@ -663,10 +689,37 @@ class Config(object):
) )
) )
def _get_primary_rom_override(self):
mem_start = None
mem_size = None
if hasattr(self.target, "mbed_rom_start"):
mem_start = getattr(self.target, "mbed_rom_start")
if hasattr(self.target, "mbed_rom_size"):
mem_size = getattr(self.target, "mbed_rom_size")
if (
self.target.is_PSA_non_secure_target or
self.target.is_PSA_secure_target
):
config, _ = self.get_config_data()
if self.target.is_PSA_secure_target:
mem_start = config.get("target.secure-rom-start", mem_start).value
mem_size = config.get("target.secure-rom-size", mem_size).value
elif self.target.is_PSA_non_secure_target:
mem_start = config.get(
"target.non-secure-rom-start", mem_start
).value
mem_size = config.get("target.non-secure-rom-size", mem_size).value
if mem_start and not isinstance(mem_start, int):
mem_start = int(mem_start, 0)
if mem_size and not isinstance(mem_size, int):
mem_size = int(mem_size, 0)
return mem_start, mem_size
def get_all_active_memories(self, memory_list): def get_all_active_memories(self, memory_list):
"""Get information of all available rom/ram memories in the form of dictionary """Get information of all available rom/ram memories in the form of
{Memory: [start_addr, size]}. Takes in the argument, a list of all available dictionary {Memory: [start_addr, size]}. Takes in the argument, a
regions within the ram/rom memory""" list of all available regions within the ram/rom memory
"""
# Override rom_start/rom_size # Override rom_start/rom_size
# #
# This is usually done for a target which: # This is usually done for a target which:
@ -676,23 +729,43 @@ class Config(object):
# Counter to keep track of ROM/RAM memories supported by target # Counter to keep track of ROM/RAM memories supported by target
active_memory_counter = 0 active_memory_counter = 0
# Find which memory we are dealing with, RAM/ROM # Find which memory we are dealing with, RAM/ROM
active_memory = 'ROM' if any('ROM' in mem_list for mem_list in memory_list) else 'RAM' if any('ROM' in mem_list for mem_list in memory_list):
active_memory = 'ROM'
else:
active_memory = 'RAM'
try: try:
cmsis_part = self._get_cmsis_part() cmsis_part = self._get_cmsis_part()
except ConfigException: except ConfigException:
""" If the target doesn't exits in cmsis, but present in targets.json """ If the target doesn't exits in cmsis, but present in targets.json
with ram and rom start/size defined""" with ram and rom start/size defined"""
if getattr(self.target, "mbed_ram_start") and \ if (
getattr(self.target, "mbed_rom_start"): getattr(self.target, "mbed_ram_start")
mem_start = int(getattr(self.target, "mbed_" + active_memory.lower() + "_start"), 0) and active_memory == 'RAM'
mem_size = int(getattr(self.target, "mbed_" + active_memory.lower() + "_size"), 0) ):
mem_start = int(getattr(self.target, "mbed_ram_start"), 0)
mem_size = int(getattr(self.target, "mbed_ram_size"), 0)
available_memories[active_memory] = [mem_start, mem_size] available_memories[active_memory] = [mem_start, mem_size]
return available_memories return available_memories
elif active_memory == 'ROM':
start, size = self._get_primary_rom_override()
if not start:
raise ConfigException(
"Bootloader not supported on this target. rom "
"start not found in targets.json."
)
if not size:
raise ConfigException(
"Bootloader not supported on this target. rom "
"size not found in targets.json."
)
available_memories[active_memory] = [start, size]
return available_memories
else: else:
raise ConfigException("Bootloader not supported on this target. " raise ConfigException(
"ram/rom start/size not found in " "Bootloader not supported on this target. ram/rom "
"targets.json.") "start/size not found in targets.json."
)
present_memories = set(cmsis_part['memories'].keys()) present_memories = set(cmsis_part['memories'].keys())
valid_memories = set(memory_list).intersection(present_memories) valid_memories = set(memory_list).intersection(present_memories)
@ -704,16 +777,20 @@ class Config(object):
for memory in valid_memories: for memory in valid_memories:
mem_start = memories[memory]["start"] mem_start = memories[memory]["start"]
mem_size = memories[memory]["size"] mem_size = memories[memory]["size"]
if memory=='IROM1' or memory=='PROGRAM_FLASH': if memory in ['IROM1', 'PROGRAM_FLASH']:
mem_start = getattr(self.target, "mbed_rom_start", False) or mem_start start, size = self._get_primary_rom_override()
mem_size = getattr(self.target, "mbed_rom_size", False) or mem_size if start:
mem_start = start
if size:
mem_size = size
memory = 'ROM' memory = 'ROM'
elif memory == 'IRAM1' or memory == 'SRAM_OC' or \ elif memory in ['IRAM1', 'SRAM_OC', 'SRAM_UPPER', 'SRAM']:
memory == 'SRAM_UPPER' or memory == 'SRAM':
if (self.has_ram_regions): if (self.has_ram_regions):
continue continue
mem_start = getattr(self.target, "mbed_ram_start", False) or mem_start if getattr(self.target, "mbed_ram_start", False):
mem_size = getattr(self.target, "mbed_ram_size", False) or mem_size mem_start = getattr(self.target, "mbed_ram_start")
if getattr(self.target, "mbed_ram_start", False):
mem_size = getattr(self.target, "mbed_ram_size")
memory = 'RAM' memory = 'RAM'
else: else:
active_memory_counter += 1 active_memory_counter += 1
@ -754,23 +831,26 @@ class Config(object):
if not getattr(self.target, "bootloader_supported", False): if not getattr(self.target, "bootloader_supported", False):
raise ConfigException("Bootloader not supported on this target.") raise ConfigException("Bootloader not supported on this target.")
"""Generate a list of regions from the config""" """Generate a list of regions from the config"""
if ((self.target.bootloader_img or self.target.restrict_size) and if (
(self.target.mbed_app_start or self.target.mbed_app_size)): (self.target.bootloader_img or self.target.restrict_size) and
(self.target.mbed_app_start or self.target.mbed_app_size)
):
raise ConfigException( raise ConfigException(
"target.bootloader_img and target.restrict_size are " "target.bootloader_img and target.restrict_size are "
"incompatible with target.mbed_app_start and " "incompatible with target.mbed_app_start and "
"target.mbed_app_size") "target.mbed_app_size")
rom = self.get_all_active_memories(ROM_ALL_MEMORIES)
if self.target.bootloader_img or self.target.restrict_size: if self.target.bootloader_img or self.target.restrict_size:
return self._generate_bootloader_build(self.get_all_active_memories(ROM_ALL_MEMORIES)) return self._generate_bootloader_build(rom)
else: else:
return self._generate_linker_overrides(self.get_all_active_memories(ROM_ALL_MEMORIES)) return self._generate_linker_overrides(rom)
@staticmethod @staticmethod
def header_member_size(member): def header_member_size(member):
_, _, subtype, _ = member _, _, subtype, _ = member
try: try:
return int(subtype[:-2]) // 8 return int(subtype[:-2]) // 8
except: except Exception:
if subtype.startswith("CRCITT32"): if subtype.startswith("CRCITT32"):
return 32 // 8 return 32 // 8
elif subtype == "SHA256": elif subtype == "SHA256":
@ -799,7 +879,10 @@ class Config(object):
for s, e in regions: for s, e in regions:
if newstart > s and newstart < e: if newstart > s and newstart < e:
raise ConfigException( raise ConfigException(
"Can not place %r region inside previous region" % region_name) "Can not place {} region inside previous region".format(
region_name
)
)
return newstart return newstart
@staticmethod @staticmethod
@ -810,7 +893,7 @@ class Config(object):
next section, whichever is smaller next section, whichever is smaller
""" """
# Sort the list by starting address # Sort the list by starting address
region_list = sorted(region_list, key=lambda x:x[0]) region_list = sorted(region_list, key=lambda x: x[0])
for s, e in region_list: for s, e in region_list:
if start_address < s: if start_address < s:
return s return s
@ -848,17 +931,32 @@ class Config(object):
end_address = stop end_address = stop
else: else:
break break
if end_address == None: if end_address is None:
raise ConfigException("bootloader segments don't fit within rom") raise ConfigException(
part_size = Config._align_ceiling(end_address, self.sectors) - rom_start "bootloader segments don't fit within rom"
# Generate the region in the loop (bootloader0, bootloader1, ...) )
yield Region("bootloader"+str(part_count), start, part_size, False, filename) part_size = Config._align_ceiling(
end_address, self.sectors
) - rom_start
# Generate the region in the loop
# (bootloader0, bootloader1, ...)
yield Region(
"bootloader{}".format(str(part_count)),
start,
part_size,
False,
filename
)
else: else:
# Number of segments is 1 # Number of segments is 1
_, end_address = part.segments()[0] _, end_address = part.segments()[0]
if (end_address > rom_end): if (end_address > rom_end):
raise ConfigException("bootloader segments don't fit within rom") raise ConfigException(
part_size = Config._align_ceiling(end_address, self.sectors) - rom_start "bootloader segments don't fit within rom"
)
part_size = Config._align_ceiling(
end_address, self.sectors
) - rom_start
yield Region("bootloader", rom_start, part_size, False, yield Region("bootloader", rom_start, part_size, False,
filename) filename)
@ -866,26 +964,42 @@ class Config(object):
if self.target.header_format: if self.target.header_format:
if self.target.header_offset: if self.target.header_offset:
start = self._assign_new_offset( start = self._assign_new_offset(
rom_start, self.target.header_offset, "header", regions) rom_start,
self.target.header_offset,
"header",
regions
)
start, region = self._make_header_region( start, region = self._make_header_region(
start, self.target.header_format) start, self.target.header_format)
yield region._replace(filename=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
if self.target.app_offset: if self.target.app_offset:
start = self._assign_new_offset(rom_start, self.target.app_offset, "application", regions) start = self._assign_new_offset(
rom_start,
self.target.app_offset,
"application",
regions
)
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 and not self.target.bootloader_img: if self.target.header_format and not self.target.bootloader_img:
if self.target.header_offset: if self.target.header_offset:
start = self._assign_new_offset( start = self._assign_new_offset(
rom_start, self.target.header_offset, "header", regions) rom_start,
self.target.header_offset,
"header",
regions
)
start, region = self._make_header_region( start, region = self._make_header_region(
start, self.target.header_format) start, self.target.header_format
)
yield region yield region
yield Region("post_application", start, rom_end - start, yield Region("post_application", start, rom_end - start,
@ -894,7 +1008,8 @@ class Config(object):
if self.target.app_offset: if self.target.app_offset:
start = self._assign_new_offset( start = self._assign_new_offset(
rom_start, self.target.app_offset, "application", regions) rom_start, self.target.app_offset, "application", regions)
# compute the end address of the application region based on existing segments # compute the end address of the application region based on
# existing segments
end = self._get_end_address(regions, start, rom_end) end = self._get_end_address(regions, start, rom_end)
yield Region("application", start, end - start, yield Region("application", start, end - start,
True, None) True, None)
@ -924,13 +1039,18 @@ class Config(object):
@staticmethod @staticmethod
def _align_ceiling(address, sectors): def _align_ceiling(address, sectors):
target_start, target_size = Config._find_sector(address, sectors) target_start, target_size = Config._find_sector(address, sectors)
sector_num = ((address - target_start) + target_size - 1) // target_size sector = ((address - target_start) + target_size - 1) // target_size
return target_start + (sector_num * target_size) return target_start + (sector * target_size)
@property @property
def report(self): def report(self):
return {'app_config': self.app_config_location, return {
'library_configs': list(map(relpath, self.processed_configs.keys()))} 'app_config': self.app_config_location,
'library_configs': list(map(
relpath,
self.processed_configs.keys()
))
}
def _generate_linker_overrides(self, rom_memories): def _generate_linker_overrides(self, rom_memories):
rom_start, rom_size = rom_memories.get('ROM') rom_start, rom_size = rom_memories.get('ROM')
@ -948,7 +1068,13 @@ class Config(object):
raise ConfigException("Application ends after ROM") raise ConfigException("Application ends after ROM")
yield Region("application", start, size, True, None) yield Region("application", start, size, True, None)
def _process_config_and_overrides(self, data, params, unit_name, unit_kind): def _process_config_and_overrides(
self,
data,
params,
unit_name,
unit_kind
):
"""Process "config_parameters" and "target_config_overrides" into a """Process "config_parameters" and "target_config_overrides" into a
given dictionary given dictionary
@ -1018,9 +1144,11 @@ class Config(object):
if full_name in params: if full_name in params:
params[full_name].set_value(val, unit_name, unit_kind, params[full_name].set_value(val, unit_name, unit_kind,
label) label)
elif (name.startswith("target.") and elif (
name.startswith("target.") and
(unit_kind is "application" or (unit_kind is "application" or
name in BOOTLOADER_OVERRIDES)): name in BOOTLOADER_OVERRIDES)
):
_, attribute = name.split(".") _, attribute = name.split(".")
setattr(self.target, attribute, val) setattr(self.target, attribute, val)
continue continue
@ -1039,9 +1167,10 @@ class Config(object):
We consider the resolution order for our target and sort it by level We consider the resolution order for our target and sort it by level
reversed, so that we first look at the top level target (the parent), reversed, so that we first look at the top level target (the parent),
then its direct children, then the children of those children and so on, then its direct children, then the children of those children and so
until we reach self.target on, until we reach self.target
TODO: this might not work so well in some multiple inheritance scenarios TODO: this might not work so well in some multiple inheritance
scenarios.
At each step, look at two keys of the target data: At each step, look at two keys of the target data:
- config_parameters: used to define new configuration parameters - config_parameters: used to define new configuration parameters
- config_overrides: used to override already defined configuration - config_overrides: used to override already defined configuration
@ -1062,12 +1191,14 @@ class Config(object):
tname, "target") tname, "target")
# Then process overrides # Then process overrides
for name, val in target_data.get("overrides", {}).items(): for name, val in target_data.get("overrides", {}).items():
full_name = ConfigParameter.get_full_name(name, tname, "target") full_name = ConfigParameter.get_full_name(
name, tname, "target"
)
# If the parameter name is not defined or if there isn't a path # If the parameter name is not defined or if there isn't a path
# from this target to the target where the parameter was defined # from this target to the target where the parameter was
# in the target inheritance tree, raise an error We need to use # defined in the target inheritance tree, raise an error We
# 'defined_by[7:]' to remove the "target:" prefix from # need to use 'defined_by[7:]' to remove the "target:"
# defined_by # prefix from defined_by
rel_names = [tgt for tgt, _ in rel_names = [tgt for tgt, _ in
get_resolution_order(self.target.json_data, tname, get_resolution_order(self.target.json_data, tname,
[])] [])]
@ -1082,10 +1213,10 @@ class Config(object):
def get_lib_config_data(self, target_data): def get_lib_config_data(self, target_data):
""" Read and interpret configuration data defined by libraries. It is """ Read and interpret configuration data defined by libraries. It is
assumed that "add_config_files" above was already called and the library assumed that "add_config_files" above was already called and the
configuration data exists in self.lib_config_data library configuration data exists in self.lib_config_data
Arguments: None Arguments: target_data
""" """
macros = {} macros = {}
for lib_name, lib_data in self.lib_config_data.items(): for lib_name, lib_data in self.lib_config_data.items():
@ -1161,7 +1292,8 @@ class Config(object):
} }
parameter_macros = { parameter_macros = {
p.macro_name: p.value for p in params.values() if p.value is not None p.macro_name: p.value for p in params.values()
if p.value is not None
} }
all_macros.update(parameter_macros) all_macros.update(parameter_macros)
@ -1235,23 +1367,29 @@ class Config(object):
err_msg = "" err_msg = ""
for name, param in sorted(params.items()): for name, param in sorted(params.items()):
min = param.value_min min = param.value_min
max = param.value_max max = param.value_max
accepted = param.accepted_values accepted = param.accepted_values
value = param.value value = param.value
# Config parameters that are only defined but do not have a default # Config parameters that are only defined but do not have a default
# value should not be range limited # value should not be range limited
if value is not None: if value is not None:
if (min is not None or max is not None) and (accepted is not None): if (
err_msg += "\n%s has both a range and list of accepted values specified. Please only "\ (min is not None or max is not None) and
"specify either value_min and/or value_max, or accepted_values"\ (accepted is not None)
% param ):
err_msg += (
"\n%s has both a range and list of accepted values "
"specified. Please only specify either value_min "
"and/or value_max, or accepted_values"
% param
)
else: else:
if re.match(r'^(0[xX])[A-Fa-f0-9]+$|^[0-9]+$', str(value)): if re.match(r'^(0[xX])[A-Fa-f0-9]+$|^[0-9]+$', str(value)):
# Value is a hexadecimal or numerical string value # Value is a hexadecimal or numerical string value
# Convert to a python integer and range check/compare to # Convert to a python integer and range check/compare
# accepted list accordingly # to accepted list accordingly
if min is not None or max is not None: if min is not None or max is not None:
# Numerical range check # Numerical range check
@ -1261,31 +1399,54 @@ class Config(object):
min = int(str(min), 0) if min is not None else None min = int(str(min), 0) if min is not None else None
max = int(str(max), 0) if max is not None else None max = int(str(max), 0) if max is not None else None
if (min is not None and value < min) or (max is not None and value > max): if (
err_msg += "\nInvalid config range for %s, is not in the required range: [%s:%s]"\ (min is not None and value < min) or
% (param, (max is not None and value > max)
min if min is not None else "-inf", ):
max if max is not None else "inf") err_msg += (
"\nInvalid config range for {}, is not in "
"the required range: [{}:{}]".format(
param,
min if min is not None else "-inf",
max if max is not None else "inf"
)
)
# Numerical accepted value check # Numerical accepted value check
elif accepted is not None and value not in accepted: elif accepted is not None and value not in accepted:
err_msg += "\nInvalid value for %s, is not an accepted value: %s"\ err_msg += (
% (param, ", ".join(map(str, accepted))) "\nInvalid value for {}, is not an accepted "
"value: {}".format(
param,
", ".join(map(str, accepted))
)
)
else: else:
if min is not None or max is not None: if min is not None or max is not None:
err_msg += "\nInvalid config range settings for %s. Range specifiers are not "\ err_msg += (
"applicable to non-decimal/hexadecimal string values" % param "\nInvalid config range settings for {}. "
"Range specifiers are not applicable to "
"non-decimal/hexadecimal string values".format(
param
)
)
if accepted is not None and value not in accepted: if accepted is not None and value not in accepted:
err_msg += "\nInvalid config range for %s, is not an accepted value: %s"\ err_msg += (
% (param, ", ".join(accepted)) "\nInvalid config range for {}, is not an "
"accepted value: {}".format(
param, ", ".join(accepted)
)
)
if (err_msg): if (err_msg):
raise ConfigException(err_msg) raise ConfigException(err_msg)
for error in self.config_errors: for error in self.config_errors:
if (isinstance(error, UndefinedParameter) and if (
error.param in params): isinstance(error, UndefinedParameter) and
error.param in params
):
continue continue
else: else:
raise error raise error
@ -1309,11 +1470,8 @@ class Config(object):
param.name, param.value, conf.name, conf.value param.name, param.value, conf.name, conf.value
) )
) )
return True return True
@property @property
def name(self): def name(self):
if "artifact_name" in self.app_config_data: if "artifact_name" in self.app_config_data:
@ -1371,9 +1529,11 @@ class Config(object):
if abspath(ref.path) in all_json_paths if abspath(ref.path) in all_json_paths
] ]
resources.filter_by_libraries(included_json_files) resources.filter_by_libraries(included_json_files)
if (hasattr(self.target, "release_versions") and if (
"5" not in self.target.release_versions and hasattr(self.target, "release_versions") and
"rtos" in self.lib_config_data): "5" not in self.target.release_versions and
"rtos" in self.lib_config_data
):
raise NotSupportedException("Target does not support mbed OS 5") raise NotSupportedException("Target does not support mbed OS 5")
@staticmethod @staticmethod
@ -1393,7 +1553,9 @@ class Config(object):
""" """
params, macros = config[0] or {}, config[1] or {} params, macros = config[0] or {}, config[1] or {}
Config._check_required_parameters(params) Config._check_required_parameters(params)
params_with_values = [p for p in params.values() if p.value is not None] params_with_values = [
p for p in params.values() if p.value is not None
]
ctx = { ctx = {
"cfg_params": sorted([ "cfg_params": sorted([
(p.macro_name, str(p.value), p.set_by) (p.macro_name, str(p.value), p.set_by)
@ -1406,9 +1568,9 @@ class Config(object):
"name_len": max([len(m.macro_name) for m in macros.values()] + "name_len": max([len(m.macro_name) for m in macros.values()] +
[len(m.macro_name) for m in params_with_values] [len(m.macro_name) for m in params_with_values]
+ [0]), + [0]),
"val_len" : max([len(str(m.value)) for m in params_with_values] + "val_len": max([len(str(m.value)) for m in params_with_values] +
[len(m.macro_value or "") for m in macros.values()] [len(m.macro_value or "") for m in macros.values()]
+ [0]), + [0]),
} }
jinja_loader = FileSystemLoader(dirname(abspath(__file__))) jinja_loader = FileSystemLoader(dirname(abspath(__file__)))
jinja_environment = Environment(loader=jinja_loader, jinja_environment = Environment(loader=jinja_loader,

View File

@ -16,16 +16,15 @@ limitations under the License.
""" """
import os import os
import sys
import json import json
import pytest import pytest
from mock import patch from mock import patch
from hypothesis import given
from hypothesis.strategies import sampled_from
from os.path import join, isfile, dirname, abspath from os.path import join, isfile, dirname, abspath
from tools.build_api import get_config from tools.build_api import get_config
from tools.targets import set_targets_json_location, Target, TARGET_NAMES from tools.targets import set_targets_json_location
from tools.config import ConfigException, Config, ConfigParameter, ConfigMacro from tools.config import (
ConfigException, Config, ConfigParameter, ConfigMacro, ROM_ALL_MEMORIES
)
from tools.resources import Resources from tools.resources import Resources
NOT_CONFIG = [ NOT_CONFIG = [
@ -250,3 +249,16 @@ def test_parameters_and_config_macros_to_macros():
macro_list = Config._parameters_and_config_macros_to_macros(params, macros) macro_list = Config._parameters_and_config_macros_to_macros(params, macros)
assert macro_list == ["CUSTOM_MACRO_NAME=1"] assert macro_list == ["CUSTOM_MACRO_NAME=1"]
@pytest.mark.parametrize("target_start_size", [
("FUTURE_SEQUANA_PSA", 0x10080000, 0x78000),
("FUTURE_SEQUANA_M0_PSA", 0x10000000, 0x80000)
])
def test_PSA_overrides(target_start_size):
target, start, size = target_start_size
set_targets_json_location()
config = Config(target)
roms = config.get_all_active_memories(ROM_ALL_MEMORIES)
assert("ROM" in roms)
assert(roms["ROM"] == [start, size])