1# SPDX-License-Identifier: GPL-2.0+ 2# Copyright (c) 2016 Google, Inc 3# Written by Simon Glass <sjg@chromium.org> 4# 5# To run a single test, change to this directory, and: 6# 7# python -m unittest func_test.TestFunctional.testHelp 8 9import collections 10import gzip 11import hashlib 12from optparse import OptionParser 13import os 14import re 15import shutil 16import struct 17import sys 18import tempfile 19import unittest 20 21from binman import cbfs_util 22from binman import cmdline 23from binman import control 24from binman import elf 25from binman import elf_test 26from binman import fmap_util 27from binman import state 28from dtoc import fdt 29from dtoc import fdt_util 30from binman.etype import fdtmap 31from binman.etype import image_header 32from binman.image import Image 33from patman import command 34from patman import test_util 35from patman import tools 36from patman import tout 37 38# Contents of test files, corresponding to different entry types 39U_BOOT_DATA = b'1234' 40U_BOOT_IMG_DATA = b'img' 41U_BOOT_SPL_DATA = b'56780123456789abcdefghi' 42U_BOOT_TPL_DATA = b'tpl9876543210fedcbazyw' 43BLOB_DATA = b'89' 44ME_DATA = b'0abcd' 45VGA_DATA = b'vga' 46U_BOOT_DTB_DATA = b'udtb' 47U_BOOT_SPL_DTB_DATA = b'spldtb' 48U_BOOT_TPL_DTB_DATA = b'tpldtb' 49X86_START16_DATA = b'start16' 50X86_START16_SPL_DATA = b'start16spl' 51X86_START16_TPL_DATA = b'start16tpl' 52X86_RESET16_DATA = b'reset16' 53X86_RESET16_SPL_DATA = b'reset16spl' 54X86_RESET16_TPL_DATA = b'reset16tpl' 55PPC_MPC85XX_BR_DATA = b'ppcmpc85xxbr' 56U_BOOT_NODTB_DATA = b'nodtb with microcode pointer somewhere in here' 57U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here' 58U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here' 59FSP_DATA = b'fsp' 60CMC_DATA = b'cmc' 61VBT_DATA = b'vbt' 62MRC_DATA = b'mrc' 63TEXT_DATA = 'text' 64TEXT_DATA2 = 'text2' 65TEXT_DATA3 = 'text3' 66CROS_EC_RW_DATA = b'ecrw' 67GBB_DATA = b'gbbd' 68BMPBLK_DATA = b'bmp' 69VBLOCK_DATA = b'vblk' 70FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " + 71 b"sorry you're alive\n") 72COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data' 73COMPRESS_DATA_BIG = COMPRESS_DATA * 2 74REFCODE_DATA = b'refcode' 75FSP_M_DATA = b'fsp_m' 76FSP_S_DATA = b'fsp_s' 77FSP_T_DATA = b'fsp_t' 78ATF_BL31_DATA = b'bl31' 79OPENSBI_DATA = b'opensbi' 80SCP_DATA = b'scp' 81TEST_FDT1_DATA = b'fdt1' 82TEST_FDT2_DATA = b'test-fdt2' 83ENV_DATA = b'var1=1\nvar2="2"' 84 85# Subdirectory of the input dir to use to put test FDTs 86TEST_FDT_SUBDIR = 'fdts' 87 88# The expected size for the device tree in some tests 89EXTRACT_DTB_SIZE = 0x3c9 90 91# Properties expected to be in the device tree when update_dtb is used 92BASE_DTB_PROPS = ['offset', 'size', 'image-pos'] 93 94# Extra properties expected to be in the device tree when allow-repack is used 95REPACK_DTB_PROPS = ['orig-offset', 'orig-size'] 96 97 98class TestFunctional(unittest.TestCase): 99 """Functional tests for binman 100 101 Most of these use a sample .dts file to build an image and then check 102 that it looks correct. The sample files are in the test/ subdirectory 103 and are numbered. 104 105 For each entry type a very small test file is created using fixed 106 string contents. This makes it easy to test that things look right, and 107 debug problems. 108 109 In some cases a 'real' file must be used - these are also supplied in 110 the test/ diurectory. 111 """ 112 @classmethod 113 def setUpClass(cls): 114 global entry 115 from binman import entry 116 117 # Handle the case where argv[0] is 'python' 118 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0])) 119 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman') 120 121 # Create a temporary directory for input files 122 cls._indir = tempfile.mkdtemp(prefix='binmant.') 123 124 # Create some test files 125 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA) 126 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA) 127 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA) 128 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA) 129 TestFunctional._MakeInputFile('blobfile', BLOB_DATA) 130 TestFunctional._MakeInputFile('me.bin', ME_DATA) 131 TestFunctional._MakeInputFile('vga.bin', VGA_DATA) 132 cls._ResetDtbs() 133 134 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA) 135 136 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA) 137 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin', 138 X86_START16_SPL_DATA) 139 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin', 140 X86_START16_TPL_DATA) 141 142 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin', 143 X86_RESET16_DATA) 144 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin', 145 X86_RESET16_SPL_DATA) 146 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin', 147 X86_RESET16_TPL_DATA) 148 149 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA) 150 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin', 151 U_BOOT_SPL_NODTB_DATA) 152 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin', 153 U_BOOT_TPL_NODTB_DATA) 154 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA) 155 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA) 156 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA) 157 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA) 158 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA) 159 TestFunctional._MakeInputDir('devkeys') 160 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA) 161 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA) 162 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA) 163 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA) 164 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA) 165 166 cls._elf_testdir = os.path.join(cls._indir, 'elftest') 167 elf_test.BuildElfTestFiles(cls._elf_testdir) 168 169 # ELF file with a '_dt_ucode_base_size' symbol 170 TestFunctional._MakeInputFile('u-boot', 171 tools.ReadFile(cls.ElfTestFile('u_boot_ucode_ptr'))) 172 173 # Intel flash descriptor file 174 cls._SetupDescriptor() 175 176 shutil.copytree(cls.TestFile('files'), 177 os.path.join(cls._indir, 'files')) 178 179 TestFunctional._MakeInputFile('compress', COMPRESS_DATA) 180 TestFunctional._MakeInputFile('compress_big', COMPRESS_DATA_BIG) 181 TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA) 182 TestFunctional._MakeInputFile('fw_dynamic.bin', OPENSBI_DATA) 183 TestFunctional._MakeInputFile('scp.bin', SCP_DATA) 184 185 # Add a few .dtb files for testing 186 TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR, 187 TEST_FDT1_DATA) 188 TestFunctional._MakeInputFile('%s/test-fdt2.dtb' % TEST_FDT_SUBDIR, 189 TEST_FDT2_DATA) 190 191 TestFunctional._MakeInputFile('env.txt', ENV_DATA) 192 193 # Travis-CI may have an old lz4 194 cls.have_lz4 = True 195 try: 196 tools.Run('lz4', '--no-frame-crc', '-c', 197 os.path.join(cls._indir, 'u-boot.bin'), binary=True) 198 except: 199 cls.have_lz4 = False 200 201 @classmethod 202 def tearDownClass(cls): 203 """Remove the temporary input directory and its contents""" 204 if cls.preserve_indir: 205 print('Preserving input dir: %s' % cls._indir) 206 else: 207 if cls._indir: 208 shutil.rmtree(cls._indir) 209 cls._indir = None 210 211 @classmethod 212 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False, 213 toolpath=None, verbosity=None): 214 """Accept arguments controlling test execution 215 216 Args: 217 preserve_indir: Preserve the shared input directory used by all 218 tests in this class. 219 preserve_outdir: Preserve the output directories used by tests. Each 220 test has its own, so this is normally only useful when running a 221 single test. 222 toolpath: ist of paths to use for tools 223 """ 224 cls.preserve_indir = preserve_indir 225 cls.preserve_outdirs = preserve_outdirs 226 cls.toolpath = toolpath 227 cls.verbosity = verbosity 228 229 def _CheckLz4(self): 230 if not self.have_lz4: 231 self.skipTest('lz4 --no-frame-crc not available') 232 233 def _CleanupOutputDir(self): 234 """Remove the temporary output directory""" 235 if self.preserve_outdirs: 236 print('Preserving output dir: %s' % tools.outdir) 237 else: 238 tools._FinaliseForTest() 239 240 def setUp(self): 241 # Enable this to turn on debugging output 242 # tout.Init(tout.DEBUG) 243 command.test_result = None 244 245 def tearDown(self): 246 """Remove the temporary output directory""" 247 self._CleanupOutputDir() 248 249 def _SetupImageInTmpdir(self): 250 """Set up the output image in a new temporary directory 251 252 This is used when an image has been generated in the output directory, 253 but we want to run binman again. This will create a new output 254 directory and fail to delete the original one. 255 256 This creates a new temporary directory, copies the image to it (with a 257 new name) and removes the old output directory. 258 259 Returns: 260 Tuple: 261 Temporary directory to use 262 New image filename 263 """ 264 image_fname = tools.GetOutputFilename('image.bin') 265 tmpdir = tempfile.mkdtemp(prefix='binman.') 266 updated_fname = os.path.join(tmpdir, 'image-updated.bin') 267 tools.WriteFile(updated_fname, tools.ReadFile(image_fname)) 268 self._CleanupOutputDir() 269 return tmpdir, updated_fname 270 271 @classmethod 272 def _ResetDtbs(cls): 273 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA) 274 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA) 275 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA) 276 277 def _RunBinman(self, *args, **kwargs): 278 """Run binman using the command line 279 280 Args: 281 Arguments to pass, as a list of strings 282 kwargs: Arguments to pass to Command.RunPipe() 283 """ 284 result = command.RunPipe([[self._binman_pathname] + list(args)], 285 capture=True, capture_stderr=True, raise_on_error=False) 286 if result.return_code and kwargs.get('raise_on_error', True): 287 raise Exception("Error running '%s': %s" % (' '.join(args), 288 result.stdout + result.stderr)) 289 return result 290 291 def _DoBinman(self, *argv): 292 """Run binman using directly (in the same process) 293 294 Args: 295 Arguments to pass, as a list of strings 296 Returns: 297 Return value (0 for success) 298 """ 299 argv = list(argv) 300 args = cmdline.ParseArgs(argv) 301 args.pager = 'binman-invalid-pager' 302 args.build_dir = self._indir 303 304 # For testing, you can force an increase in verbosity here 305 # args.verbosity = tout.DEBUG 306 return control.Binman(args) 307 308 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False, 309 entry_args=None, images=None, use_real_dtb=False, 310 use_expanded=False, verbosity=None, allow_missing=False, 311 extra_indirs=None): 312 """Run binman with a given test file 313 314 Args: 315 fname: Device-tree source filename to use (e.g. 005_simple.dts) 316 debug: True to enable debugging output 317 map: True to output map files for the images 318 update_dtb: Update the offset and size of each entry in the device 319 tree before packing it into the image 320 entry_args: Dict of entry args to supply to binman 321 key: arg name 322 value: value of that arg 323 images: List of image names to build 324 use_real_dtb: True to use the test file as the contents of 325 the u-boot-dtb entry. Normally this is not needed and the 326 test contents (the U_BOOT_DTB_DATA string) can be used. 327 But in some test we need the real contents. 328 use_expanded: True to use expanded entries where available, e.g. 329 'u-boot-expanded' instead of 'u-boot' 330 verbosity: Verbosity level to use (0-3, None=don't set it) 331 allow_missing: Set the '--allow-missing' flag so that missing 332 external binaries just produce a warning instead of an error 333 extra_indirs: Extra input directories to add using -I 334 """ 335 args = [] 336 if debug: 337 args.append('-D') 338 if verbosity is not None: 339 args.append('-v%d' % verbosity) 340 elif self.verbosity: 341 args.append('-v%d' % self.verbosity) 342 if self.toolpath: 343 for path in self.toolpath: 344 args += ['--toolpath', path] 345 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)] 346 if map: 347 args.append('-m') 348 if update_dtb: 349 args.append('-u') 350 if not use_real_dtb: 351 args.append('--fake-dtb') 352 if not use_expanded: 353 args.append('--no-expanded') 354 if entry_args: 355 for arg, value in entry_args.items(): 356 args.append('-a%s=%s' % (arg, value)) 357 if allow_missing: 358 args.append('-M') 359 if images: 360 for image in images: 361 args += ['-i', image] 362 if extra_indirs: 363 for indir in extra_indirs: 364 args += ['-I', indir] 365 return self._DoBinman(*args) 366 367 def _SetupDtb(self, fname, outfile='u-boot.dtb'): 368 """Set up a new test device-tree file 369 370 The given file is compiled and set up as the device tree to be used 371 for ths test. 372 373 Args: 374 fname: Filename of .dts file to read 375 outfile: Output filename for compiled device-tree binary 376 377 Returns: 378 Contents of device-tree binary 379 """ 380 tmpdir = tempfile.mkdtemp(prefix='binmant.') 381 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir) 382 with open(dtb, 'rb') as fd: 383 data = fd.read() 384 TestFunctional._MakeInputFile(outfile, data) 385 shutil.rmtree(tmpdir) 386 return data 387 388 def _GetDtbContentsForSplTpl(self, dtb_data, name): 389 """Create a version of the main DTB for SPL or SPL 390 391 For testing we don't actually have different versions of the DTB. With 392 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests 393 we don't normally have any unwanted nodes. 394 395 We still want the DTBs for SPL and TPL to be different though, since 396 otherwise it is confusing to know which one we are looking at. So add 397 an 'spl' or 'tpl' property to the top-level node. 398 399 Args: 400 dtb_data: dtb data to modify (this should be a value devicetree) 401 name: Name of a new property to add 402 403 Returns: 404 New dtb data with the property added 405 """ 406 dtb = fdt.Fdt.FromData(dtb_data) 407 dtb.Scan() 408 dtb.GetNode('/binman').AddZeroProp(name) 409 dtb.Sync(auto_resize=True) 410 dtb.Pack() 411 return dtb.GetContents() 412 413 def _DoReadFileDtb(self, fname, use_real_dtb=False, use_expanded=False, 414 map=False, update_dtb=False, entry_args=None, 415 reset_dtbs=True, extra_indirs=None): 416 """Run binman and return the resulting image 417 418 This runs binman with a given test file and then reads the resulting 419 output file. It is a shortcut function since most tests need to do 420 these steps. 421 422 Raises an assertion failure if binman returns a non-zero exit code. 423 424 Args: 425 fname: Device-tree source filename to use (e.g. 005_simple.dts) 426 use_real_dtb: True to use the test file as the contents of 427 the u-boot-dtb entry. Normally this is not needed and the 428 test contents (the U_BOOT_DTB_DATA string) can be used. 429 But in some test we need the real contents. 430 use_expanded: True to use expanded entries where available, e.g. 431 'u-boot-expanded' instead of 'u-boot' 432 map: True to output map files for the images 433 update_dtb: Update the offset and size of each entry in the device 434 tree before packing it into the image 435 entry_args: Dict of entry args to supply to binman 436 key: arg name 437 value: value of that arg 438 reset_dtbs: With use_real_dtb the test dtb is overwritten by this 439 function. If reset_dtbs is True, then the original test dtb 440 is written back before this function finishes 441 extra_indirs: Extra input directories to add using -I 442 443 Returns: 444 Tuple: 445 Resulting image contents 446 Device tree contents 447 Map data showing contents of image (or None if none) 448 Output device tree binary filename ('u-boot.dtb' path) 449 """ 450 dtb_data = None 451 # Use the compiled test file as the u-boot-dtb input 452 if use_real_dtb: 453 dtb_data = self._SetupDtb(fname) 454 455 # For testing purposes, make a copy of the DT for SPL and TPL. Add 456 # a node indicating which it is, so aid verification. 457 for name in ['spl', 'tpl']: 458 dtb_fname = '%s/u-boot-%s.dtb' % (name, name) 459 outfile = os.path.join(self._indir, dtb_fname) 460 TestFunctional._MakeInputFile(dtb_fname, 461 self._GetDtbContentsForSplTpl(dtb_data, name)) 462 463 try: 464 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb, 465 entry_args=entry_args, use_real_dtb=use_real_dtb, 466 use_expanded=use_expanded, extra_indirs=extra_indirs) 467 self.assertEqual(0, retcode) 468 out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out') 469 470 # Find the (only) image, read it and return its contents 471 image = control.images['image'] 472 image_fname = tools.GetOutputFilename('image.bin') 473 self.assertTrue(os.path.exists(image_fname)) 474 if map: 475 map_fname = tools.GetOutputFilename('image.map') 476 with open(map_fname) as fd: 477 map_data = fd.read() 478 else: 479 map_data = None 480 with open(image_fname, 'rb') as fd: 481 return fd.read(), dtb_data, map_data, out_dtb_fname 482 finally: 483 # Put the test file back 484 if reset_dtbs and use_real_dtb: 485 self._ResetDtbs() 486 487 def _DoReadFileRealDtb(self, fname): 488 """Run binman with a real .dtb file and return the resulting data 489 490 Args: 491 fname: DT source filename to use (e.g. 082_fdt_update_all.dts) 492 493 Returns: 494 Resulting image contents 495 """ 496 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0] 497 498 def _DoReadFile(self, fname, use_real_dtb=False): 499 """Helper function which discards the device-tree binary 500 501 Args: 502 fname: Device-tree source filename to use (e.g. 005_simple.dts) 503 use_real_dtb: True to use the test file as the contents of 504 the u-boot-dtb entry. Normally this is not needed and the 505 test contents (the U_BOOT_DTB_DATA string) can be used. 506 But in some test we need the real contents. 507 508 Returns: 509 Resulting image contents 510 """ 511 return self._DoReadFileDtb(fname, use_real_dtb)[0] 512 513 @classmethod 514 def _MakeInputFile(cls, fname, contents): 515 """Create a new test input file, creating directories as needed 516 517 Args: 518 fname: Filename to create 519 contents: File contents to write in to the file 520 Returns: 521 Full pathname of file created 522 """ 523 pathname = os.path.join(cls._indir, fname) 524 dirname = os.path.dirname(pathname) 525 if dirname and not os.path.exists(dirname): 526 os.makedirs(dirname) 527 with open(pathname, 'wb') as fd: 528 fd.write(contents) 529 return pathname 530 531 @classmethod 532 def _MakeInputDir(cls, dirname): 533 """Create a new test input directory, creating directories as needed 534 535 Args: 536 dirname: Directory name to create 537 538 Returns: 539 Full pathname of directory created 540 """ 541 pathname = os.path.join(cls._indir, dirname) 542 if not os.path.exists(pathname): 543 os.makedirs(pathname) 544 return pathname 545 546 @classmethod 547 def _SetupSplElf(cls, src_fname='bss_data'): 548 """Set up an ELF file with a '_dt_ucode_base_size' symbol 549 550 Args: 551 Filename of ELF file to use as SPL 552 """ 553 TestFunctional._MakeInputFile('spl/u-boot-spl', 554 tools.ReadFile(cls.ElfTestFile(src_fname))) 555 556 @classmethod 557 def _SetupTplElf(cls, src_fname='bss_data'): 558 """Set up an ELF file with a '_dt_ucode_base_size' symbol 559 560 Args: 561 Filename of ELF file to use as TPL 562 """ 563 TestFunctional._MakeInputFile('tpl/u-boot-tpl', 564 tools.ReadFile(cls.ElfTestFile(src_fname))) 565 566 @classmethod 567 def _SetupDescriptor(cls): 568 with open(cls.TestFile('descriptor.bin'), 'rb') as fd: 569 TestFunctional._MakeInputFile('descriptor.bin', fd.read()) 570 571 @classmethod 572 def TestFile(cls, fname): 573 return os.path.join(cls._binman_dir, 'test', fname) 574 575 @classmethod 576 def ElfTestFile(cls, fname): 577 return os.path.join(cls._elf_testdir, fname) 578 579 def AssertInList(self, grep_list, target): 580 """Assert that at least one of a list of things is in a target 581 582 Args: 583 grep_list: List of strings to check 584 target: Target string 585 """ 586 for grep in grep_list: 587 if grep in target: 588 return 589 self.fail("Error: '%s' not found in '%s'" % (grep_list, target)) 590 591 def CheckNoGaps(self, entries): 592 """Check that all entries fit together without gaps 593 594 Args: 595 entries: List of entries to check 596 """ 597 offset = 0 598 for entry in entries.values(): 599 self.assertEqual(offset, entry.offset) 600 offset += entry.size 601 602 def GetFdtLen(self, dtb): 603 """Get the totalsize field from a device-tree binary 604 605 Args: 606 dtb: Device-tree binary contents 607 608 Returns: 609 Total size of device-tree binary, from the header 610 """ 611 return struct.unpack('>L', dtb[4:8])[0] 612 613 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'): 614 def AddNode(node, path): 615 if node.name != '/': 616 path += '/' + node.name 617 for prop in node.props.values(): 618 if prop.name in prop_names: 619 prop_path = path + ':' + prop.name 620 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu( 621 prop.value) 622 for subnode in node.subnodes: 623 AddNode(subnode, path) 624 625 tree = {} 626 AddNode(dtb.GetRoot(), '') 627 return tree 628 629 def testRun(self): 630 """Test a basic run with valid args""" 631 result = self._RunBinman('-h') 632 633 def testFullHelp(self): 634 """Test that the full help is displayed with -H""" 635 result = self._RunBinman('-H') 636 help_file = os.path.join(self._binman_dir, 'README.rst') 637 # Remove possible extraneous strings 638 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n' 639 gothelp = result.stdout.replace(extra, '') 640 self.assertEqual(len(gothelp), os.path.getsize(help_file)) 641 self.assertEqual(0, len(result.stderr)) 642 self.assertEqual(0, result.return_code) 643 644 def testFullHelpInternal(self): 645 """Test that the full help is displayed with -H""" 646 try: 647 command.test_result = command.CommandResult() 648 result = self._DoBinman('-H') 649 help_file = os.path.join(self._binman_dir, 'README.rst') 650 finally: 651 command.test_result = None 652 653 def testHelp(self): 654 """Test that the basic help is displayed with -h""" 655 result = self._RunBinman('-h') 656 self.assertTrue(len(result.stdout) > 200) 657 self.assertEqual(0, len(result.stderr)) 658 self.assertEqual(0, result.return_code) 659 660 def testBoard(self): 661 """Test that we can run it with a specific board""" 662 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb') 663 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA) 664 result = self._DoBinman('build', '-n', '-b', 'sandbox') 665 self.assertEqual(0, result) 666 667 def testNeedBoard(self): 668 """Test that we get an error when no board ius supplied""" 669 with self.assertRaises(ValueError) as e: 670 result = self._DoBinman('build') 671 self.assertIn("Must provide a board to process (use -b <board>)", 672 str(e.exception)) 673 674 def testMissingDt(self): 675 """Test that an invalid device-tree file generates an error""" 676 with self.assertRaises(Exception) as e: 677 self._RunBinman('build', '-d', 'missing_file') 678 # We get one error from libfdt, and a different one from fdtget. 679 self.AssertInList(["Couldn't open blob from 'missing_file'", 680 'No such file or directory'], str(e.exception)) 681 682 def testBrokenDt(self): 683 """Test that an invalid device-tree source file generates an error 684 685 Since this is a source file it should be compiled and the error 686 will come from the device-tree compiler (dtc). 687 """ 688 with self.assertRaises(Exception) as e: 689 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts')) 690 self.assertIn("FATAL ERROR: Unable to parse input tree", 691 str(e.exception)) 692 693 def testMissingNode(self): 694 """Test that a device tree without a 'binman' node generates an error""" 695 with self.assertRaises(Exception) as e: 696 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts')) 697 self.assertIn("does not have a 'binman' node", str(e.exception)) 698 699 def testEmpty(self): 700 """Test that an empty binman node works OK (i.e. does nothing)""" 701 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts')) 702 self.assertEqual(0, len(result.stderr)) 703 self.assertEqual(0, result.return_code) 704 705 def testInvalidEntry(self): 706 """Test that an invalid entry is flagged""" 707 with self.assertRaises(Exception) as e: 708 result = self._RunBinman('build', '-d', 709 self.TestFile('004_invalid_entry.dts')) 710 self.assertIn("Unknown entry type 'not-a-valid-type' in node " 711 "'/binman/not-a-valid-type'", str(e.exception)) 712 713 def testSimple(self): 714 """Test a simple binman with a single file""" 715 data = self._DoReadFile('005_simple.dts') 716 self.assertEqual(U_BOOT_DATA, data) 717 718 def testSimpleDebug(self): 719 """Test a simple binman run with debugging enabled""" 720 self._DoTestFile('005_simple.dts', debug=True) 721 722 def testDual(self): 723 """Test that we can handle creating two images 724 725 This also tests image padding. 726 """ 727 retcode = self._DoTestFile('006_dual_image.dts') 728 self.assertEqual(0, retcode) 729 730 image = control.images['image1'] 731 self.assertEqual(len(U_BOOT_DATA), image.size) 732 fname = tools.GetOutputFilename('image1.bin') 733 self.assertTrue(os.path.exists(fname)) 734 with open(fname, 'rb') as fd: 735 data = fd.read() 736 self.assertEqual(U_BOOT_DATA, data) 737 738 image = control.images['image2'] 739 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size) 740 fname = tools.GetOutputFilename('image2.bin') 741 self.assertTrue(os.path.exists(fname)) 742 with open(fname, 'rb') as fd: 743 data = fd.read() 744 self.assertEqual(U_BOOT_DATA, data[3:7]) 745 self.assertEqual(tools.GetBytes(0, 3), data[:3]) 746 self.assertEqual(tools.GetBytes(0, 5), data[7:]) 747 748 def testBadAlign(self): 749 """Test that an invalid alignment value is detected""" 750 with self.assertRaises(ValueError) as e: 751 self._DoTestFile('007_bad_align.dts') 752 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power " 753 "of two", str(e.exception)) 754 755 def testPackSimple(self): 756 """Test that packing works as expected""" 757 retcode = self._DoTestFile('008_pack.dts') 758 self.assertEqual(0, retcode) 759 self.assertIn('image', control.images) 760 image = control.images['image'] 761 entries = image.GetEntries() 762 self.assertEqual(5, len(entries)) 763 764 # First u-boot 765 self.assertIn('u-boot', entries) 766 entry = entries['u-boot'] 767 self.assertEqual(0, entry.offset) 768 self.assertEqual(len(U_BOOT_DATA), entry.size) 769 770 # Second u-boot, aligned to 16-byte boundary 771 self.assertIn('u-boot-align', entries) 772 entry = entries['u-boot-align'] 773 self.assertEqual(16, entry.offset) 774 self.assertEqual(len(U_BOOT_DATA), entry.size) 775 776 # Third u-boot, size 23 bytes 777 self.assertIn('u-boot-size', entries) 778 entry = entries['u-boot-size'] 779 self.assertEqual(20, entry.offset) 780 self.assertEqual(len(U_BOOT_DATA), entry.contents_size) 781 self.assertEqual(23, entry.size) 782 783 # Fourth u-boot, placed immediate after the above 784 self.assertIn('u-boot-next', entries) 785 entry = entries['u-boot-next'] 786 self.assertEqual(43, entry.offset) 787 self.assertEqual(len(U_BOOT_DATA), entry.size) 788 789 # Fifth u-boot, placed at a fixed offset 790 self.assertIn('u-boot-fixed', entries) 791 entry = entries['u-boot-fixed'] 792 self.assertEqual(61, entry.offset) 793 self.assertEqual(len(U_BOOT_DATA), entry.size) 794 795 self.assertEqual(65, image.size) 796 797 def testPackExtra(self): 798 """Test that extra packing feature works as expected""" 799 data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts', 800 update_dtb=True) 801 802 self.assertIn('image', control.images) 803 image = control.images['image'] 804 entries = image.GetEntries() 805 self.assertEqual(5, len(entries)) 806 807 # First u-boot with padding before and after 808 self.assertIn('u-boot', entries) 809 entry = entries['u-boot'] 810 self.assertEqual(0, entry.offset) 811 self.assertEqual(3, entry.pad_before) 812 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size) 813 self.assertEqual(U_BOOT_DATA, entry.data) 814 self.assertEqual(tools.GetBytes(0, 3) + U_BOOT_DATA + 815 tools.GetBytes(0, 5), data[:entry.size]) 816 pos = entry.size 817 818 # Second u-boot has an aligned size, but it has no effect 819 self.assertIn('u-boot-align-size-nop', entries) 820 entry = entries['u-boot-align-size-nop'] 821 self.assertEqual(pos, entry.offset) 822 self.assertEqual(len(U_BOOT_DATA), entry.size) 823 self.assertEqual(U_BOOT_DATA, entry.data) 824 self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size]) 825 pos += entry.size 826 827 # Third u-boot has an aligned size too 828 self.assertIn('u-boot-align-size', entries) 829 entry = entries['u-boot-align-size'] 830 self.assertEqual(pos, entry.offset) 831 self.assertEqual(32, entry.size) 832 self.assertEqual(U_BOOT_DATA, entry.data) 833 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 32 - len(U_BOOT_DATA)), 834 data[pos:pos + entry.size]) 835 pos += entry.size 836 837 # Fourth u-boot has an aligned end 838 self.assertIn('u-boot-align-end', entries) 839 entry = entries['u-boot-align-end'] 840 self.assertEqual(48, entry.offset) 841 self.assertEqual(16, entry.size) 842 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)]) 843 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 16 - len(U_BOOT_DATA)), 844 data[pos:pos + entry.size]) 845 pos += entry.size 846 847 # Fifth u-boot immediately afterwards 848 self.assertIn('u-boot-align-both', entries) 849 entry = entries['u-boot-align-both'] 850 self.assertEqual(64, entry.offset) 851 self.assertEqual(64, entry.size) 852 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)]) 853 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 64 - len(U_BOOT_DATA)), 854 data[pos:pos + entry.size]) 855 856 self.CheckNoGaps(entries) 857 self.assertEqual(128, image.size) 858 859 dtb = fdt.Fdt(out_dtb_fname) 860 dtb.Scan() 861 props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos']) 862 expected = { 863 'image-pos': 0, 864 'offset': 0, 865 'size': 128, 866 867 'u-boot:image-pos': 0, 868 'u-boot:offset': 0, 869 'u-boot:size': 3 + 5 + len(U_BOOT_DATA), 870 871 'u-boot-align-size-nop:image-pos': 12, 872 'u-boot-align-size-nop:offset': 12, 873 'u-boot-align-size-nop:size': 4, 874 875 'u-boot-align-size:image-pos': 16, 876 'u-boot-align-size:offset': 16, 877 'u-boot-align-size:size': 32, 878 879 'u-boot-align-end:image-pos': 48, 880 'u-boot-align-end:offset': 48, 881 'u-boot-align-end:size': 16, 882 883 'u-boot-align-both:image-pos': 64, 884 'u-boot-align-both:offset': 64, 885 'u-boot-align-both:size': 64, 886 } 887 self.assertEqual(expected, props) 888 889 def testPackAlignPowerOf2(self): 890 """Test that invalid entry alignment is detected""" 891 with self.assertRaises(ValueError) as e: 892 self._DoTestFile('010_pack_align_power2.dts') 893 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power " 894 "of two", str(e.exception)) 895 896 def testPackAlignSizePowerOf2(self): 897 """Test that invalid entry size alignment is detected""" 898 with self.assertRaises(ValueError) as e: 899 self._DoTestFile('011_pack_align_size_power2.dts') 900 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a " 901 "power of two", str(e.exception)) 902 903 def testPackInvalidAlign(self): 904 """Test detection of an offset that does not match its alignment""" 905 with self.assertRaises(ValueError) as e: 906 self._DoTestFile('012_pack_inv_align.dts') 907 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match " 908 "align 0x4 (4)", str(e.exception)) 909 910 def testPackInvalidSizeAlign(self): 911 """Test that invalid entry size alignment is detected""" 912 with self.assertRaises(ValueError) as e: 913 self._DoTestFile('013_pack_inv_size_align.dts') 914 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match " 915 "align-size 0x4 (4)", str(e.exception)) 916 917 def testPackOverlap(self): 918 """Test that overlapping regions are detected""" 919 with self.assertRaises(ValueError) as e: 920 self._DoTestFile('014_pack_overlap.dts') 921 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps " 922 "with previous entry '/binman/u-boot' ending at 0x4 (4)", 923 str(e.exception)) 924 925 def testPackEntryOverflow(self): 926 """Test that entries that overflow their size are detected""" 927 with self.assertRaises(ValueError) as e: 928 self._DoTestFile('015_pack_overflow.dts') 929 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) " 930 "but entry size is 0x3 (3)", str(e.exception)) 931 932 def testPackImageOverflow(self): 933 """Test that entries which overflow the image size are detected""" 934 with self.assertRaises(ValueError) as e: 935 self._DoTestFile('016_pack_image_overflow.dts') 936 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section " 937 "size 0x3 (3)", str(e.exception)) 938 939 def testPackImageSize(self): 940 """Test that the image size can be set""" 941 retcode = self._DoTestFile('017_pack_image_size.dts') 942 self.assertEqual(0, retcode) 943 self.assertIn('image', control.images) 944 image = control.images['image'] 945 self.assertEqual(7, image.size) 946 947 def testPackImageSizeAlign(self): 948 """Test that image size alignemnt works as expected""" 949 retcode = self._DoTestFile('018_pack_image_align.dts') 950 self.assertEqual(0, retcode) 951 self.assertIn('image', control.images) 952 image = control.images['image'] 953 self.assertEqual(16, image.size) 954 955 def testPackInvalidImageAlign(self): 956 """Test that invalid image alignment is detected""" 957 with self.assertRaises(ValueError) as e: 958 self._DoTestFile('019_pack_inv_image_align.dts') 959 self.assertIn("Section '/binman': Size 0x7 (7) does not match " 960 "align-size 0x8 (8)", str(e.exception)) 961 962 def testPackAlignPowerOf2(self): 963 """Test that invalid image alignment is detected""" 964 with self.assertRaises(ValueError) as e: 965 self._DoTestFile('020_pack_inv_image_align_power2.dts') 966 self.assertIn("Image '/binman': Alignment size 131 must be a power of " 967 "two", str(e.exception)) 968 969 def testImagePadByte(self): 970 """Test that the image pad byte can be specified""" 971 self._SetupSplElf() 972 data = self._DoReadFile('021_image_pad.dts') 973 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0xff, 1) + 974 U_BOOT_DATA, data) 975 976 def testImageName(self): 977 """Test that image files can be named""" 978 retcode = self._DoTestFile('022_image_name.dts') 979 self.assertEqual(0, retcode) 980 image = control.images['image1'] 981 fname = tools.GetOutputFilename('test-name') 982 self.assertTrue(os.path.exists(fname)) 983 984 image = control.images['image2'] 985 fname = tools.GetOutputFilename('test-name.xx') 986 self.assertTrue(os.path.exists(fname)) 987 988 def testBlobFilename(self): 989 """Test that generic blobs can be provided by filename""" 990 data = self._DoReadFile('023_blob.dts') 991 self.assertEqual(BLOB_DATA, data) 992 993 def testPackSorted(self): 994 """Test that entries can be sorted""" 995 self._SetupSplElf() 996 data = self._DoReadFile('024_sorted.dts') 997 self.assertEqual(tools.GetBytes(0, 1) + U_BOOT_SPL_DATA + 998 tools.GetBytes(0, 2) + U_BOOT_DATA, data) 999 1000 def testPackZeroOffset(self): 1001 """Test that an entry at offset 0 is not given a new offset""" 1002 with self.assertRaises(ValueError) as e: 1003 self._DoTestFile('025_pack_zero_size.dts') 1004 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps " 1005 "with previous entry '/binman/u-boot' ending at 0x4 (4)", 1006 str(e.exception)) 1007 1008 def testPackUbootDtb(self): 1009 """Test that a device tree can be added to U-Boot""" 1010 data = self._DoReadFile('026_pack_u_boot_dtb.dts') 1011 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data) 1012 1013 def testPackX86RomNoSize(self): 1014 """Test that the end-at-4gb property requires a size property""" 1015 with self.assertRaises(ValueError) as e: 1016 self._DoTestFile('027_pack_4gb_no_size.dts') 1017 self.assertIn("Image '/binman': Section size must be provided when " 1018 "using end-at-4gb", str(e.exception)) 1019 1020 def test4gbAndSkipAtStartTogether(self): 1021 """Test that the end-at-4gb and skip-at-size property can't be used 1022 together""" 1023 with self.assertRaises(ValueError) as e: 1024 self._DoTestFile('098_4gb_and_skip_at_start_together.dts') 1025 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or " 1026 "'skip-at-start'", str(e.exception)) 1027 1028 def testPackX86RomOutside(self): 1029 """Test that the end-at-4gb property checks for offset boundaries""" 1030 with self.assertRaises(ValueError) as e: 1031 self._DoTestFile('028_pack_4gb_outside.dts') 1032 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) " 1033 "is outside the section '/binman' starting at " 1034 '0xffffffe0 (4294967264) of size 0x20 (32)', 1035 str(e.exception)) 1036 1037 def testPackX86Rom(self): 1038 """Test that a basic x86 ROM can be created""" 1039 self._SetupSplElf() 1040 data = self._DoReadFile('029_x86_rom.dts') 1041 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 3) + U_BOOT_SPL_DATA + 1042 tools.GetBytes(0, 2), data) 1043 1044 def testPackX86RomMeNoDesc(self): 1045 """Test that an invalid Intel descriptor entry is detected""" 1046 try: 1047 TestFunctional._MakeInputFile('descriptor-empty.bin', b'') 1048 with self.assertRaises(ValueError) as e: 1049 self._DoTestFile('163_x86_rom_me_empty.dts') 1050 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature", 1051 str(e.exception)) 1052 finally: 1053 self._SetupDescriptor() 1054 1055 def testPackX86RomBadDesc(self): 1056 """Test that the Intel requires a descriptor entry""" 1057 with self.assertRaises(ValueError) as e: 1058 self._DoTestFile('030_x86_rom_me_no_desc.dts') 1059 self.assertIn("Node '/binman/intel-me': No offset set with " 1060 "offset-unset: should another entry provide this correct " 1061 "offset?", str(e.exception)) 1062 1063 def testPackX86RomMe(self): 1064 """Test that an x86 ROM with an ME region can be created""" 1065 data = self._DoReadFile('031_x86_rom_me.dts') 1066 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin')) 1067 if data[:0x1000] != expected_desc: 1068 self.fail('Expected descriptor binary at start of image') 1069 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)]) 1070 1071 def testPackVga(self): 1072 """Test that an image with a VGA binary can be created""" 1073 data = self._DoReadFile('032_intel_vga.dts') 1074 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)]) 1075 1076 def testPackStart16(self): 1077 """Test that an image with an x86 start16 region can be created""" 1078 data = self._DoReadFile('033_x86_start16.dts') 1079 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)]) 1080 1081 def testPackPowerpcMpc85xxBootpgResetvec(self): 1082 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be 1083 created""" 1084 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts') 1085 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)]) 1086 1087 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False): 1088 """Handle running a test for insertion of microcode 1089 1090 Args: 1091 dts_fname: Name of test .dts file 1092 nodtb_data: Data that we expect in the first section 1093 ucode_second: True if the microsecond entry is second instead of 1094 third 1095 1096 Returns: 1097 Tuple: 1098 Contents of first region (U-Boot or SPL) 1099 Offset and size components of microcode pointer, as inserted 1100 in the above (two 4-byte words) 1101 """ 1102 data = self._DoReadFile(dts_fname, True) 1103 1104 # Now check the device tree has no microcode 1105 if ucode_second: 1106 ucode_content = data[len(nodtb_data):] 1107 ucode_pos = len(nodtb_data) 1108 dtb_with_ucode = ucode_content[16:] 1109 fdt_len = self.GetFdtLen(dtb_with_ucode) 1110 else: 1111 dtb_with_ucode = data[len(nodtb_data):] 1112 fdt_len = self.GetFdtLen(dtb_with_ucode) 1113 ucode_content = dtb_with_ucode[fdt_len:] 1114 ucode_pos = len(nodtb_data) + fdt_len 1115 fname = tools.GetOutputFilename('test.dtb') 1116 with open(fname, 'wb') as fd: 1117 fd.write(dtb_with_ucode) 1118 dtb = fdt.FdtScan(fname) 1119 ucode = dtb.GetNode('/microcode') 1120 self.assertTrue(ucode) 1121 for node in ucode.subnodes: 1122 self.assertFalse(node.props.get('data')) 1123 1124 # Check that the microcode appears immediately after the Fdt 1125 # This matches the concatenation of the data properties in 1126 # the /microcode/update@xxx nodes in 34_x86_ucode.dts. 1127 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000, 1128 0x78235609) 1129 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)]) 1130 1131 # Check that the microcode pointer was inserted. It should match the 1132 # expected offset and size 1133 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos, 1134 len(ucode_data)) 1135 u_boot = data[:len(nodtb_data)] 1136 return u_boot, pos_and_size 1137 1138 def testPackUbootMicrocode(self): 1139 """Test that x86 microcode can be handled correctly 1140 1141 We expect to see the following in the image, in order: 1142 u-boot-nodtb.bin with a microcode pointer inserted at the correct 1143 place 1144 u-boot.dtb with the microcode removed 1145 the microcode 1146 """ 1147 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts', 1148 U_BOOT_NODTB_DATA) 1149 self.assertEqual(b'nodtb with microcode' + pos_and_size + 1150 b' somewhere in here', first) 1151 1152 def _RunPackUbootSingleMicrocode(self): 1153 """Test that x86 microcode can be handled correctly 1154 1155 We expect to see the following in the image, in order: 1156 u-boot-nodtb.bin with a microcode pointer inserted at the correct 1157 place 1158 u-boot.dtb with the microcode 1159 an empty microcode region 1160 """ 1161 # We need the libfdt library to run this test since only that allows 1162 # finding the offset of a property. This is required by 1163 # Entry_u_boot_dtb_with_ucode.ObtainContents(). 1164 data = self._DoReadFile('035_x86_single_ucode.dts', True) 1165 1166 second = data[len(U_BOOT_NODTB_DATA):] 1167 1168 fdt_len = self.GetFdtLen(second) 1169 third = second[fdt_len:] 1170 second = second[:fdt_len] 1171 1172 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679) 1173 self.assertIn(ucode_data, second) 1174 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA) 1175 1176 # Check that the microcode pointer was inserted. It should match the 1177 # expected offset and size 1178 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos, 1179 len(ucode_data)) 1180 first = data[:len(U_BOOT_NODTB_DATA)] 1181 self.assertEqual(b'nodtb with microcode' + pos_and_size + 1182 b' somewhere in here', first) 1183 1184 def testPackUbootSingleMicrocode(self): 1185 """Test that x86 microcode can be handled correctly with fdt_normal. 1186 """ 1187 self._RunPackUbootSingleMicrocode() 1188 1189 def testUBootImg(self): 1190 """Test that u-boot.img can be put in a file""" 1191 data = self._DoReadFile('036_u_boot_img.dts') 1192 self.assertEqual(U_BOOT_IMG_DATA, data) 1193 1194 def testNoMicrocode(self): 1195 """Test that a missing microcode region is detected""" 1196 with self.assertRaises(ValueError) as e: 1197 self._DoReadFile('037_x86_no_ucode.dts', True) 1198 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode " 1199 "node found in ", str(e.exception)) 1200 1201 def testMicrocodeWithoutNode(self): 1202 """Test that a missing u-boot-dtb-with-ucode node is detected""" 1203 with self.assertRaises(ValueError) as e: 1204 self._DoReadFile('038_x86_ucode_missing_node.dts', True) 1205 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find " 1206 "microcode region u-boot-dtb-with-ucode", str(e.exception)) 1207 1208 def testMicrocodeWithoutNode2(self): 1209 """Test that a missing u-boot-ucode node is detected""" 1210 with self.assertRaises(ValueError) as e: 1211 self._DoReadFile('039_x86_ucode_missing_node2.dts', True) 1212 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find " 1213 "microcode region u-boot-ucode", str(e.exception)) 1214 1215 def testMicrocodeWithoutPtrInElf(self): 1216 """Test that a U-Boot binary without the microcode symbol is detected""" 1217 # ELF file without a '_dt_ucode_base_size' symbol 1218 try: 1219 TestFunctional._MakeInputFile('u-boot', 1220 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr'))) 1221 1222 with self.assertRaises(ValueError) as e: 1223 self._RunPackUbootSingleMicrocode() 1224 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate " 1225 "_dt_ucode_base_size symbol in u-boot", str(e.exception)) 1226 1227 finally: 1228 # Put the original file back 1229 TestFunctional._MakeInputFile('u-boot', 1230 tools.ReadFile(self.ElfTestFile('u_boot_ucode_ptr'))) 1231 1232 def testMicrocodeNotInImage(self): 1233 """Test that microcode must be placed within the image""" 1234 with self.assertRaises(ValueError) as e: 1235 self._DoReadFile('040_x86_ucode_not_in_image.dts', True) 1236 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode " 1237 "pointer _dt_ucode_base_size at fffffe14 is outside the " 1238 "section ranging from 00000000 to 0000002e", str(e.exception)) 1239 1240 def testWithoutMicrocode(self): 1241 """Test that we can cope with an image without microcode (e.g. qemu)""" 1242 TestFunctional._MakeInputFile('u-boot', 1243 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr'))) 1244 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True) 1245 1246 # Now check the device tree has no microcode 1247 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)]) 1248 second = data[len(U_BOOT_NODTB_DATA):] 1249 1250 fdt_len = self.GetFdtLen(second) 1251 self.assertEqual(dtb, second[:fdt_len]) 1252 1253 used_len = len(U_BOOT_NODTB_DATA) + fdt_len 1254 third = data[used_len:] 1255 self.assertEqual(tools.GetBytes(0, 0x200 - used_len), third) 1256 1257 def testUnknownPosSize(self): 1258 """Test that microcode must be placed within the image""" 1259 with self.assertRaises(ValueError) as e: 1260 self._DoReadFile('041_unknown_pos_size.dts', True) 1261 self.assertIn("Section '/binman': Unable to set offset/size for unknown " 1262 "entry 'invalid-entry'", str(e.exception)) 1263 1264 def testPackFsp(self): 1265 """Test that an image with a FSP binary can be created""" 1266 data = self._DoReadFile('042_intel_fsp.dts') 1267 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)]) 1268 1269 def testPackCmc(self): 1270 """Test that an image with a CMC binary can be created""" 1271 data = self._DoReadFile('043_intel_cmc.dts') 1272 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)]) 1273 1274 def testPackVbt(self): 1275 """Test that an image with a VBT binary can be created""" 1276 data = self._DoReadFile('046_intel_vbt.dts') 1277 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)]) 1278 1279 def testSplBssPad(self): 1280 """Test that we can pad SPL's BSS with zeros""" 1281 # ELF file with a '__bss_size' symbol 1282 self._SetupSplElf() 1283 data = self._DoReadFile('047_spl_bss_pad.dts') 1284 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA, 1285 data) 1286 1287 def testSplBssPadMissing(self): 1288 """Test that a missing symbol is detected""" 1289 self._SetupSplElf('u_boot_ucode_ptr') 1290 with self.assertRaises(ValueError) as e: 1291 self._DoReadFile('047_spl_bss_pad.dts') 1292 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl', 1293 str(e.exception)) 1294 1295 def testPackStart16Spl(self): 1296 """Test that an image with an x86 start16 SPL region can be created""" 1297 data = self._DoReadFile('048_x86_start16_spl.dts') 1298 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)]) 1299 1300 def _PackUbootSplMicrocode(self, dts, ucode_second=False): 1301 """Helper function for microcode tests 1302 1303 We expect to see the following in the image, in order: 1304 u-boot-spl-nodtb.bin with a microcode pointer inserted at the 1305 correct place 1306 u-boot.dtb with the microcode removed 1307 the microcode 1308 1309 Args: 1310 dts: Device tree file to use for test 1311 ucode_second: True if the microsecond entry is second instead of 1312 third 1313 """ 1314 self._SetupSplElf('u_boot_ucode_ptr') 1315 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA, 1316 ucode_second=ucode_second) 1317 self.assertEqual(b'splnodtb with microc' + pos_and_size + 1318 b'ter somewhere in here', first) 1319 1320 def testPackUbootSplMicrocode(self): 1321 """Test that x86 microcode can be handled correctly in SPL""" 1322 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts') 1323 1324 def testPackUbootSplMicrocodeReorder(self): 1325 """Test that order doesn't matter for microcode entries 1326 1327 This is the same as testPackUbootSplMicrocode but when we process the 1328 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode 1329 entry, so we reply on binman to try later. 1330 """ 1331 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts', 1332 ucode_second=True) 1333 1334 def testPackMrc(self): 1335 """Test that an image with an MRC binary can be created""" 1336 data = self._DoReadFile('050_intel_mrc.dts') 1337 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)]) 1338 1339 def testSplDtb(self): 1340 """Test that an image with spl/u-boot-spl.dtb can be created""" 1341 data = self._DoReadFile('051_u_boot_spl_dtb.dts') 1342 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)]) 1343 1344 def testSplNoDtb(self): 1345 """Test that an image with spl/u-boot-spl-nodtb.bin can be created""" 1346 self._SetupSplElf() 1347 data = self._DoReadFile('052_u_boot_spl_nodtb.dts') 1348 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)]) 1349 1350 def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None, 1351 use_expanded=False): 1352 """Check the image contains the expected symbol values 1353 1354 Args: 1355 dts: Device tree file to use for test 1356 base_data: Data before and after 'u-boot' section 1357 u_boot_offset: Offset of 'u-boot' section in image 1358 entry_args: Dict of entry args to supply to binman 1359 key: arg name 1360 value: value of that arg 1361 use_expanded: True to use expanded entries where available, e.g. 1362 'u-boot-expanded' instead of 'u-boot' 1363 """ 1364 elf_fname = self.ElfTestFile('u_boot_binman_syms') 1365 syms = elf.GetSymbols(elf_fname, ['binman', 'image']) 1366 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start') 1367 self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address, 1368 addr) 1369 1370 self._SetupSplElf('u_boot_binman_syms') 1371 data = self._DoReadFileDtb(dts, entry_args=entry_args, 1372 use_expanded=use_expanded)[0] 1373 # The image should contain the symbols from u_boot_binman_syms.c 1374 # Note that image_pos is adjusted by the base address of the image, 1375 # which is 0x10 in our test image 1376 sym_values = struct.pack('<LQLL', 0x00, 1377 u_boot_offset + len(U_BOOT_DATA), 1378 0x10 + u_boot_offset, 0x04) 1379 expected = (sym_values + base_data[20:] + 1380 tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values + 1381 base_data[20:]) 1382 self.assertEqual(expected, data) 1383 1384 def testSymbols(self): 1385 """Test binman can assign symbols embedded in U-Boot""" 1386 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x18) 1387 1388 def testSymbolsNoDtb(self): 1389 """Test binman can assign symbols embedded in U-Boot SPL""" 1390 self.checkSymbols('196_symbols_nodtb.dts', 1391 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA, 1392 0x38) 1393 1394 def testPackUnitAddress(self): 1395 """Test that we support multiple binaries with the same name""" 1396 data = self._DoReadFile('054_unit_address.dts') 1397 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data) 1398 1399 def testSections(self): 1400 """Basic test of sections""" 1401 data = self._DoReadFile('055_sections.dts') 1402 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) + 1403 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) + 1404 U_BOOT_DATA + tools.GetBytes(ord('&'), 4)) 1405 self.assertEqual(expected, data) 1406 1407 def testMap(self): 1408 """Tests outputting a map of the images""" 1409 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True) 1410 self.assertEqual('''ImagePos Offset Size Name 141100000000 00000000 00000028 main-section 141200000000 00000000 00000010 section@0 141300000000 00000000 00000004 u-boot 141400000010 00000010 00000010 section@1 141500000010 00000000 00000004 u-boot 141600000020 00000020 00000004 section@2 141700000020 00000000 00000004 u-boot 1418''', map_data) 1419 1420 def testNamePrefix(self): 1421 """Tests that name prefixes are used""" 1422 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True) 1423 self.assertEqual('''ImagePos Offset Size Name 142400000000 00000000 00000028 main-section 142500000000 00000000 00000010 section@0 142600000000 00000000 00000004 ro-u-boot 142700000010 00000010 00000010 section@1 142800000010 00000000 00000004 rw-u-boot 1429''', map_data) 1430 1431 def testUnknownContents(self): 1432 """Test that obtaining the contents works as expected""" 1433 with self.assertRaises(ValueError) as e: 1434 self._DoReadFile('057_unknown_contents.dts', True) 1435 self.assertIn("Image '/binman': Internal error: Could not complete " 1436 "processing of contents: remaining [" 1437 "<binman.etype._testing.Entry__testing ", str(e.exception)) 1438 1439 def testBadChangeSize(self): 1440 """Test that trying to change the size of an entry fails""" 1441 try: 1442 state.SetAllowEntryExpansion(False) 1443 with self.assertRaises(ValueError) as e: 1444 self._DoReadFile('059_change_size.dts', True) 1445 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3", 1446 str(e.exception)) 1447 finally: 1448 state.SetAllowEntryExpansion(True) 1449 1450 def testUpdateFdt(self): 1451 """Test that we can update the device tree with offset/size info""" 1452 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts', 1453 update_dtb=True) 1454 dtb = fdt.Fdt(out_dtb_fname) 1455 dtb.Scan() 1456 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS) 1457 self.assertEqual({ 1458 'image-pos': 0, 1459 'offset': 0, 1460 '_testing:offset': 32, 1461 '_testing:size': 2, 1462 '_testing:image-pos': 32, 1463 'section@0/u-boot:offset': 0, 1464 'section@0/u-boot:size': len(U_BOOT_DATA), 1465 'section@0/u-boot:image-pos': 0, 1466 'section@0:offset': 0, 1467 'section@0:size': 16, 1468 'section@0:image-pos': 0, 1469 1470 'section@1/u-boot:offset': 0, 1471 'section@1/u-boot:size': len(U_BOOT_DATA), 1472 'section@1/u-boot:image-pos': 16, 1473 'section@1:offset': 16, 1474 'section@1:size': 16, 1475 'section@1:image-pos': 16, 1476 'size': 40 1477 }, props) 1478 1479 def testUpdateFdtBad(self): 1480 """Test that we detect when ProcessFdt never completes""" 1481 with self.assertRaises(ValueError) as e: 1482 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True) 1483 self.assertIn('Could not complete processing of Fdt: remaining ' 1484 '[<binman.etype._testing.Entry__testing', 1485 str(e.exception)) 1486 1487 def testEntryArgs(self): 1488 """Test passing arguments to entries from the command line""" 1489 entry_args = { 1490 'test-str-arg': 'test1', 1491 'test-int-arg': '456', 1492 } 1493 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args) 1494 self.assertIn('image', control.images) 1495 entry = control.images['image'].GetEntries()['_testing'] 1496 self.assertEqual('test0', entry.test_str_fdt) 1497 self.assertEqual('test1', entry.test_str_arg) 1498 self.assertEqual(123, entry.test_int_fdt) 1499 self.assertEqual(456, entry.test_int_arg) 1500 1501 def testEntryArgsMissing(self): 1502 """Test missing arguments and properties""" 1503 entry_args = { 1504 'test-int-arg': '456', 1505 } 1506 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args) 1507 entry = control.images['image'].GetEntries()['_testing'] 1508 self.assertEqual('test0', entry.test_str_fdt) 1509 self.assertEqual(None, entry.test_str_arg) 1510 self.assertEqual(None, entry.test_int_fdt) 1511 self.assertEqual(456, entry.test_int_arg) 1512 1513 def testEntryArgsRequired(self): 1514 """Test missing arguments and properties""" 1515 entry_args = { 1516 'test-int-arg': '456', 1517 } 1518 with self.assertRaises(ValueError) as e: 1519 self._DoReadFileDtb('064_entry_args_required.dts') 1520 self.assertIn("Node '/binman/_testing': " 1521 'Missing required properties/entry args: test-str-arg, ' 1522 'test-int-fdt, test-int-arg', 1523 str(e.exception)) 1524 1525 def testEntryArgsInvalidFormat(self): 1526 """Test that an invalid entry-argument format is detected""" 1527 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'), 1528 '-ano-value'] 1529 with self.assertRaises(ValueError) as e: 1530 self._DoBinman(*args) 1531 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception)) 1532 1533 def testEntryArgsInvalidInteger(self): 1534 """Test that an invalid entry-argument integer is detected""" 1535 entry_args = { 1536 'test-int-arg': 'abc', 1537 } 1538 with self.assertRaises(ValueError) as e: 1539 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args) 1540 self.assertIn("Node '/binman/_testing': Cannot convert entry arg " 1541 "'test-int-arg' (value 'abc') to integer", 1542 str(e.exception)) 1543 1544 def testEntryArgsInvalidDatatype(self): 1545 """Test that an invalid entry-argument datatype is detected 1546 1547 This test could be written in entry_test.py except that it needs 1548 access to control.entry_args, which seems more than that module should 1549 be able to see. 1550 """ 1551 entry_args = { 1552 'test-bad-datatype-arg': '12', 1553 } 1554 with self.assertRaises(ValueError) as e: 1555 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts', 1556 entry_args=entry_args) 1557 self.assertIn('GetArg() internal error: Unknown data type ', 1558 str(e.exception)) 1559 1560 def testText(self): 1561 """Test for a text entry type""" 1562 entry_args = { 1563 'test-id': TEXT_DATA, 1564 'test-id2': TEXT_DATA2, 1565 'test-id3': TEXT_DATA3, 1566 } 1567 data, _, _, _ = self._DoReadFileDtb('066_text.dts', 1568 entry_args=entry_args) 1569 expected = (tools.ToBytes(TEXT_DATA) + 1570 tools.GetBytes(0, 8 - len(TEXT_DATA)) + 1571 tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) + 1572 b'some text' + b'more text') 1573 self.assertEqual(expected, data) 1574 1575 def testEntryDocs(self): 1576 """Test for creation of entry documentation""" 1577 with test_util.capture_sys_output() as (stdout, stderr): 1578 control.WriteEntryDocs(control.GetEntryModules()) 1579 self.assertTrue(len(stdout.getvalue()) > 0) 1580 1581 def testEntryDocsMissing(self): 1582 """Test handling of missing entry documentation""" 1583 with self.assertRaises(ValueError) as e: 1584 with test_util.capture_sys_output() as (stdout, stderr): 1585 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot') 1586 self.assertIn('Documentation is missing for modules: u_boot', 1587 str(e.exception)) 1588 1589 def testFmap(self): 1590 """Basic test of generation of a flashrom fmap""" 1591 data = self._DoReadFile('067_fmap.dts') 1592 fhdr, fentries = fmap_util.DecodeFmap(data[32:]) 1593 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) + 1594 U_BOOT_DATA + tools.GetBytes(ord('a'), 12)) 1595 self.assertEqual(expected, data[:32]) 1596 self.assertEqual(b'__FMAP__', fhdr.signature) 1597 self.assertEqual(1, fhdr.ver_major) 1598 self.assertEqual(0, fhdr.ver_minor) 1599 self.assertEqual(0, fhdr.base) 1600 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 5 1601 self.assertEqual(16 + 16 + expect_size, fhdr.image_size) 1602 self.assertEqual(b'FMAP', fhdr.name) 1603 self.assertEqual(5, fhdr.nareas) 1604 fiter = iter(fentries) 1605 1606 fentry = next(fiter) 1607 self.assertEqual(b'SECTION0', fentry.name) 1608 self.assertEqual(0, fentry.offset) 1609 self.assertEqual(16, fentry.size) 1610 self.assertEqual(0, fentry.flags) 1611 1612 fentry = next(fiter) 1613 self.assertEqual(b'RO_U_BOOT', fentry.name) 1614 self.assertEqual(0, fentry.offset) 1615 self.assertEqual(4, fentry.size) 1616 self.assertEqual(0, fentry.flags) 1617 1618 fentry = next(fiter) 1619 self.assertEqual(b'SECTION1', fentry.name) 1620 self.assertEqual(16, fentry.offset) 1621 self.assertEqual(16, fentry.size) 1622 self.assertEqual(0, fentry.flags) 1623 1624 fentry = next(fiter) 1625 self.assertEqual(b'RW_U_BOOT', fentry.name) 1626 self.assertEqual(16, fentry.offset) 1627 self.assertEqual(4, fentry.size) 1628 self.assertEqual(0, fentry.flags) 1629 1630 fentry = next(fiter) 1631 self.assertEqual(b'FMAP', fentry.name) 1632 self.assertEqual(32, fentry.offset) 1633 self.assertEqual(expect_size, fentry.size) 1634 self.assertEqual(0, fentry.flags) 1635 1636 def testBlobNamedByArg(self): 1637 """Test we can add a blob with the filename coming from an entry arg""" 1638 entry_args = { 1639 'cros-ec-rw-path': 'ecrw.bin', 1640 } 1641 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args) 1642 1643 def testFill(self): 1644 """Test for an fill entry type""" 1645 data = self._DoReadFile('069_fill.dts') 1646 expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8) 1647 self.assertEqual(expected, data) 1648 1649 def testFillNoSize(self): 1650 """Test for an fill entry type with no size""" 1651 with self.assertRaises(ValueError) as e: 1652 self._DoReadFile('070_fill_no_size.dts') 1653 self.assertIn("'fill' entry must have a size property", 1654 str(e.exception)) 1655 1656 def _HandleGbbCommand(self, pipe_list): 1657 """Fake calls to the futility utility""" 1658 if pipe_list[0][0] == 'futility': 1659 fname = pipe_list[0][-1] 1660 # Append our GBB data to the file, which will happen every time the 1661 # futility command is called. 1662 with open(fname, 'ab') as fd: 1663 fd.write(GBB_DATA) 1664 return command.CommandResult() 1665 1666 def testGbb(self): 1667 """Test for the Chromium OS Google Binary Block""" 1668 command.test_result = self._HandleGbbCommand 1669 entry_args = { 1670 'keydir': 'devkeys', 1671 'bmpblk': 'bmpblk.bin', 1672 } 1673 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args) 1674 1675 # Since futility 1676 expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) + 1677 tools.GetBytes(0, 0x2180 - 16)) 1678 self.assertEqual(expected, data) 1679 1680 def testGbbTooSmall(self): 1681 """Test for the Chromium OS Google Binary Block being large enough""" 1682 with self.assertRaises(ValueError) as e: 1683 self._DoReadFileDtb('072_gbb_too_small.dts') 1684 self.assertIn("Node '/binman/gbb': GBB is too small", 1685 str(e.exception)) 1686 1687 def testGbbNoSize(self): 1688 """Test for the Chromium OS Google Binary Block having a size""" 1689 with self.assertRaises(ValueError) as e: 1690 self._DoReadFileDtb('073_gbb_no_size.dts') 1691 self.assertIn("Node '/binman/gbb': GBB must have a fixed size", 1692 str(e.exception)) 1693 1694 def _HandleVblockCommand(self, pipe_list): 1695 """Fake calls to the futility utility 1696 1697 The expected pipe is: 1698 1699 [('futility', 'vbutil_firmware', '--vblock', 1700 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock', 1701 '--signprivate', 'devkeys/firmware_data_key.vbprivk', 1702 '--version', '1', '--fv', 'input.vblock', '--kernelkey', 1703 'devkeys/kernel_subkey.vbpubk', '--flags', '1')] 1704 1705 This writes to the output file (here, 'vblock.vblock'). If 1706 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash 1707 of the input data (here, 'input.vblock'). 1708 """ 1709 if pipe_list[0][0] == 'futility': 1710 fname = pipe_list[0][3] 1711 with open(fname, 'wb') as fd: 1712 if self._hash_data: 1713 infile = pipe_list[0][11] 1714 m = hashlib.sha256() 1715 data = tools.ReadFile(infile) 1716 m.update(data) 1717 fd.write(m.digest()) 1718 else: 1719 fd.write(VBLOCK_DATA) 1720 1721 return command.CommandResult() 1722 1723 def testVblock(self): 1724 """Test for the Chromium OS Verified Boot Block""" 1725 self._hash_data = False 1726 command.test_result = self._HandleVblockCommand 1727 entry_args = { 1728 'keydir': 'devkeys', 1729 } 1730 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts', 1731 entry_args=entry_args) 1732 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA 1733 self.assertEqual(expected, data) 1734 1735 def testVblockNoContent(self): 1736 """Test we detect a vblock which has no content to sign""" 1737 with self.assertRaises(ValueError) as e: 1738 self._DoReadFile('075_vblock_no_content.dts') 1739 self.assertIn("Node '/binman/vblock': Collection must have a 'content' " 1740 'property', str(e.exception)) 1741 1742 def testVblockBadPhandle(self): 1743 """Test that we detect a vblock with an invalid phandle in contents""" 1744 with self.assertRaises(ValueError) as e: 1745 self._DoReadFile('076_vblock_bad_phandle.dts') 1746 self.assertIn("Node '/binman/vblock': Cannot find node for phandle " 1747 '1000', str(e.exception)) 1748 1749 def testVblockBadEntry(self): 1750 """Test that we detect an entry that points to a non-entry""" 1751 with self.assertRaises(ValueError) as e: 1752 self._DoReadFile('077_vblock_bad_entry.dts') 1753 self.assertIn("Node '/binman/vblock': Cannot find entry for node " 1754 "'other'", str(e.exception)) 1755 1756 def testVblockContent(self): 1757 """Test that the vblock signs the right data""" 1758 self._hash_data = True 1759 command.test_result = self._HandleVblockCommand 1760 entry_args = { 1761 'keydir': 'devkeys', 1762 } 1763 data = self._DoReadFileDtb( 1764 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True, 1765 entry_args=entry_args)[0] 1766 hashlen = 32 # SHA256 hash is 32 bytes 1767 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)]) 1768 hashval = data[-hashlen:] 1769 dtb = data[len(U_BOOT_DATA):-hashlen] 1770 1771 expected_data = U_BOOT_DATA + dtb 1772 1773 # The hashval should be a hash of the dtb 1774 m = hashlib.sha256() 1775 m.update(expected_data) 1776 expected_hashval = m.digest() 1777 self.assertEqual(expected_hashval, hashval) 1778 1779 def testTpl(self): 1780 """Test that an image with TPL and its device tree can be created""" 1781 # ELF file with a '__bss_size' symbol 1782 self._SetupTplElf() 1783 data = self._DoReadFile('078_u_boot_tpl.dts') 1784 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data) 1785 1786 def testUsesPos(self): 1787 """Test that the 'pos' property cannot be used anymore""" 1788 with self.assertRaises(ValueError) as e: 1789 data = self._DoReadFile('079_uses_pos.dts') 1790 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of " 1791 "'pos'", str(e.exception)) 1792 1793 def testFillZero(self): 1794 """Test for an fill entry type with a size of 0""" 1795 data = self._DoReadFile('080_fill_empty.dts') 1796 self.assertEqual(tools.GetBytes(0, 16), data) 1797 1798 def testTextMissing(self): 1799 """Test for a text entry type where there is no text""" 1800 with self.assertRaises(ValueError) as e: 1801 self._DoReadFileDtb('066_text.dts',) 1802 self.assertIn("Node '/binman/text': No value provided for text label " 1803 "'test-id'", str(e.exception)) 1804 1805 def testPackStart16Tpl(self): 1806 """Test that an image with an x86 start16 TPL region can be created""" 1807 data = self._DoReadFile('081_x86_start16_tpl.dts') 1808 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)]) 1809 1810 def testSelectImage(self): 1811 """Test that we can select which images to build""" 1812 expected = 'Skipping images: image1' 1813 1814 # We should only get the expected message in verbose mode 1815 for verbosity in (0, 2): 1816 with test_util.capture_sys_output() as (stdout, stderr): 1817 retcode = self._DoTestFile('006_dual_image.dts', 1818 verbosity=verbosity, 1819 images=['image2']) 1820 self.assertEqual(0, retcode) 1821 if verbosity: 1822 self.assertIn(expected, stdout.getvalue()) 1823 else: 1824 self.assertNotIn(expected, stdout.getvalue()) 1825 1826 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin'))) 1827 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin'))) 1828 self._CleanupOutputDir() 1829 1830 def testUpdateFdtAll(self): 1831 """Test that all device trees are updated with offset/size info""" 1832 data = self._DoReadFileRealDtb('082_fdt_update_all.dts') 1833 1834 base_expected = { 1835 'section:image-pos': 0, 1836 'u-boot-tpl-dtb:size': 513, 1837 'u-boot-spl-dtb:size': 513, 1838 'u-boot-spl-dtb:offset': 493, 1839 'image-pos': 0, 1840 'section/u-boot-dtb:image-pos': 0, 1841 'u-boot-spl-dtb:image-pos': 493, 1842 'section/u-boot-dtb:size': 493, 1843 'u-boot-tpl-dtb:image-pos': 1006, 1844 'section/u-boot-dtb:offset': 0, 1845 'section:size': 493, 1846 'offset': 0, 1847 'section:offset': 0, 1848 'u-boot-tpl-dtb:offset': 1006, 1849 'size': 1519 1850 } 1851 1852 # We expect three device-tree files in the output, one after the other. 1853 # Read them in sequence. We look for an 'spl' property in the SPL tree, 1854 # and 'tpl' in the TPL tree, to make sure they are distinct from the 1855 # main U-Boot tree. All three should have the same postions and offset. 1856 start = 0 1857 for item in ['', 'spl', 'tpl']: 1858 dtb = fdt.Fdt.FromData(data[start:]) 1859 dtb.Scan() 1860 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS + 1861 ['spl', 'tpl']) 1862 expected = dict(base_expected) 1863 if item: 1864 expected[item] = 0 1865 self.assertEqual(expected, props) 1866 start += dtb._fdt_obj.totalsize() 1867 1868 def testUpdateFdtOutput(self): 1869 """Test that output DTB files are updated""" 1870 try: 1871 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts', 1872 use_real_dtb=True, update_dtb=True, reset_dtbs=False) 1873 1874 # Unfortunately, compiling a source file always results in a file 1875 # called source.dtb (see fdt_util.EnsureCompiled()). The test 1876 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter 1877 # binman as a file called u-boot.dtb. To fix this, copy the file 1878 # over to the expected place. 1879 start = 0 1880 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out', 1881 'tpl/u-boot-tpl.dtb.out']: 1882 dtb = fdt.Fdt.FromData(data[start:]) 1883 size = dtb._fdt_obj.totalsize() 1884 pathname = tools.GetOutputFilename(os.path.split(fname)[1]) 1885 outdata = tools.ReadFile(pathname) 1886 name = os.path.split(fname)[0] 1887 1888 if name: 1889 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name) 1890 else: 1891 orig_indata = dtb_data 1892 self.assertNotEqual(outdata, orig_indata, 1893 "Expected output file '%s' be updated" % pathname) 1894 self.assertEqual(outdata, data[start:start + size], 1895 "Expected output file '%s' to match output image" % 1896 pathname) 1897 start += size 1898 finally: 1899 self._ResetDtbs() 1900 1901 def _decompress(self, data): 1902 return tools.Decompress(data, 'lz4') 1903 1904 def testCompress(self): 1905 """Test compression of blobs""" 1906 self._CheckLz4() 1907 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts', 1908 use_real_dtb=True, update_dtb=True) 1909 dtb = fdt.Fdt(out_dtb_fname) 1910 dtb.Scan() 1911 props = self._GetPropTree(dtb, ['size', 'uncomp-size']) 1912 orig = self._decompress(data) 1913 self.assertEquals(COMPRESS_DATA, orig) 1914 1915 # Do a sanity check on various fields 1916 image = control.images['image'] 1917 entries = image.GetEntries() 1918 self.assertEqual(1, len(entries)) 1919 1920 entry = entries['blob'] 1921 self.assertEqual(COMPRESS_DATA, entry.uncomp_data) 1922 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size) 1923 orig = self._decompress(entry.data) 1924 self.assertEqual(orig, entry.uncomp_data) 1925 1926 self.assertEqual(image.data, entry.data) 1927 1928 expected = { 1929 'blob:uncomp-size': len(COMPRESS_DATA), 1930 'blob:size': len(data), 1931 'size': len(data), 1932 } 1933 self.assertEqual(expected, props) 1934 1935 def testFiles(self): 1936 """Test bringing in multiple files""" 1937 data = self._DoReadFile('084_files.dts') 1938 self.assertEqual(FILES_DATA, data) 1939 1940 def testFilesCompress(self): 1941 """Test bringing in multiple files and compressing them""" 1942 self._CheckLz4() 1943 data = self._DoReadFile('085_files_compress.dts') 1944 1945 image = control.images['image'] 1946 entries = image.GetEntries() 1947 files = entries['files'] 1948 entries = files._entries 1949 1950 orig = b'' 1951 for i in range(1, 3): 1952 key = '%d.dat' % i 1953 start = entries[key].image_pos 1954 len = entries[key].size 1955 chunk = data[start:start + len] 1956 orig += self._decompress(chunk) 1957 1958 self.assertEqual(FILES_DATA, orig) 1959 1960 def testFilesMissing(self): 1961 """Test missing files""" 1962 with self.assertRaises(ValueError) as e: 1963 data = self._DoReadFile('086_files_none.dts') 1964 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched " 1965 'no files', str(e.exception)) 1966 1967 def testFilesNoPattern(self): 1968 """Test missing files""" 1969 with self.assertRaises(ValueError) as e: 1970 data = self._DoReadFile('087_files_no_pattern.dts') 1971 self.assertIn("Node '/binman/files': Missing 'pattern' property", 1972 str(e.exception)) 1973 1974 def testExpandSize(self): 1975 """Test an expanding entry""" 1976 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts', 1977 map=True) 1978 expect = (tools.GetBytes(ord('a'), 8) + U_BOOT_DATA + 1979 MRC_DATA + tools.GetBytes(ord('b'), 1) + U_BOOT_DATA + 1980 tools.GetBytes(ord('c'), 8) + U_BOOT_DATA + 1981 tools.GetBytes(ord('d'), 8)) 1982 self.assertEqual(expect, data) 1983 self.assertEqual('''ImagePos Offset Size Name 198400000000 00000000 00000028 main-section 198500000000 00000000 00000008 fill 198600000008 00000008 00000004 u-boot 19870000000c 0000000c 00000004 section 19880000000c 00000000 00000003 intel-mrc 198900000010 00000010 00000004 u-boot2 199000000014 00000014 0000000c section2 199100000014 00000000 00000008 fill 19920000001c 00000008 00000004 u-boot 199300000020 00000020 00000008 fill2 1994''', map_data) 1995 1996 def testExpandSizeBad(self): 1997 """Test an expanding entry which fails to provide contents""" 1998 with test_util.capture_sys_output() as (stdout, stderr): 1999 with self.assertRaises(ValueError) as e: 2000 self._DoReadFileDtb('089_expand_size_bad.dts', map=True) 2001 self.assertIn("Node '/binman/_testing': Cannot obtain contents when " 2002 'expanding entry', str(e.exception)) 2003 2004 def testHash(self): 2005 """Test hashing of the contents of an entry""" 2006 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts', 2007 use_real_dtb=True, update_dtb=True) 2008 dtb = fdt.Fdt(out_dtb_fname) 2009 dtb.Scan() 2010 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value'] 2011 m = hashlib.sha256() 2012 m.update(U_BOOT_DATA) 2013 self.assertEqual(m.digest(), b''.join(hash_node.value)) 2014 2015 def testHashNoAlgo(self): 2016 with self.assertRaises(ValueError) as e: 2017 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True) 2018 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for " 2019 'hash node', str(e.exception)) 2020 2021 def testHashBadAlgo(self): 2022 with self.assertRaises(ValueError) as e: 2023 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True) 2024 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm", 2025 str(e.exception)) 2026 2027 def testHashSection(self): 2028 """Test hashing of the contents of an entry""" 2029 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts', 2030 use_real_dtb=True, update_dtb=True) 2031 dtb = fdt.Fdt(out_dtb_fname) 2032 dtb.Scan() 2033 hash_node = dtb.GetNode('/binman/section/hash').props['value'] 2034 m = hashlib.sha256() 2035 m.update(U_BOOT_DATA) 2036 m.update(tools.GetBytes(ord('a'), 16)) 2037 self.assertEqual(m.digest(), b''.join(hash_node.value)) 2038 2039 def testPackUBootTplMicrocode(self): 2040 """Test that x86 microcode can be handled correctly in TPL 2041 2042 We expect to see the following in the image, in order: 2043 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct 2044 place 2045 u-boot-tpl.dtb with the microcode removed 2046 the microcode 2047 """ 2048 self._SetupTplElf('u_boot_ucode_ptr') 2049 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts', 2050 U_BOOT_TPL_NODTB_DATA) 2051 self.assertEqual(b'tplnodtb with microc' + pos_and_size + 2052 b'ter somewhere in here', first) 2053 2054 def testFmapX86(self): 2055 """Basic test of generation of a flashrom fmap""" 2056 data = self._DoReadFile('094_fmap_x86.dts') 2057 fhdr, fentries = fmap_util.DecodeFmap(data[32:]) 2058 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7) 2059 self.assertEqual(expected, data[:32]) 2060 fhdr, fentries = fmap_util.DecodeFmap(data[32:]) 2061 2062 self.assertEqual(0x100, fhdr.image_size) 2063 2064 self.assertEqual(0, fentries[0].offset) 2065 self.assertEqual(4, fentries[0].size) 2066 self.assertEqual(b'U_BOOT', fentries[0].name) 2067 2068 self.assertEqual(4, fentries[1].offset) 2069 self.assertEqual(3, fentries[1].size) 2070 self.assertEqual(b'INTEL_MRC', fentries[1].name) 2071 2072 self.assertEqual(32, fentries[2].offset) 2073 self.assertEqual(fmap_util.FMAP_HEADER_LEN + 2074 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size) 2075 self.assertEqual(b'FMAP', fentries[2].name) 2076 2077 def testFmapX86Section(self): 2078 """Basic test of generation of a flashrom fmap""" 2079 data = self._DoReadFile('095_fmap_x86_section.dts') 2080 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7) 2081 self.assertEqual(expected, data[:32]) 2082 fhdr, fentries = fmap_util.DecodeFmap(data[36:]) 2083 2084 self.assertEqual(0x180, fhdr.image_size) 2085 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4 2086 fiter = iter(fentries) 2087 2088 fentry = next(fiter) 2089 self.assertEqual(b'U_BOOT', fentry.name) 2090 self.assertEqual(0, fentry.offset) 2091 self.assertEqual(4, fentry.size) 2092 2093 fentry = next(fiter) 2094 self.assertEqual(b'SECTION', fentry.name) 2095 self.assertEqual(4, fentry.offset) 2096 self.assertEqual(0x20 + expect_size, fentry.size) 2097 2098 fentry = next(fiter) 2099 self.assertEqual(b'INTEL_MRC', fentry.name) 2100 self.assertEqual(4, fentry.offset) 2101 self.assertEqual(3, fentry.size) 2102 2103 fentry = next(fiter) 2104 self.assertEqual(b'FMAP', fentry.name) 2105 self.assertEqual(36, fentry.offset) 2106 self.assertEqual(expect_size, fentry.size) 2107 2108 def testElf(self): 2109 """Basic test of ELF entries""" 2110 self._SetupSplElf() 2111 self._SetupTplElf() 2112 with open(self.ElfTestFile('bss_data'), 'rb') as fd: 2113 TestFunctional._MakeInputFile('-boot', fd.read()) 2114 data = self._DoReadFile('096_elf.dts') 2115 2116 def testElfStrip(self): 2117 """Basic test of ELF entries""" 2118 self._SetupSplElf() 2119 with open(self.ElfTestFile('bss_data'), 'rb') as fd: 2120 TestFunctional._MakeInputFile('-boot', fd.read()) 2121 data = self._DoReadFile('097_elf_strip.dts') 2122 2123 def testPackOverlapMap(self): 2124 """Test that overlapping regions are detected""" 2125 with test_util.capture_sys_output() as (stdout, stderr): 2126 with self.assertRaises(ValueError) as e: 2127 self._DoTestFile('014_pack_overlap.dts', map=True) 2128 map_fname = tools.GetOutputFilename('image.map') 2129 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname, 2130 stdout.getvalue()) 2131 2132 # We should not get an inmage, but there should be a map file 2133 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin'))) 2134 self.assertTrue(os.path.exists(map_fname)) 2135 map_data = tools.ReadFile(map_fname, binary=False) 2136 self.assertEqual('''ImagePos Offset Size Name 2137<none> 00000000 00000008 main-section 2138<none> 00000000 00000004 u-boot 2139<none> 00000003 00000004 u-boot-align 2140''', map_data) 2141 2142 def testPackRefCode(self): 2143 """Test that an image with an Intel Reference code binary works""" 2144 data = self._DoReadFile('100_intel_refcode.dts') 2145 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)]) 2146 2147 def testSectionOffset(self): 2148 """Tests use of a section with an offset""" 2149 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts', 2150 map=True) 2151 self.assertEqual('''ImagePos Offset Size Name 215200000000 00000000 00000038 main-section 215300000004 00000004 00000010 section@0 215400000004 00000000 00000004 u-boot 215500000018 00000018 00000010 section@1 215600000018 00000000 00000004 u-boot 21570000002c 0000002c 00000004 section@2 21580000002c 00000000 00000004 u-boot 2159''', map_data) 2160 self.assertEqual(data, 2161 tools.GetBytes(0x26, 4) + U_BOOT_DATA + 2162 tools.GetBytes(0x21, 12) + 2163 tools.GetBytes(0x26, 4) + U_BOOT_DATA + 2164 tools.GetBytes(0x61, 12) + 2165 tools.GetBytes(0x26, 4) + U_BOOT_DATA + 2166 tools.GetBytes(0x26, 8)) 2167 2168 def testCbfsRaw(self): 2169 """Test base handling of a Coreboot Filesystem (CBFS) 2170 2171 The exact contents of the CBFS is verified by similar tests in 2172 cbfs_util_test.py. The tests here merely check that the files added to 2173 the CBFS can be found in the final image. 2174 """ 2175 data = self._DoReadFile('102_cbfs_raw.dts') 2176 size = 0xb0 2177 2178 cbfs = cbfs_util.CbfsReader(data) 2179 self.assertEqual(size, cbfs.rom_size) 2180 2181 self.assertIn('u-boot-dtb', cbfs.files) 2182 cfile = cbfs.files['u-boot-dtb'] 2183 self.assertEqual(U_BOOT_DTB_DATA, cfile.data) 2184 2185 def testCbfsArch(self): 2186 """Test on non-x86 architecture""" 2187 data = self._DoReadFile('103_cbfs_raw_ppc.dts') 2188 size = 0x100 2189 2190 cbfs = cbfs_util.CbfsReader(data) 2191 self.assertEqual(size, cbfs.rom_size) 2192 2193 self.assertIn('u-boot-dtb', cbfs.files) 2194 cfile = cbfs.files['u-boot-dtb'] 2195 self.assertEqual(U_BOOT_DTB_DATA, cfile.data) 2196 2197 def testCbfsStage(self): 2198 """Tests handling of a Coreboot Filesystem (CBFS)""" 2199 if not elf.ELF_TOOLS: 2200 self.skipTest('Python elftools not available') 2201 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf') 2202 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA) 2203 size = 0xb0 2204 2205 data = self._DoReadFile('104_cbfs_stage.dts') 2206 cbfs = cbfs_util.CbfsReader(data) 2207 self.assertEqual(size, cbfs.rom_size) 2208 2209 self.assertIn('u-boot', cbfs.files) 2210 cfile = cbfs.files['u-boot'] 2211 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data) 2212 2213 def testCbfsRawCompress(self): 2214 """Test handling of compressing raw files""" 2215 self._CheckLz4() 2216 data = self._DoReadFile('105_cbfs_raw_compress.dts') 2217 size = 0x140 2218 2219 cbfs = cbfs_util.CbfsReader(data) 2220 self.assertIn('u-boot', cbfs.files) 2221 cfile = cbfs.files['u-boot'] 2222 self.assertEqual(COMPRESS_DATA, cfile.data) 2223 2224 def testCbfsBadArch(self): 2225 """Test handling of a bad architecture""" 2226 with self.assertRaises(ValueError) as e: 2227 self._DoReadFile('106_cbfs_bad_arch.dts') 2228 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception)) 2229 2230 def testCbfsNoSize(self): 2231 """Test handling of a missing size property""" 2232 with self.assertRaises(ValueError) as e: 2233 self._DoReadFile('107_cbfs_no_size.dts') 2234 self.assertIn('entry must have a size property', str(e.exception)) 2235 2236 def testCbfsNoCOntents(self): 2237 """Test handling of a CBFS entry which does not provide contentsy""" 2238 with self.assertRaises(ValueError) as e: 2239 self._DoReadFile('108_cbfs_no_contents.dts') 2240 self.assertIn('Could not complete processing of contents', 2241 str(e.exception)) 2242 2243 def testCbfsBadCompress(self): 2244 """Test handling of a bad architecture""" 2245 with self.assertRaises(ValueError) as e: 2246 self._DoReadFile('109_cbfs_bad_compress.dts') 2247 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'", 2248 str(e.exception)) 2249 2250 def testCbfsNamedEntries(self): 2251 """Test handling of named entries""" 2252 data = self._DoReadFile('110_cbfs_name.dts') 2253 2254 cbfs = cbfs_util.CbfsReader(data) 2255 self.assertIn('FRED', cbfs.files) 2256 cfile1 = cbfs.files['FRED'] 2257 self.assertEqual(U_BOOT_DATA, cfile1.data) 2258 2259 self.assertIn('hello', cbfs.files) 2260 cfile2 = cbfs.files['hello'] 2261 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data) 2262 2263 def _SetupIfwi(self, fname): 2264 """Set up to run an IFWI test 2265 2266 Args: 2267 fname: Filename of input file to provide (fitimage.bin or ifwi.bin) 2268 """ 2269 self._SetupSplElf() 2270 self._SetupTplElf() 2271 2272 # Intel Integrated Firmware Image (IFWI) file 2273 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd: 2274 data = fd.read() 2275 TestFunctional._MakeInputFile(fname,data) 2276 2277 def _CheckIfwi(self, data): 2278 """Check that an image with an IFWI contains the correct output 2279 2280 Args: 2281 data: Conents of output file 2282 """ 2283 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin')) 2284 if data[:0x1000] != expected_desc: 2285 self.fail('Expected descriptor binary at start of image') 2286 2287 # We expect to find the TPL wil in subpart IBBP entry IBBL 2288 image_fname = tools.GetOutputFilename('image.bin') 2289 tpl_fname = tools.GetOutputFilename('tpl.out') 2290 tools.RunIfwiTool(image_fname, tools.CMD_EXTRACT, fname=tpl_fname, 2291 subpart='IBBP', entry_name='IBBL') 2292 2293 tpl_data = tools.ReadFile(tpl_fname) 2294 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)]) 2295 2296 def testPackX86RomIfwi(self): 2297 """Test that an x86 ROM with Integrated Firmware Image can be created""" 2298 self._SetupIfwi('fitimage.bin') 2299 data = self._DoReadFile('111_x86_rom_ifwi.dts') 2300 self._CheckIfwi(data) 2301 2302 def testPackX86RomIfwiNoDesc(self): 2303 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file""" 2304 self._SetupIfwi('ifwi.bin') 2305 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts') 2306 self._CheckIfwi(data) 2307 2308 def testPackX86RomIfwiNoData(self): 2309 """Test that an x86 ROM with IFWI handles missing data""" 2310 self._SetupIfwi('ifwi.bin') 2311 with self.assertRaises(ValueError) as e: 2312 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts') 2313 self.assertIn('Could not complete processing of contents', 2314 str(e.exception)) 2315 2316 def testCbfsOffset(self): 2317 """Test a CBFS with files at particular offsets 2318 2319 Like all CFBS tests, this is just checking the logic that calls 2320 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()). 2321 """ 2322 data = self._DoReadFile('114_cbfs_offset.dts') 2323 size = 0x200 2324 2325 cbfs = cbfs_util.CbfsReader(data) 2326 self.assertEqual(size, cbfs.rom_size) 2327 2328 self.assertIn('u-boot', cbfs.files) 2329 cfile = cbfs.files['u-boot'] 2330 self.assertEqual(U_BOOT_DATA, cfile.data) 2331 self.assertEqual(0x40, cfile.cbfs_offset) 2332 2333 self.assertIn('u-boot-dtb', cbfs.files) 2334 cfile2 = cbfs.files['u-boot-dtb'] 2335 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data) 2336 self.assertEqual(0x140, cfile2.cbfs_offset) 2337 2338 def testFdtmap(self): 2339 """Test an FDT map can be inserted in the image""" 2340 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts') 2341 fdtmap_data = data[len(U_BOOT_DATA):] 2342 magic = fdtmap_data[:8] 2343 self.assertEqual(b'_FDTMAP_', magic) 2344 self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16]) 2345 2346 fdt_data = fdtmap_data[16:] 2347 dtb = fdt.Fdt.FromData(fdt_data) 2348 dtb.Scan() 2349 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/') 2350 self.assertEqual({ 2351 'image-pos': 0, 2352 'offset': 0, 2353 'u-boot:offset': 0, 2354 'u-boot:size': len(U_BOOT_DATA), 2355 'u-boot:image-pos': 0, 2356 'fdtmap:image-pos': 4, 2357 'fdtmap:offset': 4, 2358 'fdtmap:size': len(fdtmap_data), 2359 'size': len(data), 2360 }, props) 2361 2362 def testFdtmapNoMatch(self): 2363 """Check handling of an FDT map when the section cannot be found""" 2364 self.data = self._DoReadFileRealDtb('115_fdtmap.dts') 2365 2366 # Mangle the section name, which should cause a mismatch between the 2367 # correct FDT path and the one expected by the section 2368 image = control.images['image'] 2369 image._node.path += '-suffix' 2370 entries = image.GetEntries() 2371 fdtmap = entries['fdtmap'] 2372 with self.assertRaises(ValueError) as e: 2373 fdtmap._GetFdtmap() 2374 self.assertIn("Cannot locate node for path '/binman-suffix'", 2375 str(e.exception)) 2376 2377 def testFdtmapHeader(self): 2378 """Test an FDT map and image header can be inserted in the image""" 2379 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts') 2380 fdtmap_pos = len(U_BOOT_DATA) 2381 fdtmap_data = data[fdtmap_pos:] 2382 fdt_data = fdtmap_data[16:] 2383 dtb = fdt.Fdt.FromData(fdt_data) 2384 fdt_size = dtb.GetFdtObj().totalsize() 2385 hdr_data = data[-8:] 2386 self.assertEqual(b'BinM', hdr_data[:4]) 2387 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff 2388 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32)) 2389 2390 def testFdtmapHeaderStart(self): 2391 """Test an image header can be inserted at the image start""" 2392 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts') 2393 fdtmap_pos = 0x100 + len(U_BOOT_DATA) 2394 hdr_data = data[:8] 2395 self.assertEqual(b'BinM', hdr_data[:4]) 2396 offset = struct.unpack('<I', hdr_data[4:])[0] 2397 self.assertEqual(fdtmap_pos, offset) 2398 2399 def testFdtmapHeaderPos(self): 2400 """Test an image header can be inserted at a chosen position""" 2401 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts') 2402 fdtmap_pos = 0x100 + len(U_BOOT_DATA) 2403 hdr_data = data[0x80:0x88] 2404 self.assertEqual(b'BinM', hdr_data[:4]) 2405 offset = struct.unpack('<I', hdr_data[4:])[0] 2406 self.assertEqual(fdtmap_pos, offset) 2407 2408 def testHeaderMissingFdtmap(self): 2409 """Test an image header requires an fdtmap""" 2410 with self.assertRaises(ValueError) as e: 2411 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts') 2412 self.assertIn("'image_header' section must have an 'fdtmap' sibling", 2413 str(e.exception)) 2414 2415 def testHeaderNoLocation(self): 2416 """Test an image header with a no specified location is detected""" 2417 with self.assertRaises(ValueError) as e: 2418 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts') 2419 self.assertIn("Invalid location 'None', expected 'start' or 'end'", 2420 str(e.exception)) 2421 2422 def testEntryExpand(self): 2423 """Test expanding an entry after it is packed""" 2424 data = self._DoReadFile('121_entry_expand.dts') 2425 self.assertEqual(b'aaa', data[:3]) 2426 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)]) 2427 self.assertEqual(b'aaa', data[-3:]) 2428 2429 def testEntryExpandBad(self): 2430 """Test expanding an entry after it is packed, twice""" 2431 with self.assertRaises(ValueError) as e: 2432 self._DoReadFile('122_entry_expand_twice.dts') 2433 self.assertIn("Image '/binman': Entries changed size after packing", 2434 str(e.exception)) 2435 2436 def testEntryExpandSection(self): 2437 """Test expanding an entry within a section after it is packed""" 2438 data = self._DoReadFile('123_entry_expand_section.dts') 2439 self.assertEqual(b'aaa', data[:3]) 2440 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)]) 2441 self.assertEqual(b'aaa', data[-3:]) 2442 2443 def testCompressDtb(self): 2444 """Test that compress of device-tree files is supported""" 2445 self._CheckLz4() 2446 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts') 2447 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)]) 2448 comp_data = data[len(U_BOOT_DATA):] 2449 orig = self._decompress(comp_data) 2450 dtb = fdt.Fdt.FromData(orig) 2451 dtb.Scan() 2452 props = self._GetPropTree(dtb, ['size', 'uncomp-size']) 2453 expected = { 2454 'u-boot:size': len(U_BOOT_DATA), 2455 'u-boot-dtb:uncomp-size': len(orig), 2456 'u-boot-dtb:size': len(comp_data), 2457 'size': len(data), 2458 } 2459 self.assertEqual(expected, props) 2460 2461 def testCbfsUpdateFdt(self): 2462 """Test that we can update the device tree with CBFS offset/size info""" 2463 self._CheckLz4() 2464 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts', 2465 update_dtb=True) 2466 dtb = fdt.Fdt(out_dtb_fname) 2467 dtb.Scan() 2468 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size']) 2469 del props['cbfs/u-boot:size'] 2470 self.assertEqual({ 2471 'offset': 0, 2472 'size': len(data), 2473 'image-pos': 0, 2474 'cbfs:offset': 0, 2475 'cbfs:size': len(data), 2476 'cbfs:image-pos': 0, 2477 'cbfs/u-boot:offset': 0x38, 2478 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA), 2479 'cbfs/u-boot:image-pos': 0x38, 2480 'cbfs/u-boot-dtb:offset': 0xb8, 2481 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA), 2482 'cbfs/u-boot-dtb:image-pos': 0xb8, 2483 }, props) 2484 2485 def testCbfsBadType(self): 2486 """Test an image header with a no specified location is detected""" 2487 with self.assertRaises(ValueError) as e: 2488 self._DoReadFile('126_cbfs_bad_type.dts') 2489 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception)) 2490 2491 def testList(self): 2492 """Test listing the files in an image""" 2493 self._CheckLz4() 2494 data = self._DoReadFile('127_list.dts') 2495 image = control.images['image'] 2496 entries = image.BuildEntryList() 2497 self.assertEqual(7, len(entries)) 2498 2499 ent = entries[0] 2500 self.assertEqual(0, ent.indent) 2501 self.assertEqual('main-section', ent.name) 2502 self.assertEqual('section', ent.etype) 2503 self.assertEqual(len(data), ent.size) 2504 self.assertEqual(0, ent.image_pos) 2505 self.assertEqual(None, ent.uncomp_size) 2506 self.assertEqual(0, ent.offset) 2507 2508 ent = entries[1] 2509 self.assertEqual(1, ent.indent) 2510 self.assertEqual('u-boot', ent.name) 2511 self.assertEqual('u-boot', ent.etype) 2512 self.assertEqual(len(U_BOOT_DATA), ent.size) 2513 self.assertEqual(0, ent.image_pos) 2514 self.assertEqual(None, ent.uncomp_size) 2515 self.assertEqual(0, ent.offset) 2516 2517 ent = entries[2] 2518 self.assertEqual(1, ent.indent) 2519 self.assertEqual('section', ent.name) 2520 self.assertEqual('section', ent.etype) 2521 section_size = ent.size 2522 self.assertEqual(0x100, ent.image_pos) 2523 self.assertEqual(None, ent.uncomp_size) 2524 self.assertEqual(0x100, ent.offset) 2525 2526 ent = entries[3] 2527 self.assertEqual(2, ent.indent) 2528 self.assertEqual('cbfs', ent.name) 2529 self.assertEqual('cbfs', ent.etype) 2530 self.assertEqual(0x400, ent.size) 2531 self.assertEqual(0x100, ent.image_pos) 2532 self.assertEqual(None, ent.uncomp_size) 2533 self.assertEqual(0, ent.offset) 2534 2535 ent = entries[4] 2536 self.assertEqual(3, ent.indent) 2537 self.assertEqual('u-boot', ent.name) 2538 self.assertEqual('u-boot', ent.etype) 2539 self.assertEqual(len(U_BOOT_DATA), ent.size) 2540 self.assertEqual(0x138, ent.image_pos) 2541 self.assertEqual(None, ent.uncomp_size) 2542 self.assertEqual(0x38, ent.offset) 2543 2544 ent = entries[5] 2545 self.assertEqual(3, ent.indent) 2546 self.assertEqual('u-boot-dtb', ent.name) 2547 self.assertEqual('text', ent.etype) 2548 self.assertGreater(len(COMPRESS_DATA), ent.size) 2549 self.assertEqual(0x178, ent.image_pos) 2550 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size) 2551 self.assertEqual(0x78, ent.offset) 2552 2553 ent = entries[6] 2554 self.assertEqual(2, ent.indent) 2555 self.assertEqual('u-boot-dtb', ent.name) 2556 self.assertEqual('u-boot-dtb', ent.etype) 2557 self.assertEqual(0x500, ent.image_pos) 2558 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size) 2559 dtb_size = ent.size 2560 # Compressing this data expands it since headers are added 2561 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA)) 2562 self.assertEqual(0x400, ent.offset) 2563 2564 self.assertEqual(len(data), 0x100 + section_size) 2565 self.assertEqual(section_size, 0x400 + dtb_size) 2566 2567 def testFindFdtmap(self): 2568 """Test locating an FDT map in an image""" 2569 self._CheckLz4() 2570 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts') 2571 image = control.images['image'] 2572 entries = image.GetEntries() 2573 entry = entries['fdtmap'] 2574 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data)) 2575 2576 def testFindFdtmapMissing(self): 2577 """Test failing to locate an FDP map""" 2578 data = self._DoReadFile('005_simple.dts') 2579 self.assertEqual(None, fdtmap.LocateFdtmap(data)) 2580 2581 def testFindImageHeader(self): 2582 """Test locating a image header""" 2583 self._CheckLz4() 2584 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts') 2585 image = control.images['image'] 2586 entries = image.GetEntries() 2587 entry = entries['fdtmap'] 2588 # The header should point to the FDT map 2589 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data)) 2590 2591 def testFindImageHeaderStart(self): 2592 """Test locating a image header located at the start of an image""" 2593 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts') 2594 image = control.images['image'] 2595 entries = image.GetEntries() 2596 entry = entries['fdtmap'] 2597 # The header should point to the FDT map 2598 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data)) 2599 2600 def testFindImageHeaderMissing(self): 2601 """Test failing to locate an image header""" 2602 data = self._DoReadFile('005_simple.dts') 2603 self.assertEqual(None, image_header.LocateHeaderOffset(data)) 2604 2605 def testReadImage(self): 2606 """Test reading an image and accessing its FDT map""" 2607 self._CheckLz4() 2608 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts') 2609 image_fname = tools.GetOutputFilename('image.bin') 2610 orig_image = control.images['image'] 2611 image = Image.FromFile(image_fname) 2612 self.assertEqual(orig_image.GetEntries().keys(), 2613 image.GetEntries().keys()) 2614 2615 orig_entry = orig_image.GetEntries()['fdtmap'] 2616 entry = image.GetEntries()['fdtmap'] 2617 self.assertEquals(orig_entry.offset, entry.offset) 2618 self.assertEquals(orig_entry.size, entry.size) 2619 self.assertEquals(orig_entry.image_pos, entry.image_pos) 2620 2621 def testReadImageNoHeader(self): 2622 """Test accessing an image's FDT map without an image header""" 2623 self._CheckLz4() 2624 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts') 2625 image_fname = tools.GetOutputFilename('image.bin') 2626 image = Image.FromFile(image_fname) 2627 self.assertTrue(isinstance(image, Image)) 2628 self.assertEqual('image', image.image_name[-5:]) 2629 2630 def testReadImageFail(self): 2631 """Test failing to read an image image's FDT map""" 2632 self._DoReadFile('005_simple.dts') 2633 image_fname = tools.GetOutputFilename('image.bin') 2634 with self.assertRaises(ValueError) as e: 2635 image = Image.FromFile(image_fname) 2636 self.assertIn("Cannot find FDT map in image", str(e.exception)) 2637 2638 def testListCmd(self): 2639 """Test listing the files in an image using an Fdtmap""" 2640 self._CheckLz4() 2641 data = self._DoReadFileRealDtb('130_list_fdtmap.dts') 2642 2643 # lz4 compression size differs depending on the version 2644 image = control.images['image'] 2645 entries = image.GetEntries() 2646 section_size = entries['section'].size 2647 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size 2648 fdtmap_offset = entries['fdtmap'].offset 2649 2650 try: 2651 tmpdir, updated_fname = self._SetupImageInTmpdir() 2652 with test_util.capture_sys_output() as (stdout, stderr): 2653 self._DoBinman('ls', '-i', updated_fname) 2654 finally: 2655 shutil.rmtree(tmpdir) 2656 lines = stdout.getvalue().splitlines() 2657 expected = [ 2658'Name Image-pos Size Entry-type Offset Uncomp-size', 2659'----------------------------------------------------------------------', 2660'main-section 0 c00 section 0', 2661' u-boot 0 4 u-boot 0', 2662' section 100 %x section 100' % section_size, 2663' cbfs 100 400 cbfs 0', 2664' u-boot 138 4 u-boot 38', 2665' u-boot-dtb 180 105 u-boot-dtb 80 3c9', 2666' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size, 2667' fdtmap %x 3bd fdtmap %x' % 2668 (fdtmap_offset, fdtmap_offset), 2669' image-header bf8 8 image-header bf8', 2670 ] 2671 self.assertEqual(expected, lines) 2672 2673 def testListCmdFail(self): 2674 """Test failing to list an image""" 2675 self._DoReadFile('005_simple.dts') 2676 try: 2677 tmpdir, updated_fname = self._SetupImageInTmpdir() 2678 with self.assertRaises(ValueError) as e: 2679 self._DoBinman('ls', '-i', updated_fname) 2680 finally: 2681 shutil.rmtree(tmpdir) 2682 self.assertIn("Cannot find FDT map in image", str(e.exception)) 2683 2684 def _RunListCmd(self, paths, expected): 2685 """List out entries and check the result 2686 2687 Args: 2688 paths: List of paths to pass to the list command 2689 expected: Expected list of filenames to be returned, in order 2690 """ 2691 self._CheckLz4() 2692 self._DoReadFileRealDtb('130_list_fdtmap.dts') 2693 image_fname = tools.GetOutputFilename('image.bin') 2694 image = Image.FromFile(image_fname) 2695 lines = image.GetListEntries(paths)[1] 2696 files = [line[0].strip() for line in lines[1:]] 2697 self.assertEqual(expected, files) 2698 2699 def testListCmdSection(self): 2700 """Test listing the files in a section""" 2701 self._RunListCmd(['section'], 2702 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb']) 2703 2704 def testListCmdFile(self): 2705 """Test listing a particular file""" 2706 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb']) 2707 2708 def testListCmdWildcard(self): 2709 """Test listing a wildcarded file""" 2710 self._RunListCmd(['*boot*'], 2711 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb']) 2712 2713 def testListCmdWildcardMulti(self): 2714 """Test listing a wildcarded file""" 2715 self._RunListCmd(['*cb*', '*head*'], 2716 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header']) 2717 2718 def testListCmdEmpty(self): 2719 """Test listing a wildcarded file""" 2720 self._RunListCmd(['nothing'], []) 2721 2722 def testListCmdPath(self): 2723 """Test listing the files in a sub-entry of a section""" 2724 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb']) 2725 2726 def _RunExtractCmd(self, entry_name, decomp=True): 2727 """Extract an entry from an image 2728 2729 Args: 2730 entry_name: Entry name to extract 2731 decomp: True to decompress the data if compressed, False to leave 2732 it in its raw uncompressed format 2733 2734 Returns: 2735 data from entry 2736 """ 2737 self._CheckLz4() 2738 self._DoReadFileRealDtb('130_list_fdtmap.dts') 2739 image_fname = tools.GetOutputFilename('image.bin') 2740 return control.ReadEntry(image_fname, entry_name, decomp) 2741 2742 def testExtractSimple(self): 2743 """Test extracting a single file""" 2744 data = self._RunExtractCmd('u-boot') 2745 self.assertEqual(U_BOOT_DATA, data) 2746 2747 def testExtractSection(self): 2748 """Test extracting the files in a section""" 2749 data = self._RunExtractCmd('section') 2750 cbfs_data = data[:0x400] 2751 cbfs = cbfs_util.CbfsReader(cbfs_data) 2752 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys())) 2753 dtb_data = data[0x400:] 2754 dtb = self._decompress(dtb_data) 2755 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb)) 2756 2757 def testExtractCompressed(self): 2758 """Test extracting compressed data""" 2759 data = self._RunExtractCmd('section/u-boot-dtb') 2760 self.assertEqual(EXTRACT_DTB_SIZE, len(data)) 2761 2762 def testExtractRaw(self): 2763 """Test extracting compressed data without decompressing it""" 2764 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False) 2765 dtb = self._decompress(data) 2766 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb)) 2767 2768 def testExtractCbfs(self): 2769 """Test extracting CBFS data""" 2770 data = self._RunExtractCmd('section/cbfs/u-boot') 2771 self.assertEqual(U_BOOT_DATA, data) 2772 2773 def testExtractCbfsCompressed(self): 2774 """Test extracting CBFS compressed data""" 2775 data = self._RunExtractCmd('section/cbfs/u-boot-dtb') 2776 self.assertEqual(EXTRACT_DTB_SIZE, len(data)) 2777 2778 def testExtractCbfsRaw(self): 2779 """Test extracting CBFS compressed data without decompressing it""" 2780 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False) 2781 dtb = tools.Decompress(data, 'lzma', with_header=False) 2782 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb)) 2783 2784 def testExtractBadEntry(self): 2785 """Test extracting a bad section path""" 2786 with self.assertRaises(ValueError) as e: 2787 self._RunExtractCmd('section/does-not-exist') 2788 self.assertIn("Entry 'does-not-exist' not found in '/section'", 2789 str(e.exception)) 2790 2791 def testExtractMissingFile(self): 2792 """Test extracting file that does not exist""" 2793 with self.assertRaises(IOError) as e: 2794 control.ReadEntry('missing-file', 'name') 2795 2796 def testExtractBadFile(self): 2797 """Test extracting an invalid file""" 2798 fname = os.path.join(self._indir, 'badfile') 2799 tools.WriteFile(fname, b'') 2800 with self.assertRaises(ValueError) as e: 2801 control.ReadEntry(fname, 'name') 2802 2803 def testExtractCmd(self): 2804 """Test extracting a file fron an image on the command line""" 2805 self._CheckLz4() 2806 self._DoReadFileRealDtb('130_list_fdtmap.dts') 2807 fname = os.path.join(self._indir, 'output.extact') 2808 try: 2809 tmpdir, updated_fname = self._SetupImageInTmpdir() 2810 with test_util.capture_sys_output() as (stdout, stderr): 2811 self._DoBinman('extract', '-i', updated_fname, 'u-boot', 2812 '-f', fname) 2813 finally: 2814 shutil.rmtree(tmpdir) 2815 data = tools.ReadFile(fname) 2816 self.assertEqual(U_BOOT_DATA, data) 2817 2818 def testExtractOneEntry(self): 2819 """Test extracting a single entry fron an image """ 2820 self._CheckLz4() 2821 self._DoReadFileRealDtb('130_list_fdtmap.dts') 2822 image_fname = tools.GetOutputFilename('image.bin') 2823 fname = os.path.join(self._indir, 'output.extact') 2824 control.ExtractEntries(image_fname, fname, None, ['u-boot']) 2825 data = tools.ReadFile(fname) 2826 self.assertEqual(U_BOOT_DATA, data) 2827 2828 def _CheckExtractOutput(self, decomp): 2829 """Helper to test file output with and without decompression 2830 2831 Args: 2832 decomp: True to decompress entry data, False to output it raw 2833 """ 2834 def _CheckPresent(entry_path, expect_data, expect_size=None): 2835 """Check and remove expected file 2836 2837 This checks the data/size of a file and removes the file both from 2838 the outfiles set and from the output directory. Once all files are 2839 processed, both the set and directory should be empty. 2840 2841 Args: 2842 entry_path: Entry path 2843 expect_data: Data to expect in file, or None to skip check 2844 expect_size: Size of data to expect in file, or None to skip 2845 """ 2846 path = os.path.join(outdir, entry_path) 2847 data = tools.ReadFile(path) 2848 os.remove(path) 2849 if expect_data: 2850 self.assertEqual(expect_data, data) 2851 elif expect_size: 2852 self.assertEqual(expect_size, len(data)) 2853 outfiles.remove(path) 2854 2855 def _CheckDirPresent(name): 2856 """Remove expected directory 2857 2858 This gives an error if the directory does not exist as expected 2859 2860 Args: 2861 name: Name of directory to remove 2862 """ 2863 path = os.path.join(outdir, name) 2864 os.rmdir(path) 2865 2866 self._DoReadFileRealDtb('130_list_fdtmap.dts') 2867 image_fname = tools.GetOutputFilename('image.bin') 2868 outdir = os.path.join(self._indir, 'extract') 2869 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp) 2870 2871 # Create a set of all file that were output (should be 9) 2872 outfiles = set() 2873 for root, dirs, files in os.walk(outdir): 2874 outfiles |= set([os.path.join(root, fname) for fname in files]) 2875 self.assertEqual(9, len(outfiles)) 2876 self.assertEqual(9, len(einfos)) 2877 2878 image = control.images['image'] 2879 entries = image.GetEntries() 2880 2881 # Check the 9 files in various ways 2882 section = entries['section'] 2883 section_entries = section.GetEntries() 2884 cbfs_entries = section_entries['cbfs'].GetEntries() 2885 _CheckPresent('u-boot', U_BOOT_DATA) 2886 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA) 2887 dtb_len = EXTRACT_DTB_SIZE 2888 if not decomp: 2889 dtb_len = cbfs_entries['u-boot-dtb'].size 2890 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len) 2891 if not decomp: 2892 dtb_len = section_entries['u-boot-dtb'].size 2893 _CheckPresent('section/u-boot-dtb', None, dtb_len) 2894 2895 fdtmap = entries['fdtmap'] 2896 _CheckPresent('fdtmap', fdtmap.data) 2897 hdr = entries['image-header'] 2898 _CheckPresent('image-header', hdr.data) 2899 2900 _CheckPresent('section/root', section.data) 2901 cbfs = section_entries['cbfs'] 2902 _CheckPresent('section/cbfs/root', cbfs.data) 2903 data = tools.ReadFile(image_fname) 2904 _CheckPresent('root', data) 2905 2906 # There should be no files left. Remove all the directories to check. 2907 # If there are any files/dirs remaining, one of these checks will fail. 2908 self.assertEqual(0, len(outfiles)) 2909 _CheckDirPresent('section/cbfs') 2910 _CheckDirPresent('section') 2911 _CheckDirPresent('') 2912 self.assertFalse(os.path.exists(outdir)) 2913 2914 def testExtractAllEntries(self): 2915 """Test extracting all entries""" 2916 self._CheckLz4() 2917 self._CheckExtractOutput(decomp=True) 2918 2919 def testExtractAllEntriesRaw(self): 2920 """Test extracting all entries without decompressing them""" 2921 self._CheckLz4() 2922 self._CheckExtractOutput(decomp=False) 2923 2924 def testExtractSelectedEntries(self): 2925 """Test extracting some entries""" 2926 self._CheckLz4() 2927 self._DoReadFileRealDtb('130_list_fdtmap.dts') 2928 image_fname = tools.GetOutputFilename('image.bin') 2929 outdir = os.path.join(self._indir, 'extract') 2930 einfos = control.ExtractEntries(image_fname, None, outdir, 2931 ['*cb*', '*head*']) 2932 2933 # File output is tested by testExtractAllEntries(), so just check that 2934 # the expected entries are selected 2935 names = [einfo.name for einfo in einfos] 2936 self.assertEqual(names, 2937 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header']) 2938 2939 def testExtractNoEntryPaths(self): 2940 """Test extracting some entries""" 2941 self._CheckLz4() 2942 self._DoReadFileRealDtb('130_list_fdtmap.dts') 2943 image_fname = tools.GetOutputFilename('image.bin') 2944 with self.assertRaises(ValueError) as e: 2945 control.ExtractEntries(image_fname, 'fname', None, []) 2946 self.assertIn('Must specify an entry path to write with -f', 2947 str(e.exception)) 2948 2949 def testExtractTooManyEntryPaths(self): 2950 """Test extracting some entries""" 2951 self._CheckLz4() 2952 self._DoReadFileRealDtb('130_list_fdtmap.dts') 2953 image_fname = tools.GetOutputFilename('image.bin') 2954 with self.assertRaises(ValueError) as e: 2955 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b']) 2956 self.assertIn('Must specify exactly one entry path to write with -f', 2957 str(e.exception)) 2958 2959 def testPackAlignSection(self): 2960 """Test that sections can have alignment""" 2961 self._DoReadFile('131_pack_align_section.dts') 2962 2963 self.assertIn('image', control.images) 2964 image = control.images['image'] 2965 entries = image.GetEntries() 2966 self.assertEqual(3, len(entries)) 2967 2968 # First u-boot 2969 self.assertIn('u-boot', entries) 2970 entry = entries['u-boot'] 2971 self.assertEqual(0, entry.offset) 2972 self.assertEqual(0, entry.image_pos) 2973 self.assertEqual(len(U_BOOT_DATA), entry.contents_size) 2974 self.assertEqual(len(U_BOOT_DATA), entry.size) 2975 2976 # Section0 2977 self.assertIn('section0', entries) 2978 section0 = entries['section0'] 2979 self.assertEqual(0x10, section0.offset) 2980 self.assertEqual(0x10, section0.image_pos) 2981 self.assertEqual(len(U_BOOT_DATA), section0.size) 2982 2983 # Second u-boot 2984 section_entries = section0.GetEntries() 2985 self.assertIn('u-boot', section_entries) 2986 entry = section_entries['u-boot'] 2987 self.assertEqual(0, entry.offset) 2988 self.assertEqual(0x10, entry.image_pos) 2989 self.assertEqual(len(U_BOOT_DATA), entry.contents_size) 2990 self.assertEqual(len(U_BOOT_DATA), entry.size) 2991 2992 # Section1 2993 self.assertIn('section1', entries) 2994 section1 = entries['section1'] 2995 self.assertEqual(0x14, section1.offset) 2996 self.assertEqual(0x14, section1.image_pos) 2997 self.assertEqual(0x20, section1.size) 2998 2999 # Second u-boot 3000 section_entries = section1.GetEntries() 3001 self.assertIn('u-boot', section_entries) 3002 entry = section_entries['u-boot'] 3003 self.assertEqual(0, entry.offset) 3004 self.assertEqual(0x14, entry.image_pos) 3005 self.assertEqual(len(U_BOOT_DATA), entry.contents_size) 3006 self.assertEqual(len(U_BOOT_DATA), entry.size) 3007 3008 # Section2 3009 self.assertIn('section2', section_entries) 3010 section2 = section_entries['section2'] 3011 self.assertEqual(0x4, section2.offset) 3012 self.assertEqual(0x18, section2.image_pos) 3013 self.assertEqual(4, section2.size) 3014 3015 # Third u-boot 3016 section_entries = section2.GetEntries() 3017 self.assertIn('u-boot', section_entries) 3018 entry = section_entries['u-boot'] 3019 self.assertEqual(0, entry.offset) 3020 self.assertEqual(0x18, entry.image_pos) 3021 self.assertEqual(len(U_BOOT_DATA), entry.contents_size) 3022 self.assertEqual(len(U_BOOT_DATA), entry.size) 3023 3024 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True, 3025 dts='132_replace.dts'): 3026 """Replace an entry in an image 3027 3028 This writes the entry data to update it, then opens the updated file and 3029 returns the value that it now finds there. 3030 3031 Args: 3032 entry_name: Entry name to replace 3033 data: Data to replace it with 3034 decomp: True to compress the data if needed, False if data is 3035 already compressed so should be used as is 3036 allow_resize: True to allow entries to change size, False to raise 3037 an exception 3038 3039 Returns: 3040 Tuple: 3041 data from entry 3042 data from fdtmap (excluding header) 3043 Image object that was modified 3044 """ 3045 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True, 3046 update_dtb=True)[1] 3047 3048 self.assertIn('image', control.images) 3049 image = control.images['image'] 3050 entries = image.GetEntries() 3051 orig_dtb_data = entries['u-boot-dtb'].data 3052 orig_fdtmap_data = entries['fdtmap'].data 3053 3054 image_fname = tools.GetOutputFilename('image.bin') 3055 updated_fname = tools.GetOutputFilename('image-updated.bin') 3056 tools.WriteFile(updated_fname, tools.ReadFile(image_fname)) 3057 image = control.WriteEntry(updated_fname, entry_name, data, decomp, 3058 allow_resize) 3059 data = control.ReadEntry(updated_fname, entry_name, decomp) 3060 3061 # The DT data should not change unless resized: 3062 if not allow_resize: 3063 new_dtb_data = entries['u-boot-dtb'].data 3064 self.assertEqual(new_dtb_data, orig_dtb_data) 3065 new_fdtmap_data = entries['fdtmap'].data 3066 self.assertEqual(new_fdtmap_data, orig_fdtmap_data) 3067 3068 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image 3069 3070 def testReplaceSimple(self): 3071 """Test replacing a single file""" 3072 expected = b'x' * len(U_BOOT_DATA) 3073 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected, 3074 allow_resize=False) 3075 self.assertEqual(expected, data) 3076 3077 # Test that the state looks right. There should be an FDT for the fdtmap 3078 # that we jsut read back in, and it should match what we find in the 3079 # 'control' tables. Checking for an FDT that does not exist should 3080 # return None. 3081 path, fdtmap = state.GetFdtContents('fdtmap') 3082 self.assertIsNotNone(path) 3083 self.assertEqual(expected_fdtmap, fdtmap) 3084 3085 dtb = state.GetFdtForEtype('fdtmap') 3086 self.assertEqual(dtb.GetContents(), fdtmap) 3087 3088 missing_path, missing_fdtmap = state.GetFdtContents('missing') 3089 self.assertIsNone(missing_path) 3090 self.assertIsNone(missing_fdtmap) 3091 3092 missing_dtb = state.GetFdtForEtype('missing') 3093 self.assertIsNone(missing_dtb) 3094 3095 self.assertEqual('/binman', state.fdt_path_prefix) 3096 3097 def testReplaceResizeFail(self): 3098 """Test replacing a file by something larger""" 3099 expected = U_BOOT_DATA + b'x' 3100 with self.assertRaises(ValueError) as e: 3101 self._RunReplaceCmd('u-boot', expected, allow_resize=False, 3102 dts='139_replace_repack.dts') 3103 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled", 3104 str(e.exception)) 3105 3106 def testReplaceMulti(self): 3107 """Test replacing entry data where multiple images are generated""" 3108 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True, 3109 update_dtb=True)[0] 3110 expected = b'x' * len(U_BOOT_DATA) 3111 updated_fname = tools.GetOutputFilename('image-updated.bin') 3112 tools.WriteFile(updated_fname, data) 3113 entry_name = 'u-boot' 3114 control.WriteEntry(updated_fname, entry_name, expected, 3115 allow_resize=False) 3116 data = control.ReadEntry(updated_fname, entry_name) 3117 self.assertEqual(expected, data) 3118 3119 # Check the state looks right. 3120 self.assertEqual('/binman/image', state.fdt_path_prefix) 3121 3122 # Now check we can write the first image 3123 image_fname = tools.GetOutputFilename('first-image.bin') 3124 updated_fname = tools.GetOutputFilename('first-updated.bin') 3125 tools.WriteFile(updated_fname, tools.ReadFile(image_fname)) 3126 entry_name = 'u-boot' 3127 control.WriteEntry(updated_fname, entry_name, expected, 3128 allow_resize=False) 3129 data = control.ReadEntry(updated_fname, entry_name) 3130 self.assertEqual(expected, data) 3131 3132 # Check the state looks right. 3133 self.assertEqual('/binman/first-image', state.fdt_path_prefix) 3134 3135 def testUpdateFdtAllRepack(self): 3136 """Test that all device trees are updated with offset/size info""" 3137 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts') 3138 SECTION_SIZE = 0x300 3139 DTB_SIZE = 602 3140 FDTMAP_SIZE = 608 3141 base_expected = { 3142 'offset': 0, 3143 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE, 3144 'image-pos': 0, 3145 'section:offset': 0, 3146 'section:size': SECTION_SIZE, 3147 'section:image-pos': 0, 3148 'section/u-boot-dtb:offset': 4, 3149 'section/u-boot-dtb:size': 636, 3150 'section/u-boot-dtb:image-pos': 4, 3151 'u-boot-spl-dtb:offset': SECTION_SIZE, 3152 'u-boot-spl-dtb:size': DTB_SIZE, 3153 'u-boot-spl-dtb:image-pos': SECTION_SIZE, 3154 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE, 3155 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE, 3156 'u-boot-tpl-dtb:size': DTB_SIZE, 3157 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2, 3158 'fdtmap:size': FDTMAP_SIZE, 3159 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2, 3160 } 3161 main_expected = { 3162 'section:orig-size': SECTION_SIZE, 3163 'section/u-boot-dtb:orig-offset': 4, 3164 } 3165 3166 # We expect three device-tree files in the output, with the first one 3167 # within a fixed-size section. 3168 # Read them in sequence. We look for an 'spl' property in the SPL tree, 3169 # and 'tpl' in the TPL tree, to make sure they are distinct from the 3170 # main U-Boot tree. All three should have the same positions and offset 3171 # except that the main tree should include the main_expected properties 3172 start = 4 3173 for item in ['', 'spl', 'tpl', None]: 3174 if item is None: 3175 start += 16 # Move past fdtmap header 3176 dtb = fdt.Fdt.FromData(data[start:]) 3177 dtb.Scan() 3178 props = self._GetPropTree(dtb, 3179 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'], 3180 prefix='/' if item is None else '/binman/') 3181 expected = dict(base_expected) 3182 if item: 3183 expected[item] = 0 3184 else: 3185 # Main DTB and fdtdec should include the 'orig-' properties 3186 expected.update(main_expected) 3187 # Helpful for debugging: 3188 #for prop in sorted(props): 3189 #print('prop %s %s %s' % (prop, props[prop], expected[prop])) 3190 self.assertEqual(expected, props) 3191 if item == '': 3192 start = SECTION_SIZE 3193 else: 3194 start += dtb._fdt_obj.totalsize() 3195 3196 def testFdtmapHeaderMiddle(self): 3197 """Test an FDT map in the middle of an image when it should be at end""" 3198 with self.assertRaises(ValueError) as e: 3199 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts') 3200 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location", 3201 str(e.exception)) 3202 3203 def testFdtmapHeaderStartBad(self): 3204 """Test an FDT map in middle of an image when it should be at start""" 3205 with self.assertRaises(ValueError) as e: 3206 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts') 3207 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location", 3208 str(e.exception)) 3209 3210 def testFdtmapHeaderEndBad(self): 3211 """Test an FDT map at the start of an image when it should be at end""" 3212 with self.assertRaises(ValueError) as e: 3213 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts') 3214 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location", 3215 str(e.exception)) 3216 3217 def testFdtmapHeaderNoSize(self): 3218 """Test an image header at the end of an image with undefined size""" 3219 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts') 3220 3221 def testReplaceResize(self): 3222 """Test replacing a single file in an entry with a larger file""" 3223 expected = U_BOOT_DATA + b'x' 3224 data, _, image = self._RunReplaceCmd('u-boot', expected, 3225 dts='139_replace_repack.dts') 3226 self.assertEqual(expected, data) 3227 3228 entries = image.GetEntries() 3229 dtb_data = entries['u-boot-dtb'].data 3230 dtb = fdt.Fdt.FromData(dtb_data) 3231 dtb.Scan() 3232 3233 # The u-boot section should now be larger in the dtb 3234 node = dtb.GetNode('/binman/u-boot') 3235 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size')) 3236 3237 # Same for the fdtmap 3238 fdata = entries['fdtmap'].data 3239 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:]) 3240 fdtb.Scan() 3241 fnode = fdtb.GetNode('/u-boot') 3242 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size')) 3243 3244 def testReplaceResizeNoRepack(self): 3245 """Test replacing an entry with a larger file when not allowed""" 3246 expected = U_BOOT_DATA + b'x' 3247 with self.assertRaises(ValueError) as e: 3248 self._RunReplaceCmd('u-boot', expected) 3249 self.assertIn('Entry data size does not match, but allow-repack is not present for this image', 3250 str(e.exception)) 3251 3252 def testEntryShrink(self): 3253 """Test contracting an entry after it is packed""" 3254 try: 3255 state.SetAllowEntryContraction(True) 3256 data = self._DoReadFileDtb('140_entry_shrink.dts', 3257 update_dtb=True)[0] 3258 finally: 3259 state.SetAllowEntryContraction(False) 3260 self.assertEqual(b'a', data[:1]) 3261 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)]) 3262 self.assertEqual(b'a', data[-1:]) 3263 3264 def testEntryShrinkFail(self): 3265 """Test not being allowed to contract an entry after it is packed""" 3266 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0] 3267 3268 # In this case there is a spare byte at the end of the data. The size of 3269 # the contents is only 1 byte but we still have the size before it 3270 # shrunk. 3271 self.assertEqual(b'a\0', data[:2]) 3272 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)]) 3273 self.assertEqual(b'a\0', data[-2:]) 3274 3275 def testDescriptorOffset(self): 3276 """Test that the Intel descriptor is always placed at at the start""" 3277 data = self._DoReadFileDtb('141_descriptor_offset.dts') 3278 image = control.images['image'] 3279 entries = image.GetEntries() 3280 desc = entries['intel-descriptor'] 3281 self.assertEqual(0xff800000, desc.offset); 3282 self.assertEqual(0xff800000, desc.image_pos); 3283 3284 def testReplaceCbfs(self): 3285 """Test replacing a single file in CBFS without changing the size""" 3286 self._CheckLz4() 3287 expected = b'x' * len(U_BOOT_DATA) 3288 data = self._DoReadFileRealDtb('142_replace_cbfs.dts') 3289 updated_fname = tools.GetOutputFilename('image-updated.bin') 3290 tools.WriteFile(updated_fname, data) 3291 entry_name = 'section/cbfs/u-boot' 3292 control.WriteEntry(updated_fname, entry_name, expected, 3293 allow_resize=True) 3294 data = control.ReadEntry(updated_fname, entry_name) 3295 self.assertEqual(expected, data) 3296 3297 def testReplaceResizeCbfs(self): 3298 """Test replacing a single file in CBFS with one of a different size""" 3299 self._CheckLz4() 3300 expected = U_BOOT_DATA + b'x' 3301 data = self._DoReadFileRealDtb('142_replace_cbfs.dts') 3302 updated_fname = tools.GetOutputFilename('image-updated.bin') 3303 tools.WriteFile(updated_fname, data) 3304 entry_name = 'section/cbfs/u-boot' 3305 control.WriteEntry(updated_fname, entry_name, expected, 3306 allow_resize=True) 3307 data = control.ReadEntry(updated_fname, entry_name) 3308 self.assertEqual(expected, data) 3309 3310 def _SetupForReplace(self): 3311 """Set up some files to use to replace entries 3312 3313 This generates an image, copies it to a new file, extracts all the files 3314 in it and updates some of them 3315 3316 Returns: 3317 List 3318 Image filename 3319 Output directory 3320 Expected values for updated entries, each a string 3321 """ 3322 data = self._DoReadFileRealDtb('143_replace_all.dts') 3323 3324 updated_fname = tools.GetOutputFilename('image-updated.bin') 3325 tools.WriteFile(updated_fname, data) 3326 3327 outdir = os.path.join(self._indir, 'extract') 3328 einfos = control.ExtractEntries(updated_fname, None, outdir, []) 3329 3330 expected1 = b'x' + U_BOOT_DATA + b'y' 3331 u_boot_fname1 = os.path.join(outdir, 'u-boot') 3332 tools.WriteFile(u_boot_fname1, expected1) 3333 3334 expected2 = b'a' + U_BOOT_DATA + b'b' 3335 u_boot_fname2 = os.path.join(outdir, 'u-boot2') 3336 tools.WriteFile(u_boot_fname2, expected2) 3337 3338 expected_text = b'not the same text' 3339 text_fname = os.path.join(outdir, 'text') 3340 tools.WriteFile(text_fname, expected_text) 3341 3342 dtb_fname = os.path.join(outdir, 'u-boot-dtb') 3343 dtb = fdt.FdtScan(dtb_fname) 3344 node = dtb.GetNode('/binman/text') 3345 node.AddString('my-property', 'the value') 3346 dtb.Sync(auto_resize=True) 3347 dtb.Flush() 3348 3349 return updated_fname, outdir, expected1, expected2, expected_text 3350 3351 def _CheckReplaceMultiple(self, entry_paths): 3352 """Handle replacing the contents of multiple entries 3353 3354 Args: 3355 entry_paths: List of entry paths to replace 3356 3357 Returns: 3358 List 3359 Dict of entries in the image: 3360 key: Entry name 3361 Value: Entry object 3362 Expected values for updated entries, each a string 3363 """ 3364 updated_fname, outdir, expected1, expected2, expected_text = ( 3365 self._SetupForReplace()) 3366 control.ReplaceEntries(updated_fname, None, outdir, entry_paths) 3367 3368 image = Image.FromFile(updated_fname) 3369 image.LoadData() 3370 return image.GetEntries(), expected1, expected2, expected_text 3371 3372 def testReplaceAll(self): 3373 """Test replacing the contents of all entries""" 3374 entries, expected1, expected2, expected_text = ( 3375 self._CheckReplaceMultiple([])) 3376 data = entries['u-boot'].data 3377 self.assertEqual(expected1, data) 3378 3379 data = entries['u-boot2'].data 3380 self.assertEqual(expected2, data) 3381 3382 data = entries['text'].data 3383 self.assertEqual(expected_text, data) 3384 3385 # Check that the device tree is updated 3386 data = entries['u-boot-dtb'].data 3387 dtb = fdt.Fdt.FromData(data) 3388 dtb.Scan() 3389 node = dtb.GetNode('/binman/text') 3390 self.assertEqual('the value', node.props['my-property'].value) 3391 3392 def testReplaceSome(self): 3393 """Test replacing the contents of a few entries""" 3394 entries, expected1, expected2, expected_text = ( 3395 self._CheckReplaceMultiple(['u-boot2', 'text'])) 3396 3397 # This one should not change 3398 data = entries['u-boot'].data 3399 self.assertEqual(U_BOOT_DATA, data) 3400 3401 data = entries['u-boot2'].data 3402 self.assertEqual(expected2, data) 3403 3404 data = entries['text'].data 3405 self.assertEqual(expected_text, data) 3406 3407 def testReplaceCmd(self): 3408 """Test replacing a file fron an image on the command line""" 3409 self._DoReadFileRealDtb('143_replace_all.dts') 3410 3411 try: 3412 tmpdir, updated_fname = self._SetupImageInTmpdir() 3413 3414 fname = os.path.join(tmpdir, 'update-u-boot.bin') 3415 expected = b'x' * len(U_BOOT_DATA) 3416 tools.WriteFile(fname, expected) 3417 3418 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname) 3419 data = tools.ReadFile(updated_fname) 3420 self.assertEqual(expected, data[:len(expected)]) 3421 map_fname = os.path.join(tmpdir, 'image-updated.map') 3422 self.assertFalse(os.path.exists(map_fname)) 3423 finally: 3424 shutil.rmtree(tmpdir) 3425 3426 def testReplaceCmdSome(self): 3427 """Test replacing some files fron an image on the command line""" 3428 updated_fname, outdir, expected1, expected2, expected_text = ( 3429 self._SetupForReplace()) 3430 3431 self._DoBinman('replace', '-i', updated_fname, '-I', outdir, 3432 'u-boot2', 'text') 3433 3434 tools.PrepareOutputDir(None) 3435 image = Image.FromFile(updated_fname) 3436 image.LoadData() 3437 entries = image.GetEntries() 3438 3439 # This one should not change 3440 data = entries['u-boot'].data 3441 self.assertEqual(U_BOOT_DATA, data) 3442 3443 data = entries['u-boot2'].data 3444 self.assertEqual(expected2, data) 3445 3446 data = entries['text'].data 3447 self.assertEqual(expected_text, data) 3448 3449 def testReplaceMissing(self): 3450 """Test replacing entries where the file is missing""" 3451 updated_fname, outdir, expected1, expected2, expected_text = ( 3452 self._SetupForReplace()) 3453 3454 # Remove one of the files, to generate a warning 3455 u_boot_fname1 = os.path.join(outdir, 'u-boot') 3456 os.remove(u_boot_fname1) 3457 3458 with test_util.capture_sys_output() as (stdout, stderr): 3459 control.ReplaceEntries(updated_fname, None, outdir, []) 3460 self.assertIn("Skipping entry '/u-boot' from missing file", 3461 stderr.getvalue()) 3462 3463 def testReplaceCmdMap(self): 3464 """Test replacing a file fron an image on the command line""" 3465 self._DoReadFileRealDtb('143_replace_all.dts') 3466 3467 try: 3468 tmpdir, updated_fname = self._SetupImageInTmpdir() 3469 3470 fname = os.path.join(self._indir, 'update-u-boot.bin') 3471 expected = b'x' * len(U_BOOT_DATA) 3472 tools.WriteFile(fname, expected) 3473 3474 self._DoBinman('replace', '-i', updated_fname, 'u-boot', 3475 '-f', fname, '-m') 3476 map_fname = os.path.join(tmpdir, 'image-updated.map') 3477 self.assertTrue(os.path.exists(map_fname)) 3478 finally: 3479 shutil.rmtree(tmpdir) 3480 3481 def testReplaceNoEntryPaths(self): 3482 """Test replacing an entry without an entry path""" 3483 self._DoReadFileRealDtb('143_replace_all.dts') 3484 image_fname = tools.GetOutputFilename('image.bin') 3485 with self.assertRaises(ValueError) as e: 3486 control.ReplaceEntries(image_fname, 'fname', None, []) 3487 self.assertIn('Must specify an entry path to read with -f', 3488 str(e.exception)) 3489 3490 def testReplaceTooManyEntryPaths(self): 3491 """Test extracting some entries""" 3492 self._DoReadFileRealDtb('143_replace_all.dts') 3493 image_fname = tools.GetOutputFilename('image.bin') 3494 with self.assertRaises(ValueError) as e: 3495 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b']) 3496 self.assertIn('Must specify exactly one entry path to write with -f', 3497 str(e.exception)) 3498 3499 def testPackReset16(self): 3500 """Test that an image with an x86 reset16 region can be created""" 3501 data = self._DoReadFile('144_x86_reset16.dts') 3502 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)]) 3503 3504 def testPackReset16Spl(self): 3505 """Test that an image with an x86 reset16-spl region can be created""" 3506 data = self._DoReadFile('145_x86_reset16_spl.dts') 3507 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)]) 3508 3509 def testPackReset16Tpl(self): 3510 """Test that an image with an x86 reset16-tpl region can be created""" 3511 data = self._DoReadFile('146_x86_reset16_tpl.dts') 3512 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)]) 3513 3514 def testPackIntelFit(self): 3515 """Test that an image with an Intel FIT and pointer can be created""" 3516 data = self._DoReadFile('147_intel_fit.dts') 3517 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)]) 3518 fit = data[16:32]; 3519 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit) 3520 ptr = struct.unpack('<i', data[0x40:0x44])[0] 3521 3522 image = control.images['image'] 3523 entries = image.GetEntries() 3524 expected_ptr = entries['intel-fit'].image_pos - (1 << 32) 3525 self.assertEqual(expected_ptr, ptr) 3526 3527 def testPackIntelFitMissing(self): 3528 """Test detection of a FIT pointer with not FIT region""" 3529 with self.assertRaises(ValueError) as e: 3530 self._DoReadFile('148_intel_fit_missing.dts') 3531 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling", 3532 str(e.exception)) 3533 3534 def _CheckSymbolsTplSection(self, dts, expected_vals): 3535 data = self._DoReadFile(dts) 3536 sym_values = struct.pack('<LQLL', *expected_vals) 3537 upto1 = 4 + len(U_BOOT_SPL_DATA) 3538 expected1 = tools.GetBytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[20:] 3539 self.assertEqual(expected1, data[:upto1]) 3540 3541 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA) 3542 expected2 = tools.GetBytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[20:] 3543 self.assertEqual(expected2, data[upto1:upto2]) 3544 3545 upto3 = 0x34 + len(U_BOOT_DATA) 3546 expected3 = tools.GetBytes(0xff, 1) + U_BOOT_DATA 3547 self.assertEqual(expected3, data[upto2:upto3]) 3548 3549 expected4 = sym_values + U_BOOT_TPL_DATA[20:] 3550 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)]) 3551 3552 def testSymbolsTplSection(self): 3553 """Test binman can assign symbols embedded in U-Boot TPL in a section""" 3554 self._SetupSplElf('u_boot_binman_syms') 3555 self._SetupTplElf('u_boot_binman_syms') 3556 self._CheckSymbolsTplSection('149_symbols_tpl.dts', 3557 [0x04, 0x1c, 0x10 + 0x34, 0x04]) 3558 3559 def testSymbolsTplSectionX86(self): 3560 """Test binman can assign symbols in a section with end-at-4gb""" 3561 self._SetupSplElf('u_boot_binman_syms_x86') 3562 self._SetupTplElf('u_boot_binman_syms_x86') 3563 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts', 3564 [0xffffff04, 0xffffff1c, 0xffffff34, 3565 0x04]) 3566 3567 def testPackX86RomIfwiSectiom(self): 3568 """Test that a section can be placed in an IFWI region""" 3569 self._SetupIfwi('fitimage.bin') 3570 data = self._DoReadFile('151_x86_rom_ifwi_section.dts') 3571 self._CheckIfwi(data) 3572 3573 def testPackFspM(self): 3574 """Test that an image with a FSP memory-init binary can be created""" 3575 data = self._DoReadFile('152_intel_fsp_m.dts') 3576 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)]) 3577 3578 def testPackFspS(self): 3579 """Test that an image with a FSP silicon-init binary can be created""" 3580 data = self._DoReadFile('153_intel_fsp_s.dts') 3581 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)]) 3582 3583 def testPackFspT(self): 3584 """Test that an image with a FSP temp-ram-init binary can be created""" 3585 data = self._DoReadFile('154_intel_fsp_t.dts') 3586 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)]) 3587 3588 def testMkimage(self): 3589 """Test using mkimage to build an image""" 3590 data = self._DoReadFile('156_mkimage.dts') 3591 3592 # Just check that the data appears in the file somewhere 3593 self.assertIn(U_BOOT_SPL_DATA, data) 3594 3595 def testExtblob(self): 3596 """Test an image with an external blob""" 3597 data = self._DoReadFile('157_blob_ext.dts') 3598 self.assertEqual(REFCODE_DATA, data) 3599 3600 def testExtblobMissing(self): 3601 """Test an image with a missing external blob""" 3602 with self.assertRaises(ValueError) as e: 3603 self._DoReadFile('158_blob_ext_missing.dts') 3604 self.assertIn("Filename 'missing-file' not found in input path", 3605 str(e.exception)) 3606 3607 def testExtblobMissingOk(self): 3608 """Test an image with an missing external blob that is allowed""" 3609 with test_util.capture_sys_output() as (stdout, stderr): 3610 self._DoTestFile('158_blob_ext_missing.dts', allow_missing=True) 3611 err = stderr.getvalue() 3612 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext") 3613 3614 def testExtblobMissingOkSect(self): 3615 """Test an image with an missing external blob that is allowed""" 3616 with test_util.capture_sys_output() as (stdout, stderr): 3617 self._DoTestFile('159_blob_ext_missing_sect.dts', 3618 allow_missing=True) 3619 err = stderr.getvalue() 3620 self.assertRegex(err, "Image 'main-section'.*missing.*: " 3621 "blob-ext blob-ext2") 3622 3623 def testPackX86RomMeMissingDesc(self): 3624 """Test that an missing Intel descriptor entry is allowed""" 3625 with test_util.capture_sys_output() as (stdout, stderr): 3626 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True) 3627 err = stderr.getvalue() 3628 self.assertRegex(err, 3629 "Image 'main-section'.*missing.*: intel-descriptor") 3630 3631 def testPackX86RomMissingIfwi(self): 3632 """Test that an x86 ROM with Integrated Firmware Image can be created""" 3633 self._SetupIfwi('fitimage.bin') 3634 pathname = os.path.join(self._indir, 'fitimage.bin') 3635 os.remove(pathname) 3636 with test_util.capture_sys_output() as (stdout, stderr): 3637 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True) 3638 err = stderr.getvalue() 3639 self.assertRegex(err, "Image 'main-section'.*missing.*: intel-ifwi") 3640 3641 def testPackOverlap(self): 3642 """Test that zero-size overlapping regions are ignored""" 3643 self._DoTestFile('160_pack_overlap_zero.dts') 3644 3645 def testSimpleFit(self): 3646 """Test an image with a FIT inside""" 3647 data = self._DoReadFile('161_fit.dts') 3648 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)]) 3649 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):]) 3650 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)] 3651 3652 # The data should be inside the FIT 3653 dtb = fdt.Fdt.FromData(fit_data) 3654 dtb.Scan() 3655 fnode = dtb.GetNode('/images/kernel') 3656 self.assertIn('data', fnode.props) 3657 3658 fname = os.path.join(self._indir, 'fit_data.fit') 3659 tools.WriteFile(fname, fit_data) 3660 out = tools.Run('dumpimage', '-l', fname) 3661 3662 # Check a few features to make sure the plumbing works. We don't need 3663 # to test the operation of mkimage or dumpimage here. First convert the 3664 # output into a dict where the keys are the fields printed by dumpimage 3665 # and the values are a list of values for each field 3666 lines = out.splitlines() 3667 3668 # Converts "Compression: gzip compressed" into two groups: 3669 # 'Compression' and 'gzip compressed' 3670 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$') 3671 vals = collections.defaultdict(list) 3672 for line in lines: 3673 mat = re_line.match(line) 3674 vals[mat.group(1)].append(mat.group(2)) 3675 3676 self.assertEquals('FIT description: test-desc', lines[0]) 3677 self.assertIn('Created:', lines[1]) 3678 self.assertIn('Image 0 (kernel)', vals) 3679 self.assertIn('Hash value', vals) 3680 data_sizes = vals.get('Data Size') 3681 self.assertIsNotNone(data_sizes) 3682 self.assertEqual(2, len(data_sizes)) 3683 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word 3684 self.assertEqual(len(U_BOOT_DATA), int(data_sizes[0].split()[0])) 3685 self.assertEqual(len(U_BOOT_SPL_DTB_DATA), int(data_sizes[1].split()[0])) 3686 3687 def testFitExternal(self): 3688 """Test an image with an FIT with external images""" 3689 data = self._DoReadFile('162_fit_external.dts') 3690 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes 3691 3692 # The data should be outside the FIT 3693 dtb = fdt.Fdt.FromData(fit_data) 3694 dtb.Scan() 3695 fnode = dtb.GetNode('/images/kernel') 3696 self.assertNotIn('data', fnode.props) 3697 3698 def testSectionIgnoreHashSignature(self): 3699 """Test that sections ignore hash, signature nodes for its data""" 3700 data = self._DoReadFile('165_section_ignore_hash_signature.dts') 3701 expected = (U_BOOT_DATA + U_BOOT_DATA) 3702 self.assertEqual(expected, data) 3703 3704 def testPadInSections(self): 3705 """Test pad-before, pad-after for entries in sections""" 3706 data, _, _, out_dtb_fname = self._DoReadFileDtb( 3707 '166_pad_in_sections.dts', update_dtb=True) 3708 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) + 3709 U_BOOT_DATA + tools.GetBytes(ord('!'), 6) + 3710 U_BOOT_DATA) 3711 self.assertEqual(expected, data) 3712 3713 dtb = fdt.Fdt(out_dtb_fname) 3714 dtb.Scan() 3715 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset']) 3716 expected = { 3717 'image-pos': 0, 3718 'offset': 0, 3719 'size': 12 + 6 + 3 * len(U_BOOT_DATA), 3720 3721 'section:image-pos': 0, 3722 'section:offset': 0, 3723 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA), 3724 3725 'section/before:image-pos': 0, 3726 'section/before:offset': 0, 3727 'section/before:size': len(U_BOOT_DATA), 3728 3729 'section/u-boot:image-pos': 4, 3730 'section/u-boot:offset': 4, 3731 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6, 3732 3733 'section/after:image-pos': 26, 3734 'section/after:offset': 26, 3735 'section/after:size': len(U_BOOT_DATA), 3736 } 3737 self.assertEqual(expected, props) 3738 3739 def testFitImageSubentryAlignment(self): 3740 """Test relative alignability of FIT image subentries""" 3741 entry_args = { 3742 'test-id': TEXT_DATA, 3743 } 3744 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts', 3745 entry_args=entry_args) 3746 dtb = fdt.Fdt.FromData(data) 3747 dtb.Scan() 3748 3749 node = dtb.GetNode('/images/kernel') 3750 data = dtb.GetProps(node)["data"].bytes 3751 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10) 3752 expected = (tools.GetBytes(0, 0x20) + U_BOOT_SPL_DATA + 3753 tools.GetBytes(0, align_pad) + U_BOOT_DATA) 3754 self.assertEqual(expected, data) 3755 3756 node = dtb.GetNode('/images/fdt-1') 3757 data = dtb.GetProps(node)["data"].bytes 3758 expected = (U_BOOT_SPL_DTB_DATA + tools.GetBytes(0, 20) + 3759 tools.ToBytes(TEXT_DATA) + tools.GetBytes(0, 30) + 3760 U_BOOT_DTB_DATA) 3761 self.assertEqual(expected, data) 3762 3763 def testFitExtblobMissingOk(self): 3764 """Test a FIT with a missing external blob that is allowed""" 3765 with test_util.capture_sys_output() as (stdout, stderr): 3766 self._DoTestFile('168_fit_missing_blob.dts', 3767 allow_missing=True) 3768 err = stderr.getvalue() 3769 self.assertRegex(err, "Image 'main-section'.*missing.*: atf-bl31") 3770 3771 def testBlobNamedByArgMissing(self): 3772 """Test handling of a missing entry arg""" 3773 with self.assertRaises(ValueError) as e: 3774 self._DoReadFile('068_blob_named_by_arg.dts') 3775 self.assertIn("Missing required properties/entry args: cros-ec-rw-path", 3776 str(e.exception)) 3777 3778 def testPackBl31(self): 3779 """Test that an image with an ATF BL31 binary can be created""" 3780 data = self._DoReadFile('169_atf_bl31.dts') 3781 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)]) 3782 3783 def testPackScp(self): 3784 """Test that an image with an SCP binary can be created""" 3785 data = self._DoReadFile('172_scp.dts') 3786 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)]) 3787 3788 def testFitFdt(self): 3789 """Test an image with an FIT with multiple FDT images""" 3790 def _CheckFdt(seq, expected_data): 3791 """Check the FDT nodes 3792 3793 Args: 3794 seq: Sequence number to check (0 or 1) 3795 expected_data: Expected contents of 'data' property 3796 """ 3797 name = 'fdt-%d' % seq 3798 fnode = dtb.GetNode('/images/%s' % name) 3799 self.assertIsNotNone(fnode) 3800 self.assertEqual({'description','type', 'compression', 'data'}, 3801 set(fnode.props.keys())) 3802 self.assertEqual(expected_data, fnode.props['data'].bytes) 3803 self.assertEqual('fdt-test-fdt%d.dtb' % seq, 3804 fnode.props['description'].value) 3805 3806 def _CheckConfig(seq, expected_data): 3807 """Check the configuration nodes 3808 3809 Args: 3810 seq: Sequence number to check (0 or 1) 3811 expected_data: Expected contents of 'data' property 3812 """ 3813 cnode = dtb.GetNode('/configurations') 3814 self.assertIn('default', cnode.props) 3815 self.assertEqual('config-2', cnode.props['default'].value) 3816 3817 name = 'config-%d' % seq 3818 fnode = dtb.GetNode('/configurations/%s' % name) 3819 self.assertIsNotNone(fnode) 3820 self.assertEqual({'description','firmware', 'loadables', 'fdt'}, 3821 set(fnode.props.keys())) 3822 self.assertEqual('conf-test-fdt%d.dtb' % seq, 3823 fnode.props['description'].value) 3824 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value) 3825 3826 entry_args = { 3827 'of-list': 'test-fdt1 test-fdt2', 3828 'default-dt': 'test-fdt2', 3829 } 3830 data = self._DoReadFileDtb( 3831 '170_fit_fdt.dts', 3832 entry_args=entry_args, 3833 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0] 3834 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):]) 3835 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)] 3836 3837 dtb = fdt.Fdt.FromData(fit_data) 3838 dtb.Scan() 3839 fnode = dtb.GetNode('/images/kernel') 3840 self.assertIn('data', fnode.props) 3841 3842 # Check all the properties in fdt-1 and fdt-2 3843 _CheckFdt(1, TEST_FDT1_DATA) 3844 _CheckFdt(2, TEST_FDT2_DATA) 3845 3846 # Check configurations 3847 _CheckConfig(1, TEST_FDT1_DATA) 3848 _CheckConfig(2, TEST_FDT2_DATA) 3849 3850 def testFitFdtMissingList(self): 3851 """Test handling of a missing 'of-list' entry arg""" 3852 with self.assertRaises(ValueError) as e: 3853 self._DoReadFile('170_fit_fdt.dts') 3854 self.assertIn("Generator node requires 'of-list' entry argument", 3855 str(e.exception)) 3856 3857 def testFitFdtEmptyList(self): 3858 """Test handling of an empty 'of-list' entry arg""" 3859 entry_args = { 3860 'of-list': '', 3861 } 3862 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0] 3863 3864 def testFitFdtMissingProp(self): 3865 """Test handling of a missing 'fit,fdt-list' property""" 3866 with self.assertRaises(ValueError) as e: 3867 self._DoReadFile('171_fit_fdt_missing_prop.dts') 3868 self.assertIn("Generator node requires 'fit,fdt-list' property", 3869 str(e.exception)) 3870 3871 def testFitFdtEmptyList(self): 3872 """Test handling of an empty 'of-list' entry arg""" 3873 entry_args = { 3874 'of-list': '', 3875 } 3876 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0] 3877 3878 def testFitFdtMissing(self): 3879 """Test handling of a missing 'default-dt' entry arg""" 3880 entry_args = { 3881 'of-list': 'test-fdt1 test-fdt2', 3882 } 3883 with self.assertRaises(ValueError) as e: 3884 self._DoReadFileDtb( 3885 '170_fit_fdt.dts', 3886 entry_args=entry_args, 3887 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0] 3888 self.assertIn("Generated 'default' node requires default-dt entry argument", 3889 str(e.exception)) 3890 3891 def testFitFdtNotInList(self): 3892 """Test handling of a default-dt that is not in the of-list""" 3893 entry_args = { 3894 'of-list': 'test-fdt1 test-fdt2', 3895 'default-dt': 'test-fdt3', 3896 } 3897 with self.assertRaises(ValueError) as e: 3898 self._DoReadFileDtb( 3899 '170_fit_fdt.dts', 3900 entry_args=entry_args, 3901 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0] 3902 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2", 3903 str(e.exception)) 3904 3905 def testFitExtblobMissingHelp(self): 3906 """Test display of help messages when an external blob is missing""" 3907 control.missing_blob_help = control._ReadMissingBlobHelp() 3908 control.missing_blob_help['wibble'] = 'Wibble test' 3909 control.missing_blob_help['another'] = 'Another test' 3910 with test_util.capture_sys_output() as (stdout, stderr): 3911 self._DoTestFile('168_fit_missing_blob.dts', 3912 allow_missing=True) 3913 err = stderr.getvalue() 3914 3915 # We can get the tag from the name, the type or the missing-msg 3916 # property. Check all three. 3917 self.assertIn('You may need to build ARM Trusted', err) 3918 self.assertIn('Wibble test', err) 3919 self.assertIn('Another test', err) 3920 3921 def testMissingBlob(self): 3922 """Test handling of a blob containing a missing file""" 3923 with self.assertRaises(ValueError) as e: 3924 self._DoTestFile('173_missing_blob.dts', allow_missing=True) 3925 self.assertIn("Filename 'missing' not found in input path", 3926 str(e.exception)) 3927 3928 def testEnvironment(self): 3929 """Test adding a U-Boot environment""" 3930 data = self._DoReadFile('174_env.dts') 3931 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)]) 3932 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):]) 3933 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)] 3934 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff', 3935 env) 3936 3937 def testEnvironmentNoSize(self): 3938 """Test that a missing 'size' property is detected""" 3939 with self.assertRaises(ValueError) as e: 3940 self._DoTestFile('175_env_no_size.dts') 3941 self.assertIn("'u-boot-env' entry must have a size property", 3942 str(e.exception)) 3943 3944 def testEnvironmentTooSmall(self): 3945 """Test handling of an environment that does not fit""" 3946 with self.assertRaises(ValueError) as e: 3947 self._DoTestFile('176_env_too_small.dts') 3948 3949 # checksum, start byte, environment with \0 terminator, final \0 3950 need = 4 + 1 + len(ENV_DATA) + 1 + 1 3951 short = need - 0x8 3952 self.assertIn("too small to hold data (need %#x more bytes)" % short, 3953 str(e.exception)) 3954 3955 def testSkipAtStart(self): 3956 """Test handling of skip-at-start section""" 3957 data = self._DoReadFile('177_skip_at_start.dts') 3958 self.assertEqual(U_BOOT_DATA, data) 3959 3960 image = control.images['image'] 3961 entries = image.GetEntries() 3962 section = entries['section'] 3963 self.assertEqual(0, section.offset) 3964 self.assertEqual(len(U_BOOT_DATA), section.size) 3965 self.assertEqual(U_BOOT_DATA, section.GetData()) 3966 3967 entry = section.GetEntries()['u-boot'] 3968 self.assertEqual(16, entry.offset) 3969 self.assertEqual(len(U_BOOT_DATA), entry.size) 3970 self.assertEqual(U_BOOT_DATA, entry.data) 3971 3972 def testSkipAtStartPad(self): 3973 """Test handling of skip-at-start section with padded entry""" 3974 data = self._DoReadFile('178_skip_at_start_pad.dts') 3975 before = tools.GetBytes(0, 8) 3976 after = tools.GetBytes(0, 4) 3977 all = before + U_BOOT_DATA + after 3978 self.assertEqual(all, data) 3979 3980 image = control.images['image'] 3981 entries = image.GetEntries() 3982 section = entries['section'] 3983 self.assertEqual(0, section.offset) 3984 self.assertEqual(len(all), section.size) 3985 self.assertEqual(all, section.GetData()) 3986 3987 entry = section.GetEntries()['u-boot'] 3988 self.assertEqual(16, entry.offset) 3989 self.assertEqual(len(all), entry.size) 3990 self.assertEqual(U_BOOT_DATA, entry.data) 3991 3992 def testSkipAtStartSectionPad(self): 3993 """Test handling of skip-at-start section with padding""" 3994 data = self._DoReadFile('179_skip_at_start_section_pad.dts') 3995 before = tools.GetBytes(0, 8) 3996 after = tools.GetBytes(0, 4) 3997 all = before + U_BOOT_DATA + after 3998 self.assertEqual(all, data) 3999 4000 image = control.images['image'] 4001 entries = image.GetEntries() 4002 section = entries['section'] 4003 self.assertEqual(0, section.offset) 4004 self.assertEqual(len(all), section.size) 4005 self.assertEqual(U_BOOT_DATA, section.data) 4006 self.assertEqual(all, section.GetPaddedData()) 4007 4008 entry = section.GetEntries()['u-boot'] 4009 self.assertEqual(16, entry.offset) 4010 self.assertEqual(len(U_BOOT_DATA), entry.size) 4011 self.assertEqual(U_BOOT_DATA, entry.data) 4012 4013 def testSectionPad(self): 4014 """Testing padding with sections""" 4015 data = self._DoReadFile('180_section_pad.dts') 4016 expected = (tools.GetBytes(ord('&'), 3) + 4017 tools.GetBytes(ord('!'), 5) + 4018 U_BOOT_DATA + 4019 tools.GetBytes(ord('!'), 1) + 4020 tools.GetBytes(ord('&'), 2)) 4021 self.assertEqual(expected, data) 4022 4023 def testSectionAlign(self): 4024 """Testing alignment with sections""" 4025 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0] 4026 expected = (b'\0' + # fill section 4027 tools.GetBytes(ord('&'), 1) + # padding to section align 4028 b'\0' + # fill section 4029 tools.GetBytes(ord('!'), 3) + # padding to u-boot align 4030 U_BOOT_DATA + 4031 tools.GetBytes(ord('!'), 4) + # padding to u-boot size 4032 tools.GetBytes(ord('!'), 4)) # padding to section size 4033 self.assertEqual(expected, data) 4034 4035 def testCompressImage(self): 4036 """Test compression of the entire image""" 4037 self._CheckLz4() 4038 data, _, _, out_dtb_fname = self._DoReadFileDtb( 4039 '182_compress_image.dts', use_real_dtb=True, update_dtb=True) 4040 dtb = fdt.Fdt(out_dtb_fname) 4041 dtb.Scan() 4042 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size', 4043 'uncomp-size']) 4044 orig = self._decompress(data) 4045 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig) 4046 4047 # Do a sanity check on various fields 4048 image = control.images['image'] 4049 entries = image.GetEntries() 4050 self.assertEqual(2, len(entries)) 4051 4052 entry = entries['blob'] 4053 self.assertEqual(COMPRESS_DATA, entry.data) 4054 self.assertEqual(len(COMPRESS_DATA), entry.size) 4055 4056 entry = entries['u-boot'] 4057 self.assertEqual(U_BOOT_DATA, entry.data) 4058 self.assertEqual(len(U_BOOT_DATA), entry.size) 4059 4060 self.assertEqual(len(data), image.size) 4061 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data) 4062 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size) 4063 orig = self._decompress(image.data) 4064 self.assertEqual(orig, image.uncomp_data) 4065 4066 expected = { 4067 'blob:offset': 0, 4068 'blob:size': len(COMPRESS_DATA), 4069 'u-boot:offset': len(COMPRESS_DATA), 4070 'u-boot:size': len(U_BOOT_DATA), 4071 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA), 4072 'offset': 0, 4073 'image-pos': 0, 4074 'size': len(data), 4075 } 4076 self.assertEqual(expected, props) 4077 4078 def testCompressImageLess(self): 4079 """Test compression where compression reduces the image size""" 4080 self._CheckLz4() 4081 data, _, _, out_dtb_fname = self._DoReadFileDtb( 4082 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True) 4083 dtb = fdt.Fdt(out_dtb_fname) 4084 dtb.Scan() 4085 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size', 4086 'uncomp-size']) 4087 orig = self._decompress(data) 4088 4089 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig) 4090 4091 # Do a sanity check on various fields 4092 image = control.images['image'] 4093 entries = image.GetEntries() 4094 self.assertEqual(2, len(entries)) 4095 4096 entry = entries['blob'] 4097 self.assertEqual(COMPRESS_DATA_BIG, entry.data) 4098 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size) 4099 4100 entry = entries['u-boot'] 4101 self.assertEqual(U_BOOT_DATA, entry.data) 4102 self.assertEqual(len(U_BOOT_DATA), entry.size) 4103 4104 self.assertEqual(len(data), image.size) 4105 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data) 4106 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA), 4107 image.uncomp_size) 4108 orig = self._decompress(image.data) 4109 self.assertEqual(orig, image.uncomp_data) 4110 4111 expected = { 4112 'blob:offset': 0, 4113 'blob:size': len(COMPRESS_DATA_BIG), 4114 'u-boot:offset': len(COMPRESS_DATA_BIG), 4115 'u-boot:size': len(U_BOOT_DATA), 4116 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA), 4117 'offset': 0, 4118 'image-pos': 0, 4119 'size': len(data), 4120 } 4121 self.assertEqual(expected, props) 4122 4123 def testCompressSectionSize(self): 4124 """Test compression of a section with a fixed size""" 4125 self._CheckLz4() 4126 data, _, _, out_dtb_fname = self._DoReadFileDtb( 4127 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True) 4128 dtb = fdt.Fdt(out_dtb_fname) 4129 dtb.Scan() 4130 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size', 4131 'uncomp-size']) 4132 orig = self._decompress(data) 4133 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig) 4134 expected = { 4135 'section/blob:offset': 0, 4136 'section/blob:size': len(COMPRESS_DATA), 4137 'section/u-boot:offset': len(COMPRESS_DATA), 4138 'section/u-boot:size': len(U_BOOT_DATA), 4139 'section:offset': 0, 4140 'section:image-pos': 0, 4141 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA), 4142 'section:size': 0x30, 4143 'offset': 0, 4144 'image-pos': 0, 4145 'size': 0x30, 4146 } 4147 self.assertEqual(expected, props) 4148 4149 def testCompressSection(self): 4150 """Test compression of a section with no fixed size""" 4151 self._CheckLz4() 4152 data, _, _, out_dtb_fname = self._DoReadFileDtb( 4153 '185_compress_section.dts', use_real_dtb=True, update_dtb=True) 4154 dtb = fdt.Fdt(out_dtb_fname) 4155 dtb.Scan() 4156 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size', 4157 'uncomp-size']) 4158 orig = self._decompress(data) 4159 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig) 4160 expected = { 4161 'section/blob:offset': 0, 4162 'section/blob:size': len(COMPRESS_DATA), 4163 'section/u-boot:offset': len(COMPRESS_DATA), 4164 'section/u-boot:size': len(U_BOOT_DATA), 4165 'section:offset': 0, 4166 'section:image-pos': 0, 4167 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA), 4168 'section:size': len(data), 4169 'offset': 0, 4170 'image-pos': 0, 4171 'size': len(data), 4172 } 4173 self.assertEqual(expected, props) 4174 4175 def testCompressExtra(self): 4176 """Test compression of a section with no fixed size""" 4177 self._CheckLz4() 4178 data, _, _, out_dtb_fname = self._DoReadFileDtb( 4179 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True) 4180 dtb = fdt.Fdt(out_dtb_fname) 4181 dtb.Scan() 4182 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size', 4183 'uncomp-size']) 4184 4185 base = data[len(U_BOOT_DATA):] 4186 self.assertEquals(U_BOOT_DATA, base[:len(U_BOOT_DATA)]) 4187 rest = base[len(U_BOOT_DATA):] 4188 4189 # Check compressed data 4190 section1 = self._decompress(rest) 4191 expect1 = tools.Compress(COMPRESS_DATA + U_BOOT_DATA, 'lz4') 4192 self.assertEquals(expect1, rest[:len(expect1)]) 4193 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, section1) 4194 rest1 = rest[len(expect1):] 4195 4196 section2 = self._decompress(rest1) 4197 expect2 = tools.Compress(COMPRESS_DATA + COMPRESS_DATA, 'lz4') 4198 self.assertEquals(expect2, rest1[:len(expect2)]) 4199 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA, section2) 4200 rest2 = rest1[len(expect2):] 4201 4202 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) + 4203 len(expect2) + len(U_BOOT_DATA)) 4204 #self.assertEquals(expect_size, len(data)) 4205 4206 #self.assertEquals(U_BOOT_DATA, rest2) 4207 4208 self.maxDiff = None 4209 expected = { 4210 'u-boot:offset': 0, 4211 'u-boot:image-pos': 0, 4212 'u-boot:size': len(U_BOOT_DATA), 4213 4214 'base:offset': len(U_BOOT_DATA), 4215 'base:image-pos': len(U_BOOT_DATA), 4216 'base:size': len(data) - len(U_BOOT_DATA), 4217 'base/u-boot:offset': 0, 4218 'base/u-boot:image-pos': len(U_BOOT_DATA), 4219 'base/u-boot:size': len(U_BOOT_DATA), 4220 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) + 4221 len(expect2), 4222 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) + 4223 len(expect2), 4224 'base/u-boot2:size': len(U_BOOT_DATA), 4225 4226 'base/section:offset': len(U_BOOT_DATA), 4227 'base/section:image-pos': len(U_BOOT_DATA) * 2, 4228 'base/section:size': len(expect1), 4229 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA), 4230 'base/section/blob:offset': 0, 4231 'base/section/blob:size': len(COMPRESS_DATA), 4232 'base/section/u-boot:offset': len(COMPRESS_DATA), 4233 'base/section/u-boot:size': len(U_BOOT_DATA), 4234 4235 'base/section2:offset': len(U_BOOT_DATA) + len(expect1), 4236 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1), 4237 'base/section2:size': len(expect2), 4238 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA), 4239 'base/section2/blob:offset': 0, 4240 'base/section2/blob:size': len(COMPRESS_DATA), 4241 'base/section2/blob2:offset': len(COMPRESS_DATA), 4242 'base/section2/blob2:size': len(COMPRESS_DATA), 4243 4244 'offset': 0, 4245 'image-pos': 0, 4246 'size': len(data), 4247 } 4248 self.assertEqual(expected, props) 4249 4250 def testSymbolsSubsection(self): 4251 """Test binman can assign symbols from a subsection""" 4252 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x18) 4253 4254 def testReadImageEntryArg(self): 4255 """Test reading an image that would need an entry arg to generate""" 4256 entry_args = { 4257 'cros-ec-rw-path': 'ecrw.bin', 4258 } 4259 data = self.data = self._DoReadFileDtb( 4260 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True, 4261 entry_args=entry_args) 4262 4263 image_fname = tools.GetOutputFilename('image.bin') 4264 orig_image = control.images['image'] 4265 4266 # This should not generate an error about the missing 'cros-ec-rw-path' 4267 # since we are reading the image from a file. Compare with 4268 # testEntryArgsRequired() 4269 image = Image.FromFile(image_fname) 4270 self.assertEqual(orig_image.GetEntries().keys(), 4271 image.GetEntries().keys()) 4272 4273 def testFilesAlign(self): 4274 """Test alignment with files""" 4275 data = self._DoReadFile('190_files_align.dts') 4276 4277 # The first string is 15 bytes so will align to 16 4278 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:] 4279 self.assertEqual(expect, data) 4280 4281 def testReadImageSkip(self): 4282 """Test reading an image and accessing its FDT map""" 4283 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts') 4284 image_fname = tools.GetOutputFilename('image.bin') 4285 orig_image = control.images['image'] 4286 image = Image.FromFile(image_fname) 4287 self.assertEqual(orig_image.GetEntries().keys(), 4288 image.GetEntries().keys()) 4289 4290 orig_entry = orig_image.GetEntries()['fdtmap'] 4291 entry = image.GetEntries()['fdtmap'] 4292 self.assertEqual(orig_entry.offset, entry.offset) 4293 self.assertEqual(orig_entry.size, entry.size) 4294 self.assertEqual(16, entry.image_pos) 4295 4296 u_boot = image.GetEntries()['section'].GetEntries()['u-boot'] 4297 4298 self.assertEquals(U_BOOT_DATA, u_boot.ReadData()) 4299 4300 def testTplNoDtb(self): 4301 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created""" 4302 self._SetupTplElf() 4303 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts') 4304 self.assertEqual(U_BOOT_TPL_NODTB_DATA, 4305 data[:len(U_BOOT_TPL_NODTB_DATA)]) 4306 4307 def testTplBssPad(self): 4308 """Test that we can pad TPL's BSS with zeros""" 4309 # ELF file with a '__bss_size' symbol 4310 self._SetupTplElf() 4311 data = self._DoReadFile('193_tpl_bss_pad.dts') 4312 self.assertEqual(U_BOOT_TPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA, 4313 data) 4314 4315 def testTplBssPadMissing(self): 4316 """Test that a missing symbol is detected""" 4317 self._SetupTplElf('u_boot_ucode_ptr') 4318 with self.assertRaises(ValueError) as e: 4319 self._DoReadFile('193_tpl_bss_pad.dts') 4320 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl', 4321 str(e.exception)) 4322 4323 def checkDtbSizes(self, data, pad_len, start): 4324 """Check the size arguments in a dtb embedded in an image 4325 4326 Args: 4327 data: The image data 4328 pad_len: Length of the pad section in the image, in bytes 4329 start: Start offset of the devicetree to examine, within the image 4330 4331 Returns: 4332 Size of the devicetree in bytes 4333 """ 4334 dtb_data = data[start:] 4335 dtb = fdt.Fdt.FromData(dtb_data) 4336 fdt_size = dtb.GetFdtObj().totalsize() 4337 dtb.Scan() 4338 props = self._GetPropTree(dtb, 'size') 4339 self.assertEqual({ 4340 'size': len(data), 4341 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len, 4342 'u-boot-spl/u-boot-spl-dtb:size': 801, 4343 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA), 4344 'u-boot-spl:size': 860, 4345 'u-boot-tpl:size': len(U_BOOT_TPL_DATA), 4346 'u-boot/u-boot-dtb:size': 781, 4347 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA), 4348 'u-boot:size': 827, 4349 }, props) 4350 return fdt_size 4351 4352 def testExpanded(self): 4353 """Test that an expanded entry type is selected when needed""" 4354 self._SetupSplElf() 4355 self._SetupTplElf() 4356 4357 # SPL has a devicetree, TPL does not 4358 entry_args = { 4359 'spl-dtb': '1', 4360 'spl-bss-pad': 'y', 4361 'tpl-dtb': '', 4362 } 4363 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True, 4364 entry_args=entry_args) 4365 image = control.images['image'] 4366 entries = image.GetEntries() 4367 self.assertEqual(3, len(entries)) 4368 4369 # First, u-boot, which should be expanded into u-boot-nodtb and dtb 4370 self.assertIn('u-boot', entries) 4371 entry = entries['u-boot'] 4372 self.assertEqual('u-boot-expanded', entry.etype) 4373 subent = entry.GetEntries() 4374 self.assertEqual(2, len(subent)) 4375 self.assertIn('u-boot-nodtb', subent) 4376 self.assertIn('u-boot-dtb', subent) 4377 4378 # Second, u-boot-spl, which should be expanded into three parts 4379 self.assertIn('u-boot-spl', entries) 4380 entry = entries['u-boot-spl'] 4381 self.assertEqual('u-boot-spl-expanded', entry.etype) 4382 subent = entry.GetEntries() 4383 self.assertEqual(3, len(subent)) 4384 self.assertIn('u-boot-spl-nodtb', subent) 4385 self.assertIn('u-boot-spl-bss-pad', subent) 4386 self.assertIn('u-boot-spl-dtb', subent) 4387 4388 # Third, u-boot-tpl, which should be not be expanded, since TPL has no 4389 # devicetree 4390 self.assertIn('u-boot-tpl', entries) 4391 entry = entries['u-boot-tpl'] 4392 self.assertEqual('u-boot-tpl', entry.etype) 4393 self.assertEqual(None, entry.GetEntries()) 4394 4395 def testExpandedTpl(self): 4396 """Test that an expanded entry type is selected for TPL when needed""" 4397 self._SetupTplElf() 4398 4399 entry_args = { 4400 'tpl-bss-pad': 'y', 4401 'tpl-dtb': 'y', 4402 } 4403 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True, 4404 entry_args=entry_args) 4405 image = control.images['image'] 4406 entries = image.GetEntries() 4407 self.assertEqual(1, len(entries)) 4408 4409 # We only have u-boot-tpl, which be expanded 4410 self.assertIn('u-boot-tpl', entries) 4411 entry = entries['u-boot-tpl'] 4412 self.assertEqual('u-boot-tpl-expanded', entry.etype) 4413 subent = entry.GetEntries() 4414 self.assertEqual(3, len(subent)) 4415 self.assertIn('u-boot-tpl-nodtb', subent) 4416 self.assertIn('u-boot-tpl-bss-pad', subent) 4417 self.assertIn('u-boot-tpl-dtb', subent) 4418 4419 def testExpandedNoPad(self): 4420 """Test an expanded entry without BSS pad enabled""" 4421 self._SetupSplElf() 4422 self._SetupTplElf() 4423 4424 # SPL has a devicetree, TPL does not 4425 entry_args = { 4426 'spl-dtb': 'something', 4427 'spl-bss-pad': 'n', 4428 'tpl-dtb': '', 4429 } 4430 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True, 4431 entry_args=entry_args) 4432 image = control.images['image'] 4433 entries = image.GetEntries() 4434 4435 # Just check u-boot-spl, which should be expanded into two parts 4436 self.assertIn('u-boot-spl', entries) 4437 entry = entries['u-boot-spl'] 4438 self.assertEqual('u-boot-spl-expanded', entry.etype) 4439 subent = entry.GetEntries() 4440 self.assertEqual(2, len(subent)) 4441 self.assertIn('u-boot-spl-nodtb', subent) 4442 self.assertIn('u-boot-spl-dtb', subent) 4443 4444 def testExpandedTplNoPad(self): 4445 """Test that an expanded entry type with padding disabled in TPL""" 4446 self._SetupTplElf() 4447 4448 entry_args = { 4449 'tpl-bss-pad': '', 4450 'tpl-dtb': 'y', 4451 } 4452 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True, 4453 entry_args=entry_args) 4454 image = control.images['image'] 4455 entries = image.GetEntries() 4456 self.assertEqual(1, len(entries)) 4457 4458 # We only have u-boot-tpl, which be expanded 4459 self.assertIn('u-boot-tpl', entries) 4460 entry = entries['u-boot-tpl'] 4461 self.assertEqual('u-boot-tpl-expanded', entry.etype) 4462 subent = entry.GetEntries() 4463 self.assertEqual(2, len(subent)) 4464 self.assertIn('u-boot-tpl-nodtb', subent) 4465 self.assertIn('u-boot-tpl-dtb', subent) 4466 4467 def testFdtInclude(self): 4468 """Test that an Fdt is update within all binaries""" 4469 self._SetupSplElf() 4470 self._SetupTplElf() 4471 4472 # SPL has a devicetree, TPL does not 4473 self.maxDiff = None 4474 entry_args = { 4475 'spl-dtb': '1', 4476 'spl-bss-pad': 'y', 4477 'tpl-dtb': '', 4478 } 4479 # Build the image. It includes two separate devicetree binaries, each 4480 # with their own contents, but all contain the binman definition. 4481 data = self._DoReadFileDtb( 4482 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True, 4483 update_dtb=True, entry_args=entry_args)[0] 4484 pad_len = 10 4485 4486 # Check the U-Boot dtb 4487 start = len(U_BOOT_NODTB_DATA) 4488 fdt_size = self.checkDtbSizes(data, pad_len, start) 4489 4490 # Now check SPL 4491 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len 4492 fdt_size = self.checkDtbSizes(data, pad_len, start) 4493 4494 # TPL has no devicetree 4495 start += fdt_size + len(U_BOOT_TPL_DATA) 4496 self.assertEqual(len(data), start) 4497 4498 def testSymbolsExpanded(self): 4499 """Test binman can assign symbols in expanded entries""" 4500 entry_args = { 4501 'spl-dtb': '1', 4502 } 4503 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA + 4504 U_BOOT_SPL_DTB_DATA, 0x38, 4505 entry_args=entry_args, use_expanded=True) 4506 4507 def testCollection(self): 4508 """Test a collection""" 4509 data = self._DoReadFile('198_collection.dts') 4510 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA + 4511 tools.GetBytes(0xff, 2) + U_BOOT_NODTB_DATA + 4512 tools.GetBytes(0xfe, 3) + U_BOOT_DTB_DATA, 4513 data) 4514 4515 def testCollectionSection(self): 4516 """Test a collection where a section must be built first""" 4517 # Sections never have their contents when GetData() is called, but when 4518 # _BuildSectionData() is called with required=True, a section will force 4519 # building the contents, producing an error is anything is still 4520 # missing. 4521 data = self._DoReadFile('199_collection_section.dts') 4522 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA 4523 self.assertEqual(section + U_BOOT_DATA + tools.GetBytes(0xff, 2) + 4524 section + tools.GetBytes(0xfe, 3) + U_BOOT_DATA, 4525 data) 4526 4527 def testAlignDefault(self): 4528 """Test that default alignment works on sections""" 4529 data = self._DoReadFile('200_align_default.dts') 4530 expected = (U_BOOT_DATA + tools.GetBytes(0, 8 - len(U_BOOT_DATA)) + 4531 U_BOOT_DATA) 4532 # Special alignment for section 4533 expected += tools.GetBytes(0, 32 - len(expected)) 4534 # No alignment within the nested section 4535 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA; 4536 # Now the final piece, which should be default-aligned 4537 expected += tools.GetBytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA 4538 self.assertEqual(expected, data) 4539 4540 def testPackOpenSBI(self): 4541 """Test that an image with an OpenSBI binary can be created""" 4542 data = self._DoReadFile('201_opensbi.dts') 4543 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)]) 4544 4545if __name__ == "__main__": 4546 unittest.main() 4547