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