binman: Add support for a collection of entries
The vblock entry type includes code to collect the data from a number of other entries (not necessarily subentries) and concatenating it. This is a useful feature for other entry types. Make it a base class, so that vblock can use it, along with other entry types. Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
parent
3d43338293
commit
189f291914
@ -248,6 +248,19 @@ both of size 1MB.
|
||||
|
||||
|
||||
|
||||
Entry: collection: An entry which contains a collection of other entries
|
||||
------------------------------------------------------------------------
|
||||
|
||||
Properties / Entry arguments:
|
||||
- content: List of phandles to entries to include
|
||||
|
||||
This allows reusing the contents of other entries. The contents of the
|
||||
listed entries are combined to form this entry. This serves as a useful
|
||||
base class for entry types which need to process data from elsewhere in
|
||||
the image, not necessarily child entries.
|
||||
|
||||
|
||||
|
||||
Entry: cros-ec-rw: A blob entry which contains a Chromium OS read-write EC image
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
@ -438,6 +438,11 @@ class Entry(object):
|
||||
"""Convenience function to raise an error referencing a node"""
|
||||
raise ValueError("Node '%s': %s" % (self._node.path, msg))
|
||||
|
||||
def Info(self, msg):
|
||||
"""Convenience function to log info referencing a node"""
|
||||
tag = "Info '%s'" % self._node.path
|
||||
tout.Detail('%30s: %s' % (tag, msg))
|
||||
|
||||
def Detail(self, msg):
|
||||
"""Convenience function to log detail referencing a node"""
|
||||
tag = "Node '%s'" % self._node.path
|
||||
|
61
tools/binman/etype/collection.py
Normal file
61
tools/binman/etype/collection.py
Normal file
@ -0,0 +1,61 @@
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
# Copyright 2021 Google LLC
|
||||
# Written by Simon Glass <sjg@chromium.org>
|
||||
#
|
||||
|
||||
# Support for a collection of entries from other parts of an image
|
||||
|
||||
from collections import OrderedDict
|
||||
import os
|
||||
|
||||
from binman.entry import Entry
|
||||
from dtoc import fdt_util
|
||||
|
||||
class Entry_collection(Entry):
|
||||
"""An entry which contains a collection of other entries
|
||||
|
||||
Properties / Entry arguments:
|
||||
- content: List of phandles to entries to include
|
||||
|
||||
This allows reusing the contents of other entries. The contents of the
|
||||
listed entries are combined to form this entry. This serves as a useful
|
||||
base class for entry types which need to process data from elsewhere in
|
||||
the image, not necessarily child entries.
|
||||
"""
|
||||
def __init__(self, section, etype, node):
|
||||
super().__init__(section, etype, node)
|
||||
self.content = fdt_util.GetPhandleList(self._node, 'content')
|
||||
if not self.content:
|
||||
self.Raise("Collection must have a 'content' property")
|
||||
|
||||
def GetContents(self):
|
||||
"""Get the contents of this entry
|
||||
|
||||
Returns:
|
||||
bytes content of the entry
|
||||
"""
|
||||
# Join up all the data
|
||||
self.Info('Getting content')
|
||||
data = b''
|
||||
for entry_phandle in self.content:
|
||||
entry_data = self.section.GetContentsByPhandle(entry_phandle, self)
|
||||
if entry_data is None:
|
||||
# Data not available yet
|
||||
return None
|
||||
data += entry_data
|
||||
|
||||
self.Info('Returning contents size %x' % len(data))
|
||||
|
||||
return data
|
||||
|
||||
def ObtainContents(self):
|
||||
data = self.GetContents()
|
||||
if data is None:
|
||||
return False
|
||||
self.SetContents(data)
|
||||
return True
|
||||
|
||||
def ProcessContents(self):
|
||||
# The blob may have changed due to WriteSymbols()
|
||||
data = self.GetContents()
|
||||
return self.ProcessContentsUpdate(data)
|
@ -9,12 +9,13 @@
|
||||
from collections import OrderedDict
|
||||
import os
|
||||
|
||||
from binman.entry import Entry, EntryArg
|
||||
from binman.entry import EntryArg
|
||||
from binman.etype.collection import Entry_collection
|
||||
|
||||
from dtoc import fdt_util
|
||||
from patman import tools
|
||||
|
||||
class Entry_vblock(Entry):
|
||||
class Entry_vblock(Entry_collection):
|
||||
"""An entry which contains a Chromium OS verified boot block
|
||||
|
||||
Properties / Entry arguments:
|
||||
@ -37,9 +38,6 @@ class Entry_vblock(Entry):
|
||||
"""
|
||||
def __init__(self, section, etype, node):
|
||||
super().__init__(section, etype, node)
|
||||
self.content = fdt_util.GetPhandleList(self._node, 'content')
|
||||
if not self.content:
|
||||
self.Raise("Vblock must have a 'content' property")
|
||||
(self.keydir, self.keyblock, self.signprivate, self.version,
|
||||
self.kernelkey, self.preamble_flags) = self.GetEntryArgsOrProps([
|
||||
EntryArg('keydir', str),
|
||||
@ -50,14 +48,16 @@ class Entry_vblock(Entry):
|
||||
EntryArg('preamble-flags', int)])
|
||||
|
||||
def GetVblock(self):
|
||||
"""Get the contents of this entry
|
||||
|
||||
Returns:
|
||||
bytes content of the entry, which is the signed vblock for the
|
||||
provided data
|
||||
"""
|
||||
# Join up the data files to be signed
|
||||
input_data = b''
|
||||
for entry_phandle in self.content:
|
||||
data = self.section.GetContentsByPhandle(entry_phandle, self)
|
||||
if data is None:
|
||||
# Data not available yet
|
||||
return False
|
||||
input_data += data
|
||||
input_data = self.GetContents()
|
||||
if input_data is None:
|
||||
return None
|
||||
|
||||
uniq = self.GetUniqueName()
|
||||
output_fname = tools.GetOutputFilename('vblock.%s' % uniq)
|
||||
@ -80,7 +80,7 @@ class Entry_vblock(Entry):
|
||||
|
||||
def ObtainContents(self):
|
||||
data = self.GetVblock()
|
||||
if data is False:
|
||||
if data is None:
|
||||
return False
|
||||
self.SetContents(data)
|
||||
return True
|
||||
|
@ -1718,7 +1718,7 @@ class TestFunctional(unittest.TestCase):
|
||||
"""Test we detect a vblock which has no content to sign"""
|
||||
with self.assertRaises(ValueError) as e:
|
||||
self._DoReadFile('075_vblock_no_content.dts')
|
||||
self.assertIn("Node '/binman/vblock': Vblock must have a 'content' "
|
||||
self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
|
||||
'property', str(e.exception))
|
||||
|
||||
def testVblockBadPhandle(self):
|
||||
@ -4476,5 +4476,13 @@ class TestFunctional(unittest.TestCase):
|
||||
U_BOOT_SPL_DTB_DATA, 0x38,
|
||||
entry_args=entry_args, use_expanded=True)
|
||||
|
||||
def testCollection(self):
|
||||
"""Test a collection"""
|
||||
data = self._DoReadFile('198_collection.dts')
|
||||
self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
|
||||
tools.GetBytes(0xff, 2) + U_BOOT_NODTB_DATA +
|
||||
tools.GetBytes(0xfe, 3) + U_BOOT_DTB_DATA,
|
||||
data)
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
27
tools/binman/test/198_collection.dts
Normal file
27
tools/binman/test/198_collection.dts
Normal file
@ -0,0 +1,27 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
collection {
|
||||
content = <&u_boot_nodtb &dtb>;
|
||||
};
|
||||
fill {
|
||||
size = <2>;
|
||||
fill-byte = [ff];
|
||||
};
|
||||
u_boot_nodtb: u-boot-nodtb {
|
||||
};
|
||||
fill2 {
|
||||
type = "fill";
|
||||
size = <3>;
|
||||
fill-byte = [fe];
|
||||
};
|
||||
dtb: u-boot-dtb {
|
||||
};
|
||||
};
|
||||
};
|
Loading…
Reference in New Issue
Block a user