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