]> git.ipfire.org Git - people/ms/u-boot.git/blame - tools/binman/ftest.py
binman: Add a function to read ELF symbols
[people/ms/u-boot.git] / tools / binman / ftest.py
CommitLineData
4f44304b
SG
1#
2# Copyright (c) 2016 Google, Inc
3# Written by Simon Glass <sjg@chromium.org>
4#
5# SPDX-License-Identifier: GPL-2.0+
6#
7# To run a single test, change to this directory, and:
8#
9# python -m unittest func_test.TestFunctional.testHelp
10
11from optparse import OptionParser
12import os
13import shutil
14import struct
15import sys
16import tempfile
17import unittest
18
19import binman
20import cmdline
21import command
22import control
99ed4a2e 23import fdt
4f44304b
SG
24import fdt_util
25import tools
26import tout
27
28# Contents of test files, corresponding to different entry types
6b187df7
SG
29U_BOOT_DATA = '1234'
30U_BOOT_IMG_DATA = 'img'
31U_BOOT_SPL_DATA = '567'
32BLOB_DATA = '89'
33ME_DATA = '0abcd'
34VGA_DATA = 'vga'
35U_BOOT_DTB_DATA = 'udtb'
36X86_START16_DATA = 'start16'
37X86_START16_SPL_DATA = 'start16spl'
38U_BOOT_NODTB_DATA = 'nodtb with microcode pointer somewhere in here'
39U_BOOT_SPL_NODTB_DATA = 'splnodtb with microcode pointer somewhere in here'
40FSP_DATA = 'fsp'
41CMC_DATA = 'cmc'
42VBT_DATA = 'vbt'
ca4f4ff7 43MRC_DATA = 'mrc'
4f44304b
SG
44
45class TestFunctional(unittest.TestCase):
46 """Functional tests for binman
47
48 Most of these use a sample .dts file to build an image and then check
49 that it looks correct. The sample files are in the test/ subdirectory
50 and are numbered.
51
52 For each entry type a very small test file is created using fixed
53 string contents. This makes it easy to test that things look right, and
54 debug problems.
55
56 In some cases a 'real' file must be used - these are also supplied in
57 the test/ diurectory.
58 """
59 @classmethod
60 def setUpClass(self):
4d5994f9
SG
61 global entry
62 import entry
63
4f44304b
SG
64 # Handle the case where argv[0] is 'python'
65 self._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
66 self._binman_pathname = os.path.join(self._binman_dir, 'binman')
67
68 # Create a temporary directory for input files
69 self._indir = tempfile.mkdtemp(prefix='binmant.')
70
71 # Create some test files
72 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
73 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
74 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
75 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
e0ff8551
SG
76 TestFunctional._MakeInputFile('me.bin', ME_DATA)
77 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
4f44304b 78 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
e0ff8551 79 TestFunctional._MakeInputFile('u-boot-x86-16bit.bin', X86_START16_DATA)
8772213e
SG
80 TestFunctional._MakeInputFile('spl/u-boot-x86-16bit-spl.bin',
81 X86_START16_SPL_DATA)
4f44304b 82 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
6b187df7
SG
83 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
84 U_BOOT_SPL_NODTB_DATA)
da229090
SG
85 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
86 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
59ea8c25 87 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
ca4f4ff7 88 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
4f44304b
SG
89 self._output_setup = False
90
e0ff8551
SG
91 # ELF file with a '_dt_ucode_base_size' symbol
92 with open(self.TestFile('u_boot_ucode_ptr')) as fd:
93 TestFunctional._MakeInputFile('u-boot', fd.read())
94
95 # Intel flash descriptor file
96 with open(self.TestFile('descriptor.bin')) as fd:
97 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
98
4f44304b
SG
99 @classmethod
100 def tearDownClass(self):
101 """Remove the temporary input directory and its contents"""
102 if self._indir:
103 shutil.rmtree(self._indir)
104 self._indir = None
105
106 def setUp(self):
107 # Enable this to turn on debugging output
108 # tout.Init(tout.DEBUG)
109 command.test_result = None
110
111 def tearDown(self):
112 """Remove the temporary output directory"""
113 tools._FinaliseForTest()
114
115 def _RunBinman(self, *args, **kwargs):
116 """Run binman using the command line
117
118 Args:
119 Arguments to pass, as a list of strings
120 kwargs: Arguments to pass to Command.RunPipe()
121 """
122 result = command.RunPipe([[self._binman_pathname] + list(args)],
123 capture=True, capture_stderr=True, raise_on_error=False)
124 if result.return_code and kwargs.get('raise_on_error', True):
125 raise Exception("Error running '%s': %s" % (' '.join(args),
126 result.stdout + result.stderr))
127 return result
128
129 def _DoBinman(self, *args):
130 """Run binman using directly (in the same process)
131
132 Args:
133 Arguments to pass, as a list of strings
134 Returns:
135 Return value (0 for success)
136 """
137 (options, args) = cmdline.ParseArgs(list(args))
138 options.pager = 'binman-invalid-pager'
139 options.build_dir = self._indir
140
141 # For testing, you can force an increase in verbosity here
142 # options.verbosity = tout.DEBUG
143 return control.Binman(options, args)
144
145 def _DoTestFile(self, fname):
146 """Run binman with a given test file
147
148 Args:
149 fname: Device tree source filename to use (e.g. 05_simple.dts)
150 """
151 return self._DoBinman('-p', '-I', self._indir,
152 '-d', self.TestFile(fname))
153
154 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
e0ff8551
SG
155 """Set up a new test device-tree file
156
157 The given file is compiled and set up as the device tree to be used
158 for ths test.
159
160 Args:
161 fname: Filename of .dts file to read
162 outfile: Output filename for compiled device tree binary
163
164 Returns:
165 Contents of device tree binary
166 """
4f44304b
SG
167 if not self._output_setup:
168 tools.PrepareOutputDir(self._indir, True)
169 self._output_setup = True
170 dtb = fdt_util.EnsureCompiled(self.TestFile(fname))
171 with open(dtb) as fd:
172 data = fd.read()
173 TestFunctional._MakeInputFile(outfile, data)
e0ff8551 174 return data
4f44304b 175
e0ff8551 176 def _DoReadFileDtb(self, fname, use_real_dtb=False):
4f44304b
SG
177 """Run binman and return the resulting image
178
179 This runs binman with a given test file and then reads the resulting
180 output file. It is a shortcut function since most tests need to do
181 these steps.
182
183 Raises an assertion failure if binman returns a non-zero exit code.
184
185 Args:
186 fname: Device tree source filename to use (e.g. 05_simple.dts)
187 use_real_dtb: True to use the test file as the contents of
188 the u-boot-dtb entry. Normally this is not needed and the
189 test contents (the U_BOOT_DTB_DATA string) can be used.
190 But in some test we need the real contents.
e0ff8551
SG
191
192 Returns:
193 Tuple:
194 Resulting image contents
195 Device tree contents
4f44304b 196 """
e0ff8551 197 dtb_data = None
4f44304b
SG
198 # Use the compiled test file as the u-boot-dtb input
199 if use_real_dtb:
e0ff8551 200 dtb_data = self._SetupDtb(fname)
4f44304b
SG
201
202 try:
203 retcode = self._DoTestFile(fname)
204 self.assertEqual(0, retcode)
205
206 # Find the (only) image, read it and return its contents
207 image = control.images['image']
208 fname = tools.GetOutputFilename('image.bin')
209 self.assertTrue(os.path.exists(fname))
210 with open(fname) as fd:
e0ff8551 211 return fd.read(), dtb_data
4f44304b
SG
212 finally:
213 # Put the test file back
214 if use_real_dtb:
215 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
216
e0ff8551
SG
217 def _DoReadFile(self, fname, use_real_dtb=False):
218 """Helper function which discards the device-tree binary"""
219 return self._DoReadFileDtb(fname, use_real_dtb)[0]
220
4f44304b
SG
221 @classmethod
222 def _MakeInputFile(self, fname, contents):
223 """Create a new test input file, creating directories as needed
224
225 Args:
226 fname: Filenaem to create
227 contents: File contents to write in to the file
228 Returns:
229 Full pathname of file created
230 """
231 pathname = os.path.join(self._indir, fname)
232 dirname = os.path.dirname(pathname)
233 if dirname and not os.path.exists(dirname):
234 os.makedirs(dirname)
235 with open(pathname, 'wb') as fd:
236 fd.write(contents)
237 return pathname
238
239 @classmethod
240 def TestFile(self, fname):
241 return os.path.join(self._binman_dir, 'test', fname)
242
243 def AssertInList(self, grep_list, target):
244 """Assert that at least one of a list of things is in a target
245
246 Args:
247 grep_list: List of strings to check
248 target: Target string
249 """
250 for grep in grep_list:
251 if grep in target:
252 return
253 self.fail("Error: '%' not found in '%s'" % (grep_list, target))
254
255 def CheckNoGaps(self, entries):
256 """Check that all entries fit together without gaps
257
258 Args:
259 entries: List of entries to check
260 """
261 pos = 0
262 for entry in entries.values():
263 self.assertEqual(pos, entry.pos)
264 pos += entry.size
265
e0ff8551
SG
266 def GetFdtLen(self, dtb):
267 """Get the totalsize field from a device tree binary
268
269 Args:
270 dtb: Device tree binary contents
271
272 Returns:
273 Total size of device tree binary, from the header
274 """
275 return struct.unpack('>L', dtb[4:8])[0]
276
4f44304b
SG
277 def testRun(self):
278 """Test a basic run with valid args"""
279 result = self._RunBinman('-h')
280
281 def testFullHelp(self):
282 """Test that the full help is displayed with -H"""
283 result = self._RunBinman('-H')
284 help_file = os.path.join(self._binman_dir, 'README')
285 self.assertEqual(len(result.stdout), os.path.getsize(help_file))
286 self.assertEqual(0, len(result.stderr))
287 self.assertEqual(0, result.return_code)
288
289 def testFullHelpInternal(self):
290 """Test that the full help is displayed with -H"""
291 try:
292 command.test_result = command.CommandResult()
293 result = self._DoBinman('-H')
294 help_file = os.path.join(self._binman_dir, 'README')
295 finally:
296 command.test_result = None
297
298 def testHelp(self):
299 """Test that the basic help is displayed with -h"""
300 result = self._RunBinman('-h')
301 self.assertTrue(len(result.stdout) > 200)
302 self.assertEqual(0, len(result.stderr))
303 self.assertEqual(0, result.return_code)
304
305 # Not yet available.
306 def testBoard(self):
307 """Test that we can run it with a specific board"""
308 self._SetupDtb('05_simple.dts', 'sandbox/u-boot.dtb')
309 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
310 result = self._DoBinman('-b', 'sandbox')
311 self.assertEqual(0, result)
312
313 def testNeedBoard(self):
314 """Test that we get an error when no board ius supplied"""
315 with self.assertRaises(ValueError) as e:
316 result = self._DoBinman()
317 self.assertIn("Must provide a board to process (use -b <board>)",
318 str(e.exception))
319
320 def testMissingDt(self):
321 """Test that an invalid device tree file generates an error"""
322 with self.assertRaises(Exception) as e:
323 self._RunBinman('-d', 'missing_file')
324 # We get one error from libfdt, and a different one from fdtget.
325 self.AssertInList(["Couldn't open blob from 'missing_file'",
326 'No such file or directory'], str(e.exception))
327
328 def testBrokenDt(self):
329 """Test that an invalid device tree source file generates an error
330
331 Since this is a source file it should be compiled and the error
332 will come from the device-tree compiler (dtc).
333 """
334 with self.assertRaises(Exception) as e:
335 self._RunBinman('-d', self.TestFile('01_invalid.dts'))
336 self.assertIn("FATAL ERROR: Unable to parse input tree",
337 str(e.exception))
338
339 def testMissingNode(self):
340 """Test that a device tree without a 'binman' node generates an error"""
341 with self.assertRaises(Exception) as e:
342 self._DoBinman('-d', self.TestFile('02_missing_node.dts'))
343 self.assertIn("does not have a 'binman' node", str(e.exception))
344
345 def testEmpty(self):
346 """Test that an empty binman node works OK (i.e. does nothing)"""
347 result = self._RunBinman('-d', self.TestFile('03_empty.dts'))
348 self.assertEqual(0, len(result.stderr))
349 self.assertEqual(0, result.return_code)
350
351 def testInvalidEntry(self):
352 """Test that an invalid entry is flagged"""
353 with self.assertRaises(Exception) as e:
354 result = self._RunBinman('-d',
355 self.TestFile('04_invalid_entry.dts'))
356 #print e.exception
357 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
358 "'/binman/not-a-valid-type'", str(e.exception))
359
360 def testSimple(self):
361 """Test a simple binman with a single file"""
362 data = self._DoReadFile('05_simple.dts')
363 self.assertEqual(U_BOOT_DATA, data)
364
365 def testDual(self):
366 """Test that we can handle creating two images
367
368 This also tests image padding.
369 """
370 retcode = self._DoTestFile('06_dual_image.dts')
371 self.assertEqual(0, retcode)
372
373 image = control.images['image1']
374 self.assertEqual(len(U_BOOT_DATA), image._size)
375 fname = tools.GetOutputFilename('image1.bin')
376 self.assertTrue(os.path.exists(fname))
377 with open(fname) as fd:
378 data = fd.read()
379 self.assertEqual(U_BOOT_DATA, data)
380
381 image = control.images['image2']
382 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image._size)
383 fname = tools.GetOutputFilename('image2.bin')
384 self.assertTrue(os.path.exists(fname))
385 with open(fname) as fd:
386 data = fd.read()
387 self.assertEqual(U_BOOT_DATA, data[3:7])
388 self.assertEqual(chr(0) * 3, data[:3])
389 self.assertEqual(chr(0) * 5, data[7:])
390
391 def testBadAlign(self):
392 """Test that an invalid alignment value is detected"""
393 with self.assertRaises(ValueError) as e:
394 self._DoTestFile('07_bad_align.dts')
395 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
396 "of two", str(e.exception))
397
398 def testPackSimple(self):
399 """Test that packing works as expected"""
400 retcode = self._DoTestFile('08_pack.dts')
401 self.assertEqual(0, retcode)
402 self.assertIn('image', control.images)
403 image = control.images['image']
404 entries = image._entries
405 self.assertEqual(5, len(entries))
406
407 # First u-boot
408 self.assertIn('u-boot', entries)
409 entry = entries['u-boot']
410 self.assertEqual(0, entry.pos)
411 self.assertEqual(len(U_BOOT_DATA), entry.size)
412
413 # Second u-boot, aligned to 16-byte boundary
414 self.assertIn('u-boot-align', entries)
415 entry = entries['u-boot-align']
416 self.assertEqual(16, entry.pos)
417 self.assertEqual(len(U_BOOT_DATA), entry.size)
418
419 # Third u-boot, size 23 bytes
420 self.assertIn('u-boot-size', entries)
421 entry = entries['u-boot-size']
422 self.assertEqual(20, entry.pos)
423 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
424 self.assertEqual(23, entry.size)
425
426 # Fourth u-boot, placed immediate after the above
427 self.assertIn('u-boot-next', entries)
428 entry = entries['u-boot-next']
429 self.assertEqual(43, entry.pos)
430 self.assertEqual(len(U_BOOT_DATA), entry.size)
431
432 # Fifth u-boot, placed at a fixed position
433 self.assertIn('u-boot-fixed', entries)
434 entry = entries['u-boot-fixed']
435 self.assertEqual(61, entry.pos)
436 self.assertEqual(len(U_BOOT_DATA), entry.size)
437
438 self.assertEqual(65, image._size)
439
440 def testPackExtra(self):
441 """Test that extra packing feature works as expected"""
442 retcode = self._DoTestFile('09_pack_extra.dts')
443
444 self.assertEqual(0, retcode)
445 self.assertIn('image', control.images)
446 image = control.images['image']
447 entries = image._entries
448 self.assertEqual(5, len(entries))
449
450 # First u-boot with padding before and after
451 self.assertIn('u-boot', entries)
452 entry = entries['u-boot']
453 self.assertEqual(0, entry.pos)
454 self.assertEqual(3, entry.pad_before)
455 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
456
457 # Second u-boot has an aligned size, but it has no effect
458 self.assertIn('u-boot-align-size-nop', entries)
459 entry = entries['u-boot-align-size-nop']
460 self.assertEqual(12, entry.pos)
461 self.assertEqual(4, entry.size)
462
463 # Third u-boot has an aligned size too
464 self.assertIn('u-boot-align-size', entries)
465 entry = entries['u-boot-align-size']
466 self.assertEqual(16, entry.pos)
467 self.assertEqual(32, entry.size)
468
469 # Fourth u-boot has an aligned end
470 self.assertIn('u-boot-align-end', entries)
471 entry = entries['u-boot-align-end']
472 self.assertEqual(48, entry.pos)
473 self.assertEqual(16, entry.size)
474
475 # Fifth u-boot immediately afterwards
476 self.assertIn('u-boot-align-both', entries)
477 entry = entries['u-boot-align-both']
478 self.assertEqual(64, entry.pos)
479 self.assertEqual(64, entry.size)
480
481 self.CheckNoGaps(entries)
482 self.assertEqual(128, image._size)
483
484 def testPackAlignPowerOf2(self):
485 """Test that invalid entry alignment is detected"""
486 with self.assertRaises(ValueError) as e:
487 self._DoTestFile('10_pack_align_power2.dts')
488 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
489 "of two", str(e.exception))
490
491 def testPackAlignSizePowerOf2(self):
492 """Test that invalid entry size alignment is detected"""
493 with self.assertRaises(ValueError) as e:
494 self._DoTestFile('11_pack_align_size_power2.dts')
495 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
496 "power of two", str(e.exception))
497
498 def testPackInvalidAlign(self):
499 """Test detection of an position that does not match its alignment"""
500 with self.assertRaises(ValueError) as e:
501 self._DoTestFile('12_pack_inv_align.dts')
502 self.assertIn("Node '/binman/u-boot': Position 0x5 (5) does not match "
503 "align 0x4 (4)", str(e.exception))
504
505 def testPackInvalidSizeAlign(self):
506 """Test that invalid entry size alignment is detected"""
507 with self.assertRaises(ValueError) as e:
508 self._DoTestFile('13_pack_inv_size_align.dts')
509 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
510 "align-size 0x4 (4)", str(e.exception))
511
512 def testPackOverlap(self):
513 """Test that overlapping regions are detected"""
514 with self.assertRaises(ValueError) as e:
515 self._DoTestFile('14_pack_overlap.dts')
516 self.assertIn("Node '/binman/u-boot-align': Position 0x3 (3) overlaps "
517 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
518 str(e.exception))
519
520 def testPackEntryOverflow(self):
521 """Test that entries that overflow their size are detected"""
522 with self.assertRaises(ValueError) as e:
523 self._DoTestFile('15_pack_overflow.dts')
524 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
525 "but entry size is 0x3 (3)", str(e.exception))
526
527 def testPackImageOverflow(self):
528 """Test that entries which overflow the image size are detected"""
529 with self.assertRaises(ValueError) as e:
530 self._DoTestFile('16_pack_image_overflow.dts')
531 self.assertIn("Image '/binman': contents size 0x4 (4) exceeds image "
532 "size 0x3 (3)", str(e.exception))
533
534 def testPackImageSize(self):
535 """Test that the image size can be set"""
536 retcode = self._DoTestFile('17_pack_image_size.dts')
537 self.assertEqual(0, retcode)
538 self.assertIn('image', control.images)
539 image = control.images['image']
540 self.assertEqual(7, image._size)
541
542 def testPackImageSizeAlign(self):
543 """Test that image size alignemnt works as expected"""
544 retcode = self._DoTestFile('18_pack_image_align.dts')
545 self.assertEqual(0, retcode)
546 self.assertIn('image', control.images)
547 image = control.images['image']
548 self.assertEqual(16, image._size)
549
550 def testPackInvalidImageAlign(self):
551 """Test that invalid image alignment is detected"""
552 with self.assertRaises(ValueError) as e:
553 self._DoTestFile('19_pack_inv_image_align.dts')
554 self.assertIn("Image '/binman': Size 0x7 (7) does not match "
555 "align-size 0x8 (8)", str(e.exception))
556
557 def testPackAlignPowerOf2(self):
558 """Test that invalid image alignment is detected"""
559 with self.assertRaises(ValueError) as e:
560 self._DoTestFile('20_pack_inv_image_align_power2.dts')
561 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
562 "two", str(e.exception))
563
564 def testImagePadByte(self):
565 """Test that the image pad byte can be specified"""
566 data = self._DoReadFile('21_image_pad.dts')
567 self.assertEqual(U_BOOT_SPL_DATA + (chr(0xff) * 9) + U_BOOT_DATA, data)
568
569 def testImageName(self):
570 """Test that image files can be named"""
571 retcode = self._DoTestFile('22_image_name.dts')
572 self.assertEqual(0, retcode)
573 image = control.images['image1']
574 fname = tools.GetOutputFilename('test-name')
575 self.assertTrue(os.path.exists(fname))
576
577 image = control.images['image2']
578 fname = tools.GetOutputFilename('test-name.xx')
579 self.assertTrue(os.path.exists(fname))
580
581 def testBlobFilename(self):
582 """Test that generic blobs can be provided by filename"""
583 data = self._DoReadFile('23_blob.dts')
584 self.assertEqual(BLOB_DATA, data)
585
586 def testPackSorted(self):
587 """Test that entries can be sorted"""
588 data = self._DoReadFile('24_sorted.dts')
589 self.assertEqual(chr(0) * 5 + U_BOOT_SPL_DATA + chr(0) * 2 +
590 U_BOOT_DATA, data)
591
592 def testPackZeroPosition(self):
593 """Test that an entry at position 0 is not given a new position"""
594 with self.assertRaises(ValueError) as e:
595 self._DoTestFile('25_pack_zero_size.dts')
596 self.assertIn("Node '/binman/u-boot-spl': Position 0x0 (0) overlaps "
597 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
598 str(e.exception))
599
600 def testPackUbootDtb(self):
601 """Test that a device tree can be added to U-Boot"""
602 data = self._DoReadFile('26_pack_u_boot_dtb.dts')
603 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
e0ff8551
SG
604
605 def testPackX86RomNoSize(self):
606 """Test that the end-at-4gb property requires a size property"""
607 with self.assertRaises(ValueError) as e:
608 self._DoTestFile('27_pack_4gb_no_size.dts')
609 self.assertIn("Image '/binman': Image size must be provided when "
610 "using end-at-4gb", str(e.exception))
611
612 def testPackX86RomOutside(self):
613 """Test that the end-at-4gb property checks for position boundaries"""
614 with self.assertRaises(ValueError) as e:
615 self._DoTestFile('28_pack_4gb_outside.dts')
616 self.assertIn("Node '/binman/u-boot': Position 0x0 (0) is outside "
617 "the image starting at 0xfffffff0 (4294967280)",
618 str(e.exception))
619
620 def testPackX86Rom(self):
621 """Test that a basic x86 ROM can be created"""
622 data = self._DoReadFile('29_x86-rom.dts')
623 self.assertEqual(U_BOOT_DATA + chr(0) * 3 + U_BOOT_SPL_DATA +
624 chr(0) * 6, data)
625
626 def testPackX86RomMeNoDesc(self):
627 """Test that an invalid Intel descriptor entry is detected"""
628 TestFunctional._MakeInputFile('descriptor.bin', '')
629 with self.assertRaises(ValueError) as e:
630 self._DoTestFile('31_x86-rom-me.dts')
631 self.assertIn("Node '/binman/intel-descriptor': Cannot find FD "
632 "signature", str(e.exception))
633
634 def testPackX86RomBadDesc(self):
635 """Test that the Intel requires a descriptor entry"""
636 with self.assertRaises(ValueError) as e:
637 self._DoTestFile('30_x86-rom-me-no-desc.dts')
638 self.assertIn("Node '/binman/intel-me': No position set with "
639 "pos-unset: should another entry provide this correct "
640 "position?", str(e.exception))
641
642 def testPackX86RomMe(self):
643 """Test that an x86 ROM with an ME region can be created"""
644 data = self._DoReadFile('31_x86-rom-me.dts')
645 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
646
647 def testPackVga(self):
648 """Test that an image with a VGA binary can be created"""
649 data = self._DoReadFile('32_intel-vga.dts')
650 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
651
652 def testPackStart16(self):
653 """Test that an image with an x86 start16 region can be created"""
654 data = self._DoReadFile('33_x86-start16.dts')
655 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
656
6b187df7
SG
657 def _RunMicrocodeTest(self, dts_fname, nodtb_data):
658 data = self._DoReadFile(dts_fname, True)
e0ff8551
SG
659
660 # Now check the device tree has no microcode
6b187df7 661 second = data[len(nodtb_data):]
e0ff8551
SG
662 fname = tools.GetOutputFilename('test.dtb')
663 with open(fname, 'wb') as fd:
664 fd.write(second)
ec3f378a
SG
665 dtb = fdt.FdtScan(fname)
666 ucode = dtb.GetNode('/microcode')
e0ff8551
SG
667 self.assertTrue(ucode)
668 for node in ucode.subnodes:
669 self.assertFalse(node.props.get('data'))
670
671 fdt_len = self.GetFdtLen(second)
672 third = second[fdt_len:]
673
674 # Check that the microcode appears immediately after the Fdt
675 # This matches the concatenation of the data properties in
8772213e 676 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
e0ff8551
SG
677 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
678 0x78235609)
679 self.assertEqual(ucode_data, third[:len(ucode_data)])
6b187df7 680 ucode_pos = len(nodtb_data) + fdt_len
e0ff8551
SG
681
682 # Check that the microcode pointer was inserted. It should match the
683 # expected position and size
684 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
685 len(ucode_data))
6b187df7
SG
686 first = data[:len(nodtb_data)]
687 return first, pos_and_size
688
689 def testPackUbootMicrocode(self):
690 """Test that x86 microcode can be handled correctly
691
692 We expect to see the following in the image, in order:
693 u-boot-nodtb.bin with a microcode pointer inserted at the correct
694 place
695 u-boot.dtb with the microcode removed
696 the microcode
697 """
698 first, pos_and_size = self._RunMicrocodeTest('34_x86_ucode.dts',
699 U_BOOT_NODTB_DATA)
e0ff8551
SG
700 self.assertEqual('nodtb with microcode' + pos_and_size +
701 ' somewhere in here', first)
702
160a7664 703 def _RunPackUbootSingleMicrocode(self):
e0ff8551
SG
704 """Test that x86 microcode can be handled correctly
705
706 We expect to see the following in the image, in order:
707 u-boot-nodtb.bin with a microcode pointer inserted at the correct
708 place
709 u-boot.dtb with the microcode
710 an empty microcode region
711 """
712 # We need the libfdt library to run this test since only that allows
713 # finding the offset of a property. This is required by
714 # Entry_u_boot_dtb_with_ucode.ObtainContents().
e0ff8551
SG
715 data = self._DoReadFile('35_x86_single_ucode.dts', True)
716
717 second = data[len(U_BOOT_NODTB_DATA):]
718
719 fdt_len = self.GetFdtLen(second)
720 third = second[fdt_len:]
721 second = second[:fdt_len]
722
160a7664
SG
723 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
724 self.assertIn(ucode_data, second)
725 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
e0ff8551 726
160a7664
SG
727 # Check that the microcode pointer was inserted. It should match the
728 # expected position and size
729 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
730 len(ucode_data))
731 first = data[:len(U_BOOT_NODTB_DATA)]
732 self.assertEqual('nodtb with microcode' + pos_and_size +
733 ' somewhere in here', first)
c49deb83 734
75db0860
SG
735 def testPackUbootSingleMicrocode(self):
736 """Test that x86 microcode can be handled correctly with fdt_normal.
737 """
160a7664 738 self._RunPackUbootSingleMicrocode()
75db0860 739
c49deb83
SG
740 def testUBootImg(self):
741 """Test that u-boot.img can be put in a file"""
742 data = self._DoReadFile('36_u_boot_img.dts')
743 self.assertEqual(U_BOOT_IMG_DATA, data)
75db0860
SG
744
745 def testNoMicrocode(self):
746 """Test that a missing microcode region is detected"""
747 with self.assertRaises(ValueError) as e:
748 self._DoReadFile('37_x86_no_ucode.dts', True)
749 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
750 "node found in ", str(e.exception))
751
752 def testMicrocodeWithoutNode(self):
753 """Test that a missing u-boot-dtb-with-ucode node is detected"""
754 with self.assertRaises(ValueError) as e:
755 self._DoReadFile('38_x86_ucode_missing_node.dts', True)
756 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
757 "microcode region u-boot-dtb-with-ucode", str(e.exception))
758
759 def testMicrocodeWithoutNode2(self):
760 """Test that a missing u-boot-ucode node is detected"""
761 with self.assertRaises(ValueError) as e:
762 self._DoReadFile('39_x86_ucode_missing_node2.dts', True)
763 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
764 "microcode region u-boot-ucode", str(e.exception))
765
766 def testMicrocodeWithoutPtrInElf(self):
767 """Test that a U-Boot binary without the microcode symbol is detected"""
768 # ELF file without a '_dt_ucode_base_size' symbol
75db0860
SG
769 try:
770 with open(self.TestFile('u_boot_no_ucode_ptr')) as fd:
771 TestFunctional._MakeInputFile('u-boot', fd.read())
772
773 with self.assertRaises(ValueError) as e:
160a7664 774 self._RunPackUbootSingleMicrocode()
75db0860
SG
775 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
776 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
777
778 finally:
779 # Put the original file back
780 with open(self.TestFile('u_boot_ucode_ptr')) as fd:
781 TestFunctional._MakeInputFile('u-boot', fd.read())
782
783 def testMicrocodeNotInImage(self):
784 """Test that microcode must be placed within the image"""
785 with self.assertRaises(ValueError) as e:
786 self._DoReadFile('40_x86_ucode_not_in_image.dts', True)
787 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
788 "pointer _dt_ucode_base_size at fffffe14 is outside the "
789 "image ranging from 00000000 to 0000002e", str(e.exception))
790
791 def testWithoutMicrocode(self):
792 """Test that we can cope with an image without microcode (e.g. qemu)"""
793 with open(self.TestFile('u_boot_no_ucode_ptr')) as fd:
794 TestFunctional._MakeInputFile('u-boot', fd.read())
795 data, dtb = self._DoReadFileDtb('44_x86_optional_ucode.dts', True)
796
797 # Now check the device tree has no microcode
798 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
799 second = data[len(U_BOOT_NODTB_DATA):]
800
801 fdt_len = self.GetFdtLen(second)
802 self.assertEqual(dtb, second[:fdt_len])
803
804 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
805 third = data[used_len:]
806 self.assertEqual(chr(0) * (0x200 - used_len), third)
807
808 def testUnknownPosSize(self):
809 """Test that microcode must be placed within the image"""
810 with self.assertRaises(ValueError) as e:
811 self._DoReadFile('41_unknown_pos_size.dts', True)
812 self.assertIn("Image '/binman': Unable to set pos/size for unknown "
813 "entry 'invalid-entry'", str(e.exception))
da229090
SG
814
815 def testPackFsp(self):
816 """Test that an image with a FSP binary can be created"""
817 data = self._DoReadFile('42_intel-fsp.dts')
818 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
819
820 def testPackCmc(self):
59ea8c25 821 """Test that an image with a CMC binary can be created"""
da229090
SG
822 data = self._DoReadFile('43_intel-cmc.dts')
823 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
59ea8c25
BM
824
825 def testPackVbt(self):
826 """Test that an image with a VBT binary can be created"""
827 data = self._DoReadFile('46_intel-vbt.dts')
828 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
9fc60b49 829
56509843
SG
830 def testSplBssPad(self):
831 """Test that we can pad SPL's BSS with zeros"""
6b187df7
SG
832 # ELF file with a '__bss_size' symbol
833 with open(self.TestFile('bss_data')) as fd:
834 TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
56509843
SG
835 data = self._DoReadFile('47_spl_bss_pad.dts')
836 self.assertEqual(U_BOOT_SPL_DATA + (chr(0) * 10) + U_BOOT_DATA, data)
837
b50e5611
SG
838 with open(self.TestFile('u_boot_ucode_ptr')) as fd:
839 TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
840 with self.assertRaises(ValueError) as e:
841 data = self._DoReadFile('47_spl_bss_pad.dts')
842 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
843 str(e.exception))
844
8772213e
SG
845 def testPackStart16Spl(self):
846 """Test that an image with an x86 start16 region can be created"""
847 data = self._DoReadFile('48_x86-start16-spl.dts')
848 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
849
6b187df7
SG
850 def testPackUbootSplMicrocode(self):
851 """Test that x86 microcode can be handled correctly in SPL
852
853 We expect to see the following in the image, in order:
854 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
855 correct place
856 u-boot.dtb with the microcode removed
857 the microcode
858 """
859 # ELF file with a '_dt_ucode_base_size' symbol
860 with open(self.TestFile('u_boot_ucode_ptr')) as fd:
861 TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
862 first, pos_and_size = self._RunMicrocodeTest('49_x86_ucode_spl.dts',
863 U_BOOT_SPL_NODTB_DATA)
864 self.assertEqual('splnodtb with microc' + pos_and_size +
865 'ter somewhere in here', first)
866
ca4f4ff7
SG
867 def testPackMrc(self):
868 """Test that an image with an MRC binary can be created"""
869 data = self._DoReadFile('50_intel_mrc.dts')
870 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
871
9fc60b49
SG
872
873if __name__ == "__main__":
874 unittest.main()