cbfs_util_test.py 24 KB

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