14f44304bSSimon Glass# 24f44304bSSimon Glass# Copyright (c) 2016 Google, Inc 34f44304bSSimon Glass# Written by Simon Glass <sjg@chromium.org> 44f44304bSSimon Glass# 54f44304bSSimon Glass# SPDX-License-Identifier: GPL-2.0+ 64f44304bSSimon Glass# 74f44304bSSimon Glass# To run a single test, change to this directory, and: 84f44304bSSimon Glass# 94f44304bSSimon Glass# python -m unittest func_test.TestFunctional.testHelp 104f44304bSSimon Glass 114f44304bSSimon Glassfrom optparse import OptionParser 124f44304bSSimon Glassimport os 134f44304bSSimon Glassimport shutil 144f44304bSSimon Glassimport struct 154f44304bSSimon Glassimport sys 164f44304bSSimon Glassimport tempfile 174f44304bSSimon Glassimport unittest 184f44304bSSimon Glass 194f44304bSSimon Glassimport binman 204f44304bSSimon Glassimport cmdline 214f44304bSSimon Glassimport command 224f44304bSSimon Glassimport control 234f44304bSSimon Glassimport entry 244f44304bSSimon Glassimport fdt_select 254f44304bSSimon Glassimport fdt_util 264f44304bSSimon Glassimport tools 274f44304bSSimon Glassimport tout 284f44304bSSimon Glass 294f44304bSSimon Glass# Contents of test files, corresponding to different entry types 304f44304bSSimon GlassU_BOOT_DATA = '1234' 314f44304bSSimon GlassU_BOOT_IMG_DATA = 'img' 324f44304bSSimon GlassU_BOOT_SPL_DATA = '567' 334f44304bSSimon GlassBLOB_DATA = '89' 344f44304bSSimon GlassME_DATA = '0abcd' 354f44304bSSimon GlassVGA_DATA = 'vga' 364f44304bSSimon GlassU_BOOT_DTB_DATA = 'udtb' 374f44304bSSimon GlassX86_START16_DATA = 'start16' 384f44304bSSimon GlassU_BOOT_NODTB_DATA = 'nodtb with microcode pointer somewhere in here' 394f44304bSSimon Glass 404f44304bSSimon Glassclass TestFunctional(unittest.TestCase): 414f44304bSSimon Glass """Functional tests for binman 424f44304bSSimon Glass 434f44304bSSimon Glass Most of these use a sample .dts file to build an image and then check 444f44304bSSimon Glass that it looks correct. The sample files are in the test/ subdirectory 454f44304bSSimon Glass and are numbered. 464f44304bSSimon Glass 474f44304bSSimon Glass For each entry type a very small test file is created using fixed 484f44304bSSimon Glass string contents. This makes it easy to test that things look right, and 494f44304bSSimon Glass debug problems. 504f44304bSSimon Glass 514f44304bSSimon Glass In some cases a 'real' file must be used - these are also supplied in 524f44304bSSimon Glass the test/ diurectory. 534f44304bSSimon Glass """ 544f44304bSSimon Glass @classmethod 554f44304bSSimon Glass def setUpClass(self): 564f44304bSSimon Glass # Handle the case where argv[0] is 'python' 574f44304bSSimon Glass self._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0])) 584f44304bSSimon Glass self._binman_pathname = os.path.join(self._binman_dir, 'binman') 594f44304bSSimon Glass 604f44304bSSimon Glass # Create a temporary directory for input files 614f44304bSSimon Glass self._indir = tempfile.mkdtemp(prefix='binmant.') 624f44304bSSimon Glass 634f44304bSSimon Glass # Create some test files 644f44304bSSimon Glass TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA) 654f44304bSSimon Glass TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA) 664f44304bSSimon Glass TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA) 674f44304bSSimon Glass TestFunctional._MakeInputFile('blobfile', BLOB_DATA) 68*e0ff8551SSimon Glass TestFunctional._MakeInputFile('me.bin', ME_DATA) 69*e0ff8551SSimon Glass TestFunctional._MakeInputFile('vga.bin', VGA_DATA) 704f44304bSSimon Glass TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA) 71*e0ff8551SSimon Glass TestFunctional._MakeInputFile('u-boot-x86-16bit.bin', X86_START16_DATA) 724f44304bSSimon Glass TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA) 734f44304bSSimon Glass self._output_setup = False 744f44304bSSimon Glass 75*e0ff8551SSimon Glass # ELF file with a '_dt_ucode_base_size' symbol 76*e0ff8551SSimon Glass with open(self.TestFile('u_boot_ucode_ptr')) as fd: 77*e0ff8551SSimon Glass TestFunctional._MakeInputFile('u-boot', fd.read()) 78*e0ff8551SSimon Glass 79*e0ff8551SSimon Glass # Intel flash descriptor file 80*e0ff8551SSimon Glass with open(self.TestFile('descriptor.bin')) as fd: 81*e0ff8551SSimon Glass TestFunctional._MakeInputFile('descriptor.bin', fd.read()) 82*e0ff8551SSimon Glass 834f44304bSSimon Glass @classmethod 844f44304bSSimon Glass def tearDownClass(self): 854f44304bSSimon Glass """Remove the temporary input directory and its contents""" 864f44304bSSimon Glass if self._indir: 874f44304bSSimon Glass shutil.rmtree(self._indir) 884f44304bSSimon Glass self._indir = None 894f44304bSSimon Glass 904f44304bSSimon Glass def setUp(self): 914f44304bSSimon Glass # Enable this to turn on debugging output 924f44304bSSimon Glass # tout.Init(tout.DEBUG) 934f44304bSSimon Glass command.test_result = None 944f44304bSSimon Glass 954f44304bSSimon Glass def tearDown(self): 964f44304bSSimon Glass """Remove the temporary output directory""" 974f44304bSSimon Glass tools._FinaliseForTest() 984f44304bSSimon Glass 994f44304bSSimon Glass def _RunBinman(self, *args, **kwargs): 1004f44304bSSimon Glass """Run binman using the command line 1014f44304bSSimon Glass 1024f44304bSSimon Glass Args: 1034f44304bSSimon Glass Arguments to pass, as a list of strings 1044f44304bSSimon Glass kwargs: Arguments to pass to Command.RunPipe() 1054f44304bSSimon Glass """ 1064f44304bSSimon Glass result = command.RunPipe([[self._binman_pathname] + list(args)], 1074f44304bSSimon Glass capture=True, capture_stderr=True, raise_on_error=False) 1084f44304bSSimon Glass if result.return_code and kwargs.get('raise_on_error', True): 1094f44304bSSimon Glass raise Exception("Error running '%s': %s" % (' '.join(args), 1104f44304bSSimon Glass result.stdout + result.stderr)) 1114f44304bSSimon Glass return result 1124f44304bSSimon Glass 1134f44304bSSimon Glass def _DoBinman(self, *args): 1144f44304bSSimon Glass """Run binman using directly (in the same process) 1154f44304bSSimon Glass 1164f44304bSSimon Glass Args: 1174f44304bSSimon Glass Arguments to pass, as a list of strings 1184f44304bSSimon Glass Returns: 1194f44304bSSimon Glass Return value (0 for success) 1204f44304bSSimon Glass """ 1214f44304bSSimon Glass (options, args) = cmdline.ParseArgs(list(args)) 1224f44304bSSimon Glass options.pager = 'binman-invalid-pager' 1234f44304bSSimon Glass options.build_dir = self._indir 1244f44304bSSimon Glass 1254f44304bSSimon Glass # For testing, you can force an increase in verbosity here 1264f44304bSSimon Glass # options.verbosity = tout.DEBUG 1274f44304bSSimon Glass return control.Binman(options, args) 1284f44304bSSimon Glass 1294f44304bSSimon Glass def _DoTestFile(self, fname): 1304f44304bSSimon Glass """Run binman with a given test file 1314f44304bSSimon Glass 1324f44304bSSimon Glass Args: 1334f44304bSSimon Glass fname: Device tree source filename to use (e.g. 05_simple.dts) 1344f44304bSSimon Glass """ 1354f44304bSSimon Glass return self._DoBinman('-p', '-I', self._indir, 1364f44304bSSimon Glass '-d', self.TestFile(fname)) 1374f44304bSSimon Glass 1384f44304bSSimon Glass def _SetupDtb(self, fname, outfile='u-boot.dtb'): 139*e0ff8551SSimon Glass """Set up a new test device-tree file 140*e0ff8551SSimon Glass 141*e0ff8551SSimon Glass The given file is compiled and set up as the device tree to be used 142*e0ff8551SSimon Glass for ths test. 143*e0ff8551SSimon Glass 144*e0ff8551SSimon Glass Args: 145*e0ff8551SSimon Glass fname: Filename of .dts file to read 146*e0ff8551SSimon Glass outfile: Output filename for compiled device tree binary 147*e0ff8551SSimon Glass 148*e0ff8551SSimon Glass Returns: 149*e0ff8551SSimon Glass Contents of device tree binary 150*e0ff8551SSimon Glass """ 1514f44304bSSimon Glass if not self._output_setup: 1524f44304bSSimon Glass tools.PrepareOutputDir(self._indir, True) 1534f44304bSSimon Glass self._output_setup = True 1544f44304bSSimon Glass dtb = fdt_util.EnsureCompiled(self.TestFile(fname)) 1554f44304bSSimon Glass with open(dtb) as fd: 1564f44304bSSimon Glass data = fd.read() 1574f44304bSSimon Glass TestFunctional._MakeInputFile(outfile, data) 158*e0ff8551SSimon Glass return data 1594f44304bSSimon Glass 160*e0ff8551SSimon Glass def _DoReadFileDtb(self, fname, use_real_dtb=False): 1614f44304bSSimon Glass """Run binman and return the resulting image 1624f44304bSSimon Glass 1634f44304bSSimon Glass This runs binman with a given test file and then reads the resulting 1644f44304bSSimon Glass output file. It is a shortcut function since most tests need to do 1654f44304bSSimon Glass these steps. 1664f44304bSSimon Glass 1674f44304bSSimon Glass Raises an assertion failure if binman returns a non-zero exit code. 1684f44304bSSimon Glass 1694f44304bSSimon Glass Args: 1704f44304bSSimon Glass fname: Device tree source filename to use (e.g. 05_simple.dts) 1714f44304bSSimon Glass use_real_dtb: True to use the test file as the contents of 1724f44304bSSimon Glass the u-boot-dtb entry. Normally this is not needed and the 1734f44304bSSimon Glass test contents (the U_BOOT_DTB_DATA string) can be used. 1744f44304bSSimon Glass But in some test we need the real contents. 175*e0ff8551SSimon Glass 176*e0ff8551SSimon Glass Returns: 177*e0ff8551SSimon Glass Tuple: 178*e0ff8551SSimon Glass Resulting image contents 179*e0ff8551SSimon Glass Device tree contents 1804f44304bSSimon Glass """ 181*e0ff8551SSimon Glass dtb_data = None 1824f44304bSSimon Glass # Use the compiled test file as the u-boot-dtb input 1834f44304bSSimon Glass if use_real_dtb: 184*e0ff8551SSimon Glass dtb_data = self._SetupDtb(fname) 1854f44304bSSimon Glass 1864f44304bSSimon Glass try: 1874f44304bSSimon Glass retcode = self._DoTestFile(fname) 1884f44304bSSimon Glass self.assertEqual(0, retcode) 1894f44304bSSimon Glass 1904f44304bSSimon Glass # Find the (only) image, read it and return its contents 1914f44304bSSimon Glass image = control.images['image'] 1924f44304bSSimon Glass fname = tools.GetOutputFilename('image.bin') 1934f44304bSSimon Glass self.assertTrue(os.path.exists(fname)) 1944f44304bSSimon Glass with open(fname) as fd: 195*e0ff8551SSimon Glass return fd.read(), dtb_data 1964f44304bSSimon Glass finally: 1974f44304bSSimon Glass # Put the test file back 1984f44304bSSimon Glass if use_real_dtb: 1994f44304bSSimon Glass TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA) 2004f44304bSSimon Glass 201*e0ff8551SSimon Glass def _DoReadFile(self, fname, use_real_dtb=False): 202*e0ff8551SSimon Glass """Helper function which discards the device-tree binary""" 203*e0ff8551SSimon Glass return self._DoReadFileDtb(fname, use_real_dtb)[0] 204*e0ff8551SSimon Glass 2054f44304bSSimon Glass @classmethod 2064f44304bSSimon Glass def _MakeInputFile(self, fname, contents): 2074f44304bSSimon Glass """Create a new test input file, creating directories as needed 2084f44304bSSimon Glass 2094f44304bSSimon Glass Args: 2104f44304bSSimon Glass fname: Filenaem to create 2114f44304bSSimon Glass contents: File contents to write in to the file 2124f44304bSSimon Glass Returns: 2134f44304bSSimon Glass Full pathname of file created 2144f44304bSSimon Glass """ 2154f44304bSSimon Glass pathname = os.path.join(self._indir, fname) 2164f44304bSSimon Glass dirname = os.path.dirname(pathname) 2174f44304bSSimon Glass if dirname and not os.path.exists(dirname): 2184f44304bSSimon Glass os.makedirs(dirname) 2194f44304bSSimon Glass with open(pathname, 'wb') as fd: 2204f44304bSSimon Glass fd.write(contents) 2214f44304bSSimon Glass return pathname 2224f44304bSSimon Glass 2234f44304bSSimon Glass @classmethod 2244f44304bSSimon Glass def TestFile(self, fname): 2254f44304bSSimon Glass return os.path.join(self._binman_dir, 'test', fname) 2264f44304bSSimon Glass 2274f44304bSSimon Glass def AssertInList(self, grep_list, target): 2284f44304bSSimon Glass """Assert that at least one of a list of things is in a target 2294f44304bSSimon Glass 2304f44304bSSimon Glass Args: 2314f44304bSSimon Glass grep_list: List of strings to check 2324f44304bSSimon Glass target: Target string 2334f44304bSSimon Glass """ 2344f44304bSSimon Glass for grep in grep_list: 2354f44304bSSimon Glass if grep in target: 2364f44304bSSimon Glass return 2374f44304bSSimon Glass self.fail("Error: '%' not found in '%s'" % (grep_list, target)) 2384f44304bSSimon Glass 2394f44304bSSimon Glass def CheckNoGaps(self, entries): 2404f44304bSSimon Glass """Check that all entries fit together without gaps 2414f44304bSSimon Glass 2424f44304bSSimon Glass Args: 2434f44304bSSimon Glass entries: List of entries to check 2444f44304bSSimon Glass """ 2454f44304bSSimon Glass pos = 0 2464f44304bSSimon Glass for entry in entries.values(): 2474f44304bSSimon Glass self.assertEqual(pos, entry.pos) 2484f44304bSSimon Glass pos += entry.size 2494f44304bSSimon Glass 250*e0ff8551SSimon Glass def GetFdtLen(self, dtb): 251*e0ff8551SSimon Glass """Get the totalsize field from a device tree binary 252*e0ff8551SSimon Glass 253*e0ff8551SSimon Glass Args: 254*e0ff8551SSimon Glass dtb: Device tree binary contents 255*e0ff8551SSimon Glass 256*e0ff8551SSimon Glass Returns: 257*e0ff8551SSimon Glass Total size of device tree binary, from the header 258*e0ff8551SSimon Glass """ 259*e0ff8551SSimon Glass return struct.unpack('>L', dtb[4:8])[0] 260*e0ff8551SSimon Glass 2614f44304bSSimon Glass def testRun(self): 2624f44304bSSimon Glass """Test a basic run with valid args""" 2634f44304bSSimon Glass result = self._RunBinman('-h') 2644f44304bSSimon Glass 2654f44304bSSimon Glass def testFullHelp(self): 2664f44304bSSimon Glass """Test that the full help is displayed with -H""" 2674f44304bSSimon Glass result = self._RunBinman('-H') 2684f44304bSSimon Glass help_file = os.path.join(self._binman_dir, 'README') 2694f44304bSSimon Glass self.assertEqual(len(result.stdout), os.path.getsize(help_file)) 2704f44304bSSimon Glass self.assertEqual(0, len(result.stderr)) 2714f44304bSSimon Glass self.assertEqual(0, result.return_code) 2724f44304bSSimon Glass 2734f44304bSSimon Glass def testFullHelpInternal(self): 2744f44304bSSimon Glass """Test that the full help is displayed with -H""" 2754f44304bSSimon Glass try: 2764f44304bSSimon Glass command.test_result = command.CommandResult() 2774f44304bSSimon Glass result = self._DoBinman('-H') 2784f44304bSSimon Glass help_file = os.path.join(self._binman_dir, 'README') 2794f44304bSSimon Glass finally: 2804f44304bSSimon Glass command.test_result = None 2814f44304bSSimon Glass 2824f44304bSSimon Glass def testHelp(self): 2834f44304bSSimon Glass """Test that the basic help is displayed with -h""" 2844f44304bSSimon Glass result = self._RunBinman('-h') 2854f44304bSSimon Glass self.assertTrue(len(result.stdout) > 200) 2864f44304bSSimon Glass self.assertEqual(0, len(result.stderr)) 2874f44304bSSimon Glass self.assertEqual(0, result.return_code) 2884f44304bSSimon Glass 2894f44304bSSimon Glass # Not yet available. 2904f44304bSSimon Glass def testBoard(self): 2914f44304bSSimon Glass """Test that we can run it with a specific board""" 2924f44304bSSimon Glass self._SetupDtb('05_simple.dts', 'sandbox/u-boot.dtb') 2934f44304bSSimon Glass TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA) 2944f44304bSSimon Glass result = self._DoBinman('-b', 'sandbox') 2954f44304bSSimon Glass self.assertEqual(0, result) 2964f44304bSSimon Glass 2974f44304bSSimon Glass def testNeedBoard(self): 2984f44304bSSimon Glass """Test that we get an error when no board ius supplied""" 2994f44304bSSimon Glass with self.assertRaises(ValueError) as e: 3004f44304bSSimon Glass result = self._DoBinman() 3014f44304bSSimon Glass self.assertIn("Must provide a board to process (use -b <board>)", 3024f44304bSSimon Glass str(e.exception)) 3034f44304bSSimon Glass 3044f44304bSSimon Glass def testMissingDt(self): 3054f44304bSSimon Glass """Test that an invalid device tree file generates an error""" 3064f44304bSSimon Glass with self.assertRaises(Exception) as e: 3074f44304bSSimon Glass self._RunBinman('-d', 'missing_file') 3084f44304bSSimon Glass # We get one error from libfdt, and a different one from fdtget. 3094f44304bSSimon Glass self.AssertInList(["Couldn't open blob from 'missing_file'", 3104f44304bSSimon Glass 'No such file or directory'], str(e.exception)) 3114f44304bSSimon Glass 3124f44304bSSimon Glass def testBrokenDt(self): 3134f44304bSSimon Glass """Test that an invalid device tree source file generates an error 3144f44304bSSimon Glass 3154f44304bSSimon Glass Since this is a source file it should be compiled and the error 3164f44304bSSimon Glass will come from the device-tree compiler (dtc). 3174f44304bSSimon Glass """ 3184f44304bSSimon Glass with self.assertRaises(Exception) as e: 3194f44304bSSimon Glass self._RunBinman('-d', self.TestFile('01_invalid.dts')) 3204f44304bSSimon Glass self.assertIn("FATAL ERROR: Unable to parse input tree", 3214f44304bSSimon Glass str(e.exception)) 3224f44304bSSimon Glass 3234f44304bSSimon Glass def testMissingNode(self): 3244f44304bSSimon Glass """Test that a device tree without a 'binman' node generates an error""" 3254f44304bSSimon Glass with self.assertRaises(Exception) as e: 3264f44304bSSimon Glass self._DoBinman('-d', self.TestFile('02_missing_node.dts')) 3274f44304bSSimon Glass self.assertIn("does not have a 'binman' node", str(e.exception)) 3284f44304bSSimon Glass 3294f44304bSSimon Glass def testEmpty(self): 3304f44304bSSimon Glass """Test that an empty binman node works OK (i.e. does nothing)""" 3314f44304bSSimon Glass result = self._RunBinman('-d', self.TestFile('03_empty.dts')) 3324f44304bSSimon Glass self.assertEqual(0, len(result.stderr)) 3334f44304bSSimon Glass self.assertEqual(0, result.return_code) 3344f44304bSSimon Glass 3354f44304bSSimon Glass def testInvalidEntry(self): 3364f44304bSSimon Glass """Test that an invalid entry is flagged""" 3374f44304bSSimon Glass with self.assertRaises(Exception) as e: 3384f44304bSSimon Glass result = self._RunBinman('-d', 3394f44304bSSimon Glass self.TestFile('04_invalid_entry.dts')) 3404f44304bSSimon Glass #print e.exception 3414f44304bSSimon Glass self.assertIn("Unknown entry type 'not-a-valid-type' in node " 3424f44304bSSimon Glass "'/binman/not-a-valid-type'", str(e.exception)) 3434f44304bSSimon Glass 3444f44304bSSimon Glass def testSimple(self): 3454f44304bSSimon Glass """Test a simple binman with a single file""" 3464f44304bSSimon Glass data = self._DoReadFile('05_simple.dts') 3474f44304bSSimon Glass self.assertEqual(U_BOOT_DATA, data) 3484f44304bSSimon Glass 3494f44304bSSimon Glass def testDual(self): 3504f44304bSSimon Glass """Test that we can handle creating two images 3514f44304bSSimon Glass 3524f44304bSSimon Glass This also tests image padding. 3534f44304bSSimon Glass """ 3544f44304bSSimon Glass retcode = self._DoTestFile('06_dual_image.dts') 3554f44304bSSimon Glass self.assertEqual(0, retcode) 3564f44304bSSimon Glass 3574f44304bSSimon Glass image = control.images['image1'] 3584f44304bSSimon Glass self.assertEqual(len(U_BOOT_DATA), image._size) 3594f44304bSSimon Glass fname = tools.GetOutputFilename('image1.bin') 3604f44304bSSimon Glass self.assertTrue(os.path.exists(fname)) 3614f44304bSSimon Glass with open(fname) as fd: 3624f44304bSSimon Glass data = fd.read() 3634f44304bSSimon Glass self.assertEqual(U_BOOT_DATA, data) 3644f44304bSSimon Glass 3654f44304bSSimon Glass image = control.images['image2'] 3664f44304bSSimon Glass self.assertEqual(3 + len(U_BOOT_DATA) + 5, image._size) 3674f44304bSSimon Glass fname = tools.GetOutputFilename('image2.bin') 3684f44304bSSimon Glass self.assertTrue(os.path.exists(fname)) 3694f44304bSSimon Glass with open(fname) as fd: 3704f44304bSSimon Glass data = fd.read() 3714f44304bSSimon Glass self.assertEqual(U_BOOT_DATA, data[3:7]) 3724f44304bSSimon Glass self.assertEqual(chr(0) * 3, data[:3]) 3734f44304bSSimon Glass self.assertEqual(chr(0) * 5, data[7:]) 3744f44304bSSimon Glass 3754f44304bSSimon Glass def testBadAlign(self): 3764f44304bSSimon Glass """Test that an invalid alignment value is detected""" 3774f44304bSSimon Glass with self.assertRaises(ValueError) as e: 3784f44304bSSimon Glass self._DoTestFile('07_bad_align.dts') 3794f44304bSSimon Glass self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power " 3804f44304bSSimon Glass "of two", str(e.exception)) 3814f44304bSSimon Glass 3824f44304bSSimon Glass def testPackSimple(self): 3834f44304bSSimon Glass """Test that packing works as expected""" 3844f44304bSSimon Glass retcode = self._DoTestFile('08_pack.dts') 3854f44304bSSimon Glass self.assertEqual(0, retcode) 3864f44304bSSimon Glass self.assertIn('image', control.images) 3874f44304bSSimon Glass image = control.images['image'] 3884f44304bSSimon Glass entries = image._entries 3894f44304bSSimon Glass self.assertEqual(5, len(entries)) 3904f44304bSSimon Glass 3914f44304bSSimon Glass # First u-boot 3924f44304bSSimon Glass self.assertIn('u-boot', entries) 3934f44304bSSimon Glass entry = entries['u-boot'] 3944f44304bSSimon Glass self.assertEqual(0, entry.pos) 3954f44304bSSimon Glass self.assertEqual(len(U_BOOT_DATA), entry.size) 3964f44304bSSimon Glass 3974f44304bSSimon Glass # Second u-boot, aligned to 16-byte boundary 3984f44304bSSimon Glass self.assertIn('u-boot-align', entries) 3994f44304bSSimon Glass entry = entries['u-boot-align'] 4004f44304bSSimon Glass self.assertEqual(16, entry.pos) 4014f44304bSSimon Glass self.assertEqual(len(U_BOOT_DATA), entry.size) 4024f44304bSSimon Glass 4034f44304bSSimon Glass # Third u-boot, size 23 bytes 4044f44304bSSimon Glass self.assertIn('u-boot-size', entries) 4054f44304bSSimon Glass entry = entries['u-boot-size'] 4064f44304bSSimon Glass self.assertEqual(20, entry.pos) 4074f44304bSSimon Glass self.assertEqual(len(U_BOOT_DATA), entry.contents_size) 4084f44304bSSimon Glass self.assertEqual(23, entry.size) 4094f44304bSSimon Glass 4104f44304bSSimon Glass # Fourth u-boot, placed immediate after the above 4114f44304bSSimon Glass self.assertIn('u-boot-next', entries) 4124f44304bSSimon Glass entry = entries['u-boot-next'] 4134f44304bSSimon Glass self.assertEqual(43, entry.pos) 4144f44304bSSimon Glass self.assertEqual(len(U_BOOT_DATA), entry.size) 4154f44304bSSimon Glass 4164f44304bSSimon Glass # Fifth u-boot, placed at a fixed position 4174f44304bSSimon Glass self.assertIn('u-boot-fixed', entries) 4184f44304bSSimon Glass entry = entries['u-boot-fixed'] 4194f44304bSSimon Glass self.assertEqual(61, entry.pos) 4204f44304bSSimon Glass self.assertEqual(len(U_BOOT_DATA), entry.size) 4214f44304bSSimon Glass 4224f44304bSSimon Glass self.assertEqual(65, image._size) 4234f44304bSSimon Glass 4244f44304bSSimon Glass def testPackExtra(self): 4254f44304bSSimon Glass """Test that extra packing feature works as expected""" 4264f44304bSSimon Glass retcode = self._DoTestFile('09_pack_extra.dts') 4274f44304bSSimon Glass 4284f44304bSSimon Glass self.assertEqual(0, retcode) 4294f44304bSSimon Glass self.assertIn('image', control.images) 4304f44304bSSimon Glass image = control.images['image'] 4314f44304bSSimon Glass entries = image._entries 4324f44304bSSimon Glass self.assertEqual(5, len(entries)) 4334f44304bSSimon Glass 4344f44304bSSimon Glass # First u-boot with padding before and after 4354f44304bSSimon Glass self.assertIn('u-boot', entries) 4364f44304bSSimon Glass entry = entries['u-boot'] 4374f44304bSSimon Glass self.assertEqual(0, entry.pos) 4384f44304bSSimon Glass self.assertEqual(3, entry.pad_before) 4394f44304bSSimon Glass self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size) 4404f44304bSSimon Glass 4414f44304bSSimon Glass # Second u-boot has an aligned size, but it has no effect 4424f44304bSSimon Glass self.assertIn('u-boot-align-size-nop', entries) 4434f44304bSSimon Glass entry = entries['u-boot-align-size-nop'] 4444f44304bSSimon Glass self.assertEqual(12, entry.pos) 4454f44304bSSimon Glass self.assertEqual(4, entry.size) 4464f44304bSSimon Glass 4474f44304bSSimon Glass # Third u-boot has an aligned size too 4484f44304bSSimon Glass self.assertIn('u-boot-align-size', entries) 4494f44304bSSimon Glass entry = entries['u-boot-align-size'] 4504f44304bSSimon Glass self.assertEqual(16, entry.pos) 4514f44304bSSimon Glass self.assertEqual(32, entry.size) 4524f44304bSSimon Glass 4534f44304bSSimon Glass # Fourth u-boot has an aligned end 4544f44304bSSimon Glass self.assertIn('u-boot-align-end', entries) 4554f44304bSSimon Glass entry = entries['u-boot-align-end'] 4564f44304bSSimon Glass self.assertEqual(48, entry.pos) 4574f44304bSSimon Glass self.assertEqual(16, entry.size) 4584f44304bSSimon Glass 4594f44304bSSimon Glass # Fifth u-boot immediately afterwards 4604f44304bSSimon Glass self.assertIn('u-boot-align-both', entries) 4614f44304bSSimon Glass entry = entries['u-boot-align-both'] 4624f44304bSSimon Glass self.assertEqual(64, entry.pos) 4634f44304bSSimon Glass self.assertEqual(64, entry.size) 4644f44304bSSimon Glass 4654f44304bSSimon Glass self.CheckNoGaps(entries) 4664f44304bSSimon Glass self.assertEqual(128, image._size) 4674f44304bSSimon Glass 4684f44304bSSimon Glass def testPackAlignPowerOf2(self): 4694f44304bSSimon Glass """Test that invalid entry alignment is detected""" 4704f44304bSSimon Glass with self.assertRaises(ValueError) as e: 4714f44304bSSimon Glass self._DoTestFile('10_pack_align_power2.dts') 4724f44304bSSimon Glass self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power " 4734f44304bSSimon Glass "of two", str(e.exception)) 4744f44304bSSimon Glass 4754f44304bSSimon Glass def testPackAlignSizePowerOf2(self): 4764f44304bSSimon Glass """Test that invalid entry size alignment is detected""" 4774f44304bSSimon Glass with self.assertRaises(ValueError) as e: 4784f44304bSSimon Glass self._DoTestFile('11_pack_align_size_power2.dts') 4794f44304bSSimon Glass self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a " 4804f44304bSSimon Glass "power of two", str(e.exception)) 4814f44304bSSimon Glass 4824f44304bSSimon Glass def testPackInvalidAlign(self): 4834f44304bSSimon Glass """Test detection of an position that does not match its alignment""" 4844f44304bSSimon Glass with self.assertRaises(ValueError) as e: 4854f44304bSSimon Glass self._DoTestFile('12_pack_inv_align.dts') 4864f44304bSSimon Glass self.assertIn("Node '/binman/u-boot': Position 0x5 (5) does not match " 4874f44304bSSimon Glass "align 0x4 (4)", str(e.exception)) 4884f44304bSSimon Glass 4894f44304bSSimon Glass def testPackInvalidSizeAlign(self): 4904f44304bSSimon Glass """Test that invalid entry size alignment is detected""" 4914f44304bSSimon Glass with self.assertRaises(ValueError) as e: 4924f44304bSSimon Glass self._DoTestFile('13_pack_inv_size_align.dts') 4934f44304bSSimon Glass self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match " 4944f44304bSSimon Glass "align-size 0x4 (4)", str(e.exception)) 4954f44304bSSimon Glass 4964f44304bSSimon Glass def testPackOverlap(self): 4974f44304bSSimon Glass """Test that overlapping regions are detected""" 4984f44304bSSimon Glass with self.assertRaises(ValueError) as e: 4994f44304bSSimon Glass self._DoTestFile('14_pack_overlap.dts') 5004f44304bSSimon Glass self.assertIn("Node '/binman/u-boot-align': Position 0x3 (3) overlaps " 5014f44304bSSimon Glass "with previous entry '/binman/u-boot' ending at 0x4 (4)", 5024f44304bSSimon Glass str(e.exception)) 5034f44304bSSimon Glass 5044f44304bSSimon Glass def testPackEntryOverflow(self): 5054f44304bSSimon Glass """Test that entries that overflow their size are detected""" 5064f44304bSSimon Glass with self.assertRaises(ValueError) as e: 5074f44304bSSimon Glass self._DoTestFile('15_pack_overflow.dts') 5084f44304bSSimon Glass self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) " 5094f44304bSSimon Glass "but entry size is 0x3 (3)", str(e.exception)) 5104f44304bSSimon Glass 5114f44304bSSimon Glass def testPackImageOverflow(self): 5124f44304bSSimon Glass """Test that entries which overflow the image size are detected""" 5134f44304bSSimon Glass with self.assertRaises(ValueError) as e: 5144f44304bSSimon Glass self._DoTestFile('16_pack_image_overflow.dts') 5154f44304bSSimon Glass self.assertIn("Image '/binman': contents size 0x4 (4) exceeds image " 5164f44304bSSimon Glass "size 0x3 (3)", str(e.exception)) 5174f44304bSSimon Glass 5184f44304bSSimon Glass def testPackImageSize(self): 5194f44304bSSimon Glass """Test that the image size can be set""" 5204f44304bSSimon Glass retcode = self._DoTestFile('17_pack_image_size.dts') 5214f44304bSSimon Glass self.assertEqual(0, retcode) 5224f44304bSSimon Glass self.assertIn('image', control.images) 5234f44304bSSimon Glass image = control.images['image'] 5244f44304bSSimon Glass self.assertEqual(7, image._size) 5254f44304bSSimon Glass 5264f44304bSSimon Glass def testPackImageSizeAlign(self): 5274f44304bSSimon Glass """Test that image size alignemnt works as expected""" 5284f44304bSSimon Glass retcode = self._DoTestFile('18_pack_image_align.dts') 5294f44304bSSimon Glass self.assertEqual(0, retcode) 5304f44304bSSimon Glass self.assertIn('image', control.images) 5314f44304bSSimon Glass image = control.images['image'] 5324f44304bSSimon Glass self.assertEqual(16, image._size) 5334f44304bSSimon Glass 5344f44304bSSimon Glass def testPackInvalidImageAlign(self): 5354f44304bSSimon Glass """Test that invalid image alignment is detected""" 5364f44304bSSimon Glass with self.assertRaises(ValueError) as e: 5374f44304bSSimon Glass self._DoTestFile('19_pack_inv_image_align.dts') 5384f44304bSSimon Glass self.assertIn("Image '/binman': Size 0x7 (7) does not match " 5394f44304bSSimon Glass "align-size 0x8 (8)", str(e.exception)) 5404f44304bSSimon Glass 5414f44304bSSimon Glass def testPackAlignPowerOf2(self): 5424f44304bSSimon Glass """Test that invalid image alignment is detected""" 5434f44304bSSimon Glass with self.assertRaises(ValueError) as e: 5444f44304bSSimon Glass self._DoTestFile('20_pack_inv_image_align_power2.dts') 5454f44304bSSimon Glass self.assertIn("Image '/binman': Alignment size 131 must be a power of " 5464f44304bSSimon Glass "two", str(e.exception)) 5474f44304bSSimon Glass 5484f44304bSSimon Glass def testImagePadByte(self): 5494f44304bSSimon Glass """Test that the image pad byte can be specified""" 5504f44304bSSimon Glass data = self._DoReadFile('21_image_pad.dts') 5514f44304bSSimon Glass self.assertEqual(U_BOOT_SPL_DATA + (chr(0xff) * 9) + U_BOOT_DATA, data) 5524f44304bSSimon Glass 5534f44304bSSimon Glass def testImageName(self): 5544f44304bSSimon Glass """Test that image files can be named""" 5554f44304bSSimon Glass retcode = self._DoTestFile('22_image_name.dts') 5564f44304bSSimon Glass self.assertEqual(0, retcode) 5574f44304bSSimon Glass image = control.images['image1'] 5584f44304bSSimon Glass fname = tools.GetOutputFilename('test-name') 5594f44304bSSimon Glass self.assertTrue(os.path.exists(fname)) 5604f44304bSSimon Glass 5614f44304bSSimon Glass image = control.images['image2'] 5624f44304bSSimon Glass fname = tools.GetOutputFilename('test-name.xx') 5634f44304bSSimon Glass self.assertTrue(os.path.exists(fname)) 5644f44304bSSimon Glass 5654f44304bSSimon Glass def testBlobFilename(self): 5664f44304bSSimon Glass """Test that generic blobs can be provided by filename""" 5674f44304bSSimon Glass data = self._DoReadFile('23_blob.dts') 5684f44304bSSimon Glass self.assertEqual(BLOB_DATA, data) 5694f44304bSSimon Glass 5704f44304bSSimon Glass def testPackSorted(self): 5714f44304bSSimon Glass """Test that entries can be sorted""" 5724f44304bSSimon Glass data = self._DoReadFile('24_sorted.dts') 5734f44304bSSimon Glass self.assertEqual(chr(0) * 5 + U_BOOT_SPL_DATA + chr(0) * 2 + 5744f44304bSSimon Glass U_BOOT_DATA, data) 5754f44304bSSimon Glass 5764f44304bSSimon Glass def testPackZeroPosition(self): 5774f44304bSSimon Glass """Test that an entry at position 0 is not given a new position""" 5784f44304bSSimon Glass with self.assertRaises(ValueError) as e: 5794f44304bSSimon Glass self._DoTestFile('25_pack_zero_size.dts') 5804f44304bSSimon Glass self.assertIn("Node '/binman/u-boot-spl': Position 0x0 (0) overlaps " 5814f44304bSSimon Glass "with previous entry '/binman/u-boot' ending at 0x4 (4)", 5824f44304bSSimon Glass str(e.exception)) 5834f44304bSSimon Glass 5844f44304bSSimon Glass def testPackUbootDtb(self): 5854f44304bSSimon Glass """Test that a device tree can be added to U-Boot""" 5864f44304bSSimon Glass data = self._DoReadFile('26_pack_u_boot_dtb.dts') 5874f44304bSSimon Glass self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data) 588*e0ff8551SSimon Glass 589*e0ff8551SSimon Glass def testPackX86RomNoSize(self): 590*e0ff8551SSimon Glass """Test that the end-at-4gb property requires a size property""" 591*e0ff8551SSimon Glass with self.assertRaises(ValueError) as e: 592*e0ff8551SSimon Glass self._DoTestFile('27_pack_4gb_no_size.dts') 593*e0ff8551SSimon Glass self.assertIn("Image '/binman': Image size must be provided when " 594*e0ff8551SSimon Glass "using end-at-4gb", str(e.exception)) 595*e0ff8551SSimon Glass 596*e0ff8551SSimon Glass def testPackX86RomOutside(self): 597*e0ff8551SSimon Glass """Test that the end-at-4gb property checks for position boundaries""" 598*e0ff8551SSimon Glass with self.assertRaises(ValueError) as e: 599*e0ff8551SSimon Glass self._DoTestFile('28_pack_4gb_outside.dts') 600*e0ff8551SSimon Glass self.assertIn("Node '/binman/u-boot': Position 0x0 (0) is outside " 601*e0ff8551SSimon Glass "the image starting at 0xfffffff0 (4294967280)", 602*e0ff8551SSimon Glass str(e.exception)) 603*e0ff8551SSimon Glass 604*e0ff8551SSimon Glass def testPackX86Rom(self): 605*e0ff8551SSimon Glass """Test that a basic x86 ROM can be created""" 606*e0ff8551SSimon Glass data = self._DoReadFile('29_x86-rom.dts') 607*e0ff8551SSimon Glass self.assertEqual(U_BOOT_DATA + chr(0) * 3 + U_BOOT_SPL_DATA + 608*e0ff8551SSimon Glass chr(0) * 6, data) 609*e0ff8551SSimon Glass 610*e0ff8551SSimon Glass def testPackX86RomMeNoDesc(self): 611*e0ff8551SSimon Glass """Test that an invalid Intel descriptor entry is detected""" 612*e0ff8551SSimon Glass TestFunctional._MakeInputFile('descriptor.bin', '') 613*e0ff8551SSimon Glass with self.assertRaises(ValueError) as e: 614*e0ff8551SSimon Glass self._DoTestFile('31_x86-rom-me.dts') 615*e0ff8551SSimon Glass self.assertIn("Node '/binman/intel-descriptor': Cannot find FD " 616*e0ff8551SSimon Glass "signature", str(e.exception)) 617*e0ff8551SSimon Glass 618*e0ff8551SSimon Glass def testPackX86RomBadDesc(self): 619*e0ff8551SSimon Glass """Test that the Intel requires a descriptor entry""" 620*e0ff8551SSimon Glass with self.assertRaises(ValueError) as e: 621*e0ff8551SSimon Glass self._DoTestFile('30_x86-rom-me-no-desc.dts') 622*e0ff8551SSimon Glass self.assertIn("Node '/binman/intel-me': No position set with " 623*e0ff8551SSimon Glass "pos-unset: should another entry provide this correct " 624*e0ff8551SSimon Glass "position?", str(e.exception)) 625*e0ff8551SSimon Glass 626*e0ff8551SSimon Glass def testPackX86RomMe(self): 627*e0ff8551SSimon Glass """Test that an x86 ROM with an ME region can be created""" 628*e0ff8551SSimon Glass data = self._DoReadFile('31_x86-rom-me.dts') 629*e0ff8551SSimon Glass self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)]) 630*e0ff8551SSimon Glass 631*e0ff8551SSimon Glass def testPackVga(self): 632*e0ff8551SSimon Glass """Test that an image with a VGA binary can be created""" 633*e0ff8551SSimon Glass data = self._DoReadFile('32_intel-vga.dts') 634*e0ff8551SSimon Glass self.assertEqual(VGA_DATA, data[:len(VGA_DATA)]) 635*e0ff8551SSimon Glass 636*e0ff8551SSimon Glass def testPackStart16(self): 637*e0ff8551SSimon Glass """Test that an image with an x86 start16 region can be created""" 638*e0ff8551SSimon Glass data = self._DoReadFile('33_x86-start16.dts') 639*e0ff8551SSimon Glass self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)]) 640*e0ff8551SSimon Glass 641*e0ff8551SSimon Glass def testPackUbootMicrocode(self): 642*e0ff8551SSimon Glass """Test that x86 microcode can be handled correctly 643*e0ff8551SSimon Glass 644*e0ff8551SSimon Glass We expect to see the following in the image, in order: 645*e0ff8551SSimon Glass u-boot-nodtb.bin with a microcode pointer inserted at the correct 646*e0ff8551SSimon Glass place 647*e0ff8551SSimon Glass u-boot.dtb with the microcode removed 648*e0ff8551SSimon Glass the microcode 649*e0ff8551SSimon Glass """ 650*e0ff8551SSimon Glass data = self._DoReadFile('34_x86_ucode.dts', True) 651*e0ff8551SSimon Glass 652*e0ff8551SSimon Glass # Now check the device tree has no microcode 653*e0ff8551SSimon Glass second = data[len(U_BOOT_NODTB_DATA):] 654*e0ff8551SSimon Glass fname = tools.GetOutputFilename('test.dtb') 655*e0ff8551SSimon Glass with open(fname, 'wb') as fd: 656*e0ff8551SSimon Glass fd.write(second) 657*e0ff8551SSimon Glass fdt = fdt_select.FdtScan(fname) 658*e0ff8551SSimon Glass ucode = fdt.GetNode('/microcode') 659*e0ff8551SSimon Glass self.assertTrue(ucode) 660*e0ff8551SSimon Glass for node in ucode.subnodes: 661*e0ff8551SSimon Glass self.assertFalse(node.props.get('data')) 662*e0ff8551SSimon Glass 663*e0ff8551SSimon Glass fdt_len = self.GetFdtLen(second) 664*e0ff8551SSimon Glass third = second[fdt_len:] 665*e0ff8551SSimon Glass 666*e0ff8551SSimon Glass # Check that the microcode appears immediately after the Fdt 667*e0ff8551SSimon Glass # This matches the concatenation of the data properties in 668*e0ff8551SSimon Glass # the /microcode/update@xxx nodes in x86_ucode.dts. 669*e0ff8551SSimon Glass ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000, 670*e0ff8551SSimon Glass 0x78235609) 671*e0ff8551SSimon Glass self.assertEqual(ucode_data, third[:len(ucode_data)]) 672*e0ff8551SSimon Glass ucode_pos = len(U_BOOT_NODTB_DATA) + fdt_len 673*e0ff8551SSimon Glass 674*e0ff8551SSimon Glass # Check that the microcode pointer was inserted. It should match the 675*e0ff8551SSimon Glass # expected position and size 676*e0ff8551SSimon Glass pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos, 677*e0ff8551SSimon Glass len(ucode_data)) 678*e0ff8551SSimon Glass first = data[:len(U_BOOT_NODTB_DATA)] 679*e0ff8551SSimon Glass self.assertEqual('nodtb with microcode' + pos_and_size + 680*e0ff8551SSimon Glass ' somewhere in here', first) 681*e0ff8551SSimon Glass 682*e0ff8551SSimon Glass def _RunPackUbootSingleMicrocode(self, collate): 683*e0ff8551SSimon Glass """Test that x86 microcode can be handled correctly 684*e0ff8551SSimon Glass 685*e0ff8551SSimon Glass We expect to see the following in the image, in order: 686*e0ff8551SSimon Glass u-boot-nodtb.bin with a microcode pointer inserted at the correct 687*e0ff8551SSimon Glass place 688*e0ff8551SSimon Glass u-boot.dtb with the microcode 689*e0ff8551SSimon Glass an empty microcode region 690*e0ff8551SSimon Glass """ 691*e0ff8551SSimon Glass # We need the libfdt library to run this test since only that allows 692*e0ff8551SSimon Glass # finding the offset of a property. This is required by 693*e0ff8551SSimon Glass # Entry_u_boot_dtb_with_ucode.ObtainContents(). 694*e0ff8551SSimon Glass if not fdt_select.have_libfdt: 695*e0ff8551SSimon Glass return 696*e0ff8551SSimon Glass data = self._DoReadFile('35_x86_single_ucode.dts', True) 697*e0ff8551SSimon Glass 698*e0ff8551SSimon Glass second = data[len(U_BOOT_NODTB_DATA):] 699*e0ff8551SSimon Glass 700*e0ff8551SSimon Glass fdt_len = self.GetFdtLen(second) 701*e0ff8551SSimon Glass third = second[fdt_len:] 702*e0ff8551SSimon Glass second = second[:fdt_len] 703*e0ff8551SSimon Glass 704*e0ff8551SSimon Glass if not collate: 705*e0ff8551SSimon Glass ucode_data = struct.pack('>2L', 0x12345678, 0x12345679) 706*e0ff8551SSimon Glass self.assertIn(ucode_data, second) 707*e0ff8551SSimon Glass ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA) 708*e0ff8551SSimon Glass 709*e0ff8551SSimon Glass # Check that the microcode pointer was inserted. It should match the 710*e0ff8551SSimon Glass # expected position and size 711*e0ff8551SSimon Glass pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos, 712*e0ff8551SSimon Glass len(ucode_data)) 713*e0ff8551SSimon Glass first = data[:len(U_BOOT_NODTB_DATA)] 714*e0ff8551SSimon Glass self.assertEqual('nodtb with microcode' + pos_and_size + 715*e0ff8551SSimon Glass ' somewhere in here', first) 716