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