1#!/usr/bin/env python 2# SPDX-License-Identifier: GPL-2.0+ 3# Copyright 2019 Google LLC 4# Written by Simon Glass <sjg@chromium.org> 5 6"""Tests for cbfs_util 7 8These create and read various CBFSs and compare the results with expected 9values and with cbfstool 10""" 11 12import io 13import os 14import shutil 15import struct 16import tempfile 17import unittest 18 19from binman import cbfs_util 20from binman.cbfs_util import CbfsWriter 21from binman import elf 22from patman import test_util 23from patman import tools 24 25U_BOOT_DATA = b'1234' 26U_BOOT_DTB_DATA = b'udtb' 27COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data' 28 29 30class TestCbfs(unittest.TestCase): 31 """Test of cbfs_util classes""" 32 #pylint: disable=W0212 33 @classmethod 34 def setUpClass(cls): 35 # Create a temporary directory for test files 36 cls._indir = tempfile.mkdtemp(prefix='cbfs_util.') 37 tools.SetInputDirs([cls._indir]) 38 39 # Set up some useful data files 40 TestCbfs._make_input_file('u-boot.bin', U_BOOT_DATA) 41 TestCbfs._make_input_file('u-boot.dtb', U_BOOT_DTB_DATA) 42 TestCbfs._make_input_file('compress', COMPRESS_DATA) 43 44 # Set up a temporary output directory, used by the tools library when 45 # compressing files 46 tools.PrepareOutputDir(None) 47 48 cls.have_cbfstool = True 49 try: 50 tools.Run('which', 'cbfstool') 51 except: 52 cls.have_cbfstool = False 53 54 cls.have_lz4 = True 55 try: 56 tools.Run('lz4', '--no-frame-crc', '-c', 57 tools.GetInputFilename('u-boot.bin'), binary=True) 58 except: 59 cls.have_lz4 = False 60 61 @classmethod 62 def tearDownClass(cls): 63 """Remove the temporary input directory and its contents""" 64 if cls._indir: 65 shutil.rmtree(cls._indir) 66 cls._indir = None 67 tools.FinaliseOutputDir() 68 69 @classmethod 70 def _make_input_file(cls, fname, contents): 71 """Create a new test input file, creating directories as needed 72 73 Args: 74 fname: Filename to create 75 contents: File contents to write in to the file 76 Returns: 77 Full pathname of file created 78 """ 79 pathname = os.path.join(cls._indir, fname) 80 tools.WriteFile(pathname, contents) 81 return pathname 82 83 def _check_hdr(self, data, size, offset=0, arch=cbfs_util.ARCHITECTURE_X86): 84 """Check that the CBFS has the expected header 85 86 Args: 87 data: Data to check 88 size: Expected ROM size 89 offset: Expected offset to first CBFS file 90 arch: Expected architecture 91 92 Returns: 93 CbfsReader object containing the CBFS 94 """ 95 cbfs = cbfs_util.CbfsReader(data) 96 self.assertEqual(cbfs_util.HEADER_MAGIC, cbfs.magic) 97 self.assertEqual(cbfs_util.HEADER_VERSION2, cbfs.version) 98 self.assertEqual(size, cbfs.rom_size) 99 self.assertEqual(0, cbfs.boot_block_size) 100 self.assertEqual(cbfs_util.ENTRY_ALIGN, cbfs.align) 101 self.assertEqual(offset, cbfs.cbfs_offset) 102 self.assertEqual(arch, cbfs.arch) 103 return cbfs 104 105 def _check_uboot(self, cbfs, ftype=cbfs_util.TYPE_RAW, offset=0x38, 106 data=U_BOOT_DATA, cbfs_offset=None): 107 """Check that the U-Boot file is as expected 108 109 Args: 110 cbfs: CbfsReader object to check 111 ftype: Expected file type 112 offset: Expected offset of file 113 data: Expected data in file 114 cbfs_offset: Expected CBFS offset for file's data 115 116 Returns: 117 CbfsFile object containing the file 118 """ 119 self.assertIn('u-boot', cbfs.files) 120 cfile = cbfs.files['u-boot'] 121 self.assertEqual('u-boot', cfile.name) 122 self.assertEqual(offset, cfile.offset) 123 if cbfs_offset is not None: 124 self.assertEqual(cbfs_offset, cfile.cbfs_offset) 125 self.assertEqual(data, cfile.data) 126 self.assertEqual(ftype, cfile.ftype) 127 self.assertEqual(cbfs_util.COMPRESS_NONE, cfile.compress) 128 self.assertEqual(len(data), cfile.memlen) 129 return cfile 130 131 def _check_dtb(self, cbfs, offset=0x38, data=U_BOOT_DTB_DATA, 132 cbfs_offset=None): 133 """Check that the U-Boot dtb file is as expected 134 135 Args: 136 cbfs: CbfsReader object to check 137 offset: Expected offset of file 138 data: Expected data in file 139 cbfs_offset: Expected CBFS offset for file's data 140 """ 141 self.assertIn('u-boot-dtb', cbfs.files) 142 cfile = cbfs.files['u-boot-dtb'] 143 self.assertEqual('u-boot-dtb', cfile.name) 144 self.assertEqual(offset, cfile.offset) 145 if cbfs_offset is not None: 146 self.assertEqual(cbfs_offset, cfile.cbfs_offset) 147 self.assertEqual(U_BOOT_DTB_DATA, cfile.data) 148 self.assertEqual(cbfs_util.TYPE_RAW, cfile.ftype) 149 self.assertEqual(cbfs_util.COMPRESS_NONE, cfile.compress) 150 self.assertEqual(len(U_BOOT_DTB_DATA), cfile.memlen) 151 152 def _check_raw(self, data, size, offset=0, arch=cbfs_util.ARCHITECTURE_X86): 153 """Check that two raw files are added as expected 154 155 Args: 156 data: Data to check 157 size: Expected ROM size 158 offset: Expected offset to first CBFS file 159 arch: Expected architecture 160 """ 161 cbfs = self._check_hdr(data, size, offset=offset, arch=arch) 162 self._check_uboot(cbfs) 163 self._check_dtb(cbfs) 164 165 def _get_expected_cbfs(self, size, arch='x86', compress=None, base=None): 166 """Get the file created by cbfstool for a particular scenario 167 168 Args: 169 size: Size of the CBFS in bytes 170 arch: Architecture of the CBFS, as a string 171 compress: Compression to use, e.g. cbfs_util.COMPRESS_LZMA 172 base: Base address of file, or None to put it anywhere 173 174 Returns: 175 Resulting CBFS file, or None if cbfstool is not available 176 """ 177 if not self.have_cbfstool or not self.have_lz4: 178 return None 179 cbfs_fname = os.path.join(self._indir, 'test.cbfs') 180 cbfs_util.cbfstool(cbfs_fname, 'create', '-m', arch, '-s', '%#x' % size) 181 if base: 182 base = [(1 << 32) - size + b for b in base] 183 cbfs_util.cbfstool(cbfs_fname, 'add', '-n', 'u-boot', '-t', 'raw', 184 '-c', compress and compress[0] or 'none', 185 '-f', tools.GetInputFilename( 186 compress and 'compress' or 'u-boot.bin'), 187 base=base[0] if base else None) 188 cbfs_util.cbfstool(cbfs_fname, 'add', '-n', 'u-boot-dtb', '-t', 'raw', 189 '-c', compress and compress[1] or 'none', 190 '-f', tools.GetInputFilename( 191 compress and 'compress' or 'u-boot.dtb'), 192 base=base[1] if base else None) 193 return cbfs_fname 194 195 def _compare_expected_cbfs(self, data, cbfstool_fname): 196 """Compare against what cbfstool creates 197 198 This compares what binman creates with what cbfstool creates for what 199 is proportedly the same thing. 200 201 Args: 202 data: CBFS created by binman 203 cbfstool_fname: CBFS created by cbfstool 204 """ 205 if not self.have_cbfstool or not self.have_lz4: 206 return 207 expect = tools.ReadFile(cbfstool_fname) 208 if expect != data: 209 tools.WriteFile('/tmp/expect', expect) 210 tools.WriteFile('/tmp/actual', data) 211 print('diff -y <(xxd -g1 /tmp/expect) <(xxd -g1 /tmp/actual) | colordiff') 212 self.fail('cbfstool produced a different result') 213 214 def test_cbfs_functions(self): 215 """Test global functions of cbfs_util""" 216 self.assertEqual(cbfs_util.ARCHITECTURE_X86, cbfs_util.find_arch('x86')) 217 self.assertIsNone(cbfs_util.find_arch('bad-arch')) 218 219 self.assertEqual(cbfs_util.COMPRESS_LZMA, cbfs_util.find_compress('lzma')) 220 self.assertIsNone(cbfs_util.find_compress('bad-comp')) 221 222 def test_cbfstool_failure(self): 223 """Test failure to run cbfstool""" 224 if not self.have_cbfstool: 225 self.skipTest('No cbfstool available') 226 try: 227 # In verbose mode this test fails since stderr is not captured. Fix 228 # this by turning off verbosity. 229 old_verbose = cbfs_util.VERBOSE 230 cbfs_util.VERBOSE = False 231 with test_util.capture_sys_output() as (_stdout, stderr): 232 with self.assertRaises(Exception) as e: 233 cbfs_util.cbfstool('missing-file', 'bad-command') 234 finally: 235 cbfs_util.VERBOSE = old_verbose 236 self.assertIn('Unknown command', stderr.getvalue()) 237 self.assertIn('Failed to run', str(e.exception)) 238 239 def test_cbfs_raw(self): 240 """Test base handling of a Coreboot Filesystem (CBFS)""" 241 size = 0xb0 242 cbw = CbfsWriter(size) 243 cbw.add_file_raw('u-boot', U_BOOT_DATA) 244 cbw.add_file_raw('u-boot-dtb', U_BOOT_DTB_DATA) 245 data = cbw.get_data() 246 self._check_raw(data, size) 247 cbfs_fname = self._get_expected_cbfs(size=size) 248 self._compare_expected_cbfs(data, cbfs_fname) 249 250 def test_cbfs_invalid_file_type(self): 251 """Check handling of an invalid file type when outputiing a CBFS""" 252 size = 0xb0 253 cbw = CbfsWriter(size) 254 cfile = cbw.add_file_raw('u-boot', U_BOOT_DATA) 255 256 # Change the type manually before generating the CBFS, and make sure 257 # that the generator complains 258 cfile.ftype = 0xff 259 with self.assertRaises(ValueError) as e: 260 cbw.get_data() 261 self.assertIn('Unknown type 0xff when writing', str(e.exception)) 262 263 def test_cbfs_invalid_file_type_on_read(self): 264 """Check handling of an invalid file type when reading the CBFS""" 265 size = 0xb0 266 cbw = CbfsWriter(size) 267 cbw.add_file_raw('u-boot', U_BOOT_DATA) 268 269 data = cbw.get_data() 270 271 # Read in the first file header 272 cbr = cbfs_util.CbfsReader(data, read=False) 273 with io.BytesIO(data) as fd: 274 self.assertTrue(cbr._find_and_read_header(fd, len(data))) 275 pos = fd.tell() 276 hdr_data = fd.read(cbfs_util.FILE_HEADER_LEN) 277 magic, size, ftype, attr, offset = struct.unpack( 278 cbfs_util.FILE_HEADER_FORMAT, hdr_data) 279 280 # Create a new CBFS with a change to the file type 281 ftype = 0xff 282 newdata = data[:pos] 283 newdata += struct.pack(cbfs_util.FILE_HEADER_FORMAT, magic, size, ftype, 284 attr, offset) 285 newdata += data[pos + cbfs_util.FILE_HEADER_LEN:] 286 287 # Read in this CBFS and make sure that the reader complains 288 with self.assertRaises(ValueError) as e: 289 cbfs_util.CbfsReader(newdata) 290 self.assertIn('Unknown type 0xff when reading', str(e.exception)) 291 292 def test_cbfs_no_space(self): 293 """Check handling of running out of space in the CBFS""" 294 size = 0x60 295 cbw = CbfsWriter(size) 296 cbw.add_file_raw('u-boot', U_BOOT_DATA) 297 with self.assertRaises(ValueError) as e: 298 cbw.get_data() 299 self.assertIn('No space for header', str(e.exception)) 300 301 def test_cbfs_no_space_skip(self): 302 """Check handling of running out of space in CBFS with file header""" 303 size = 0x5c 304 cbw = CbfsWriter(size, arch=cbfs_util.ARCHITECTURE_PPC64) 305 cbw._add_fileheader = True 306 cbw.add_file_raw('u-boot', U_BOOT_DATA) 307 with self.assertRaises(ValueError) as e: 308 cbw.get_data() 309 self.assertIn('No space for data before offset', str(e.exception)) 310 311 def test_cbfs_no_space_pad(self): 312 """Check handling of running out of space in CBFS with file header""" 313 size = 0x70 314 cbw = CbfsWriter(size) 315 cbw._add_fileheader = True 316 cbw.add_file_raw('u-boot', U_BOOT_DATA) 317 with self.assertRaises(ValueError) as e: 318 cbw.get_data() 319 self.assertIn('No space for data before pad offset', str(e.exception)) 320 321 def test_cbfs_bad_header_ptr(self): 322 """Check handling of a bad master-header pointer""" 323 size = 0x70 324 cbw = CbfsWriter(size) 325 cbw.add_file_raw('u-boot', U_BOOT_DATA) 326 data = cbw.get_data() 327 328 # Add one to the pointer to make it invalid 329 newdata = data[:-4] + struct.pack('<I', cbw._header_offset + 1) 330 331 # We should still be able to find the master header by searching 332 with test_util.capture_sys_output() as (stdout, _stderr): 333 cbfs = cbfs_util.CbfsReader(newdata) 334 self.assertIn('Relative offset seems wrong', stdout.getvalue()) 335 self.assertIn('u-boot', cbfs.files) 336 self.assertEqual(size, cbfs.rom_size) 337 338 def test_cbfs_bad_header(self): 339 """Check handling of a bad master header""" 340 size = 0x70 341 cbw = CbfsWriter(size) 342 cbw.add_file_raw('u-boot', U_BOOT_DATA) 343 data = cbw.get_data() 344 345 # Drop most of the header and try reading the modified CBFS 346 newdata = data[:cbw._header_offset + 4] 347 348 with test_util.capture_sys_output() as (stdout, _stderr): 349 with self.assertRaises(ValueError) as e: 350 cbfs_util.CbfsReader(newdata) 351 self.assertIn('Relative offset seems wrong', stdout.getvalue()) 352 self.assertIn('Cannot find master header', str(e.exception)) 353 354 def test_cbfs_bad_file_header(self): 355 """Check handling of a bad file header""" 356 size = 0x70 357 cbw = CbfsWriter(size) 358 cbw.add_file_raw('u-boot', U_BOOT_DATA) 359 data = cbw.get_data() 360 361 # Read in the CBFS master header (only), then stop 362 cbr = cbfs_util.CbfsReader(data, read=False) 363 with io.BytesIO(data) as fd: 364 self.assertTrue(cbr._find_and_read_header(fd, len(data))) 365 pos = fd.tell() 366 367 # Remove all but 4 bytes of the file headerm and try to read the file 368 newdata = data[:pos + 4] 369 with test_util.capture_sys_output() as (stdout, _stderr): 370 with io.BytesIO(newdata) as fd: 371 fd.seek(pos) 372 self.assertEqual(False, cbr._read_next_file(fd)) 373 self.assertIn('File header at 0x0 ran out of data', stdout.getvalue()) 374 375 def test_cbfs_bad_file_string(self): 376 """Check handling of an incomplete filename string""" 377 size = 0x70 378 cbw = CbfsWriter(size) 379 cbw.add_file_raw('16-characters xx', U_BOOT_DATA) 380 data = cbw.get_data() 381 382 # Read in the CBFS master header (only), then stop 383 cbr = cbfs_util.CbfsReader(data, read=False) 384 with io.BytesIO(data) as fd: 385 self.assertTrue(cbr._find_and_read_header(fd, len(data))) 386 pos = fd.tell() 387 388 # Create a new CBFS with only the first 16 bytes of the file name, then 389 # try to read the file 390 newdata = data[:pos + cbfs_util.FILE_HEADER_LEN + 16] 391 with test_util.capture_sys_output() as (stdout, _stderr): 392 with io.BytesIO(newdata) as fd: 393 fd.seek(pos) 394 self.assertEqual(False, cbr._read_next_file(fd)) 395 self.assertIn('String at %#x ran out of data' % 396 cbfs_util.FILE_HEADER_LEN, stdout.getvalue()) 397 398 def test_cbfs_debug(self): 399 """Check debug output""" 400 size = 0x70 401 cbw = CbfsWriter(size) 402 cbw.add_file_raw('u-boot', U_BOOT_DATA) 403 data = cbw.get_data() 404 405 try: 406 cbfs_util.DEBUG = True 407 with test_util.capture_sys_output() as (stdout, _stderr): 408 cbfs_util.CbfsReader(data) 409 self.assertEqual('name u-boot\ndata %s\n' % U_BOOT_DATA, 410 stdout.getvalue()) 411 finally: 412 cbfs_util.DEBUG = False 413 414 def test_cbfs_bad_attribute(self): 415 """Check handling of bad attribute tag""" 416 if not self.have_lz4: 417 self.skipTest('lz4 --no-frame-crc not available') 418 size = 0x140 419 cbw = CbfsWriter(size) 420 cbw.add_file_raw('u-boot', COMPRESS_DATA, None, 421 compress=cbfs_util.COMPRESS_LZ4) 422 data = cbw.get_data() 423 424 # Search the CBFS for the expected compression tag 425 with io.BytesIO(data) as fd: 426 while True: 427 pos = fd.tell() 428 tag, = struct.unpack('>I', fd.read(4)) 429 if tag == cbfs_util.FILE_ATTR_TAG_COMPRESSION: 430 break 431 432 # Create a new CBFS with the tag changed to something invalid 433 newdata = data[:pos] + struct.pack('>I', 0x123) + data[pos + 4:] 434 with test_util.capture_sys_output() as (stdout, _stderr): 435 cbfs_util.CbfsReader(newdata) 436 self.assertEqual('Unknown attribute tag 123\n', stdout.getvalue()) 437 438 def test_cbfs_missing_attribute(self): 439 """Check handling of an incomplete attribute tag""" 440 if not self.have_lz4: 441 self.skipTest('lz4 --no-frame-crc not available') 442 size = 0x140 443 cbw = CbfsWriter(size) 444 cbw.add_file_raw('u-boot', COMPRESS_DATA, None, 445 compress=cbfs_util.COMPRESS_LZ4) 446 data = cbw.get_data() 447 448 # Read in the CBFS master header (only), then stop 449 cbr = cbfs_util.CbfsReader(data, read=False) 450 with io.BytesIO(data) as fd: 451 self.assertTrue(cbr._find_and_read_header(fd, len(data))) 452 pos = fd.tell() 453 454 # Create a new CBFS with only the first 4 bytes of the compression tag, 455 # then try to read the file 456 tag_pos = pos + cbfs_util.FILE_HEADER_LEN + cbfs_util.FILENAME_ALIGN 457 newdata = data[:tag_pos + 4] 458 with test_util.capture_sys_output() as (stdout, _stderr): 459 with io.BytesIO(newdata) as fd: 460 fd.seek(pos) 461 self.assertEqual(False, cbr._read_next_file(fd)) 462 self.assertIn('Attribute tag at %x ran out of data' % tag_pos, 463 stdout.getvalue()) 464 465 def test_cbfs_file_master_header(self): 466 """Check handling of a file containing a master header""" 467 size = 0x100 468 cbw = CbfsWriter(size) 469 cbw._add_fileheader = True 470 cbw.add_file_raw('u-boot', U_BOOT_DATA) 471 data = cbw.get_data() 472 473 cbr = cbfs_util.CbfsReader(data) 474 self.assertIn('u-boot', cbr.files) 475 self.assertEqual(size, cbr.rom_size) 476 477 def test_cbfs_arch(self): 478 """Test on non-x86 architecture""" 479 size = 0x100 480 cbw = CbfsWriter(size, arch=cbfs_util.ARCHITECTURE_PPC64) 481 cbw.add_file_raw('u-boot', U_BOOT_DATA) 482 cbw.add_file_raw('u-boot-dtb', U_BOOT_DTB_DATA) 483 data = cbw.get_data() 484 self._check_raw(data, size, offset=0x40, 485 arch=cbfs_util.ARCHITECTURE_PPC64) 486 487 # Compare against what cbfstool creates 488 cbfs_fname = self._get_expected_cbfs(size=size, arch='ppc64') 489 self._compare_expected_cbfs(data, cbfs_fname) 490 491 def test_cbfs_stage(self): 492 """Tests handling of a Coreboot Filesystem (CBFS)""" 493 if not elf.ELF_TOOLS: 494 self.skipTest('Python elftools not available') 495 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf') 496 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA) 497 498 size = 0xb0 499 cbw = CbfsWriter(size) 500 cbw.add_file_stage('u-boot', tools.ReadFile(elf_fname)) 501 502 data = cbw.get_data() 503 cbfs = self._check_hdr(data, size) 504 load = 0xfef20000 505 entry = load + 2 506 507 cfile = self._check_uboot(cbfs, cbfs_util.TYPE_STAGE, offset=0x28, 508 data=U_BOOT_DATA + U_BOOT_DTB_DATA) 509 510 self.assertEqual(entry, cfile.entry) 511 self.assertEqual(load, cfile.load) 512 self.assertEqual(len(U_BOOT_DATA) + len(U_BOOT_DTB_DATA), 513 cfile.data_len) 514 515 # Compare against what cbfstool creates 516 if self.have_cbfstool: 517 cbfs_fname = os.path.join(self._indir, 'test.cbfs') 518 cbfs_util.cbfstool(cbfs_fname, 'create', '-m', 'x86', '-s', 519 '%#x' % size) 520 cbfs_util.cbfstool(cbfs_fname, 'add-stage', '-n', 'u-boot', 521 '-f', elf_fname) 522 self._compare_expected_cbfs(data, cbfs_fname) 523 524 def test_cbfs_raw_compress(self): 525 """Test base handling of compressing raw files""" 526 if not self.have_lz4: 527 self.skipTest('lz4 --no-frame-crc not available') 528 size = 0x140 529 cbw = CbfsWriter(size) 530 cbw.add_file_raw('u-boot', COMPRESS_DATA, None, 531 compress=cbfs_util.COMPRESS_LZ4) 532 cbw.add_file_raw('u-boot-dtb', COMPRESS_DATA, None, 533 compress=cbfs_util.COMPRESS_LZMA) 534 data = cbw.get_data() 535 536 cbfs = self._check_hdr(data, size) 537 self.assertIn('u-boot', cbfs.files) 538 cfile = cbfs.files['u-boot'] 539 self.assertEqual(cfile.name, 'u-boot') 540 self.assertEqual(cfile.offset, 56) 541 self.assertEqual(cfile.data, COMPRESS_DATA) 542 self.assertEqual(cfile.ftype, cbfs_util.TYPE_RAW) 543 self.assertEqual(cfile.compress, cbfs_util.COMPRESS_LZ4) 544 self.assertEqual(cfile.memlen, len(COMPRESS_DATA)) 545 546 self.assertIn('u-boot-dtb', cbfs.files) 547 cfile = cbfs.files['u-boot-dtb'] 548 self.assertEqual(cfile.name, 'u-boot-dtb') 549 self.assertEqual(cfile.offset, 56) 550 self.assertEqual(cfile.data, COMPRESS_DATA) 551 self.assertEqual(cfile.ftype, cbfs_util.TYPE_RAW) 552 self.assertEqual(cfile.compress, cbfs_util.COMPRESS_LZMA) 553 self.assertEqual(cfile.memlen, len(COMPRESS_DATA)) 554 555 cbfs_fname = self._get_expected_cbfs(size=size, compress=['lz4', 'lzma']) 556 self._compare_expected_cbfs(data, cbfs_fname) 557 558 def test_cbfs_raw_space(self): 559 """Test files with unused space in the CBFS""" 560 size = 0xf0 561 cbw = CbfsWriter(size) 562 cbw.add_file_raw('u-boot', U_BOOT_DATA) 563 cbw.add_file_raw('u-boot-dtb', U_BOOT_DTB_DATA) 564 data = cbw.get_data() 565 self._check_raw(data, size) 566 cbfs_fname = self._get_expected_cbfs(size=size) 567 self._compare_expected_cbfs(data, cbfs_fname) 568 569 def test_cbfs_offset(self): 570 """Test a CBFS with files at particular offsets""" 571 size = 0x200 572 cbw = CbfsWriter(size) 573 cbw.add_file_raw('u-boot', U_BOOT_DATA, 0x40) 574 cbw.add_file_raw('u-boot-dtb', U_BOOT_DTB_DATA, 0x140) 575 576 data = cbw.get_data() 577 cbfs = self._check_hdr(data, size) 578 self._check_uboot(cbfs, ftype=cbfs_util.TYPE_RAW, offset=0x40, 579 cbfs_offset=0x40) 580 self._check_dtb(cbfs, offset=0x40, cbfs_offset=0x140) 581 582 cbfs_fname = self._get_expected_cbfs(size=size, base=(0x40, 0x140)) 583 self._compare_expected_cbfs(data, cbfs_fname) 584 585 def test_cbfs_invalid_file_type_header(self): 586 """Check handling of an invalid file type when outputting a header""" 587 size = 0xb0 588 cbw = CbfsWriter(size) 589 cfile = cbw.add_file_raw('u-boot', U_BOOT_DATA, 0) 590 591 # Change the type manually before generating the CBFS, and make sure 592 # that the generator complains 593 cfile.ftype = 0xff 594 with self.assertRaises(ValueError) as e: 595 cbw.get_data() 596 self.assertIn('Unknown file type 0xff', str(e.exception)) 597 598 def test_cbfs_offset_conflict(self): 599 """Test a CBFS with files that want to overlap""" 600 size = 0x200 601 cbw = CbfsWriter(size) 602 cbw.add_file_raw('u-boot', U_BOOT_DATA, 0x40) 603 cbw.add_file_raw('u-boot-dtb', U_BOOT_DTB_DATA, 0x80) 604 605 with self.assertRaises(ValueError) as e: 606 cbw.get_data() 607 self.assertIn('No space for data before pad offset', str(e.exception)) 608 609 def test_cbfs_check_offset(self): 610 """Test that we can discover the offset of a file after writing it""" 611 size = 0xb0 612 cbw = CbfsWriter(size) 613 cbw.add_file_raw('u-boot', U_BOOT_DATA) 614 cbw.add_file_raw('u-boot-dtb', U_BOOT_DTB_DATA) 615 data = cbw.get_data() 616 617 cbfs = cbfs_util.CbfsReader(data) 618 self.assertEqual(0x38, cbfs.files['u-boot'].cbfs_offset) 619 self.assertEqual(0x78, cbfs.files['u-boot-dtb'].cbfs_offset) 620 621 622if __name__ == '__main__': 623 unittest.main() 624