]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | # SPDX-License-Identifier: GPL-2.0+ |
4f44304b SG |
2 | # Copyright (c) 2016 Google, Inc |
3 | # Written by Simon Glass <sjg@chromium.org> | |
4 | # | |
4f44304b SG |
5 | # To run a single test, change to this directory, and: |
6 | # | |
7 | # python -m unittest func_test.TestFunctional.testHelp | |
8 | ||
e0e5df93 | 9 | import hashlib |
4f44304b SG |
10 | from optparse import OptionParser |
11 | import os | |
12 | import shutil | |
13 | import struct | |
14 | import sys | |
15 | import tempfile | |
16 | import unittest | |
17 | ||
18 | import binman | |
19 | import cmdline | |
20 | import command | |
21 | import control | |
19790632 | 22 | import elf |
99ed4a2e | 23 | import fdt |
4f44304b | 24 | import fdt_util |
11e36cce | 25 | import fmap_util |
fd8d1f79 | 26 | import test_util |
c55a50f5 | 27 | import state |
4f44304b SG |
28 | import tools |
29 | import tout | |
30 | ||
31 | # Contents of test files, corresponding to different entry types | |
6b187df7 SG |
32 | U_BOOT_DATA = '1234' |
33 | U_BOOT_IMG_DATA = 'img' | |
f689890d | 34 | U_BOOT_SPL_DATA = '56780123456789abcde' |
b8ef5b6b | 35 | U_BOOT_TPL_DATA = 'tpl' |
6b187df7 SG |
36 | BLOB_DATA = '89' |
37 | ME_DATA = '0abcd' | |
38 | VGA_DATA = 'vga' | |
39 | U_BOOT_DTB_DATA = 'udtb' | |
47419eae | 40 | U_BOOT_SPL_DTB_DATA = 'spldtb' |
b8ef5b6b | 41 | U_BOOT_TPL_DTB_DATA = 'tpldtb' |
6b187df7 SG |
42 | X86_START16_DATA = 'start16' |
43 | X86_START16_SPL_DATA = 'start16spl' | |
35b384cb | 44 | X86_START16_TPL_DATA = 'start16tpl' |
9d368f32 | 45 | PPC_MPC85XX_BR_DATA = 'ppcmpc85xxbr' |
6b187df7 SG |
46 | U_BOOT_NODTB_DATA = 'nodtb with microcode pointer somewhere in here' |
47 | U_BOOT_SPL_NODTB_DATA = 'splnodtb with microcode pointer somewhere in here' | |
f0253635 | 48 | U_BOOT_TPL_NODTB_DATA = 'tplnodtb with microcode pointer somewhere in here' |
6b187df7 SG |
49 | FSP_DATA = 'fsp' |
50 | CMC_DATA = 'cmc' | |
51 | VBT_DATA = 'vbt' | |
ca4f4ff7 | 52 | MRC_DATA = 'mrc' |
bb74837c SG |
53 | TEXT_DATA = 'text' |
54 | TEXT_DATA2 = 'text2' | |
55 | TEXT_DATA3 = 'text3' | |
ec127af0 | 56 | CROS_EC_RW_DATA = 'ecrw' |
0ef87aa3 SG |
57 | GBB_DATA = 'gbbd' |
58 | BMPBLK_DATA = 'bmp' | |
24d0d3c3 | 59 | VBLOCK_DATA = 'vblk' |
0a98b28b SG |
60 | FILES_DATA = ("sorry I'm late\nOh, don't bother apologising, I'm " + |
61 | "sorry you're alive\n") | |
83d73c2f | 62 | COMPRESS_DATA = 'data to compress' |
ec127af0 | 63 | |
4f44304b SG |
64 | |
65 | class TestFunctional(unittest.TestCase): | |
66 | """Functional tests for binman | |
67 | ||
68 | Most of these use a sample .dts file to build an image and then check | |
69 | that it looks correct. The sample files are in the test/ subdirectory | |
70 | and are numbered. | |
71 | ||
72 | For each entry type a very small test file is created using fixed | |
73 | string contents. This makes it easy to test that things look right, and | |
74 | debug problems. | |
75 | ||
76 | In some cases a 'real' file must be used - these are also supplied in | |
77 | the test/ diurectory. | |
78 | """ | |
79 | @classmethod | |
80 | def setUpClass(self): | |
4d5994f9 SG |
81 | global entry |
82 | import entry | |
83 | ||
4f44304b SG |
84 | # Handle the case where argv[0] is 'python' |
85 | self._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0])) | |
86 | self._binman_pathname = os.path.join(self._binman_dir, 'binman') | |
87 | ||
88 | # Create a temporary directory for input files | |
89 | self._indir = tempfile.mkdtemp(prefix='binmant.') | |
90 | ||
91 | # Create some test files | |
92 | TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA) | |
93 | TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA) | |
94 | TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA) | |
b8ef5b6b | 95 | TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA) |
4f44304b | 96 | TestFunctional._MakeInputFile('blobfile', BLOB_DATA) |
e0ff8551 SG |
97 | TestFunctional._MakeInputFile('me.bin', ME_DATA) |
98 | TestFunctional._MakeInputFile('vga.bin', VGA_DATA) | |
b8ef5b6b | 99 | self._ResetDtbs() |
e0ff8551 | 100 | TestFunctional._MakeInputFile('u-boot-x86-16bit.bin', X86_START16_DATA) |
9d368f32 | 101 | TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA) |
8772213e SG |
102 | TestFunctional._MakeInputFile('spl/u-boot-x86-16bit-spl.bin', |
103 | X86_START16_SPL_DATA) | |
35b384cb SG |
104 | TestFunctional._MakeInputFile('tpl/u-boot-x86-16bit-tpl.bin', |
105 | X86_START16_TPL_DATA) | |
4f44304b | 106 | TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA) |
6b187df7 SG |
107 | TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin', |
108 | U_BOOT_SPL_NODTB_DATA) | |
f0253635 SG |
109 | TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin', |
110 | U_BOOT_TPL_NODTB_DATA) | |
da229090 SG |
111 | TestFunctional._MakeInputFile('fsp.bin', FSP_DATA) |
112 | TestFunctional._MakeInputFile('cmc.bin', CMC_DATA) | |
59ea8c25 | 113 | TestFunctional._MakeInputFile('vbt.bin', VBT_DATA) |
ca4f4ff7 | 114 | TestFunctional._MakeInputFile('mrc.bin', MRC_DATA) |
ec127af0 | 115 | TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA) |
0ef87aa3 SG |
116 | TestFunctional._MakeInputDir('devkeys') |
117 | TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA) | |
4f44304b | 118 | |
e0ff8551 SG |
119 | # ELF file with a '_dt_ucode_base_size' symbol |
120 | with open(self.TestFile('u_boot_ucode_ptr')) as fd: | |
121 | TestFunctional._MakeInputFile('u-boot', fd.read()) | |
122 | ||
123 | # Intel flash descriptor file | |
124 | with open(self.TestFile('descriptor.bin')) as fd: | |
125 | TestFunctional._MakeInputFile('descriptor.bin', fd.read()) | |
126 | ||
0a98b28b SG |
127 | shutil.copytree(self.TestFile('files'), |
128 | os.path.join(self._indir, 'files')) | |
129 | ||
83d73c2f SG |
130 | TestFunctional._MakeInputFile('compress', COMPRESS_DATA) |
131 | ||
4f44304b SG |
132 | @classmethod |
133 | def tearDownClass(self): | |
134 | """Remove the temporary input directory and its contents""" | |
135 | if self._indir: | |
136 | shutil.rmtree(self._indir) | |
137 | self._indir = None | |
138 | ||
139 | def setUp(self): | |
140 | # Enable this to turn on debugging output | |
141 | # tout.Init(tout.DEBUG) | |
142 | command.test_result = None | |
143 | ||
144 | def tearDown(self): | |
145 | """Remove the temporary output directory""" | |
146 | tools._FinaliseForTest() | |
147 | ||
b8ef5b6b SG |
148 | @classmethod |
149 | def _ResetDtbs(self): | |
150 | TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA) | |
151 | TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA) | |
152 | TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA) | |
153 | ||
4f44304b SG |
154 | def _RunBinman(self, *args, **kwargs): |
155 | """Run binman using the command line | |
156 | ||
157 | Args: | |
158 | Arguments to pass, as a list of strings | |
159 | kwargs: Arguments to pass to Command.RunPipe() | |
160 | """ | |
161 | result = command.RunPipe([[self._binman_pathname] + list(args)], | |
162 | capture=True, capture_stderr=True, raise_on_error=False) | |
163 | if result.return_code and kwargs.get('raise_on_error', True): | |
164 | raise Exception("Error running '%s': %s" % (' '.join(args), | |
165 | result.stdout + result.stderr)) | |
166 | return result | |
167 | ||
168 | def _DoBinman(self, *args): | |
169 | """Run binman using directly (in the same process) | |
170 | ||
171 | Args: | |
172 | Arguments to pass, as a list of strings | |
173 | Returns: | |
174 | Return value (0 for success) | |
175 | """ | |
7fe9173b SG |
176 | args = list(args) |
177 | if '-D' in sys.argv: | |
178 | args = args + ['-D'] | |
179 | (options, args) = cmdline.ParseArgs(args) | |
4f44304b SG |
180 | options.pager = 'binman-invalid-pager' |
181 | options.build_dir = self._indir | |
182 | ||
183 | # For testing, you can force an increase in verbosity here | |
184 | # options.verbosity = tout.DEBUG | |
185 | return control.Binman(options, args) | |
186 | ||
53af22a9 | 187 | def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False, |
93d17413 | 188 | entry_args=None, images=None, use_real_dtb=False): |
4f44304b SG |
189 | """Run binman with a given test file |
190 | ||
191 | Args: | |
741f2d62 | 192 | fname: Device-tree source filename to use (e.g. 005_simple.dts) |
7ae5f315 | 193 | debug: True to enable debugging output |
3b0c3821 | 194 | map: True to output map files for the images |
3ab9598d | 195 | update_dtb: Update the offset and size of each entry in the device |
16b8d6b7 | 196 | tree before packing it into the image |
0bfa7b09 SG |
197 | entry_args: Dict of entry args to supply to binman |
198 | key: arg name | |
199 | value: value of that arg | |
200 | images: List of image names to build | |
4f44304b | 201 | """ |
7fe9173b SG |
202 | args = ['-p', '-I', self._indir, '-d', self.TestFile(fname)] |
203 | if debug: | |
204 | args.append('-D') | |
3b0c3821 SG |
205 | if map: |
206 | args.append('-m') | |
16b8d6b7 SG |
207 | if update_dtb: |
208 | args.append('-up') | |
93d17413 SG |
209 | if not use_real_dtb: |
210 | args.append('--fake-dtb') | |
53af22a9 SG |
211 | if entry_args: |
212 | for arg, value in entry_args.iteritems(): | |
213 | args.append('-a%s=%s' % (arg, value)) | |
0bfa7b09 SG |
214 | if images: |
215 | for image in images: | |
216 | args += ['-i', image] | |
7fe9173b | 217 | return self._DoBinman(*args) |
4f44304b SG |
218 | |
219 | def _SetupDtb(self, fname, outfile='u-boot.dtb'): | |
e0ff8551 SG |
220 | """Set up a new test device-tree file |
221 | ||
222 | The given file is compiled and set up as the device tree to be used | |
223 | for ths test. | |
224 | ||
225 | Args: | |
226 | fname: Filename of .dts file to read | |
7ae5f315 | 227 | outfile: Output filename for compiled device-tree binary |
e0ff8551 SG |
228 | |
229 | Returns: | |
7ae5f315 | 230 | Contents of device-tree binary |
e0ff8551 | 231 | """ |
e0e6275f | 232 | tools.PrepareOutputDir(None) |
4f44304b SG |
233 | dtb = fdt_util.EnsureCompiled(self.TestFile(fname)) |
234 | with open(dtb) as fd: | |
235 | data = fd.read() | |
236 | TestFunctional._MakeInputFile(outfile, data) | |
e0e6275f SG |
237 | tools.FinaliseOutputDir() |
238 | return data | |
4f44304b | 239 | |
6ed45ba0 SG |
240 | def _GetDtbContentsForSplTpl(self, dtb_data, name): |
241 | """Create a version of the main DTB for SPL or SPL | |
242 | ||
243 | For testing we don't actually have different versions of the DTB. With | |
244 | U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests | |
245 | we don't normally have any unwanted nodes. | |
246 | ||
247 | We still want the DTBs for SPL and TPL to be different though, since | |
248 | otherwise it is confusing to know which one we are looking at. So add | |
249 | an 'spl' or 'tpl' property to the top-level node. | |
250 | """ | |
251 | dtb = fdt.Fdt.FromData(dtb_data) | |
252 | dtb.Scan() | |
253 | dtb.GetNode('/binman').AddZeroProp(name) | |
254 | dtb.Sync(auto_resize=True) | |
255 | dtb.Pack() | |
256 | return dtb.GetContents() | |
257 | ||
16b8d6b7 | 258 | def _DoReadFileDtb(self, fname, use_real_dtb=False, map=False, |
6ed45ba0 | 259 | update_dtb=False, entry_args=None, reset_dtbs=True): |
4f44304b SG |
260 | """Run binman and return the resulting image |
261 | ||
262 | This runs binman with a given test file and then reads the resulting | |
263 | output file. It is a shortcut function since most tests need to do | |
264 | these steps. | |
265 | ||
266 | Raises an assertion failure if binman returns a non-zero exit code. | |
267 | ||
268 | Args: | |
741f2d62 | 269 | fname: Device-tree source filename to use (e.g. 005_simple.dts) |
4f44304b SG |
270 | use_real_dtb: True to use the test file as the contents of |
271 | the u-boot-dtb entry. Normally this is not needed and the | |
272 | test contents (the U_BOOT_DTB_DATA string) can be used. | |
273 | But in some test we need the real contents. | |
3b0c3821 | 274 | map: True to output map files for the images |
3ab9598d | 275 | update_dtb: Update the offset and size of each entry in the device |
16b8d6b7 | 276 | tree before packing it into the image |
e0ff8551 SG |
277 | |
278 | Returns: | |
279 | Tuple: | |
280 | Resulting image contents | |
281 | Device tree contents | |
3b0c3821 | 282 | Map data showing contents of image (or None if none) |
ea6922e3 | 283 | Output device tree binary filename ('u-boot.dtb' path) |
4f44304b | 284 | """ |
e0ff8551 | 285 | dtb_data = None |
4f44304b SG |
286 | # Use the compiled test file as the u-boot-dtb input |
287 | if use_real_dtb: | |
e0ff8551 | 288 | dtb_data = self._SetupDtb(fname) |
6ed45ba0 SG |
289 | infile = os.path.join(self._indir, 'u-boot.dtb') |
290 | ||
291 | # For testing purposes, make a copy of the DT for SPL and TPL. Add | |
292 | # a node indicating which it is, so aid verification. | |
293 | for name in ['spl', 'tpl']: | |
294 | dtb_fname = '%s/u-boot-%s.dtb' % (name, name) | |
295 | outfile = os.path.join(self._indir, dtb_fname) | |
296 | TestFunctional._MakeInputFile(dtb_fname, | |
297 | self._GetDtbContentsForSplTpl(dtb_data, name)) | |
4f44304b SG |
298 | |
299 | try: | |
53af22a9 | 300 | retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb, |
6ed45ba0 | 301 | entry_args=entry_args, use_real_dtb=use_real_dtb) |
4f44304b | 302 | self.assertEqual(0, retcode) |
6ed45ba0 | 303 | out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out') |
4f44304b SG |
304 | |
305 | # Find the (only) image, read it and return its contents | |
306 | image = control.images['image'] | |
16b8d6b7 SG |
307 | image_fname = tools.GetOutputFilename('image.bin') |
308 | self.assertTrue(os.path.exists(image_fname)) | |
3b0c3821 SG |
309 | if map: |
310 | map_fname = tools.GetOutputFilename('image.map') | |
311 | with open(map_fname) as fd: | |
312 | map_data = fd.read() | |
313 | else: | |
314 | map_data = None | |
16b8d6b7 SG |
315 | with open(image_fname) as fd: |
316 | return fd.read(), dtb_data, map_data, out_dtb_fname | |
4f44304b SG |
317 | finally: |
318 | # Put the test file back | |
6ed45ba0 | 319 | if reset_dtbs and use_real_dtb: |
b8ef5b6b | 320 | self._ResetDtbs() |
4f44304b | 321 | |
e0ff8551 | 322 | def _DoReadFile(self, fname, use_real_dtb=False): |
7ae5f315 SG |
323 | """Helper function which discards the device-tree binary |
324 | ||
325 | Args: | |
741f2d62 | 326 | fname: Device-tree source filename to use (e.g. 005_simple.dts) |
7ae5f315 SG |
327 | use_real_dtb: True to use the test file as the contents of |
328 | the u-boot-dtb entry. Normally this is not needed and the | |
329 | test contents (the U_BOOT_DTB_DATA string) can be used. | |
330 | But in some test we need the real contents. | |
ea6922e3 SG |
331 | |
332 | Returns: | |
333 | Resulting image contents | |
7ae5f315 | 334 | """ |
e0ff8551 SG |
335 | return self._DoReadFileDtb(fname, use_real_dtb)[0] |
336 | ||
4f44304b SG |
337 | @classmethod |
338 | def _MakeInputFile(self, fname, contents): | |
339 | """Create a new test input file, creating directories as needed | |
340 | ||
341 | Args: | |
3ab9598d | 342 | fname: Filename to create |
4f44304b SG |
343 | contents: File contents to write in to the file |
344 | Returns: | |
345 | Full pathname of file created | |
346 | """ | |
347 | pathname = os.path.join(self._indir, fname) | |
348 | dirname = os.path.dirname(pathname) | |
349 | if dirname and not os.path.exists(dirname): | |
350 | os.makedirs(dirname) | |
351 | with open(pathname, 'wb') as fd: | |
352 | fd.write(contents) | |
353 | return pathname | |
354 | ||
0ef87aa3 SG |
355 | @classmethod |
356 | def _MakeInputDir(self, dirname): | |
357 | """Create a new test input directory, creating directories as needed | |
358 | ||
359 | Args: | |
360 | dirname: Directory name to create | |
361 | ||
362 | Returns: | |
363 | Full pathname of directory created | |
364 | """ | |
365 | pathname = os.path.join(self._indir, dirname) | |
366 | if not os.path.exists(pathname): | |
367 | os.makedirs(pathname) | |
368 | return pathname | |
369 | ||
11ae93ee SG |
370 | @classmethod |
371 | def _SetupSplElf(self, src_fname='bss_data'): | |
372 | """Set up an ELF file with a '_dt_ucode_base_size' symbol | |
373 | ||
374 | Args: | |
375 | Filename of ELF file to use as SPL | |
376 | """ | |
377 | with open(self.TestFile(src_fname)) as fd: | |
378 | TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read()) | |
379 | ||
4f44304b SG |
380 | @classmethod |
381 | def TestFile(self, fname): | |
382 | return os.path.join(self._binman_dir, 'test', fname) | |
383 | ||
384 | def AssertInList(self, grep_list, target): | |
385 | """Assert that at least one of a list of things is in a target | |
386 | ||
387 | Args: | |
388 | grep_list: List of strings to check | |
389 | target: Target string | |
390 | """ | |
391 | for grep in grep_list: | |
392 | if grep in target: | |
393 | return | |
394 | self.fail("Error: '%' not found in '%s'" % (grep_list, target)) | |
395 | ||
396 | def CheckNoGaps(self, entries): | |
397 | """Check that all entries fit together without gaps | |
398 | ||
399 | Args: | |
400 | entries: List of entries to check | |
401 | """ | |
3ab9598d | 402 | offset = 0 |
4f44304b | 403 | for entry in entries.values(): |
3ab9598d SG |
404 | self.assertEqual(offset, entry.offset) |
405 | offset += entry.size | |
4f44304b | 406 | |
e0ff8551 | 407 | def GetFdtLen(self, dtb): |
7ae5f315 | 408 | """Get the totalsize field from a device-tree binary |
e0ff8551 SG |
409 | |
410 | Args: | |
7ae5f315 | 411 | dtb: Device-tree binary contents |
e0ff8551 SG |
412 | |
413 | Returns: | |
7ae5f315 | 414 | Total size of device-tree binary, from the header |
e0ff8551 SG |
415 | """ |
416 | return struct.unpack('>L', dtb[4:8])[0] | |
417 | ||
cee02e6f | 418 | def _GetPropTree(self, dtb, prop_names): |
16b8d6b7 SG |
419 | def AddNode(node, path): |
420 | if node.name != '/': | |
421 | path += '/' + node.name | |
16b8d6b7 SG |
422 | for subnode in node.subnodes: |
423 | for prop in subnode.props.values(): | |
cee02e6f | 424 | if prop.name in prop_names: |
16b8d6b7 SG |
425 | prop_path = path + '/' + subnode.name + ':' + prop.name |
426 | tree[prop_path[len('/binman/'):]] = fdt_util.fdt32_to_cpu( | |
427 | prop.value) | |
16b8d6b7 SG |
428 | AddNode(subnode, path) |
429 | ||
430 | tree = {} | |
16b8d6b7 SG |
431 | AddNode(dtb.GetRoot(), '') |
432 | return tree | |
433 | ||
4f44304b SG |
434 | def testRun(self): |
435 | """Test a basic run with valid args""" | |
436 | result = self._RunBinman('-h') | |
437 | ||
438 | def testFullHelp(self): | |
439 | """Test that the full help is displayed with -H""" | |
440 | result = self._RunBinman('-H') | |
441 | help_file = os.path.join(self._binman_dir, 'README') | |
3759df0c TR |
442 | # Remove possible extraneous strings |
443 | extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n' | |
444 | gothelp = result.stdout.replace(extra, '') | |
445 | self.assertEqual(len(gothelp), os.path.getsize(help_file)) | |
4f44304b SG |
446 | self.assertEqual(0, len(result.stderr)) |
447 | self.assertEqual(0, result.return_code) | |
448 | ||
449 | def testFullHelpInternal(self): | |
450 | """Test that the full help is displayed with -H""" | |
451 | try: | |
452 | command.test_result = command.CommandResult() | |
453 | result = self._DoBinman('-H') | |
454 | help_file = os.path.join(self._binman_dir, 'README') | |
455 | finally: | |
456 | command.test_result = None | |
457 | ||
458 | def testHelp(self): | |
459 | """Test that the basic help is displayed with -h""" | |
460 | result = self._RunBinman('-h') | |
461 | self.assertTrue(len(result.stdout) > 200) | |
462 | self.assertEqual(0, len(result.stderr)) | |
463 | self.assertEqual(0, result.return_code) | |
464 | ||
4f44304b SG |
465 | def testBoard(self): |
466 | """Test that we can run it with a specific board""" | |
741f2d62 | 467 | self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb') |
4f44304b SG |
468 | TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA) |
469 | result = self._DoBinman('-b', 'sandbox') | |
470 | self.assertEqual(0, result) | |
471 | ||
472 | def testNeedBoard(self): | |
473 | """Test that we get an error when no board ius supplied""" | |
474 | with self.assertRaises(ValueError) as e: | |
475 | result = self._DoBinman() | |
476 | self.assertIn("Must provide a board to process (use -b <board>)", | |
477 | str(e.exception)) | |
478 | ||
479 | def testMissingDt(self): | |
7ae5f315 | 480 | """Test that an invalid device-tree file generates an error""" |
4f44304b SG |
481 | with self.assertRaises(Exception) as e: |
482 | self._RunBinman('-d', 'missing_file') | |
483 | # We get one error from libfdt, and a different one from fdtget. | |
484 | self.AssertInList(["Couldn't open blob from 'missing_file'", | |
485 | 'No such file or directory'], str(e.exception)) | |
486 | ||
487 | def testBrokenDt(self): | |
7ae5f315 | 488 | """Test that an invalid device-tree source file generates an error |
4f44304b SG |
489 | |
490 | Since this is a source file it should be compiled and the error | |
491 | will come from the device-tree compiler (dtc). | |
492 | """ | |
493 | with self.assertRaises(Exception) as e: | |
741f2d62 | 494 | self._RunBinman('-d', self.TestFile('001_invalid.dts')) |
4f44304b SG |
495 | self.assertIn("FATAL ERROR: Unable to parse input tree", |
496 | str(e.exception)) | |
497 | ||
498 | def testMissingNode(self): | |
499 | """Test that a device tree without a 'binman' node generates an error""" | |
500 | with self.assertRaises(Exception) as e: | |
741f2d62 | 501 | self._DoBinman('-d', self.TestFile('002_missing_node.dts')) |
4f44304b SG |
502 | self.assertIn("does not have a 'binman' node", str(e.exception)) |
503 | ||
504 | def testEmpty(self): | |
505 | """Test that an empty binman node works OK (i.e. does nothing)""" | |
741f2d62 | 506 | result = self._RunBinman('-d', self.TestFile('003_empty.dts')) |
4f44304b SG |
507 | self.assertEqual(0, len(result.stderr)) |
508 | self.assertEqual(0, result.return_code) | |
509 | ||
510 | def testInvalidEntry(self): | |
511 | """Test that an invalid entry is flagged""" | |
512 | with self.assertRaises(Exception) as e: | |
513 | result = self._RunBinman('-d', | |
741f2d62 | 514 | self.TestFile('004_invalid_entry.dts')) |
4f44304b SG |
515 | self.assertIn("Unknown entry type 'not-a-valid-type' in node " |
516 | "'/binman/not-a-valid-type'", str(e.exception)) | |
517 | ||
518 | def testSimple(self): | |
519 | """Test a simple binman with a single file""" | |
741f2d62 | 520 | data = self._DoReadFile('005_simple.dts') |
4f44304b SG |
521 | self.assertEqual(U_BOOT_DATA, data) |
522 | ||
7fe9173b SG |
523 | def testSimpleDebug(self): |
524 | """Test a simple binman run with debugging enabled""" | |
741f2d62 | 525 | data = self._DoTestFile('005_simple.dts', debug=True) |
7fe9173b | 526 | |
4f44304b SG |
527 | def testDual(self): |
528 | """Test that we can handle creating two images | |
529 | ||
530 | This also tests image padding. | |
531 | """ | |
741f2d62 | 532 | retcode = self._DoTestFile('006_dual_image.dts') |
4f44304b SG |
533 | self.assertEqual(0, retcode) |
534 | ||
535 | image = control.images['image1'] | |
536 | self.assertEqual(len(U_BOOT_DATA), image._size) | |
537 | fname = tools.GetOutputFilename('image1.bin') | |
538 | self.assertTrue(os.path.exists(fname)) | |
539 | with open(fname) as fd: | |
540 | data = fd.read() | |
541 | self.assertEqual(U_BOOT_DATA, data) | |
542 | ||
543 | image = control.images['image2'] | |
544 | self.assertEqual(3 + len(U_BOOT_DATA) + 5, image._size) | |
545 | fname = tools.GetOutputFilename('image2.bin') | |
546 | self.assertTrue(os.path.exists(fname)) | |
547 | with open(fname) as fd: | |
548 | data = fd.read() | |
549 | self.assertEqual(U_BOOT_DATA, data[3:7]) | |
550 | self.assertEqual(chr(0) * 3, data[:3]) | |
551 | self.assertEqual(chr(0) * 5, data[7:]) | |
552 | ||
553 | def testBadAlign(self): | |
554 | """Test that an invalid alignment value is detected""" | |
555 | with self.assertRaises(ValueError) as e: | |
741f2d62 | 556 | self._DoTestFile('007_bad_align.dts') |
4f44304b SG |
557 | self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power " |
558 | "of two", str(e.exception)) | |
559 | ||
560 | def testPackSimple(self): | |
561 | """Test that packing works as expected""" | |
741f2d62 | 562 | retcode = self._DoTestFile('008_pack.dts') |
4f44304b SG |
563 | self.assertEqual(0, retcode) |
564 | self.assertIn('image', control.images) | |
565 | image = control.images['image'] | |
8f1da50c | 566 | entries = image.GetEntries() |
4f44304b SG |
567 | self.assertEqual(5, len(entries)) |
568 | ||
569 | # First u-boot | |
570 | self.assertIn('u-boot', entries) | |
571 | entry = entries['u-boot'] | |
3ab9598d | 572 | self.assertEqual(0, entry.offset) |
4f44304b SG |
573 | self.assertEqual(len(U_BOOT_DATA), entry.size) |
574 | ||
575 | # Second u-boot, aligned to 16-byte boundary | |
576 | self.assertIn('u-boot-align', entries) | |
577 | entry = entries['u-boot-align'] | |
3ab9598d | 578 | self.assertEqual(16, entry.offset) |
4f44304b SG |
579 | self.assertEqual(len(U_BOOT_DATA), entry.size) |
580 | ||
581 | # Third u-boot, size 23 bytes | |
582 | self.assertIn('u-boot-size', entries) | |
583 | entry = entries['u-boot-size'] | |
3ab9598d | 584 | self.assertEqual(20, entry.offset) |
4f44304b SG |
585 | self.assertEqual(len(U_BOOT_DATA), entry.contents_size) |
586 | self.assertEqual(23, entry.size) | |
587 | ||
588 | # Fourth u-boot, placed immediate after the above | |
589 | self.assertIn('u-boot-next', entries) | |
590 | entry = entries['u-boot-next'] | |
3ab9598d | 591 | self.assertEqual(43, entry.offset) |
4f44304b SG |
592 | self.assertEqual(len(U_BOOT_DATA), entry.size) |
593 | ||
3ab9598d | 594 | # Fifth u-boot, placed at a fixed offset |
4f44304b SG |
595 | self.assertIn('u-boot-fixed', entries) |
596 | entry = entries['u-boot-fixed'] | |
3ab9598d | 597 | self.assertEqual(61, entry.offset) |
4f44304b SG |
598 | self.assertEqual(len(U_BOOT_DATA), entry.size) |
599 | ||
600 | self.assertEqual(65, image._size) | |
601 | ||
602 | def testPackExtra(self): | |
603 | """Test that extra packing feature works as expected""" | |
741f2d62 | 604 | retcode = self._DoTestFile('009_pack_extra.dts') |
4f44304b SG |
605 | |
606 | self.assertEqual(0, retcode) | |
607 | self.assertIn('image', control.images) | |
608 | image = control.images['image'] | |
8f1da50c | 609 | entries = image.GetEntries() |
4f44304b SG |
610 | self.assertEqual(5, len(entries)) |
611 | ||
612 | # First u-boot with padding before and after | |
613 | self.assertIn('u-boot', entries) | |
614 | entry = entries['u-boot'] | |
3ab9598d | 615 | self.assertEqual(0, entry.offset) |
4f44304b SG |
616 | self.assertEqual(3, entry.pad_before) |
617 | self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size) | |
618 | ||
619 | # Second u-boot has an aligned size, but it has no effect | |
620 | self.assertIn('u-boot-align-size-nop', entries) | |
621 | entry = entries['u-boot-align-size-nop'] | |
3ab9598d | 622 | self.assertEqual(12, entry.offset) |
4f44304b SG |
623 | self.assertEqual(4, entry.size) |
624 | ||
625 | # Third u-boot has an aligned size too | |
626 | self.assertIn('u-boot-align-size', entries) | |
627 | entry = entries['u-boot-align-size'] | |
3ab9598d | 628 | self.assertEqual(16, entry.offset) |
4f44304b SG |
629 | self.assertEqual(32, entry.size) |
630 | ||
631 | # Fourth u-boot has an aligned end | |
632 | self.assertIn('u-boot-align-end', entries) | |
633 | entry = entries['u-boot-align-end'] | |
3ab9598d | 634 | self.assertEqual(48, entry.offset) |
4f44304b SG |
635 | self.assertEqual(16, entry.size) |
636 | ||
637 | # Fifth u-boot immediately afterwards | |
638 | self.assertIn('u-boot-align-both', entries) | |
639 | entry = entries['u-boot-align-both'] | |
3ab9598d | 640 | self.assertEqual(64, entry.offset) |
4f44304b SG |
641 | self.assertEqual(64, entry.size) |
642 | ||
643 | self.CheckNoGaps(entries) | |
644 | self.assertEqual(128, image._size) | |
645 | ||
646 | def testPackAlignPowerOf2(self): | |
647 | """Test that invalid entry alignment is detected""" | |
648 | with self.assertRaises(ValueError) as e: | |
741f2d62 | 649 | self._DoTestFile('010_pack_align_power2.dts') |
4f44304b SG |
650 | self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power " |
651 | "of two", str(e.exception)) | |
652 | ||
653 | def testPackAlignSizePowerOf2(self): | |
654 | """Test that invalid entry size alignment is detected""" | |
655 | with self.assertRaises(ValueError) as e: | |
741f2d62 | 656 | self._DoTestFile('011_pack_align_size_power2.dts') |
4f44304b SG |
657 | self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a " |
658 | "power of two", str(e.exception)) | |
659 | ||
660 | def testPackInvalidAlign(self): | |
3ab9598d | 661 | """Test detection of an offset that does not match its alignment""" |
4f44304b | 662 | with self.assertRaises(ValueError) as e: |
741f2d62 | 663 | self._DoTestFile('012_pack_inv_align.dts') |
3ab9598d | 664 | self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match " |
4f44304b SG |
665 | "align 0x4 (4)", str(e.exception)) |
666 | ||
667 | def testPackInvalidSizeAlign(self): | |
668 | """Test that invalid entry size alignment is detected""" | |
669 | with self.assertRaises(ValueError) as e: | |
741f2d62 | 670 | self._DoTestFile('013_pack_inv_size_align.dts') |
4f44304b SG |
671 | self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match " |
672 | "align-size 0x4 (4)", str(e.exception)) | |
673 | ||
674 | def testPackOverlap(self): | |
675 | """Test that overlapping regions are detected""" | |
676 | with self.assertRaises(ValueError) as e: | |
741f2d62 | 677 | self._DoTestFile('014_pack_overlap.dts') |
3ab9598d | 678 | self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps " |
4f44304b SG |
679 | "with previous entry '/binman/u-boot' ending at 0x4 (4)", |
680 | str(e.exception)) | |
681 | ||
682 | def testPackEntryOverflow(self): | |
683 | """Test that entries that overflow their size are detected""" | |
684 | with self.assertRaises(ValueError) as e: | |
741f2d62 | 685 | self._DoTestFile('015_pack_overflow.dts') |
4f44304b SG |
686 | self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) " |
687 | "but entry size is 0x3 (3)", str(e.exception)) | |
688 | ||
689 | def testPackImageOverflow(self): | |
690 | """Test that entries which overflow the image size are detected""" | |
691 | with self.assertRaises(ValueError) as e: | |
741f2d62 | 692 | self._DoTestFile('016_pack_image_overflow.dts') |
8f1da50c | 693 | self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section " |
4f44304b SG |
694 | "size 0x3 (3)", str(e.exception)) |
695 | ||
696 | def testPackImageSize(self): | |
697 | """Test that the image size can be set""" | |
741f2d62 | 698 | retcode = self._DoTestFile('017_pack_image_size.dts') |
4f44304b SG |
699 | self.assertEqual(0, retcode) |
700 | self.assertIn('image', control.images) | |
701 | image = control.images['image'] | |
702 | self.assertEqual(7, image._size) | |
703 | ||
704 | def testPackImageSizeAlign(self): | |
705 | """Test that image size alignemnt works as expected""" | |
741f2d62 | 706 | retcode = self._DoTestFile('018_pack_image_align.dts') |
4f44304b SG |
707 | self.assertEqual(0, retcode) |
708 | self.assertIn('image', control.images) | |
709 | image = control.images['image'] | |
710 | self.assertEqual(16, image._size) | |
711 | ||
712 | def testPackInvalidImageAlign(self): | |
713 | """Test that invalid image alignment is detected""" | |
714 | with self.assertRaises(ValueError) as e: | |
741f2d62 | 715 | self._DoTestFile('019_pack_inv_image_align.dts') |
8f1da50c | 716 | self.assertIn("Section '/binman': Size 0x7 (7) does not match " |
4f44304b SG |
717 | "align-size 0x8 (8)", str(e.exception)) |
718 | ||
719 | def testPackAlignPowerOf2(self): | |
720 | """Test that invalid image alignment is detected""" | |
721 | with self.assertRaises(ValueError) as e: | |
741f2d62 | 722 | self._DoTestFile('020_pack_inv_image_align_power2.dts') |
8f1da50c | 723 | self.assertIn("Section '/binman': Alignment size 131 must be a power of " |
4f44304b SG |
724 | "two", str(e.exception)) |
725 | ||
726 | def testImagePadByte(self): | |
727 | """Test that the image pad byte can be specified""" | |
11ae93ee | 728 | self._SetupSplElf() |
741f2d62 | 729 | data = self._DoReadFile('021_image_pad.dts') |
f689890d | 730 | self.assertEqual(U_BOOT_SPL_DATA + (chr(0xff) * 1) + U_BOOT_DATA, data) |
4f44304b SG |
731 | |
732 | def testImageName(self): | |
733 | """Test that image files can be named""" | |
741f2d62 | 734 | retcode = self._DoTestFile('022_image_name.dts') |
4f44304b SG |
735 | self.assertEqual(0, retcode) |
736 | image = control.images['image1'] | |
737 | fname = tools.GetOutputFilename('test-name') | |
738 | self.assertTrue(os.path.exists(fname)) | |
739 | ||
740 | image = control.images['image2'] | |
741 | fname = tools.GetOutputFilename('test-name.xx') | |
742 | self.assertTrue(os.path.exists(fname)) | |
743 | ||
744 | def testBlobFilename(self): | |
745 | """Test that generic blobs can be provided by filename""" | |
741f2d62 | 746 | data = self._DoReadFile('023_blob.dts') |
4f44304b SG |
747 | self.assertEqual(BLOB_DATA, data) |
748 | ||
749 | def testPackSorted(self): | |
750 | """Test that entries can be sorted""" | |
11ae93ee | 751 | self._SetupSplElf() |
741f2d62 | 752 | data = self._DoReadFile('024_sorted.dts') |
f689890d | 753 | self.assertEqual(chr(0) * 1 + U_BOOT_SPL_DATA + chr(0) * 2 + |
4f44304b SG |
754 | U_BOOT_DATA, data) |
755 | ||
3ab9598d SG |
756 | def testPackZeroOffset(self): |
757 | """Test that an entry at offset 0 is not given a new offset""" | |
4f44304b | 758 | with self.assertRaises(ValueError) as e: |
741f2d62 | 759 | self._DoTestFile('025_pack_zero_size.dts') |
3ab9598d | 760 | self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps " |
4f44304b SG |
761 | "with previous entry '/binman/u-boot' ending at 0x4 (4)", |
762 | str(e.exception)) | |
763 | ||
764 | def testPackUbootDtb(self): | |
765 | """Test that a device tree can be added to U-Boot""" | |
741f2d62 | 766 | data = self._DoReadFile('026_pack_u_boot_dtb.dts') |
4f44304b | 767 | self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data) |
e0ff8551 SG |
768 | |
769 | def testPackX86RomNoSize(self): | |
770 | """Test that the end-at-4gb property requires a size property""" | |
771 | with self.assertRaises(ValueError) as e: | |
741f2d62 | 772 | self._DoTestFile('027_pack_4gb_no_size.dts') |
8f1da50c | 773 | self.assertIn("Section '/binman': Section size must be provided when " |
e0ff8551 SG |
774 | "using end-at-4gb", str(e.exception)) |
775 | ||
94b57db0 JG |
776 | def test4gbAndSkipAtStartTogether(self): |
777 | """Test that the end-at-4gb and skip-at-size property can't be used | |
778 | together""" | |
779 | with self.assertRaises(ValueError) as e: | |
780 | self._DoTestFile('80_4gb_and_skip_at_start_together.dts') | |
781 | self.assertIn("Section '/binman': Provide either 'end-at-4gb' or " | |
782 | "'skip-at-start'", str(e.exception)) | |
783 | ||
e0ff8551 | 784 | def testPackX86RomOutside(self): |
3ab9598d | 785 | """Test that the end-at-4gb property checks for offset boundaries""" |
e0ff8551 | 786 | with self.assertRaises(ValueError) as e: |
741f2d62 | 787 | self._DoTestFile('028_pack_4gb_outside.dts') |
3ab9598d | 788 | self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) is outside " |
8f1da50c | 789 | "the section starting at 0xffffffe0 (4294967264)", |
e0ff8551 SG |
790 | str(e.exception)) |
791 | ||
792 | def testPackX86Rom(self): | |
793 | """Test that a basic x86 ROM can be created""" | |
11ae93ee | 794 | self._SetupSplElf() |
741f2d62 | 795 | data = self._DoReadFile('029_x86-rom.dts') |
f689890d SG |
796 | self.assertEqual(U_BOOT_DATA + chr(0) * 7 + U_BOOT_SPL_DATA + |
797 | chr(0) * 2, data) | |
e0ff8551 SG |
798 | |
799 | def testPackX86RomMeNoDesc(self): | |
800 | """Test that an invalid Intel descriptor entry is detected""" | |
801 | TestFunctional._MakeInputFile('descriptor.bin', '') | |
802 | with self.assertRaises(ValueError) as e: | |
741f2d62 | 803 | self._DoTestFile('031_x86-rom-me.dts') |
e0ff8551 SG |
804 | self.assertIn("Node '/binman/intel-descriptor': Cannot find FD " |
805 | "signature", str(e.exception)) | |
806 | ||
807 | def testPackX86RomBadDesc(self): | |
808 | """Test that the Intel requires a descriptor entry""" | |
809 | with self.assertRaises(ValueError) as e: | |
741f2d62 | 810 | self._DoTestFile('030_x86-rom-me-no-desc.dts') |
3ab9598d SG |
811 | self.assertIn("Node '/binman/intel-me': No offset set with " |
812 | "offset-unset: should another entry provide this correct " | |
813 | "offset?", str(e.exception)) | |
e0ff8551 SG |
814 | |
815 | def testPackX86RomMe(self): | |
816 | """Test that an x86 ROM with an ME region can be created""" | |
741f2d62 | 817 | data = self._DoReadFile('031_x86-rom-me.dts') |
e0ff8551 SG |
818 | self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)]) |
819 | ||
820 | def testPackVga(self): | |
821 | """Test that an image with a VGA binary can be created""" | |
741f2d62 | 822 | data = self._DoReadFile('032_intel-vga.dts') |
e0ff8551 SG |
823 | self.assertEqual(VGA_DATA, data[:len(VGA_DATA)]) |
824 | ||
825 | def testPackStart16(self): | |
826 | """Test that an image with an x86 start16 region can be created""" | |
741f2d62 | 827 | data = self._DoReadFile('033_x86-start16.dts') |
e0ff8551 SG |
828 | self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)]) |
829 | ||
9d368f32 JG |
830 | def testPackPowerpcMpc85xxBootpgResetvec(self): |
831 | """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be | |
832 | created""" | |
833 | data = self._DoReadFile('81_powerpc_mpc85xx_bootpg_resetvec.dts') | |
834 | self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)]) | |
835 | ||
736bb0ae | 836 | def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False): |
adc57011 SG |
837 | """Handle running a test for insertion of microcode |
838 | ||
839 | Args: | |
840 | dts_fname: Name of test .dts file | |
841 | nodtb_data: Data that we expect in the first section | |
736bb0ae SG |
842 | ucode_second: True if the microsecond entry is second instead of |
843 | third | |
adc57011 SG |
844 | |
845 | Returns: | |
846 | Tuple: | |
847 | Contents of first region (U-Boot or SPL) | |
3ab9598d | 848 | Offset and size components of microcode pointer, as inserted |
adc57011 SG |
849 | in the above (two 4-byte words) |
850 | """ | |
6b187df7 | 851 | data = self._DoReadFile(dts_fname, True) |
e0ff8551 SG |
852 | |
853 | # Now check the device tree has no microcode | |
736bb0ae SG |
854 | if ucode_second: |
855 | ucode_content = data[len(nodtb_data):] | |
856 | ucode_pos = len(nodtb_data) | |
857 | dtb_with_ucode = ucode_content[16:] | |
858 | fdt_len = self.GetFdtLen(dtb_with_ucode) | |
859 | else: | |
860 | dtb_with_ucode = data[len(nodtb_data):] | |
861 | fdt_len = self.GetFdtLen(dtb_with_ucode) | |
862 | ucode_content = dtb_with_ucode[fdt_len:] | |
863 | ucode_pos = len(nodtb_data) + fdt_len | |
e0ff8551 SG |
864 | fname = tools.GetOutputFilename('test.dtb') |
865 | with open(fname, 'wb') as fd: | |
adc57011 | 866 | fd.write(dtb_with_ucode) |
ec3f378a SG |
867 | dtb = fdt.FdtScan(fname) |
868 | ucode = dtb.GetNode('/microcode') | |
e0ff8551 SG |
869 | self.assertTrue(ucode) |
870 | for node in ucode.subnodes: | |
871 | self.assertFalse(node.props.get('data')) | |
872 | ||
e0ff8551 SG |
873 | # Check that the microcode appears immediately after the Fdt |
874 | # This matches the concatenation of the data properties in | |
8772213e | 875 | # the /microcode/update@xxx nodes in 34_x86_ucode.dts. |
e0ff8551 SG |
876 | ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000, |
877 | 0x78235609) | |
adc57011 | 878 | self.assertEqual(ucode_data, ucode_content[:len(ucode_data)]) |
e0ff8551 SG |
879 | |
880 | # Check that the microcode pointer was inserted. It should match the | |
3ab9598d | 881 | # expected offset and size |
e0ff8551 SG |
882 | pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos, |
883 | len(ucode_data)) | |
736bb0ae SG |
884 | u_boot = data[:len(nodtb_data)] |
885 | return u_boot, pos_and_size | |
6b187df7 SG |
886 | |
887 | def testPackUbootMicrocode(self): | |
888 | """Test that x86 microcode can be handled correctly | |
889 | ||
890 | We expect to see the following in the image, in order: | |
891 | u-boot-nodtb.bin with a microcode pointer inserted at the correct | |
892 | place | |
893 | u-boot.dtb with the microcode removed | |
894 | the microcode | |
895 | """ | |
741f2d62 | 896 | first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts', |
6b187df7 | 897 | U_BOOT_NODTB_DATA) |
e0ff8551 SG |
898 | self.assertEqual('nodtb with microcode' + pos_and_size + |
899 | ' somewhere in here', first) | |
900 | ||
160a7664 | 901 | def _RunPackUbootSingleMicrocode(self): |
e0ff8551 SG |
902 | """Test that x86 microcode can be handled correctly |
903 | ||
904 | We expect to see the following in the image, in order: | |
905 | u-boot-nodtb.bin with a microcode pointer inserted at the correct | |
906 | place | |
907 | u-boot.dtb with the microcode | |
908 | an empty microcode region | |
909 | """ | |
910 | # We need the libfdt library to run this test since only that allows | |
911 | # finding the offset of a property. This is required by | |
912 | # Entry_u_boot_dtb_with_ucode.ObtainContents(). | |
741f2d62 | 913 | data = self._DoReadFile('035_x86_single_ucode.dts', True) |
e0ff8551 SG |
914 | |
915 | second = data[len(U_BOOT_NODTB_DATA):] | |
916 | ||
917 | fdt_len = self.GetFdtLen(second) | |
918 | third = second[fdt_len:] | |
919 | second = second[:fdt_len] | |
920 | ||
160a7664 SG |
921 | ucode_data = struct.pack('>2L', 0x12345678, 0x12345679) |
922 | self.assertIn(ucode_data, second) | |
923 | ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA) | |
e0ff8551 | 924 | |
160a7664 | 925 | # Check that the microcode pointer was inserted. It should match the |
3ab9598d | 926 | # expected offset and size |
160a7664 SG |
927 | pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos, |
928 | len(ucode_data)) | |
929 | first = data[:len(U_BOOT_NODTB_DATA)] | |
930 | self.assertEqual('nodtb with microcode' + pos_and_size + | |
931 | ' somewhere in here', first) | |
c49deb83 | 932 | |
75db0860 SG |
933 | def testPackUbootSingleMicrocode(self): |
934 | """Test that x86 microcode can be handled correctly with fdt_normal. | |
935 | """ | |
160a7664 | 936 | self._RunPackUbootSingleMicrocode() |
75db0860 | 937 | |
c49deb83 SG |
938 | def testUBootImg(self): |
939 | """Test that u-boot.img can be put in a file""" | |
741f2d62 | 940 | data = self._DoReadFile('036_u_boot_img.dts') |
c49deb83 | 941 | self.assertEqual(U_BOOT_IMG_DATA, data) |
75db0860 SG |
942 | |
943 | def testNoMicrocode(self): | |
944 | """Test that a missing microcode region is detected""" | |
945 | with self.assertRaises(ValueError) as e: | |
741f2d62 | 946 | self._DoReadFile('037_x86_no_ucode.dts', True) |
75db0860 SG |
947 | self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode " |
948 | "node found in ", str(e.exception)) | |
949 | ||
950 | def testMicrocodeWithoutNode(self): | |
951 | """Test that a missing u-boot-dtb-with-ucode node is detected""" | |
952 | with self.assertRaises(ValueError) as e: | |
741f2d62 | 953 | self._DoReadFile('038_x86_ucode_missing_node.dts', True) |
75db0860 SG |
954 | self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find " |
955 | "microcode region u-boot-dtb-with-ucode", str(e.exception)) | |
956 | ||
957 | def testMicrocodeWithoutNode2(self): | |
958 | """Test that a missing u-boot-ucode node is detected""" | |
959 | with self.assertRaises(ValueError) as e: | |
741f2d62 | 960 | self._DoReadFile('039_x86_ucode_missing_node2.dts', True) |
75db0860 SG |
961 | self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find " |
962 | "microcode region u-boot-ucode", str(e.exception)) | |
963 | ||
964 | def testMicrocodeWithoutPtrInElf(self): | |
965 | """Test that a U-Boot binary without the microcode symbol is detected""" | |
966 | # ELF file without a '_dt_ucode_base_size' symbol | |
75db0860 SG |
967 | try: |
968 | with open(self.TestFile('u_boot_no_ucode_ptr')) as fd: | |
969 | TestFunctional._MakeInputFile('u-boot', fd.read()) | |
970 | ||
971 | with self.assertRaises(ValueError) as e: | |
160a7664 | 972 | self._RunPackUbootSingleMicrocode() |
75db0860 SG |
973 | self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate " |
974 | "_dt_ucode_base_size symbol in u-boot", str(e.exception)) | |
975 | ||
976 | finally: | |
977 | # Put the original file back | |
978 | with open(self.TestFile('u_boot_ucode_ptr')) as fd: | |
979 | TestFunctional._MakeInputFile('u-boot', fd.read()) | |
980 | ||
981 | def testMicrocodeNotInImage(self): | |
982 | """Test that microcode must be placed within the image""" | |
983 | with self.assertRaises(ValueError) as e: | |
741f2d62 | 984 | self._DoReadFile('040_x86_ucode_not_in_image.dts', True) |
75db0860 SG |
985 | self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode " |
986 | "pointer _dt_ucode_base_size at fffffe14 is outside the " | |
25ac0e61 | 987 | "section ranging from 00000000 to 0000002e", str(e.exception)) |
75db0860 SG |
988 | |
989 | def testWithoutMicrocode(self): | |
990 | """Test that we can cope with an image without microcode (e.g. qemu)""" | |
991 | with open(self.TestFile('u_boot_no_ucode_ptr')) as fd: | |
992 | TestFunctional._MakeInputFile('u-boot', fd.read()) | |
741f2d62 | 993 | data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True) |
75db0860 SG |
994 | |
995 | # Now check the device tree has no microcode | |
996 | self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)]) | |
997 | second = data[len(U_BOOT_NODTB_DATA):] | |
998 | ||
999 | fdt_len = self.GetFdtLen(second) | |
1000 | self.assertEqual(dtb, second[:fdt_len]) | |
1001 | ||
1002 | used_len = len(U_BOOT_NODTB_DATA) + fdt_len | |
1003 | third = data[used_len:] | |
1004 | self.assertEqual(chr(0) * (0x200 - used_len), third) | |
1005 | ||
1006 | def testUnknownPosSize(self): | |
1007 | """Test that microcode must be placed within the image""" | |
1008 | with self.assertRaises(ValueError) as e: | |
741f2d62 | 1009 | self._DoReadFile('041_unknown_pos_size.dts', True) |
3ab9598d | 1010 | self.assertIn("Section '/binman': Unable to set offset/size for unknown " |
75db0860 | 1011 | "entry 'invalid-entry'", str(e.exception)) |
da229090 SG |
1012 | |
1013 | def testPackFsp(self): | |
1014 | """Test that an image with a FSP binary can be created""" | |
741f2d62 | 1015 | data = self._DoReadFile('042_intel-fsp.dts') |
da229090 SG |
1016 | self.assertEqual(FSP_DATA, data[:len(FSP_DATA)]) |
1017 | ||
1018 | def testPackCmc(self): | |
59ea8c25 | 1019 | """Test that an image with a CMC binary can be created""" |
741f2d62 | 1020 | data = self._DoReadFile('043_intel-cmc.dts') |
da229090 | 1021 | self.assertEqual(CMC_DATA, data[:len(CMC_DATA)]) |
59ea8c25 BM |
1022 | |
1023 | def testPackVbt(self): | |
1024 | """Test that an image with a VBT binary can be created""" | |
741f2d62 | 1025 | data = self._DoReadFile('046_intel-vbt.dts') |
59ea8c25 | 1026 | self.assertEqual(VBT_DATA, data[:len(VBT_DATA)]) |
9fc60b49 | 1027 | |
56509843 SG |
1028 | def testSplBssPad(self): |
1029 | """Test that we can pad SPL's BSS with zeros""" | |
6b187df7 | 1030 | # ELF file with a '__bss_size' symbol |
11ae93ee | 1031 | self._SetupSplElf() |
741f2d62 | 1032 | data = self._DoReadFile('047_spl_bss_pad.dts') |
56509843 SG |
1033 | self.assertEqual(U_BOOT_SPL_DATA + (chr(0) * 10) + U_BOOT_DATA, data) |
1034 | ||
86af511d SG |
1035 | def testSplBssPadMissing(self): |
1036 | """Test that a missing symbol is detected""" | |
11ae93ee | 1037 | self._SetupSplElf('u_boot_ucode_ptr') |
b50e5611 | 1038 | with self.assertRaises(ValueError) as e: |
741f2d62 | 1039 | self._DoReadFile('047_spl_bss_pad.dts') |
b50e5611 SG |
1040 | self.assertIn('Expected __bss_size symbol in spl/u-boot-spl', |
1041 | str(e.exception)) | |
1042 | ||
8772213e | 1043 | def testPackStart16Spl(self): |
35b384cb | 1044 | """Test that an image with an x86 start16 SPL region can be created""" |
741f2d62 | 1045 | data = self._DoReadFile('048_x86-start16-spl.dts') |
8772213e SG |
1046 | self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)]) |
1047 | ||
736bb0ae SG |
1048 | def _PackUbootSplMicrocode(self, dts, ucode_second=False): |
1049 | """Helper function for microcode tests | |
6b187df7 SG |
1050 | |
1051 | We expect to see the following in the image, in order: | |
1052 | u-boot-spl-nodtb.bin with a microcode pointer inserted at the | |
1053 | correct place | |
1054 | u-boot.dtb with the microcode removed | |
1055 | the microcode | |
736bb0ae SG |
1056 | |
1057 | Args: | |
1058 | dts: Device tree file to use for test | |
1059 | ucode_second: True if the microsecond entry is second instead of | |
1060 | third | |
6b187df7 | 1061 | """ |
11ae93ee | 1062 | self._SetupSplElf('u_boot_ucode_ptr') |
736bb0ae SG |
1063 | first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA, |
1064 | ucode_second=ucode_second) | |
6b187df7 SG |
1065 | self.assertEqual('splnodtb with microc' + pos_and_size + |
1066 | 'ter somewhere in here', first) | |
1067 | ||
736bb0ae SG |
1068 | def testPackUbootSplMicrocode(self): |
1069 | """Test that x86 microcode can be handled correctly in SPL""" | |
741f2d62 | 1070 | self._PackUbootSplMicrocode('049_x86_ucode_spl.dts') |
736bb0ae SG |
1071 | |
1072 | def testPackUbootSplMicrocodeReorder(self): | |
1073 | """Test that order doesn't matter for microcode entries | |
1074 | ||
1075 | This is the same as testPackUbootSplMicrocode but when we process the | |
1076 | u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode | |
1077 | entry, so we reply on binman to try later. | |
1078 | """ | |
741f2d62 | 1079 | self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts', |
736bb0ae SG |
1080 | ucode_second=True) |
1081 | ||
ca4f4ff7 SG |
1082 | def testPackMrc(self): |
1083 | """Test that an image with an MRC binary can be created""" | |
741f2d62 | 1084 | data = self._DoReadFile('050_intel_mrc.dts') |
ca4f4ff7 SG |
1085 | self.assertEqual(MRC_DATA, data[:len(MRC_DATA)]) |
1086 | ||
47419eae SG |
1087 | def testSplDtb(self): |
1088 | """Test that an image with spl/u-boot-spl.dtb can be created""" | |
741f2d62 | 1089 | data = self._DoReadFile('051_u_boot_spl_dtb.dts') |
47419eae SG |
1090 | self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)]) |
1091 | ||
4e6fdbef SG |
1092 | def testSplNoDtb(self): |
1093 | """Test that an image with spl/u-boot-spl-nodtb.bin can be created""" | |
741f2d62 | 1094 | data = self._DoReadFile('052_u_boot_spl_nodtb.dts') |
4e6fdbef SG |
1095 | self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)]) |
1096 | ||
19790632 SG |
1097 | def testSymbols(self): |
1098 | """Test binman can assign symbols embedded in U-Boot""" | |
1099 | elf_fname = self.TestFile('u_boot_binman_syms') | |
1100 | syms = elf.GetSymbols(elf_fname, ['binman', 'image']) | |
1101 | addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start') | |
3ab9598d | 1102 | self.assertEqual(syms['_binman_u_boot_spl_prop_offset'].address, addr) |
19790632 | 1103 | |
11ae93ee | 1104 | self._SetupSplElf('u_boot_binman_syms') |
741f2d62 | 1105 | data = self._DoReadFile('053_symbols.dts') |
19790632 SG |
1106 | sym_values = struct.pack('<LQL', 0x24 + 0, 0x24 + 24, 0x24 + 20) |
1107 | expected = (sym_values + U_BOOT_SPL_DATA[16:] + chr(0xff) + | |
1108 | U_BOOT_DATA + | |
1109 | sym_values + U_BOOT_SPL_DATA[16:]) | |
1110 | self.assertEqual(expected, data) | |
1111 | ||
dd57c13b SG |
1112 | def testPackUnitAddress(self): |
1113 | """Test that we support multiple binaries with the same name""" | |
741f2d62 | 1114 | data = self._DoReadFile('054_unit_address.dts') |
dd57c13b SG |
1115 | self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data) |
1116 | ||
1854695b SG |
1117 | def testSections(self): |
1118 | """Basic test of sections""" | |
741f2d62 | 1119 | data = self._DoReadFile('055_sections.dts') |
8122f396 SG |
1120 | expected = (U_BOOT_DATA + '!' * 12 + U_BOOT_DATA + 'a' * 12 + |
1121 | U_BOOT_DATA + '&' * 4) | |
1854695b | 1122 | self.assertEqual(expected, data) |
9fc60b49 | 1123 | |
3b0c3821 SG |
1124 | def testMap(self): |
1125 | """Tests outputting a map of the images""" | |
741f2d62 | 1126 | _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True) |
1be70d20 SG |
1127 | self.assertEqual('''ImagePos Offset Size Name |
1128 | 00000000 00000000 00000028 main-section | |
1129 | 00000000 00000000 00000010 section@0 | |
1130 | 00000000 00000000 00000004 u-boot | |
1131 | 00000010 00000010 00000010 section@1 | |
1132 | 00000010 00000000 00000004 u-boot | |
1133 | 00000020 00000020 00000004 section@2 | |
1134 | 00000020 00000000 00000004 u-boot | |
3b0c3821 SG |
1135 | ''', map_data) |
1136 | ||
c8d48efb SG |
1137 | def testNamePrefix(self): |
1138 | """Tests that name prefixes are used""" | |
741f2d62 | 1139 | _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True) |
1be70d20 SG |
1140 | self.assertEqual('''ImagePos Offset Size Name |
1141 | 00000000 00000000 00000028 main-section | |
1142 | 00000000 00000000 00000010 section@0 | |
1143 | 00000000 00000000 00000004 ro-u-boot | |
1144 | 00000010 00000010 00000010 section@1 | |
1145 | 00000010 00000000 00000004 rw-u-boot | |
c8d48efb SG |
1146 | ''', map_data) |
1147 | ||
736bb0ae SG |
1148 | def testUnknownContents(self): |
1149 | """Test that obtaining the contents works as expected""" | |
1150 | with self.assertRaises(ValueError) as e: | |
741f2d62 | 1151 | self._DoReadFile('057_unknown_contents.dts', True) |
736bb0ae SG |
1152 | self.assertIn("Section '/binman': Internal error: Could not complete " |
1153 | "processing of contents: remaining [<_testing.Entry__testing ", | |
1154 | str(e.exception)) | |
1155 | ||
5c890238 SG |
1156 | def testBadChangeSize(self): |
1157 | """Test that trying to change the size of an entry fails""" | |
1158 | with self.assertRaises(ValueError) as e: | |
741f2d62 | 1159 | self._DoReadFile('059_change_size.dts', True) |
5c890238 SG |
1160 | self.assertIn("Node '/binman/_testing': Cannot update entry size from " |
1161 | '2 to 1', str(e.exception)) | |
1162 | ||
16b8d6b7 | 1163 | def testUpdateFdt(self): |
3ab9598d | 1164 | """Test that we can update the device tree with offset/size info""" |
741f2d62 | 1165 | _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts', |
16b8d6b7 | 1166 | update_dtb=True) |
cee02e6f SG |
1167 | dtb = fdt.Fdt(out_dtb_fname) |
1168 | dtb.Scan() | |
1169 | props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos']) | |
16b8d6b7 | 1170 | self.assertEqual({ |
dbf6be9f | 1171 | 'image-pos': 0, |
8122f396 | 1172 | 'offset': 0, |
3ab9598d | 1173 | '_testing:offset': 32, |
16b8d6b7 | 1174 | '_testing:size': 1, |
dbf6be9f | 1175 | '_testing:image-pos': 32, |
3ab9598d | 1176 | 'section@0/u-boot:offset': 0, |
16b8d6b7 | 1177 | 'section@0/u-boot:size': len(U_BOOT_DATA), |
dbf6be9f | 1178 | 'section@0/u-boot:image-pos': 0, |
3ab9598d | 1179 | 'section@0:offset': 0, |
16b8d6b7 | 1180 | 'section@0:size': 16, |
dbf6be9f | 1181 | 'section@0:image-pos': 0, |
16b8d6b7 | 1182 | |
3ab9598d | 1183 | 'section@1/u-boot:offset': 0, |
16b8d6b7 | 1184 | 'section@1/u-boot:size': len(U_BOOT_DATA), |
dbf6be9f | 1185 | 'section@1/u-boot:image-pos': 16, |
3ab9598d | 1186 | 'section@1:offset': 16, |
16b8d6b7 | 1187 | 'section@1:size': 16, |
dbf6be9f | 1188 | 'section@1:image-pos': 16, |
16b8d6b7 SG |
1189 | 'size': 40 |
1190 | }, props) | |
1191 | ||
1192 | def testUpdateFdtBad(self): | |
1193 | """Test that we detect when ProcessFdt never completes""" | |
1194 | with self.assertRaises(ValueError) as e: | |
741f2d62 | 1195 | self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True) |
16b8d6b7 SG |
1196 | self.assertIn('Could not complete processing of Fdt: remaining ' |
1197 | '[<_testing.Entry__testing', str(e.exception)) | |
5c890238 | 1198 | |
53af22a9 SG |
1199 | def testEntryArgs(self): |
1200 | """Test passing arguments to entries from the command line""" | |
1201 | entry_args = { | |
1202 | 'test-str-arg': 'test1', | |
1203 | 'test-int-arg': '456', | |
1204 | } | |
741f2d62 | 1205 | self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args) |
53af22a9 SG |
1206 | self.assertIn('image', control.images) |
1207 | entry = control.images['image'].GetEntries()['_testing'] | |
1208 | self.assertEqual('test0', entry.test_str_fdt) | |
1209 | self.assertEqual('test1', entry.test_str_arg) | |
1210 | self.assertEqual(123, entry.test_int_fdt) | |
1211 | self.assertEqual(456, entry.test_int_arg) | |
1212 | ||
1213 | def testEntryArgsMissing(self): | |
1214 | """Test missing arguments and properties""" | |
1215 | entry_args = { | |
1216 | 'test-int-arg': '456', | |
1217 | } | |
741f2d62 | 1218 | self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args) |
53af22a9 SG |
1219 | entry = control.images['image'].GetEntries()['_testing'] |
1220 | self.assertEqual('test0', entry.test_str_fdt) | |
1221 | self.assertEqual(None, entry.test_str_arg) | |
1222 | self.assertEqual(None, entry.test_int_fdt) | |
1223 | self.assertEqual(456, entry.test_int_arg) | |
1224 | ||
1225 | def testEntryArgsRequired(self): | |
1226 | """Test missing arguments and properties""" | |
1227 | entry_args = { | |
1228 | 'test-int-arg': '456', | |
1229 | } | |
1230 | with self.assertRaises(ValueError) as e: | |
741f2d62 | 1231 | self._DoReadFileDtb('064_entry_args_required.dts') |
53af22a9 SG |
1232 | self.assertIn("Node '/binman/_testing': Missing required " |
1233 | 'properties/entry args: test-str-arg, test-int-fdt, test-int-arg', | |
1234 | str(e.exception)) | |
1235 | ||
1236 | def testEntryArgsInvalidFormat(self): | |
1237 | """Test that an invalid entry-argument format is detected""" | |
741f2d62 | 1238 | args = ['-d', self.TestFile('064_entry_args_required.dts'), '-ano-value'] |
53af22a9 SG |
1239 | with self.assertRaises(ValueError) as e: |
1240 | self._DoBinman(*args) | |
1241 | self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception)) | |
1242 | ||
1243 | def testEntryArgsInvalidInteger(self): | |
1244 | """Test that an invalid entry-argument integer is detected""" | |
1245 | entry_args = { | |
1246 | 'test-int-arg': 'abc', | |
1247 | } | |
1248 | with self.assertRaises(ValueError) as e: | |
741f2d62 | 1249 | self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args) |
53af22a9 SG |
1250 | self.assertIn("Node '/binman/_testing': Cannot convert entry arg " |
1251 | "'test-int-arg' (value 'abc') to integer", | |
1252 | str(e.exception)) | |
1253 | ||
1254 | def testEntryArgsInvalidDatatype(self): | |
1255 | """Test that an invalid entry-argument datatype is detected | |
1256 | ||
1257 | This test could be written in entry_test.py except that it needs | |
1258 | access to control.entry_args, which seems more than that module should | |
1259 | be able to see. | |
1260 | """ | |
1261 | entry_args = { | |
1262 | 'test-bad-datatype-arg': '12', | |
1263 | } | |
1264 | with self.assertRaises(ValueError) as e: | |
741f2d62 | 1265 | self._DoReadFileDtb('065_entry_args_unknown_datatype.dts', |
53af22a9 SG |
1266 | entry_args=entry_args) |
1267 | self.assertIn('GetArg() internal error: Unknown data type ', | |
1268 | str(e.exception)) | |
1269 | ||
bb74837c SG |
1270 | def testText(self): |
1271 | """Test for a text entry type""" | |
1272 | entry_args = { | |
1273 | 'test-id': TEXT_DATA, | |
1274 | 'test-id2': TEXT_DATA2, | |
1275 | 'test-id3': TEXT_DATA3, | |
1276 | } | |
741f2d62 | 1277 | data, _, _, _ = self._DoReadFileDtb('066_text.dts', |
bb74837c SG |
1278 | entry_args=entry_args) |
1279 | expected = (TEXT_DATA + chr(0) * (8 - len(TEXT_DATA)) + TEXT_DATA2 + | |
1280 | TEXT_DATA3 + 'some text') | |
1281 | self.assertEqual(expected, data) | |
1282 | ||
fd8d1f79 SG |
1283 | def testEntryDocs(self): |
1284 | """Test for creation of entry documentation""" | |
1285 | with test_util.capture_sys_output() as (stdout, stderr): | |
1286 | control.WriteEntryDocs(binman.GetEntryModules()) | |
1287 | self.assertTrue(len(stdout.getvalue()) > 0) | |
1288 | ||
1289 | def testEntryDocsMissing(self): | |
1290 | """Test handling of missing entry documentation""" | |
1291 | with self.assertRaises(ValueError) as e: | |
1292 | with test_util.capture_sys_output() as (stdout, stderr): | |
1293 | control.WriteEntryDocs(binman.GetEntryModules(), 'u_boot') | |
1294 | self.assertIn('Documentation is missing for modules: u_boot', | |
1295 | str(e.exception)) | |
1296 | ||
11e36cce SG |
1297 | def testFmap(self): |
1298 | """Basic test of generation of a flashrom fmap""" | |
741f2d62 | 1299 | data = self._DoReadFile('067_fmap.dts') |
11e36cce SG |
1300 | fhdr, fentries = fmap_util.DecodeFmap(data[32:]) |
1301 | expected = U_BOOT_DATA + '!' * 12 + U_BOOT_DATA + 'a' * 12 | |
1302 | self.assertEqual(expected, data[:32]) | |
1303 | self.assertEqual('__FMAP__', fhdr.signature) | |
1304 | self.assertEqual(1, fhdr.ver_major) | |
1305 | self.assertEqual(0, fhdr.ver_minor) | |
1306 | self.assertEqual(0, fhdr.base) | |
1307 | self.assertEqual(16 + 16 + | |
1308 | fmap_util.FMAP_HEADER_LEN + | |
1309 | fmap_util.FMAP_AREA_LEN * 3, fhdr.image_size) | |
1310 | self.assertEqual('FMAP', fhdr.name) | |
1311 | self.assertEqual(3, fhdr.nareas) | |
1312 | for fentry in fentries: | |
1313 | self.assertEqual(0, fentry.flags) | |
1314 | ||
1315 | self.assertEqual(0, fentries[0].offset) | |
1316 | self.assertEqual(4, fentries[0].size) | |
1317 | self.assertEqual('RO_U_BOOT', fentries[0].name) | |
1318 | ||
1319 | self.assertEqual(16, fentries[1].offset) | |
1320 | self.assertEqual(4, fentries[1].size) | |
1321 | self.assertEqual('RW_U_BOOT', fentries[1].name) | |
1322 | ||
1323 | self.assertEqual(32, fentries[2].offset) | |
1324 | self.assertEqual(fmap_util.FMAP_HEADER_LEN + | |
1325 | fmap_util.FMAP_AREA_LEN * 3, fentries[2].size) | |
1326 | self.assertEqual('FMAP', fentries[2].name) | |
1327 | ||
ec127af0 SG |
1328 | def testBlobNamedByArg(self): |
1329 | """Test we can add a blob with the filename coming from an entry arg""" | |
1330 | entry_args = { | |
1331 | 'cros-ec-rw-path': 'ecrw.bin', | |
1332 | } | |
741f2d62 | 1333 | data, _, _, _ = self._DoReadFileDtb('068_blob_named_by_arg.dts', |
ec127af0 SG |
1334 | entry_args=entry_args) |
1335 | ||
3af8e49c SG |
1336 | def testFill(self): |
1337 | """Test for an fill entry type""" | |
741f2d62 | 1338 | data = self._DoReadFile('069_fill.dts') |
3af8e49c SG |
1339 | expected = 8 * chr(0xff) + 8 * chr(0) |
1340 | self.assertEqual(expected, data) | |
1341 | ||
1342 | def testFillNoSize(self): | |
1343 | """Test for an fill entry type with no size""" | |
1344 | with self.assertRaises(ValueError) as e: | |
741f2d62 | 1345 | self._DoReadFile('070_fill_no_size.dts') |
3af8e49c SG |
1346 | self.assertIn("'fill' entry must have a size property", |
1347 | str(e.exception)) | |
1348 | ||
0ef87aa3 SG |
1349 | def _HandleGbbCommand(self, pipe_list): |
1350 | """Fake calls to the futility utility""" | |
1351 | if pipe_list[0][0] == 'futility': | |
1352 | fname = pipe_list[0][-1] | |
1353 | # Append our GBB data to the file, which will happen every time the | |
1354 | # futility command is called. | |
1355 | with open(fname, 'a') as fd: | |
1356 | fd.write(GBB_DATA) | |
1357 | return command.CommandResult() | |
1358 | ||
1359 | def testGbb(self): | |
1360 | """Test for the Chromium OS Google Binary Block""" | |
1361 | command.test_result = self._HandleGbbCommand | |
1362 | entry_args = { | |
1363 | 'keydir': 'devkeys', | |
1364 | 'bmpblk': 'bmpblk.bin', | |
1365 | } | |
741f2d62 | 1366 | data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args) |
0ef87aa3 SG |
1367 | |
1368 | # Since futility | |
1369 | expected = GBB_DATA + GBB_DATA + 8 * chr(0) + (0x2180 - 16) * chr(0) | |
1370 | self.assertEqual(expected, data) | |
1371 | ||
1372 | def testGbbTooSmall(self): | |
1373 | """Test for the Chromium OS Google Binary Block being large enough""" | |
1374 | with self.assertRaises(ValueError) as e: | |
741f2d62 | 1375 | self._DoReadFileDtb('072_gbb_too_small.dts') |
0ef87aa3 SG |
1376 | self.assertIn("Node '/binman/gbb': GBB is too small", |
1377 | str(e.exception)) | |
1378 | ||
1379 | def testGbbNoSize(self): | |
1380 | """Test for the Chromium OS Google Binary Block having a size""" | |
1381 | with self.assertRaises(ValueError) as e: | |
741f2d62 | 1382 | self._DoReadFileDtb('073_gbb_no_size.dts') |
0ef87aa3 SG |
1383 | self.assertIn("Node '/binman/gbb': GBB must have a fixed size", |
1384 | str(e.exception)) | |
1385 | ||
24d0d3c3 SG |
1386 | def _HandleVblockCommand(self, pipe_list): |
1387 | """Fake calls to the futility utility""" | |
1388 | if pipe_list[0][0] == 'futility': | |
1389 | fname = pipe_list[0][3] | |
a326b495 | 1390 | with open(fname, 'wb') as fd: |
24d0d3c3 SG |
1391 | fd.write(VBLOCK_DATA) |
1392 | return command.CommandResult() | |
1393 | ||
1394 | def testVblock(self): | |
1395 | """Test for the Chromium OS Verified Boot Block""" | |
1396 | command.test_result = self._HandleVblockCommand | |
1397 | entry_args = { | |
1398 | 'keydir': 'devkeys', | |
1399 | } | |
741f2d62 | 1400 | data, _, _, _ = self._DoReadFileDtb('074_vblock.dts', |
24d0d3c3 SG |
1401 | entry_args=entry_args) |
1402 | expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA | |
1403 | self.assertEqual(expected, data) | |
1404 | ||
1405 | def testVblockNoContent(self): | |
1406 | """Test we detect a vblock which has no content to sign""" | |
1407 | with self.assertRaises(ValueError) as e: | |
741f2d62 | 1408 | self._DoReadFile('075_vblock_no_content.dts') |
24d0d3c3 SG |
1409 | self.assertIn("Node '/binman/vblock': Vblock must have a 'content' " |
1410 | 'property', str(e.exception)) | |
1411 | ||
1412 | def testVblockBadPhandle(self): | |
1413 | """Test that we detect a vblock with an invalid phandle in contents""" | |
1414 | with self.assertRaises(ValueError) as e: | |
741f2d62 | 1415 | self._DoReadFile('076_vblock_bad_phandle.dts') |
24d0d3c3 SG |
1416 | self.assertIn("Node '/binman/vblock': Cannot find node for phandle " |
1417 | '1000', str(e.exception)) | |
1418 | ||
1419 | def testVblockBadEntry(self): | |
1420 | """Test that we detect an entry that points to a non-entry""" | |
1421 | with self.assertRaises(ValueError) as e: | |
741f2d62 | 1422 | self._DoReadFile('077_vblock_bad_entry.dts') |
24d0d3c3 SG |
1423 | self.assertIn("Node '/binman/vblock': Cannot find entry for node " |
1424 | "'other'", str(e.exception)) | |
1425 | ||
b8ef5b6b SG |
1426 | def testTpl(self): |
1427 | """Test that an image with TPL and ots device tree can be created""" | |
1428 | # ELF file with a '__bss_size' symbol | |
1429 | with open(self.TestFile('bss_data')) as fd: | |
1430 | TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read()) | |
741f2d62 | 1431 | data = self._DoReadFile('078_u_boot_tpl.dts') |
b8ef5b6b SG |
1432 | self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data) |
1433 | ||
15a587c9 SG |
1434 | def testUsesPos(self): |
1435 | """Test that the 'pos' property cannot be used anymore""" | |
1436 | with self.assertRaises(ValueError) as e: | |
741f2d62 | 1437 | data = self._DoReadFile('079_uses_pos.dts') |
15a587c9 SG |
1438 | self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of " |
1439 | "'pos'", str(e.exception)) | |
1440 | ||
d178eab8 SG |
1441 | def testFillZero(self): |
1442 | """Test for an fill entry type with a size of 0""" | |
741f2d62 | 1443 | data = self._DoReadFile('080_fill_empty.dts') |
d178eab8 SG |
1444 | self.assertEqual(chr(0) * 16, data) |
1445 | ||
0b489364 SG |
1446 | def testTextMissing(self): |
1447 | """Test for a text entry type where there is no text""" | |
1448 | with self.assertRaises(ValueError) as e: | |
741f2d62 | 1449 | self._DoReadFileDtb('066_text.dts',) |
0b489364 SG |
1450 | self.assertIn("Node '/binman/text': No value provided for text label " |
1451 | "'test-id'", str(e.exception)) | |
1452 | ||
35b384cb SG |
1453 | def testPackStart16Tpl(self): |
1454 | """Test that an image with an x86 start16 TPL region can be created""" | |
741f2d62 | 1455 | data = self._DoReadFile('081_x86-start16-tpl.dts') |
35b384cb SG |
1456 | self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)]) |
1457 | ||
0bfa7b09 SG |
1458 | def testSelectImage(self): |
1459 | """Test that we can select which images to build""" | |
1460 | with test_util.capture_sys_output() as (stdout, stderr): | |
741f2d62 | 1461 | retcode = self._DoTestFile('006_dual_image.dts', images=['image2']) |
0bfa7b09 SG |
1462 | self.assertEqual(0, retcode) |
1463 | self.assertIn('Skipping images: image1', stdout.getvalue()) | |
1464 | ||
1465 | self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin'))) | |
1466 | self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin'))) | |
1467 | ||
6ed45ba0 SG |
1468 | def testUpdateFdtAll(self): |
1469 | """Test that all device trees are updated with offset/size info""" | |
741f2d62 | 1470 | data, _, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts', |
6ed45ba0 SG |
1471 | use_real_dtb=True, update_dtb=True) |
1472 | ||
1473 | base_expected = { | |
1474 | 'section:image-pos': 0, | |
1475 | 'u-boot-tpl-dtb:size': 513, | |
1476 | 'u-boot-spl-dtb:size': 513, | |
1477 | 'u-boot-spl-dtb:offset': 493, | |
1478 | 'image-pos': 0, | |
1479 | 'section/u-boot-dtb:image-pos': 0, | |
1480 | 'u-boot-spl-dtb:image-pos': 493, | |
1481 | 'section/u-boot-dtb:size': 493, | |
1482 | 'u-boot-tpl-dtb:image-pos': 1006, | |
1483 | 'section/u-boot-dtb:offset': 0, | |
1484 | 'section:size': 493, | |
1485 | 'offset': 0, | |
1486 | 'section:offset': 0, | |
1487 | 'u-boot-tpl-dtb:offset': 1006, | |
1488 | 'size': 1519 | |
1489 | } | |
1490 | ||
1491 | # We expect three device-tree files in the output, one after the other. | |
1492 | # Read them in sequence. We look for an 'spl' property in the SPL tree, | |
1493 | # and 'tpl' in the TPL tree, to make sure they are distinct from the | |
1494 | # main U-Boot tree. All three should have the same postions and offset. | |
1495 | start = 0 | |
1496 | for item in ['', 'spl', 'tpl']: | |
1497 | dtb = fdt.Fdt.FromData(data[start:]) | |
1498 | dtb.Scan() | |
1499 | props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos', | |
1500 | 'spl', 'tpl']) | |
1501 | expected = dict(base_expected) | |
1502 | if item: | |
1503 | expected[item] = 0 | |
1504 | self.assertEqual(expected, props) | |
1505 | start += dtb._fdt_obj.totalsize() | |
1506 | ||
1507 | def testUpdateFdtOutput(self): | |
1508 | """Test that output DTB files are updated""" | |
1509 | try: | |
741f2d62 | 1510 | data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts', |
6ed45ba0 SG |
1511 | use_real_dtb=True, update_dtb=True, reset_dtbs=False) |
1512 | ||
1513 | # Unfortunately, compiling a source file always results in a file | |
1514 | # called source.dtb (see fdt_util.EnsureCompiled()). The test | |
741f2d62 | 1515 | # source file (e.g. test/075_fdt_update_all.dts) thus does not enter |
6ed45ba0 SG |
1516 | # binman as a file called u-boot.dtb. To fix this, copy the file |
1517 | # over to the expected place. | |
1518 | #tools.WriteFile(os.path.join(self._indir, 'u-boot.dtb'), | |
1519 | #tools.ReadFile(tools.GetOutputFilename('source.dtb'))) | |
1520 | start = 0 | |
1521 | for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out', | |
1522 | 'tpl/u-boot-tpl.dtb.out']: | |
1523 | dtb = fdt.Fdt.FromData(data[start:]) | |
1524 | size = dtb._fdt_obj.totalsize() | |
1525 | pathname = tools.GetOutputFilename(os.path.split(fname)[1]) | |
1526 | outdata = tools.ReadFile(pathname) | |
1527 | name = os.path.split(fname)[0] | |
1528 | ||
1529 | if name: | |
1530 | orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name) | |
1531 | else: | |
1532 | orig_indata = dtb_data | |
1533 | self.assertNotEqual(outdata, orig_indata, | |
1534 | "Expected output file '%s' be updated" % pathname) | |
1535 | self.assertEqual(outdata, data[start:start + size], | |
1536 | "Expected output file '%s' to match output image" % | |
1537 | pathname) | |
1538 | start += size | |
1539 | finally: | |
1540 | self._ResetDtbs() | |
1541 | ||
83d73c2f SG |
1542 | def _decompress(self, data): |
1543 | out = os.path.join(self._indir, 'lz4.tmp') | |
1544 | with open(out, 'wb') as fd: | |
1545 | fd.write(data) | |
1546 | return tools.Run('lz4', '-dc', out) | |
1547 | ''' | |
1548 | try: | |
1549 | orig = lz4.frame.decompress(data) | |
1550 | except AttributeError: | |
1551 | orig = lz4.decompress(data) | |
1552 | ''' | |
1553 | ||
1554 | def testCompress(self): | |
1555 | """Test compression of blobs""" | |
741f2d62 | 1556 | data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts', |
83d73c2f SG |
1557 | use_real_dtb=True, update_dtb=True) |
1558 | dtb = fdt.Fdt(out_dtb_fname) | |
1559 | dtb.Scan() | |
1560 | props = self._GetPropTree(dtb, ['size', 'uncomp-size']) | |
1561 | orig = self._decompress(data) | |
1562 | self.assertEquals(COMPRESS_DATA, orig) | |
1563 | expected = { | |
1564 | 'blob:uncomp-size': len(COMPRESS_DATA), | |
1565 | 'blob:size': len(data), | |
1566 | 'size': len(data), | |
1567 | } | |
1568 | self.assertEqual(expected, props) | |
1569 | ||
0a98b28b SG |
1570 | def testFiles(self): |
1571 | """Test bringing in multiple files""" | |
741f2d62 | 1572 | data = self._DoReadFile('084_files.dts') |
0a98b28b SG |
1573 | self.assertEqual(FILES_DATA, data) |
1574 | ||
1575 | def testFilesCompress(self): | |
1576 | """Test bringing in multiple files and compressing them""" | |
741f2d62 | 1577 | data = self._DoReadFile('085_files_compress.dts') |
0a98b28b SG |
1578 | |
1579 | image = control.images['image'] | |
1580 | entries = image.GetEntries() | |
1581 | files = entries['files'] | |
1582 | entries = files._section._entries | |
1583 | ||
1584 | orig = '' | |
1585 | for i in range(1, 3): | |
1586 | key = '%d.dat' % i | |
1587 | start = entries[key].image_pos | |
1588 | len = entries[key].size | |
1589 | chunk = data[start:start + len] | |
1590 | orig += self._decompress(chunk) | |
1591 | ||
1592 | self.assertEqual(FILES_DATA, orig) | |
1593 | ||
1594 | def testFilesMissing(self): | |
1595 | """Test missing files""" | |
1596 | with self.assertRaises(ValueError) as e: | |
741f2d62 | 1597 | data = self._DoReadFile('086_files_none.dts') |
0a98b28b SG |
1598 | self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched " |
1599 | 'no files', str(e.exception)) | |
1600 | ||
1601 | def testFilesNoPattern(self): | |
1602 | """Test missing files""" | |
1603 | with self.assertRaises(ValueError) as e: | |
741f2d62 | 1604 | data = self._DoReadFile('087_files_no_pattern.dts') |
0a98b28b SG |
1605 | self.assertIn("Node '/binman/files': Missing 'pattern' property", |
1606 | str(e.exception)) | |
1607 | ||
ba64a0bb SG |
1608 | def testExpandSize(self): |
1609 | """Test an expanding entry""" | |
741f2d62 | 1610 | data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts', |
ba64a0bb SG |
1611 | map=True) |
1612 | expect = ('a' * 8 + U_BOOT_DATA + | |
1613 | MRC_DATA + 'b' * 1 + U_BOOT_DATA + | |
1614 | 'c' * 8 + U_BOOT_DATA + | |
1615 | 'd' * 8) | |
1616 | self.assertEqual(expect, data) | |
1617 | self.assertEqual('''ImagePos Offset Size Name | |
1618 | 00000000 00000000 00000028 main-section | |
1619 | 00000000 00000000 00000008 fill | |
1620 | 00000008 00000008 00000004 u-boot | |
1621 | 0000000c 0000000c 00000004 section | |
1622 | 0000000c 00000000 00000003 intel-mrc | |
1623 | 00000010 00000010 00000004 u-boot2 | |
1624 | 00000014 00000014 0000000c section2 | |
1625 | 00000014 00000000 00000008 fill | |
1626 | 0000001c 00000008 00000004 u-boot | |
1627 | 00000020 00000020 00000008 fill2 | |
1628 | ''', map_data) | |
1629 | ||
1630 | def testExpandSizeBad(self): | |
1631 | """Test an expanding entry which fails to provide contents""" | |
163ed6c3 SG |
1632 | with test_util.capture_sys_output() as (stdout, stderr): |
1633 | with self.assertRaises(ValueError) as e: | |
741f2d62 | 1634 | self._DoReadFileDtb('089_expand_size_bad.dts', map=True) |
ba64a0bb SG |
1635 | self.assertIn("Node '/binman/_testing': Cannot obtain contents when " |
1636 | 'expanding entry', str(e.exception)) | |
1637 | ||
e0e5df93 SG |
1638 | def testHash(self): |
1639 | """Test hashing of the contents of an entry""" | |
741f2d62 | 1640 | _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts', |
e0e5df93 SG |
1641 | use_real_dtb=True, update_dtb=True) |
1642 | dtb = fdt.Fdt(out_dtb_fname) | |
1643 | dtb.Scan() | |
1644 | hash_node = dtb.GetNode('/binman/u-boot/hash').props['value'] | |
1645 | m = hashlib.sha256() | |
1646 | m.update(U_BOOT_DATA) | |
1647 | self.assertEqual(m.digest(), ''.join(hash_node.value)) | |
1648 | ||
1649 | def testHashNoAlgo(self): | |
1650 | with self.assertRaises(ValueError) as e: | |
741f2d62 | 1651 | self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True) |
e0e5df93 SG |
1652 | self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for " |
1653 | 'hash node', str(e.exception)) | |
1654 | ||
1655 | def testHashBadAlgo(self): | |
1656 | with self.assertRaises(ValueError) as e: | |
741f2d62 | 1657 | self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True) |
e0e5df93 SG |
1658 | self.assertIn("Node '/binman/u-boot': Unknown hash algorithm", |
1659 | str(e.exception)) | |
1660 | ||
1661 | def testHashSection(self): | |
1662 | """Test hashing of the contents of an entry""" | |
741f2d62 | 1663 | _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts', |
e0e5df93 SG |
1664 | use_real_dtb=True, update_dtb=True) |
1665 | dtb = fdt.Fdt(out_dtb_fname) | |
1666 | dtb.Scan() | |
1667 | hash_node = dtb.GetNode('/binman/section/hash').props['value'] | |
1668 | m = hashlib.sha256() | |
1669 | m.update(U_BOOT_DATA) | |
1670 | m.update(16 * 'a') | |
1671 | self.assertEqual(m.digest(), ''.join(hash_node.value)) | |
1672 | ||
f0253635 SG |
1673 | def testPackUBootTplMicrocode(self): |
1674 | """Test that x86 microcode can be handled correctly in TPL | |
1675 | ||
1676 | We expect to see the following in the image, in order: | |
1677 | u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct | |
1678 | place | |
1679 | u-boot-tpl.dtb with the microcode removed | |
1680 | the microcode | |
1681 | """ | |
1682 | with open(self.TestFile('u_boot_ucode_ptr')) as fd: | |
1683 | TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read()) | |
741f2d62 | 1684 | first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts', |
f0253635 SG |
1685 | U_BOOT_TPL_NODTB_DATA) |
1686 | self.assertEqual('tplnodtb with microc' + pos_and_size + | |
1687 | 'ter somewhere in here', first) | |
1688 | ||
f8f8df6e SG |
1689 | def testFmapX86(self): |
1690 | """Basic test of generation of a flashrom fmap""" | |
741f2d62 | 1691 | data = self._DoReadFile('094_fmap_x86.dts') |
f8f8df6e SG |
1692 | fhdr, fentries = fmap_util.DecodeFmap(data[32:]) |
1693 | expected = U_BOOT_DATA + MRC_DATA + 'a' * (32 - 7) | |
1694 | self.assertEqual(expected, data[:32]) | |
1695 | fhdr, fentries = fmap_util.DecodeFmap(data[32:]) | |
1696 | ||
1697 | self.assertEqual(0x100, fhdr.image_size) | |
1698 | ||
1699 | self.assertEqual(0, fentries[0].offset) | |
1700 | self.assertEqual(4, fentries[0].size) | |
1701 | self.assertEqual('U_BOOT', fentries[0].name) | |
1702 | ||
1703 | self.assertEqual(4, fentries[1].offset) | |
1704 | self.assertEqual(3, fentries[1].size) | |
1705 | self.assertEqual('INTEL_MRC', fentries[1].name) | |
1706 | ||
1707 | self.assertEqual(32, fentries[2].offset) | |
1708 | self.assertEqual(fmap_util.FMAP_HEADER_LEN + | |
1709 | fmap_util.FMAP_AREA_LEN * 3, fentries[2].size) | |
1710 | self.assertEqual('FMAP', fentries[2].name) | |
1711 | ||
1712 | def testFmapX86Section(self): | |
1713 | """Basic test of generation of a flashrom fmap""" | |
741f2d62 | 1714 | data = self._DoReadFile('095_fmap_x86_section.dts') |
f8f8df6e SG |
1715 | expected = U_BOOT_DATA + MRC_DATA + 'b' * (32 - 7) |
1716 | self.assertEqual(expected, data[:32]) | |
1717 | fhdr, fentries = fmap_util.DecodeFmap(data[36:]) | |
1718 | ||
1719 | self.assertEqual(0x100, fhdr.image_size) | |
1720 | ||
1721 | self.assertEqual(0, fentries[0].offset) | |
1722 | self.assertEqual(4, fentries[0].size) | |
1723 | self.assertEqual('U_BOOT', fentries[0].name) | |
1724 | ||
1725 | self.assertEqual(4, fentries[1].offset) | |
1726 | self.assertEqual(3, fentries[1].size) | |
1727 | self.assertEqual('INTEL_MRC', fentries[1].name) | |
1728 | ||
1729 | self.assertEqual(36, fentries[2].offset) | |
1730 | self.assertEqual(fmap_util.FMAP_HEADER_LEN + | |
1731 | fmap_util.FMAP_AREA_LEN * 3, fentries[2].size) | |
1732 | self.assertEqual('FMAP', fentries[2].name) | |
1733 | ||
fe1ae3ec SG |
1734 | def testElf(self): |
1735 | """Basic test of ELF entries""" | |
11ae93ee | 1736 | self._SetupSplElf() |
fe1ae3ec SG |
1737 | with open(self.TestFile('bss_data')) as fd: |
1738 | TestFunctional._MakeInputFile('-boot', fd.read()) | |
741f2d62 | 1739 | data = self._DoReadFile('096_elf.dts') |
fe1ae3ec SG |
1740 | |
1741 | def testElfStripg(self): | |
1742 | """Basic test of ELF entries""" | |
11ae93ee | 1743 | self._SetupSplElf() |
fe1ae3ec SG |
1744 | with open(self.TestFile('bss_data')) as fd: |
1745 | TestFunctional._MakeInputFile('-boot', fd.read()) | |
741f2d62 | 1746 | data = self._DoReadFile('097_elf_strip.dts') |
fe1ae3ec | 1747 | |
163ed6c3 SG |
1748 | def testPackOverlapMap(self): |
1749 | """Test that overlapping regions are detected""" | |
1750 | with test_util.capture_sys_output() as (stdout, stderr): | |
1751 | with self.assertRaises(ValueError) as e: | |
741f2d62 | 1752 | self._DoTestFile('014_pack_overlap.dts', map=True) |
163ed6c3 SG |
1753 | map_fname = tools.GetOutputFilename('image.map') |
1754 | self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname, | |
1755 | stdout.getvalue()) | |
1756 | ||
1757 | # We should not get an inmage, but there should be a map file | |
1758 | self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin'))) | |
1759 | self.assertTrue(os.path.exists(map_fname)) | |
1760 | map_data = tools.ReadFile(map_fname) | |
1761 | self.assertEqual('''ImagePos Offset Size Name | |
1762 | <none> 00000000 00000007 main-section | |
1763 | <none> 00000000 00000004 u-boot | |
1764 | <none> 00000003 00000004 u-boot-align | |
1765 | ''', map_data) | |
1766 | ||
53af22a9 | 1767 | |
9fc60b49 SG |
1768 | if __name__ == "__main__": |
1769 | unittest.main() |