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