mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-11 07:34:31 +00:00
binman: Allow vblock to include devicetree blobs
At present if a devicetree blob is included in a vblock it does not deal with updates. This is because the vblock is created once at the start and does not have a method to update itself later, after all the entry contents are finalised. Fix this by adjusting how the vblock is created. Also simplify Image.ProcessEntryContents() since it effectively duplicates the code in Section.ProcessContents(). Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
parent
939d1062d0
commit
5af9ebc4bc
5 changed files with 96 additions and 10 deletions
|
@ -66,3 +66,7 @@ class Entry_blob(Entry):
|
||||||
|
|
||||||
def GetDefaultFilename(self):
|
def GetDefaultFilename(self):
|
||||||
return self._filename
|
return self._filename
|
||||||
|
|
||||||
|
def ProcessContents(self):
|
||||||
|
# The blob may have changed due to WriteSymbols()
|
||||||
|
return self.ProcessContentsUpdate(self.data)
|
||||||
|
|
|
@ -49,7 +49,7 @@ class Entry_vblock(Entry):
|
||||||
EntryArg('kernelkey', str),
|
EntryArg('kernelkey', str),
|
||||||
EntryArg('preamble-flags', int)])
|
EntryArg('preamble-flags', int)])
|
||||||
|
|
||||||
def ObtainContents(self):
|
def GetVblock(self):
|
||||||
# Join up the data files to be signed
|
# Join up the data files to be signed
|
||||||
input_data = b''
|
input_data = b''
|
||||||
for entry_phandle in self.content:
|
for entry_phandle in self.content:
|
||||||
|
@ -76,5 +76,16 @@ class Entry_vblock(Entry):
|
||||||
]
|
]
|
||||||
#out.Notice("Sign '%s' into %s" % (', '.join(self.value), self.label))
|
#out.Notice("Sign '%s' into %s" % (', '.join(self.value), self.label))
|
||||||
stdout = tools.Run('futility', *args)
|
stdout = tools.Run('futility', *args)
|
||||||
self.SetContents(tools.ReadFile(output_fname))
|
return tools.ReadFile(output_fname)
|
||||||
|
|
||||||
|
def ObtainContents(self):
|
||||||
|
data = self.GetVblock()
|
||||||
|
if data is False:
|
||||||
|
return False
|
||||||
|
self.SetContents(data)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def ProcessContents(self):
|
||||||
|
# The blob may have changed due to WriteSymbols()
|
||||||
|
data = self.GetVblock()
|
||||||
|
return self.ProcessContentsUpdate(data)
|
||||||
|
|
|
@ -1638,15 +1638,37 @@ class TestFunctional(unittest.TestCase):
|
||||||
str(e.exception))
|
str(e.exception))
|
||||||
|
|
||||||
def _HandleVblockCommand(self, pipe_list):
|
def _HandleVblockCommand(self, pipe_list):
|
||||||
"""Fake calls to the futility utility"""
|
"""Fake calls to the futility utility
|
||||||
|
|
||||||
|
The expected pipe is:
|
||||||
|
|
||||||
|
[('futility', 'vbutil_firmware', '--vblock',
|
||||||
|
'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
|
||||||
|
'--signprivate', 'devkeys/firmware_data_key.vbprivk',
|
||||||
|
'--version', '1', '--fv', 'input.vblock', '--kernelkey',
|
||||||
|
'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
|
||||||
|
|
||||||
|
This writes to the output file (here, 'vblock.vblock'). If
|
||||||
|
self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
|
||||||
|
of the input data (here, 'input.vblock').
|
||||||
|
"""
|
||||||
if pipe_list[0][0] == 'futility':
|
if pipe_list[0][0] == 'futility':
|
||||||
fname = pipe_list[0][3]
|
fname = pipe_list[0][3]
|
||||||
with open(fname, 'wb') as fd:
|
with open(fname, 'wb') as fd:
|
||||||
fd.write(VBLOCK_DATA)
|
if self._hash_data:
|
||||||
|
infile = pipe_list[0][11]
|
||||||
|
m = hashlib.sha256()
|
||||||
|
data = tools.ReadFile(infile)
|
||||||
|
m.update(data)
|
||||||
|
fd.write(m.digest())
|
||||||
|
else:
|
||||||
|
fd.write(VBLOCK_DATA)
|
||||||
|
|
||||||
return command.CommandResult()
|
return command.CommandResult()
|
||||||
|
|
||||||
def testVblock(self):
|
def testVblock(self):
|
||||||
"""Test for the Chromium OS Verified Boot Block"""
|
"""Test for the Chromium OS Verified Boot Block"""
|
||||||
|
self._hash_data = False
|
||||||
command.test_result = self._HandleVblockCommand
|
command.test_result = self._HandleVblockCommand
|
||||||
entry_args = {
|
entry_args = {
|
||||||
'keydir': 'devkeys',
|
'keydir': 'devkeys',
|
||||||
|
@ -1677,6 +1699,29 @@ class TestFunctional(unittest.TestCase):
|
||||||
self.assertIn("Node '/binman/vblock': Cannot find entry for node "
|
self.assertIn("Node '/binman/vblock': Cannot find entry for node "
|
||||||
"'other'", str(e.exception))
|
"'other'", str(e.exception))
|
||||||
|
|
||||||
|
def testVblockContent(self):
|
||||||
|
"""Test that the vblock signs the right data"""
|
||||||
|
self._hash_data = True
|
||||||
|
command.test_result = self._HandleVblockCommand
|
||||||
|
entry_args = {
|
||||||
|
'keydir': 'devkeys',
|
||||||
|
}
|
||||||
|
data = self._DoReadFileDtb(
|
||||||
|
'189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
|
||||||
|
entry_args=entry_args)[0]
|
||||||
|
hashlen = 32 # SHA256 hash is 32 bytes
|
||||||
|
self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
|
||||||
|
hashval = data[-hashlen:]
|
||||||
|
dtb = data[len(U_BOOT_DATA):-hashlen]
|
||||||
|
|
||||||
|
expected_data = U_BOOT_DATA + dtb
|
||||||
|
|
||||||
|
# The hashval should be a hash of the dtb
|
||||||
|
m = hashlib.sha256()
|
||||||
|
m.update(expected_data)
|
||||||
|
expected_hashval = m.digest()
|
||||||
|
self.assertEqual(expected_hashval, hashval)
|
||||||
|
|
||||||
def testTpl(self):
|
def testTpl(self):
|
||||||
"""Test that an image with TPL and its device tree can be created"""
|
"""Test that an image with TPL and its device tree can be created"""
|
||||||
# ELF file with a '__bss_size' symbol
|
# ELF file with a '__bss_size' symbol
|
||||||
|
|
|
@ -136,12 +136,7 @@ class Image(section.Entry_section):
|
||||||
Returns:
|
Returns:
|
||||||
True if the new data size is OK, False if expansion is needed
|
True if the new data size is OK, False if expansion is needed
|
||||||
"""
|
"""
|
||||||
sizes_ok = True
|
return super().ProcessContents()
|
||||||
for entry in self._entries.values():
|
|
||||||
if not entry.ProcessContents():
|
|
||||||
sizes_ok = False
|
|
||||||
tout.Debug("Entry '%s' size change" % self._node.path)
|
|
||||||
return sizes_ok
|
|
||||||
|
|
||||||
def WriteSymbols(self):
|
def WriteSymbols(self):
|
||||||
"""Write symbol values into binary files for access at run time"""
|
"""Write symbol values into binary files for access at run time"""
|
||||||
|
|
31
tools/binman/test/189_vblock_content.dts
Normal file
31
tools/binman/test/189_vblock_content.dts
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <1>;
|
||||||
|
|
||||||
|
binman {
|
||||||
|
u_boot: u-boot {
|
||||||
|
};
|
||||||
|
|
||||||
|
dtb: u-boot-dtb {
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Put the vblock after the dtb so that the dtb is updated
|
||||||
|
* before the vblock reads its data. At present binman does not
|
||||||
|
* understand dependencies between entries, but simply
|
||||||
|
* iterates again when it thinks something needs to be
|
||||||
|
* recalculated.
|
||||||
|
*/
|
||||||
|
vblock {
|
||||||
|
content = <&u_boot &dtb>;
|
||||||
|
keyblock = "firmware.keyblock";
|
||||||
|
signprivate = "firmware_data_key.vbprivk";
|
||||||
|
version = <1>;
|
||||||
|
kernelkey = "kernel_subkey.vbpubk";
|
||||||
|
preamble-flags = <1>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
Loading…
Reference in a new issue