binman: Support expanding entries

It is useful to have entries which can grow automatically to fill
available space. Add support for this.

Signed-off-by: Simon Glass <sjg@chromium.org>
lime2-spi
Simon Glass 6 years ago
parent 0a98b28b06
commit ba64a0bbb7
  1. 4
      tools/binman/README
  2. 22
      tools/binman/bsection.py
  3. 11
      tools/binman/entry.py
  4. 7
      tools/binman/etype/_testing.py
  5. 8
      tools/binman/etype/section.py
  6. 29
      tools/binman/ftest.py
  7. 43
      tools/binman/test/88_expand_size.dts
  8. 14
      tools/binman/test/89_expand_size_bad.dts

@ -330,6 +330,10 @@ image-pos:
for each entry. This makes it easy to find out exactly where the entry
ended up in the image, regardless of parent sections, etc.
expand-size:
Expand the size of this entry to fit available space. This space is only
limited by the size of the image/section and the position of the next
entry.
The attributes supported for images are described below. Several are similar
to those for entries.

@ -253,10 +253,26 @@ class Section(object):
for entry in entries:
self._entries[entry._node.name] = entry
def _ExpandEntries(self):
"""Expand any entries that are permitted to"""
exp_entry = None
for entry in self._entries.values():
if exp_entry:
exp_entry.ExpandToLimit(entry.offset)
exp_entry = None
if entry.expand_size:
exp_entry = entry
if exp_entry:
exp_entry.ExpandToLimit(self._size)
def CheckEntries(self):
"""Check that entries do not overlap or extend outside the section"""
"""Check that entries do not overlap or extend outside the section
This also sorts entries, if needed and expands
"""
if self._sort:
self._SortEntries()
self._ExpandEntries()
offset = 0
prev_name = 'None'
for entry in self._entries.values():
@ -419,3 +435,7 @@ class Section(object):
return None
return entry.data
source_entry.Raise("Cannot find entry for node '%s'" % node.name)
def ExpandSize(self, size):
if size != self._size:
self._size = size

@ -76,6 +76,7 @@ class Entry(object):
self.pad_after = 0
self.offset_unset = False
self.image_pos = None
self._expand_size = False
if read_node:
self.ReadNode()
@ -161,6 +162,7 @@ class Entry(object):
"of two" % (self._node.path, self.align_size))
self.align_end = fdt_util.GetInt(self._node, 'align-end')
self.offset_unset = fdt_util.GetBool(self._node, 'offset-unset')
self.expand_size = fdt_util.GetBool(self._node, 'expand-size')
def GetDefaultFilename(self):
return None
@ -507,3 +509,12 @@ features to produce new behaviours.
break
name = '%s.%s' % (node.name, name)
return name
def ExpandToLimit(self, limit):
"""Expand an entry so that it ends at the given offset limit"""
if self.offset + self.size < limit:
self.size = limit - self.offset
# Request the contents again, since changing the size requires that
# the data grows. This should not fail, but check it to be sure.
if not self.ObtainContents():
self.Raise('Cannot obtain contents when expanding entry')

@ -48,6 +48,8 @@ class Entry__testing(Entry):
'return-unknown-contents')
self.bad_update_contents = fdt_util.GetBool(self._node,
'bad-update-contents')
self.return_contents_once = fdt_util.GetBool(self._node,
'return-contents-once')
# Set to True when the entry is ready to process the FDT.
self.process_fdt_ready = False
@ -68,12 +70,15 @@ class Entry__testing(Entry):
EntryArg('test-existing-prop', str)], self.require_args)
if self.force_bad_datatype:
self.GetEntryArgsOrProps([EntryArg('test-bad-datatype-arg', bool)])
self.return_contents = True
def ObtainContents(self):
if self.return_unknown_contents:
if self.return_unknown_contents or not self.return_contents:
return False
self.data = 'a'
self.contents_size = len(self.data)
if self.return_contents_once:
self.return_contents = False
return True
def GetOffsets(self):

@ -40,6 +40,10 @@ class Entry_section(Entry):
def ProcessFdt(self, fdt):
return self._section.ProcessFdt(fdt)
def ExpandEntries(self):
Entry.ExpandEntries(self)
self._section.ExpandEntries()
def AddMissingProperties(self):
Entry.AddMissingProperties(self)
self._section.AddMissingProperties()
@ -95,3 +99,7 @@ class Entry_section(Entry):
def GetEntries(self):
return self._section.GetEntries()
def ExpandToLimit(self, limit):
super(Entry_section, self).ExpandToLimit(limit)
self._section.ExpandSize(self.size)

@ -1579,6 +1579,35 @@ class TestFunctional(unittest.TestCase):
self.assertIn("Node '/binman/files': Missing 'pattern' property",
str(e.exception))
def testExpandSize(self):
"""Test an expanding entry"""
data, _, map_data, _ = self._DoReadFileDtb('88_expand_size.dts',
map=True)
expect = ('a' * 8 + U_BOOT_DATA +
MRC_DATA + 'b' * 1 + U_BOOT_DATA +
'c' * 8 + U_BOOT_DATA +
'd' * 8)
self.assertEqual(expect, data)
self.assertEqual('''ImagePos Offset Size Name
00000000 00000000 00000028 main-section
00000000 00000000 00000008 fill
00000008 00000008 00000004 u-boot
0000000c 0000000c 00000004 section
0000000c 00000000 00000003 intel-mrc
00000010 00000010 00000004 u-boot2
00000014 00000014 0000000c section2
00000014 00000000 00000008 fill
0000001c 00000008 00000004 u-boot
00000020 00000020 00000008 fill2
''', map_data)
def testExpandSizeBad(self):
"""Test an expanding entry which fails to provide contents"""
with self.assertRaises(ValueError) as e:
self._DoReadFileDtb('89_expand_size_bad.dts', map=True)
self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
'expanding entry', str(e.exception))
if __name__ == "__main__":
unittest.main()

@ -0,0 +1,43 @@
// SPDX-License-Identifier: GPL-2.0+
/dts-v1/;
/ {
binman {
size = <40>;
fill {
expand-size;
fill-byte = [61];
size = <0>;
};
u-boot {
offset = <8>;
};
section {
expand-size;
pad-byte = <0x62>;
intel-mrc {
};
};
u-boot2 {
type = "u-boot";
offset = <16>;
};
section2 {
type = "section";
fill {
expand-size;
fill-byte = [63];
size = <0>;
};
u-boot {
offset = <8>;
};
};
fill2 {
type = "fill";
expand-size;
fill-byte = [64];
size = <0>;
};
};
};

@ -0,0 +1,14 @@
// SPDX-License-Identifier: GPL-2.0+
/dts-v1/;
/ {
binman {
_testing {
expand-size;
return-contents-once;
};
u-boot {
offset = <8>;
};
};
};
Loading…
Cancel
Save