|
@@ -74,6 +74,12 @@ REFCODE_DATA = b'refcode'
|
|
|
FSP_M_DATA = b'fsp_m'
|
|
|
FSP_S_DATA = b'fsp_s'
|
|
|
FSP_T_DATA = b'fsp_t'
|
|
|
+ATF_BL31_DATA = b'bl31'
|
|
|
+TEST_FDT1_DATA = b'fdt1'
|
|
|
+TEST_FDT2_DATA = b'test-fdt2'
|
|
|
+
|
|
|
+# Subdirectory of the input dir to use to put test FDTs
|
|
|
+TEST_FDT_SUBDIR = 'fdts'
|
|
|
|
|
|
# The expected size for the device tree in some tests
|
|
|
EXTRACT_DTB_SIZE = 0x3c9
|
|
@@ -167,6 +173,13 @@ class TestFunctional(unittest.TestCase):
|
|
|
os.path.join(cls._indir, 'files'))
|
|
|
|
|
|
TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
|
|
|
+ TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA)
|
|
|
+
|
|
|
+ # Add a few .dtb files for testing
|
|
|
+ TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR,
|
|
|
+ TEST_FDT1_DATA)
|
|
|
+ TestFunctional._MakeInputFile('%s/test-fdt2.dtb' % TEST_FDT_SUBDIR,
|
|
|
+ TEST_FDT2_DATA)
|
|
|
|
|
|
# Travis-CI may have an old lz4
|
|
|
cls.have_lz4 = True
|
|
@@ -285,7 +298,7 @@ class TestFunctional(unittest.TestCase):
|
|
|
|
|
|
def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
|
|
|
entry_args=None, images=None, use_real_dtb=False,
|
|
|
- verbosity=None, allow_missing=False):
|
|
|
+ verbosity=None, allow_missing=False, extra_indirs=None):
|
|
|
"""Run binman with a given test file
|
|
|
|
|
|
Args:
|
|
@@ -298,6 +311,14 @@ class TestFunctional(unittest.TestCase):
|
|
|
key: arg name
|
|
|
value: value of that arg
|
|
|
images: List of image names to build
|
|
|
+ use_real_dtb: True to use the test file as the contents of
|
|
|
+ the u-boot-dtb entry. Normally this is not needed and the
|
|
|
+ test contents (the U_BOOT_DTB_DATA string) can be used.
|
|
|
+ But in some test we need the real contents.
|
|
|
+ verbosity: Verbosity level to use (0-3, None=don't set it)
|
|
|
+ allow_missing: Set the '--allow-missing' flag so that missing
|
|
|
+ external binaries just produce a warning instead of an error
|
|
|
+ extra_indirs: Extra input directories to add using -I
|
|
|
"""
|
|
|
args = []
|
|
|
if debug:
|
|
@@ -324,6 +345,9 @@ class TestFunctional(unittest.TestCase):
|
|
|
if images:
|
|
|
for image in images:
|
|
|
args += ['-i', image]
|
|
|
+ if extra_indirs:
|
|
|
+ for indir in extra_indirs:
|
|
|
+ args += ['-I', indir]
|
|
|
return self._DoBinman(*args)
|
|
|
|
|
|
def _SetupDtb(self, fname, outfile='u-boot.dtb'):
|
|
@@ -357,6 +381,13 @@ class TestFunctional(unittest.TestCase):
|
|
|
We still want the DTBs for SPL and TPL to be different though, since
|
|
|
otherwise it is confusing to know which one we are looking at. So add
|
|
|
an 'spl' or 'tpl' property to the top-level node.
|
|
|
+
|
|
|
+ Args:
|
|
|
+ dtb_data: dtb data to modify (this should be a value devicetree)
|
|
|
+ name: Name of a new property to add
|
|
|
+
|
|
|
+ Returns:
|
|
|
+ New dtb data with the property added
|
|
|
"""
|
|
|
dtb = fdt.Fdt.FromData(dtb_data)
|
|
|
dtb.Scan()
|
|
@@ -366,7 +397,8 @@ class TestFunctional(unittest.TestCase):
|
|
|
return dtb.GetContents()
|
|
|
|
|
|
def _DoReadFileDtb(self, fname, use_real_dtb=False, map=False,
|
|
|
- update_dtb=False, entry_args=None, reset_dtbs=True):
|
|
|
+ update_dtb=False, entry_args=None, reset_dtbs=True,
|
|
|
+ extra_indirs=None):
|
|
|
"""Run binman and return the resulting image
|
|
|
|
|
|
This runs binman with a given test file and then reads the resulting
|
|
@@ -384,6 +416,13 @@ class TestFunctional(unittest.TestCase):
|
|
|
map: True to output map files for the images
|
|
|
update_dtb: Update the offset and size of each entry in the device
|
|
|
tree before packing it into the image
|
|
|
+ entry_args: Dict of entry args to supply to binman
|
|
|
+ key: arg name
|
|
|
+ value: value of that arg
|
|
|
+ reset_dtbs: With use_real_dtb the test dtb is overwritten by this
|
|
|
+ function. If reset_dtbs is True, then the original test dtb
|
|
|
+ is written back before this function finishes
|
|
|
+ extra_indirs: Extra input directories to add using -I
|
|
|
|
|
|
Returns:
|
|
|
Tuple:
|
|
@@ -407,7 +446,8 @@ class TestFunctional(unittest.TestCase):
|
|
|
|
|
|
try:
|
|
|
retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
|
|
|
- entry_args=entry_args, use_real_dtb=use_real_dtb)
|
|
|
+ entry_args=entry_args, use_real_dtb=use_real_dtb,
|
|
|
+ extra_indirs=extra_indirs)
|
|
|
self.assertEqual(0, retcode)
|
|
|
out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
|
|
|
|
|
@@ -1382,8 +1422,9 @@ class TestFunctional(unittest.TestCase):
|
|
|
}
|
|
|
with self.assertRaises(ValueError) as e:
|
|
|
self._DoReadFileDtb('064_entry_args_required.dts')
|
|
|
- self.assertIn("Node '/binman/_testing': Missing required "
|
|
|
- 'properties/entry args: test-str-arg, test-int-fdt, test-int-arg',
|
|
|
+ self.assertIn("Node '/binman/_testing': "
|
|
|
+ 'Missing required properties/entry args: test-str-arg, '
|
|
|
+ 'test-int-fdt, test-int-arg',
|
|
|
str(e.exception))
|
|
|
|
|
|
def testEntryArgsInvalidFormat(self):
|
|
@@ -1487,8 +1528,7 @@ class TestFunctional(unittest.TestCase):
|
|
|
entry_args = {
|
|
|
'cros-ec-rw-path': 'ecrw.bin',
|
|
|
}
|
|
|
- data, _, _, _ = self._DoReadFileDtb('068_blob_named_by_arg.dts',
|
|
|
- entry_args=entry_args)
|
|
|
+ self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
|
|
|
|
|
|
def testFill(self):
|
|
|
"""Test for an fill entry type"""
|
|
@@ -3467,7 +3507,7 @@ class TestFunctional(unittest.TestCase):
|
|
|
self.assertEqual(len(U_BOOT_SPL_DTB_DATA), int(data_sizes[1].split()[0]))
|
|
|
|
|
|
def testFitExternal(self):
|
|
|
- """Test an image with an FIT"""
|
|
|
+ """Test an image with an FIT with external images"""
|
|
|
data = self._DoReadFile('162_fit_external.dts')
|
|
|
fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
|
|
|
|
|
@@ -3477,5 +3517,196 @@ class TestFunctional(unittest.TestCase):
|
|
|
fnode = dtb.GetNode('/images/kernel')
|
|
|
self.assertNotIn('data', fnode.props)
|
|
|
|
|
|
+ def testSectionIgnoreHashSignature(self):
|
|
|
+ """Test that sections ignore hash, signature nodes for its data"""
|
|
|
+ data = self._DoReadFile('165_section_ignore_hash_signature.dts')
|
|
|
+ expected = (U_BOOT_DATA + U_BOOT_DATA)
|
|
|
+ self.assertEqual(expected, data)
|
|
|
+
|
|
|
+ def testPadInSections(self):
|
|
|
+ """Test pad-before, pad-after for entries in sections"""
|
|
|
+ data = self._DoReadFile('166_pad_in_sections.dts')
|
|
|
+ expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
|
|
|
+ U_BOOT_DATA + tools.GetBytes(ord('!'), 6) +
|
|
|
+ U_BOOT_DATA)
|
|
|
+ self.assertEqual(expected, data)
|
|
|
+
|
|
|
+ def testFitImageSubentryAlignment(self):
|
|
|
+ """Test relative alignability of FIT image subentries"""
|
|
|
+ entry_args = {
|
|
|
+ 'test-id': TEXT_DATA,
|
|
|
+ }
|
|
|
+ data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
|
|
|
+ entry_args=entry_args)
|
|
|
+ dtb = fdt.Fdt.FromData(data)
|
|
|
+ dtb.Scan()
|
|
|
+
|
|
|
+ node = dtb.GetNode('/images/kernel')
|
|
|
+ data = dtb.GetProps(node)["data"].bytes
|
|
|
+ align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
|
|
|
+ expected = (tools.GetBytes(0, 0x20) + U_BOOT_SPL_DATA +
|
|
|
+ tools.GetBytes(0, align_pad) + U_BOOT_DATA)
|
|
|
+ self.assertEqual(expected, data)
|
|
|
+
|
|
|
+ node = dtb.GetNode('/images/fdt-1')
|
|
|
+ data = dtb.GetProps(node)["data"].bytes
|
|
|
+ expected = (U_BOOT_SPL_DTB_DATA + tools.GetBytes(0, 20) +
|
|
|
+ tools.ToBytes(TEXT_DATA) + tools.GetBytes(0, 30) +
|
|
|
+ U_BOOT_DTB_DATA)
|
|
|
+ self.assertEqual(expected, data)
|
|
|
+
|
|
|
+ def testFitExtblobMissingOk(self):
|
|
|
+ """Test a FIT with a missing external blob that is allowed"""
|
|
|
+ with test_util.capture_sys_output() as (stdout, stderr):
|
|
|
+ self._DoTestFile('168_fit_missing_blob.dts',
|
|
|
+ allow_missing=True)
|
|
|
+ err = stderr.getvalue()
|
|
|
+ self.assertRegex(err, "Image 'main-section'.*missing.*: atf-bl31")
|
|
|
+
|
|
|
+ def testBlobNamedByArgMissing(self):
|
|
|
+ """Test handling of a missing entry arg"""
|
|
|
+ with self.assertRaises(ValueError) as e:
|
|
|
+ self._DoReadFile('068_blob_named_by_arg.dts')
|
|
|
+ self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
|
|
|
+ str(e.exception))
|
|
|
+
|
|
|
+ def testPackBl31(self):
|
|
|
+ """Test that an image with an ATF BL31 binary can be created"""
|
|
|
+ data = self._DoReadFile('169_atf_bl31.dts')
|
|
|
+ self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
|
|
|
+
|
|
|
+ def testFitFdt(self):
|
|
|
+ """Test an image with an FIT with multiple FDT images"""
|
|
|
+ def _CheckFdt(seq, expected_data):
|
|
|
+ """Check the FDT nodes
|
|
|
+
|
|
|
+ Args:
|
|
|
+ seq: Sequence number to check (0 or 1)
|
|
|
+ expected_data: Expected contents of 'data' property
|
|
|
+ """
|
|
|
+ name = 'fdt-%d' % seq
|
|
|
+ fnode = dtb.GetNode('/images/%s' % name)
|
|
|
+ self.assertIsNotNone(fnode)
|
|
|
+ self.assertEqual({'description','type', 'compression', 'data'},
|
|
|
+ set(fnode.props.keys()))
|
|
|
+ self.assertEqual(expected_data, fnode.props['data'].bytes)
|
|
|
+ self.assertEqual('fdt-test-fdt%d.dtb' % seq,
|
|
|
+ fnode.props['description'].value)
|
|
|
+
|
|
|
+ def _CheckConfig(seq, expected_data):
|
|
|
+ """Check the configuration nodes
|
|
|
+
|
|
|
+ Args:
|
|
|
+ seq: Sequence number to check (0 or 1)
|
|
|
+ expected_data: Expected contents of 'data' property
|
|
|
+ """
|
|
|
+ cnode = dtb.GetNode('/configurations')
|
|
|
+ self.assertIn('default', cnode.props)
|
|
|
+ self.assertEqual('config-2', cnode.props['default'].value)
|
|
|
+
|
|
|
+ name = 'config-%d' % seq
|
|
|
+ fnode = dtb.GetNode('/configurations/%s' % name)
|
|
|
+ self.assertIsNotNone(fnode)
|
|
|
+ self.assertEqual({'description','firmware', 'loadables', 'fdt'},
|
|
|
+ set(fnode.props.keys()))
|
|
|
+ self.assertEqual('conf-test-fdt%d.dtb' % seq,
|
|
|
+ fnode.props['description'].value)
|
|
|
+ self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
|
|
|
+
|
|
|
+ entry_args = {
|
|
|
+ 'of-list': 'test-fdt1 test-fdt2',
|
|
|
+ 'default-dt': 'test-fdt2',
|
|
|
+ }
|
|
|
+ data = self._DoReadFileDtb(
|
|
|
+ '172_fit_fdt.dts',
|
|
|
+ entry_args=entry_args,
|
|
|
+ extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
|
|
|
+ self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
|
|
|
+ fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
|
|
|
+
|
|
|
+ dtb = fdt.Fdt.FromData(fit_data)
|
|
|
+ dtb.Scan()
|
|
|
+ fnode = dtb.GetNode('/images/kernel')
|
|
|
+ self.assertIn('data', fnode.props)
|
|
|
+
|
|
|
+ # Check all the properties in fdt-1 and fdt-2
|
|
|
+ _CheckFdt(1, TEST_FDT1_DATA)
|
|
|
+ _CheckFdt(2, TEST_FDT2_DATA)
|
|
|
+
|
|
|
+ # Check configurations
|
|
|
+ _CheckConfig(1, TEST_FDT1_DATA)
|
|
|
+ _CheckConfig(2, TEST_FDT2_DATA)
|
|
|
+
|
|
|
+ def testFitFdtMissingList(self):
|
|
|
+ """Test handling of a missing 'of-list' entry arg"""
|
|
|
+ with self.assertRaises(ValueError) as e:
|
|
|
+ self._DoReadFile('172_fit_fdt.dts')
|
|
|
+ self.assertIn("Generator node requires 'of-list' entry argument",
|
|
|
+ str(e.exception))
|
|
|
+
|
|
|
+ def testFitFdtEmptyList(self):
|
|
|
+ """Test handling of an empty 'of-list' entry arg"""
|
|
|
+ entry_args = {
|
|
|
+ 'of-list': '',
|
|
|
+ }
|
|
|
+ data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
|
|
|
+
|
|
|
+ def testFitFdtMissingProp(self):
|
|
|
+ """Test handling of a missing 'fit,fdt-list' property"""
|
|
|
+ with self.assertRaises(ValueError) as e:
|
|
|
+ self._DoReadFile('171_fit_fdt_missing_prop.dts')
|
|
|
+ self.assertIn("Generator node requires 'fit,fdt-list' property",
|
|
|
+ str(e.exception))
|
|
|
+
|
|
|
+ def testFitFdtEmptyList(self):
|
|
|
+ """Test handling of an empty 'of-list' entry arg"""
|
|
|
+ entry_args = {
|
|
|
+ 'of-list': '',
|
|
|
+ }
|
|
|
+ data = self._DoReadFileDtb('172_fit_fdt.dts', entry_args=entry_args)[0]
|
|
|
+
|
|
|
+ def testFitFdtMissing(self):
|
|
|
+ """Test handling of a missing 'default-dt' entry arg"""
|
|
|
+ entry_args = {
|
|
|
+ 'of-list': 'test-fdt1 test-fdt2',
|
|
|
+ }
|
|
|
+ with self.assertRaises(ValueError) as e:
|
|
|
+ self._DoReadFileDtb(
|
|
|
+ '172_fit_fdt.dts',
|
|
|
+ entry_args=entry_args,
|
|
|
+ extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
|
|
|
+ self.assertIn("Generated 'default' node requires default-dt entry argument",
|
|
|
+ str(e.exception))
|
|
|
+
|
|
|
+ def testFitFdtNotInList(self):
|
|
|
+ """Test handling of a default-dt that is not in the of-list"""
|
|
|
+ entry_args = {
|
|
|
+ 'of-list': 'test-fdt1 test-fdt2',
|
|
|
+ 'default-dt': 'test-fdt3',
|
|
|
+ }
|
|
|
+ with self.assertRaises(ValueError) as e:
|
|
|
+ self._DoReadFileDtb(
|
|
|
+ '172_fit_fdt.dts',
|
|
|
+ entry_args=entry_args,
|
|
|
+ extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
|
|
|
+ self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
|
|
|
+ str(e.exception))
|
|
|
+
|
|
|
+ def testFitExtblobMissingHelp(self):
|
|
|
+ """Test display of help messages when an external blob is missing"""
|
|
|
+ control.missing_blob_help = control._ReadMissingBlobHelp()
|
|
|
+ control.missing_blob_help['wibble'] = 'Wibble test'
|
|
|
+ control.missing_blob_help['another'] = 'Another test'
|
|
|
+ with test_util.capture_sys_output() as (stdout, stderr):
|
|
|
+ self._DoTestFile('168_fit_missing_blob.dts',
|
|
|
+ allow_missing=True)
|
|
|
+ err = stderr.getvalue()
|
|
|
+
|
|
|
+ # We can get the tag from the name, the type or the missing-msg
|
|
|
+ # property. Check all three.
|
|
|
+ self.assertIn('You may need to build ARM Trusted', err)
|
|
|
+ self.assertIn('Wibble test', err)
|
|
|
+ self.assertIn('Another test', err)
|
|
|
+
|
|
|
if __name__ == "__main__":
|
|
|
unittest.main()
|