mirror of https://github.com/ARMmbed/mbed-os.git
Merge pull request #9317 from naveenkaje/tools_bootloader_script
tools: support cases where bootloader is in chunkspull/9856/head
commit
e77f03cfbc
|
@ -423,6 +423,10 @@ def merge_region_list(region_list, destination, notify, config, padding=b'\xFF')
|
|||
merged = IntelHex()
|
||||
_, format = splitext(destination)
|
||||
notify.info("Merging Regions")
|
||||
# Merged file list: Keep track of binary/hex files that we have already
|
||||
# merged. e.g In some cases, bootloader may be split into multiple parts, but
|
||||
# all internally referring to the same bootloader file.
|
||||
merged_list = []
|
||||
|
||||
for region in region_list:
|
||||
if region.active and not region.filename:
|
||||
|
@ -432,7 +436,7 @@ def merge_region_list(region_list, destination, notify, config, padding=b'\xFF')
|
|||
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 and (region.filename not in merged_list):
|
||||
notify.info(" Filling region %s with %s" % (region.name, region.filename))
|
||||
part = intelhex_offset(region.filename, offset=region.start)
|
||||
part.start_addr = None
|
||||
|
@ -443,7 +447,10 @@ def merge_region_list(region_list, destination, notify, config, padding=b'\xFF')
|
|||
if part_size > region.size:
|
||||
raise ToolException("Contents of region %s does not fit"
|
||||
% region.name)
|
||||
merged_list.append(region.filename)
|
||||
merged.merge(part)
|
||||
elif region.filename in merged_list:
|
||||
notify.info(" Skipping %s as it is merged previously" % (region.name))
|
||||
|
||||
# Hex file can have gaps, so no padding needed. While other formats may
|
||||
# need padding. Iterate through segments and pad the gaps.
|
||||
|
|
|
@ -780,13 +780,29 @@ class Config(object):
|
|||
return (start, region)
|
||||
|
||||
@staticmethod
|
||||
def _assign_new_offset(rom_start, start, new_offset, region_name):
|
||||
def _assign_new_offset(rom_start, new_offset, region_name, regions):
|
||||
newstart = rom_start + integer(new_offset, 0)
|
||||
if newstart < start:
|
||||
raise ConfigException(
|
||||
"Can not place %r region inside previous region" % region_name)
|
||||
|
||||
for s, e in regions:
|
||||
if newstart > s and newstart < e:
|
||||
raise ConfigException(
|
||||
"Can not place %r region inside previous region" % region_name)
|
||||
return newstart
|
||||
|
||||
@staticmethod
|
||||
def _get_end_address(region_list, start_address, rom_end):
|
||||
"""Given a start address and set of regions, sort the
|
||||
regions and then compute the end address.
|
||||
The end address is either rom_end or beginning of the
|
||||
next section, whichever is smaller
|
||||
"""
|
||||
# Sort the list by starting address
|
||||
region_list = sorted(region_list, key=lambda x:x[0])
|
||||
for s, e in region_list:
|
||||
if start_address < s:
|
||||
return s
|
||||
return rom_end
|
||||
|
||||
def _generate_bootloader_build(self, rom_memories):
|
||||
rom_start, rom_size = rom_memories.get('ROM')
|
||||
start = rom_start
|
||||
|
@ -803,26 +819,41 @@ class Config(object):
|
|||
if part.minaddr() != rom_start:
|
||||
raise ConfigException("bootloader executable does not "
|
||||
"start at 0x%x" % rom_start)
|
||||
regions = part.segments()
|
||||
|
||||
# find the last valid address that's within rom_end and use that
|
||||
# to compute the bootloader size
|
||||
end_address = None
|
||||
for start, stop in part.segments():
|
||||
if (stop < rom_end):
|
||||
end_address = stop
|
||||
else:
|
||||
break
|
||||
if end_address == None:
|
||||
raise ConfigException("bootloader segments don't fit within rom region")
|
||||
part_size = Config._align_ceiling(end_address, self.sectors) - rom_start
|
||||
|
||||
yield Region("bootloader", rom_start, part_size, False,
|
||||
filename)
|
||||
# we have multiple parts in bootloader. Treat each of them as
|
||||
# a different region (BLP1, BLP2 ...)
|
||||
if len(part.segments()) > 1:
|
||||
end_address = None
|
||||
part_count = 0
|
||||
for start, stop in part.segments():
|
||||
part_count += 1
|
||||
if (stop < rom_end):
|
||||
end_address = stop
|
||||
else:
|
||||
break
|
||||
if end_address == None:
|
||||
raise ConfigException("bootloader segments don't fit within rom")
|
||||
part_size = Config._align_ceiling(end_address, self.sectors) - rom_start
|
||||
# Generate the region in the loop (bootloader0, bootloader1, ...)
|
||||
yield Region("bootloader"+str(part_count), start, part_size, False, filename)
|
||||
else:
|
||||
# Number of segments is 1
|
||||
_, end_address = part.segments()[0]
|
||||
if (end_address > rom_end):
|
||||
raise ConfigException("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,
|
||||
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")
|
||||
rom_start, self.target.header_offset, "header", regions)
|
||||
start, region = self._make_header_region(
|
||||
start, self.target.header_format)
|
||||
yield region._replace(filename=self.target.header_format)
|
||||
|
@ -832,14 +863,14 @@ class Config(object):
|
|||
new_size = Config._align_floor(start + new_size, self.sectors) - start
|
||||
|
||||
if self.target.app_offset:
|
||||
start = self._assign_new_offset(rom_start, start, self.target.app_offset, "application")
|
||||
start = self._assign_new_offset(rom_start, self.target.app_offset, "application", regions)
|
||||
|
||||
yield Region("application", start, new_size, True, None)
|
||||
start += new_size
|
||||
if self.target.header_format and not self.target.bootloader_img:
|
||||
if self.target.header_offset:
|
||||
start = self._assign_new_offset(
|
||||
rom_start, start, self.target.header_offset, "header")
|
||||
rom_start, self.target.header_offset, "header", regions)
|
||||
start, region = self._make_header_region(
|
||||
start, self.target.header_format)
|
||||
yield region
|
||||
|
@ -849,8 +880,10 @@ class Config(object):
|
|||
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,
|
||||
rom_start, self.target.app_offset, "application", regions)
|
||||
# compute the end address of the application region based on existing segments
|
||||
end = self._get_end_address(regions, start, rom_end)
|
||||
yield Region("application", start, end - start,
|
||||
True, None)
|
||||
if start > rom_end:
|
||||
raise ConfigException("Not enough memory on device to fit all "
|
||||
|
|
|
@ -22,10 +22,10 @@ from tools.build_api import prepare_toolchain, build_project, build_library, mer
|
|||
from tools.resources import Resources
|
||||
from tools.toolchains import TOOLCHAINS
|
||||
from tools.notifier.mock import MockNotifier
|
||||
from tools.config import Region
|
||||
from tools.config import Region, Config, ConfigException
|
||||
from tools.utils import ToolException
|
||||
from intelhex import IntelHex
|
||||
import intelhex
|
||||
|
||||
"""
|
||||
Tests for build_api.py
|
||||
"""
|
||||
|
@ -247,7 +247,10 @@ class BuildApiTests(unittest.TestCase):
|
|||
@patch('tools.config')
|
||||
def test_merge_region_no_fit(self, mock_config, mock_intelhex_offset):
|
||||
"""
|
||||
Test that merge region fails as expected when part size overflows region size.
|
||||
Test that merge_region_list call fails when part size overflows region size.
|
||||
:param mock_config: config object that is mocked.
|
||||
:param mock_intelhex_offset: mocked intel_hex_offset call.
|
||||
:return:
|
||||
"""
|
||||
max_addr = 87444
|
||||
# create a dummy hex file with above max_addr
|
||||
|
@ -274,5 +277,90 @@ class BuildApiTests(unittest.TestCase):
|
|||
self.assertTrue(toolexception, "Expected ToolException not raised")
|
||||
|
||||
|
||||
@patch('tools.config.exists')
|
||||
@patch('tools.config.isabs')
|
||||
@patch('tools.config.intelhex_offset')
|
||||
def test_bl_pieces(self, mock_intelhex_offset, mock_exists, mock_isabs):
|
||||
"""
|
||||
|
||||
:param mock_intelhex_offset: mock intel_hex_ofset call
|
||||
:param mock_exists: mock the file exists call
|
||||
:param mock_isabs: mock the isabs call
|
||||
:return:
|
||||
"""
|
||||
"""
|
||||
Test that merge region fails as expected when part size overflows region size.
|
||||
"""
|
||||
cfg = Config('NRF52_DK')
|
||||
mock_exists.return_value = True
|
||||
mock_isabs.return_value = True
|
||||
max = 0x960
|
||||
#create mock MBR and BL and merge them
|
||||
mbr = IntelHex()
|
||||
for v in range(max):
|
||||
mbr[v] = v
|
||||
|
||||
bl = IntelHex()
|
||||
min = 0x16000
|
||||
max = 0x22000
|
||||
for v in range(min, max):
|
||||
bl[v] = v
|
||||
mbr.merge(bl)
|
||||
|
||||
mock_intelhex_offset.return_value = mbr
|
||||
|
||||
# Place application within the bootloader and verify
|
||||
# that config exception is generated
|
||||
cfg.target.bootloader_img = True
|
||||
cfg.target.app_offset = min + 0x200
|
||||
cfg.target.restrict_size = '4096'
|
||||
|
||||
ce = False
|
||||
if cfg.has_regions:
|
||||
try:
|
||||
for r in list(cfg.regions):
|
||||
print(r)
|
||||
except ConfigException:
|
||||
ce = True
|
||||
|
||||
self.assertTrue(ce)
|
||||
|
||||
@patch('tools.config.exists')
|
||||
@patch('tools.config.isabs')
|
||||
@patch('tools.config.intelhex_offset')
|
||||
def test_bl_too_large(self, mock_intelhex_offset, mock_exists, mock_isabs):
|
||||
"""
|
||||
Create a BL that's too large to fit in ROM and test that exception is
|
||||
generated.
|
||||
:param mock_intelhex_offset: mock intel hex
|
||||
:param mock_exists: mock the file exists call
|
||||
:param mock_isabs: mock the isabs call
|
||||
:return:
|
||||
"""
|
||||
cfg = Config('NRF52_DK')
|
||||
mock_exists.return_value = True
|
||||
mock_isabs.return_value = True
|
||||
|
||||
# setup the hex file
|
||||
bl = IntelHex()
|
||||
min = 0x0
|
||||
max = 0x88000
|
||||
for v in range(max):
|
||||
bl[v] = v
|
||||
mock_intelhex_offset.return_value = bl
|
||||
cfg.target.bootloader_img = True
|
||||
ce = False
|
||||
|
||||
if cfg.has_regions:
|
||||
try:
|
||||
for r in list(cfg.regions):
|
||||
print(r)
|
||||
except ConfigException as e:
|
||||
print("args %s" % (e.args))
|
||||
if (e.args[0] == "bootloader segments don't fit within rom"):
|
||||
ce = True
|
||||
|
||||
self.assertTrue(ce)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -742,6 +742,7 @@ class mbedToolchain:
|
|||
if self.config.has_regions:
|
||||
try:
|
||||
regions = list(self.config.regions)
|
||||
regions.sort(key=lambda x:x.start)
|
||||
self.notify.info("Using ROM region%s %s in this build." % (
|
||||
"s" if len(regions) > 1 else "",
|
||||
", ".join(r.name for r in regions)
|
||||
|
|
Loading…
Reference in New Issue