diff options
Diffstat (limited to 'tools/binman/ftest.py')
-rw-r--r-- | tools/binman/ftest.py | 255 |
1 files changed, 229 insertions, 26 deletions
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py index e4da04030a5..93f3d22cf57 100644 --- a/tools/binman/ftest.py +++ b/tools/binman/ftest.py @@ -7,6 +7,7 @@ # python -m unittest func_test.TestFunctional.testHelp import collections +import glob import gzip import hashlib from optparse import OptionParser @@ -546,7 +547,7 @@ class TestFunctional(unittest.TestCase): dtb_data = self._SetupDtb(fname) # For testing purposes, make a copy of the DT for SPL and TPL. Add - # a node indicating which it is, so aid verification. + # a node indicating which it is, to aid verification. for name in ['spl', 'tpl', 'vpl']: dtb_fname = '%s/u-boot-%s.dtb' % (name, name) outfile = os.path.join(self._indir, dtb_fname) @@ -4180,8 +4181,8 @@ class TestFunctional(unittest.TestCase): data = self._DoReadFile('172_scp.dts') self.assertEqual(SCP_DATA, data[:len(SCP_DATA)]) - def testFitFdt(self): - """Test an image with an FIT with multiple FDT images""" + def CheckFitFdt(self, dts='170_fit_fdt.dts', use_fdt_list=True): + """Check an image with an FIT with multiple FDT images""" def _CheckFdt(seq, expected_data): """Check the FDT nodes @@ -4220,11 +4221,12 @@ class TestFunctional(unittest.TestCase): self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value) entry_args = { - 'of-list': 'test-fdt1 test-fdt2', 'default-dt': 'test-fdt2', } + if use_fdt_list: + entry_args['of-list'] = 'test-fdt1 test-fdt2' data = self._DoReadFileDtb( - '170_fit_fdt.dts', + 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):]) @@ -4243,6 +4245,10 @@ class TestFunctional(unittest.TestCase): _CheckConfig(1, TEST_FDT1_DATA) _CheckConfig(2, TEST_FDT2_DATA) + def testFitFdt(self): + """Test an image with an FIT with multiple FDT images""" + self.CheckFitFdt() + def testFitFdtMissingList(self): """Test handling of a missing 'of-list' entry arg""" with self.assertRaises(ValueError) as e: @@ -7175,27 +7181,24 @@ fdt fdtmap Extract the devicetree blob from the fdtmap def testSplPubkeyDtb(self): - """Test u_boot_spl_pubkey_dtb etype""" - data = tools.read_file(self.TestFile("key.pem")) - self._MakeInputFile("key.crt", data) - self._DoReadFileRealDtb('306_spl_pubkey_dtb.dts') - image = control.images['image'] - entries = image.GetEntries() - dtb_entry = entries['u-boot-spl-pubkey-dtb'] - dtb_data = dtb_entry.GetData() - dtb = fdt.Fdt.FromData(dtb_data) - dtb.Scan() - - signature_node = dtb.GetNode('/signature') - self.assertIsNotNone(signature_node) - key_node = signature_node.FindNode("key-key") - self.assertIsNotNone(key_node) - self.assertEqual(fdt_util.GetString(key_node, "required"), - "conf") - self.assertEqual(fdt_util.GetString(key_node, "algo"), - "sha384,rsa4096") - self.assertEqual(fdt_util.GetString(key_node, "key-name-hint"), - "key") + """Test u_boot_spl_pubkey_dtb etype""" + data = tools.read_file(self.TestFile("key.pem")) + self._MakeInputFile("key.crt", data) + self._DoReadFileRealDtb('306_spl_pubkey_dtb.dts') + image = control.images['image'] + entries = image.GetEntries() + dtb_entry = entries['u-boot-spl-pubkey-dtb'] + dtb_data = dtb_entry.GetData() + dtb = fdt.Fdt.FromData(dtb_data) + dtb.Scan() + + signature_node = dtb.GetNode('/signature') + self.assertIsNotNone(signature_node) + key_node = signature_node.FindNode("key-key") + self.assertIsNotNone(key_node) + self.assertEqual(fdt_util.GetString(key_node, "required"), "conf") + self.assertEqual(fdt_util.GetString(key_node, "algo"), "sha384,rsa4096") + self.assertEqual(fdt_util.GetString(key_node, "key-name-hint"), "key") def testXilinxBootgenSigning(self): """Test xilinx-bootgen etype""" @@ -7487,6 +7490,206 @@ fdt fdtmap Extract the devicetree blob from the fdtmap err, "Image '.*' is missing external blobs and is non-functional: .*") + def SetupAlternateDts(self): + """Compile the .dts test files for alternative-fdt + + Returns: + tuple: + str: Test directory created + list of str: '.bin' files which we expect Binman to create + """ + testdir = TestFunctional._MakeInputDir('dtb') + dtb_list = [] + for fname in glob.glob(f'{self.TestFile("alt_dts")}/*.dts'): + tmp_fname = fdt_util.EnsureCompiled(fname, testdir) + base = os.path.splitext(os.path.basename(fname))[0] + dtb_list.append(base + '.bin') + shutil.move(tmp_fname, os.path.join(testdir, base + '.dtb')) + + return testdir, dtb_list + + def CheckAlternates(self, dts, phase, xpl_data): + """Run the test for the alterative-fdt etype + + Args: + dts (str): Devicetree file to process + phase (str): Phase to process ('spl', 'tpl' or 'vpl') + xpl_data (bytes): Expected data for the phase's binary + + Returns: + dict of .dtb files produced + key: str filename + value: Fdt object + """ + dtb_list = self.SetupAlternateDts()[1] + + entry_args = { + f'{phase}-dtb': '1', + f'{phase}-bss-pad': 'y', + 'of-spl-remove-props': 'prop-to-remove another-prop-to-get-rid-of', + } + data = self._DoReadFileDtb(dts, use_real_dtb=True, update_dtb=True, + use_expanded=True, entry_args=entry_args)[0] + self.assertEqual(xpl_data, data[:len(xpl_data)]) + rest = data[len(xpl_data):] + pad_len = 10 + self.assertEqual(tools.get_bytes(0, pad_len), rest[:pad_len]) + + # Check the dtb is using the test file + dtb_data = rest[pad_len:] + dtb = fdt.Fdt.FromData(dtb_data) + dtb.Scan() + fdt_size = dtb.GetFdtObj().totalsize() + self.assertEqual('model-not-set', + fdt_util.GetString(dtb.GetRoot(), 'compatible')) + + pad_len = 10 + + # Check the other output files + dtbs = {} + for fname in dtb_list: + pathname = tools.get_output_filename(fname) + self.assertTrue(os.path.exists(pathname)) + + data = tools.read_file(pathname) + self.assertEqual(xpl_data, data[:len(xpl_data)]) + rest = data[len(xpl_data):] + + self.assertEqual(tools.get_bytes(0, pad_len), rest[:pad_len]) + rest = rest[pad_len:] + + dtb = fdt.Fdt.FromData(rest) + dtb.Scan() + dtbs[fname] = dtb + + expected = 'one' if '1' in fname else 'two' + self.assertEqual(f'u-boot,model-{expected}', + fdt_util.GetString(dtb.GetRoot(), 'compatible')) + + # Make sure the FDT is the same size as the 'main' one + rest = rest[fdt_size:] + + self.assertEqual(b'', rest) + return dtbs + + def testAlternatesFdt(self): + """Test handling of alternates-fdt etype""" + self._SetupTplElf() + dtbs = self.CheckAlternates('328_alternates_fdt.dts', 'tpl', + U_BOOT_TPL_NODTB_DATA) + for dtb in dtbs.values(): + # Check for the node with the tag + node = dtb.GetNode('/node') + self.assertIsNotNone(node) + self.assertEqual(5, len(node.props.keys())) + + # Make sure the other node is still there + self.assertIsNotNone(dtb.GetNode('/node/other-node')) + + def testAlternatesFdtgrep(self): + """Test handling of alternates-fdt etype using fdtgrep""" + self._SetupTplElf() + dtbs = self.CheckAlternates('329_alternates_fdtgrep.dts', 'tpl', + U_BOOT_TPL_NODTB_DATA) + for dtb in dtbs.values(): + # Check for the node with the tag + node = dtb.GetNode('/node') + self.assertIsNotNone(node) + self.assertEqual({'some-prop', 'not-a-prop-to-remove'}, + node.props.keys()) + + # Make sure the other node is gone + self.assertIsNone(dtb.GetNode('/node/other-node')) + + def testAlternatesFdtgrepVpl(self): + """Test handling of alternates-fdt etype using fdtgrep with vpl""" + self._SetupVplElf() + dtbs = self.CheckAlternates('330_alternates_vpl.dts', 'vpl', + U_BOOT_VPL_NODTB_DATA) + + def testAlternatesFdtgrepSpl(self): + """Test handling of alternates-fdt etype using fdtgrep with spl""" + self._SetupSplElf() + dtbs = self.CheckAlternates('331_alternates_spl.dts', 'spl', + U_BOOT_SPL_NODTB_DATA) + + def testAlternatesFdtgrepInval(self): + """Test alternates-fdt etype using fdtgrep with invalid phase""" + self._SetupSplElf() + with self.assertRaises(ValueError) as e: + dtbs = self.CheckAlternates('332_alternates_inval.dts', 'spl', + U_BOOT_SPL_NODTB_DATA) + self.assertIn("Invalid U-Boot phase 'bad-phase': Use tpl/vpl/spl", + str(e.exception)) + + def testFitFdtListDir(self): + """Test an image with an FIT with FDT images using fit,fdt-list-dir""" + self.CheckFitFdt('333_fit_fdt_dir.dts', False) + + def testFitFdtCompat(self): + """Test an image with an FIT with compatible in the config nodes""" + entry_args = { + 'of-list': 'model1 model2', + 'default-dt': 'model2', + } + testdir, dtb_list = self.SetupAlternateDts() + data = self._DoReadFileDtb( + '334_fit_fdt_compat.dts', use_real_dtb=True, update_dtb=True, + entry_args=entry_args, extra_indirs=[testdir])[0] + + fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)] + + fit = fdt.Fdt.FromData(fit_data) + fit.Scan() + + cnode = fit.GetNode('/configurations') + self.assertIn('default', cnode.props) + self.assertEqual('config-2', cnode.props['default'].value) + + for seq in range(1, 2): + name = f'config-{seq}' + fnode = fit.GetNode('/configurations/%s' % name) + self.assertIsNotNone(fnode) + self.assertIn('compatible', fnode.props.keys()) + expected = 'one' if seq == 1 else 'two' + self.assertEqual(f'u-boot,model-{expected}', + fnode.props['compatible'].value) + + def testFitFdtPhase(self): + """Test an image with an FIT with fdt-phase in the fdt nodes""" + phase = 'tpl' + entry_args = { + f'{phase}-dtb': '1', + f'{phase}-bss-pad': 'y', + 'of-spl-remove-props': 'prop-to-remove another-prop-to-get-rid-of', + 'of-list': 'model1 model2', + 'default-dt': 'model2', + } + testdir, dtb_list = self.SetupAlternateDts() + data = self._DoReadFileDtb( + '335_fit_fdt_phase.dts', use_real_dtb=True, update_dtb=True, + entry_args=entry_args, extra_indirs=[testdir])[0] + fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)] + fit = fdt.Fdt.FromData(fit_data) + fit.Scan() + + # Check that each FDT has only the expected properties for the phase + for seq in range(1, 2): + fnode = fit.GetNode(f'/images/fdt-{seq}') + self.assertIsNotNone(fnode) + dtb = fdt.Fdt.FromData(fnode.props['data'].bytes) + dtb.Scan() + + # Make sure that the 'bootph-pre-sram' tag in /node protects it from + # removal + node = dtb.GetNode('/node') + self.assertIsNotNone(node) + self.assertEqual({'some-prop', 'not-a-prop-to-remove'}, + node.props.keys()) + + # Make sure the other node is gone + self.assertIsNone(dtb.GetNode('/node/other-node')) + if __name__ == "__main__": unittest.main() |