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 for each entry. This makes it easy to find out exactly where the entry
ended up in the image, regardless of parent sections, etc. 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 The attributes supported for images are described below. Several are similar
to those for entries. to those for entries.

@ -253,10 +253,26 @@ class Section(object):
for entry in entries: for entry in entries:
self._entries[entry._node.name] = entry 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): 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: if self._sort:
self._SortEntries() self._SortEntries()
self._ExpandEntries()
offset = 0 offset = 0
prev_name = 'None' prev_name = 'None'
for entry in self._entries.values(): for entry in self._entries.values():
@ -419,3 +435,7 @@ class Section(object):
return None return None
return entry.data return entry.data
source_entry.Raise("Cannot find entry for node '%s'" % node.name) 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.pad_after = 0
self.offset_unset = False self.offset_unset = False
self.image_pos = None self.image_pos = None
self._expand_size = False
if read_node: if read_node:
self.ReadNode() self.ReadNode()
@ -161,6 +162,7 @@ class Entry(object):
"of two" % (self._node.path, self.align_size)) "of two" % (self._node.path, self.align_size))
self.align_end = fdt_util.GetInt(self._node, 'align-end') self.align_end = fdt_util.GetInt(self._node, 'align-end')
self.offset_unset = fdt_util.GetBool(self._node, 'offset-unset') self.offset_unset = fdt_util.GetBool(self._node, 'offset-unset')
self.expand_size = fdt_util.GetBool(self._node, 'expand-size')
def GetDefaultFilename(self): def GetDefaultFilename(self):
return None return None
@ -507,3 +509,12 @@ features to produce new behaviours.
break break
name = '%s.%s' % (node.name, name) name = '%s.%s' % (node.name, name)
return 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') 'return-unknown-contents')
self.bad_update_contents = fdt_util.GetBool(self._node, self.bad_update_contents = fdt_util.GetBool(self._node,
'bad-update-contents') '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. # Set to True when the entry is ready to process the FDT.
self.process_fdt_ready = False self.process_fdt_ready = False
@ -68,12 +70,15 @@ class Entry__testing(Entry):
EntryArg('test-existing-prop', str)], self.require_args) EntryArg('test-existing-prop', str)], self.require_args)
if self.force_bad_datatype: if self.force_bad_datatype:
self.GetEntryArgsOrProps([EntryArg('test-bad-datatype-arg', bool)]) self.GetEntryArgsOrProps([EntryArg('test-bad-datatype-arg', bool)])
self.return_contents = True
def ObtainContents(self): def ObtainContents(self):
if self.return_unknown_contents: if self.return_unknown_contents or not self.return_contents:
return False return False
self.data = 'a' self.data = 'a'
self.contents_size = len(self.data) self.contents_size = len(self.data)
if self.return_contents_once:
self.return_contents = False
return True return True
def GetOffsets(self): def GetOffsets(self):

@ -40,6 +40,10 @@ class Entry_section(Entry):
def ProcessFdt(self, fdt): def ProcessFdt(self, fdt):
return self._section.ProcessFdt(fdt) return self._section.ProcessFdt(fdt)
def ExpandEntries(self):
Entry.ExpandEntries(self)
self._section.ExpandEntries()
def AddMissingProperties(self): def AddMissingProperties(self):
Entry.AddMissingProperties(self) Entry.AddMissingProperties(self)
self._section.AddMissingProperties() self._section.AddMissingProperties()
@ -95,3 +99,7 @@ class Entry_section(Entry):
def GetEntries(self): def GetEntries(self):
return self._section.GetEntries() 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", self.assertIn("Node '/binman/files': Missing 'pattern' property",
str(e.exception)) 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__": if __name__ == "__main__":
unittest.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