diff options
Diffstat (limited to 'meta/lib/oeqa/selftest/cases/fitimage.py')
-rw-r--r-- | meta/lib/oeqa/selftest/cases/fitimage.py | 537 |
1 files changed, 509 insertions, 28 deletions
diff --git a/meta/lib/oeqa/selftest/cases/fitimage.py b/meta/lib/oeqa/selftest/cases/fitimage.py index 02692de822..347c065377 100644 --- a/meta/lib/oeqa/selftest/cases/fitimage.py +++ b/meta/lib/oeqa/selftest/cases/fitimage.py | |||
@@ -1,11 +1,12 @@ | |||
1 | # | 1 | # |
2 | # Copyright OpenEmbedded Contributors | ||
3 | # | ||
2 | # SPDX-License-Identifier: MIT | 4 | # SPDX-License-Identifier: MIT |
3 | # | 5 | # |
4 | 6 | ||
5 | from oeqa.selftest.case import OESelftestTestCase | 7 | from oeqa.selftest.case import OESelftestTestCase |
6 | from oeqa.utils.commands import runCmd, bitbake, get_bb_var, runqemu | 8 | from oeqa.utils.commands import runCmd, bitbake, get_bb_var, get_bb_vars |
7 | import os | 9 | import os |
8 | import json | ||
9 | import re | 10 | import re |
10 | 11 | ||
11 | class FitImageTests(OESelftestTestCase): | 12 | class FitImageTests(OESelftestTestCase): |
@@ -32,6 +33,8 @@ KERNEL_CLASSES = " kernel-fitimage " | |||
32 | # RAM disk variables including load address and entrypoint for kernel and RAM disk | 33 | # RAM disk variables including load address and entrypoint for kernel and RAM disk |
33 | IMAGE_FSTYPES += "cpio.gz" | 34 | IMAGE_FSTYPES += "cpio.gz" |
34 | INITRAMFS_IMAGE = "core-image-minimal" | 35 | INITRAMFS_IMAGE = "core-image-minimal" |
36 | # core-image-minimal is used as initramfs here, drop the rootfs suffix | ||
37 | IMAGE_NAME_SUFFIX:pn-core-image-minimal = "" | ||
35 | UBOOT_RD_LOADADDRESS = "0x88000000" | 38 | UBOOT_RD_LOADADDRESS = "0x88000000" |
36 | UBOOT_RD_ENTRYPOINT = "0x88000000" | 39 | UBOOT_RD_ENTRYPOINT = "0x88000000" |
37 | UBOOT_LOADADDRESS = "0x80080000" | 40 | UBOOT_LOADADDRESS = "0x80080000" |
@@ -41,15 +44,14 @@ FIT_DESC = "A model description" | |||
41 | self.write_config(config) | 44 | self.write_config(config) |
42 | 45 | ||
43 | # fitImage is created as part of linux recipe | 46 | # fitImage is created as part of linux recipe |
44 | bitbake("virtual/kernel") | 47 | image = "virtual/kernel" |
48 | bitbake(image) | ||
49 | bb_vars = get_bb_vars(['DEPLOY_DIR_IMAGE', 'INITRAMFS_IMAGE_NAME', 'KERNEL_FIT_LINK_NAME'], image) | ||
45 | 50 | ||
46 | image_type = "core-image-minimal" | 51 | fitimage_its_path = os.path.join(bb_vars['DEPLOY_DIR_IMAGE'], |
47 | deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE') | 52 | "fitImage-its-%s-%s" % (bb_vars['INITRAMFS_IMAGE_NAME'], bb_vars['KERNEL_FIT_LINK_NAME'])) |
48 | machine = get_bb_var('MACHINE') | 53 | fitimage_path = os.path.join(bb_vars['DEPLOY_DIR_IMAGE'], |
49 | fitimage_its_path = os.path.join(deploy_dir_image, | 54 | "fitImage-%s-%s" % (bb_vars['INITRAMFS_IMAGE_NAME'], bb_vars['KERNEL_FIT_LINK_NAME'])) |
50 | "fitImage-its-%s-%s-%s" % (image_type, machine, machine)) | ||
51 | fitimage_path = os.path.join(deploy_dir_image, | ||
52 | "fitImage-%s-%s-%s" % (image_type, machine, machine)) | ||
53 | 55 | ||
54 | self.assertTrue(os.path.exists(fitimage_its_path), | 56 | self.assertTrue(os.path.exists(fitimage_its_path), |
55 | "%s image tree source doesn't exist" % (fitimage_its_path)) | 57 | "%s image tree source doesn't exist" % (fitimage_its_path)) |
@@ -114,22 +116,22 @@ KERNEL_CLASSES = " kernel-fitimage test-mkimage-wrapper " | |||
114 | UBOOT_SIGN_ENABLE = "1" | 116 | UBOOT_SIGN_ENABLE = "1" |
115 | FIT_GENERATE_KEYS = "1" | 117 | FIT_GENERATE_KEYS = "1" |
116 | UBOOT_SIGN_KEYDIR = "${TOPDIR}/signing-keys" | 118 | UBOOT_SIGN_KEYDIR = "${TOPDIR}/signing-keys" |
117 | UBOOT_SIGN_KEYNAME = "oe-selftest" | 119 | UBOOT_SIGN_IMG_KEYNAME = "img-oe-selftest" |
120 | UBOOT_SIGN_KEYNAME = "cfg-oe-selftest" | ||
118 | FIT_SIGN_INDIVIDUAL = "1" | 121 | FIT_SIGN_INDIVIDUAL = "1" |
119 | UBOOT_MKIMAGE_SIGN_ARGS = "-c 'a smart comment'" | 122 | UBOOT_MKIMAGE_SIGN_ARGS = "-c 'a smart comment'" |
120 | """ | 123 | """ |
121 | self.write_config(config) | 124 | self.write_config(config) |
122 | 125 | ||
123 | # fitImage is created as part of linux recipe | 126 | # fitImage is created as part of linux recipe |
124 | bitbake("virtual/kernel") | 127 | image = "virtual/kernel" |
128 | bitbake(image) | ||
129 | bb_vars = get_bb_vars(['DEPLOY_DIR_IMAGE', 'KERNEL_FIT_LINK_NAME'], image) | ||
125 | 130 | ||
126 | image_type = "core-image-minimal" | 131 | fitimage_its_path = os.path.join(bb_vars['DEPLOY_DIR_IMAGE'], |
127 | deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE') | 132 | "fitImage-its-%s" % (bb_vars['KERNEL_FIT_LINK_NAME'])) |
128 | machine = get_bb_var('MACHINE') | 133 | fitimage_path = os.path.join(bb_vars['DEPLOY_DIR_IMAGE'], |
129 | fitimage_its_path = os.path.join(deploy_dir_image, | 134 | "fitImage-%s.bin" % (bb_vars['KERNEL_FIT_LINK_NAME'])) |
130 | "fitImage-its-%s" % (machine,)) | ||
131 | fitimage_path = os.path.join(deploy_dir_image, | ||
132 | "fitImage-%s.bin" % (machine,)) | ||
133 | 135 | ||
134 | self.assertTrue(os.path.exists(fitimage_its_path), | 136 | self.assertTrue(os.path.exists(fitimage_its_path), |
135 | "%s image tree source doesn't exist" % (fitimage_its_path)) | 137 | "%s image tree source doesn't exist" % (fitimage_its_path)) |
@@ -173,11 +175,11 @@ UBOOT_MKIMAGE_SIGN_ARGS = "-c 'a smart comment'" | |||
173 | 175 | ||
174 | reqsigvalues_image = { | 176 | reqsigvalues_image = { |
175 | 'algo': '"sha256,rsa2048"', | 177 | 'algo': '"sha256,rsa2048"', |
176 | 'key-name-hint': '"oe-selftest"', | 178 | 'key-name-hint': '"img-oe-selftest"', |
177 | } | 179 | } |
178 | reqsigvalues_config = { | 180 | reqsigvalues_config = { |
179 | 'algo': '"sha256,rsa2048"', | 181 | 'algo': '"sha256,rsa2048"', |
180 | 'key-name-hint': '"oe-selftest"', | 182 | 'key-name-hint': '"cfg-oe-selftest"', |
181 | 'sign-images': '"kernel", "fdt"', | 183 | 'sign-images': '"kernel", "fdt"', |
182 | } | 184 | } |
183 | 185 | ||
@@ -202,7 +204,7 @@ UBOOT_MKIMAGE_SIGN_ARGS = "-c 'a smart comment'" | |||
202 | signed_sections = {} | 204 | signed_sections = {} |
203 | for line in result.output.splitlines(): | 205 | for line in result.output.splitlines(): |
204 | if line.startswith((' Configuration', ' Image')): | 206 | if line.startswith((' Configuration', ' Image')): |
205 | in_signed = re.search('\((.*)\)', line).groups()[0] | 207 | in_signed = re.search(r'\((.*)\)', line).groups()[0] |
206 | elif re.match('^ *', line) in (' ', ''): | 208 | elif re.match('^ *', line) in (' ', ''): |
207 | in_signed = None | 209 | in_signed = None |
208 | elif in_signed: | 210 | elif in_signed: |
@@ -215,7 +217,10 @@ UBOOT_MKIMAGE_SIGN_ARGS = "-c 'a smart comment'" | |||
215 | self.assertIn('conf-am335x-boneblack.dtb', signed_sections) | 217 | self.assertIn('conf-am335x-boneblack.dtb', signed_sections) |
216 | for signed_section, values in signed_sections.items(): | 218 | for signed_section, values in signed_sections.items(): |
217 | value = values.get('Sign algo', None) | 219 | value = values.get('Sign algo', None) |
218 | self.assertEqual(value, 'sha256,rsa2048:oe-selftest', 'Signature algorithm for %s not expected value' % signed_section) | 220 | if signed_section.startswith("conf"): |
221 | self.assertEqual(value, 'sha256,rsa2048:cfg-oe-selftest', 'Signature algorithm for %s not expected value' % signed_section) | ||
222 | else: | ||
223 | self.assertEqual(value, 'sha256,rsa2048:img-oe-selftest', 'Signature algorithm for %s not expected value' % signed_section) | ||
219 | value = values.get('Sign value', None) | 224 | value = values.get('Sign value', None) |
220 | self.assertEqual(len(value), 512, 'Signature value for section %s not expected length' % signed_section) | 225 | self.assertEqual(len(value), 512, 'Signature value for section %s not expected length' % signed_section) |
221 | 226 | ||
@@ -231,6 +236,480 @@ UBOOT_MKIMAGE_SIGN_ARGS = "-c 'a smart comment'" | |||
231 | result = runCmd('grep "### uboot-mkimage signing wrapper message" %s/log.do_assemble_fitimage' % tempdir, ignore_status=True) | 236 | result = runCmd('grep "### uboot-mkimage signing wrapper message" %s/log.do_assemble_fitimage' % tempdir, ignore_status=True) |
232 | self.assertEqual(result.status, 0, 'UBOOT_MKIMAGE_SIGN did not work') | 237 | self.assertEqual(result.status, 0, 'UBOOT_MKIMAGE_SIGN did not work') |
233 | 238 | ||
239 | def test_uboot_fit_image(self): | ||
240 | """ | ||
241 | Summary: Check if Uboot FIT image and Image Tree Source | ||
242 | (its) are built and the Image Tree Source has the | ||
243 | correct fields. | ||
244 | Expected: 1. u-boot-fitImage and u-boot-its can be built | ||
245 | 2. The type, load address, entrypoint address and | ||
246 | default values of U-boot image are correct in the | ||
247 | Image Tree Source. Not all the fields are tested, | ||
248 | only the key fields that wont vary between | ||
249 | different architectures. | ||
250 | Product: oe-core | ||
251 | Author: Klaus Heinrich Kiwi <klaus@linux.vnet.ibm.com> | ||
252 | based on work by Usama Arif <usama.arif@arm.com> | ||
253 | """ | ||
254 | config = """ | ||
255 | # We need at least CONFIG_SPL_LOAD_FIT and CONFIG_SPL_OF_CONTROL set | ||
256 | MACHINE = "qemuarm" | ||
257 | UBOOT_MACHINE = "am57xx_evm_defconfig" | ||
258 | SPL_BINARY = "MLO" | ||
259 | |||
260 | # Enable creation of the U-Boot fitImage | ||
261 | UBOOT_FITIMAGE_ENABLE = "1" | ||
262 | |||
263 | # (U-boot) fitImage properties | ||
264 | UBOOT_LOADADDRESS = "0x80080000" | ||
265 | UBOOT_ENTRYPOINT = "0x80080000" | ||
266 | UBOOT_FIT_DESC = "A model description" | ||
267 | |||
268 | # Enable creation of Kernel fitImage | ||
269 | KERNEL_IMAGETYPES += " fitImage " | ||
270 | KERNEL_CLASSES = " kernel-fitimage" | ||
271 | UBOOT_SIGN_ENABLE = "1" | ||
272 | FIT_GENERATE_KEYS = "1" | ||
273 | UBOOT_SIGN_KEYDIR = "${TOPDIR}/signing-keys" | ||
274 | UBOOT_SIGN_IMG_KEYNAME = "img-oe-selftest" | ||
275 | UBOOT_SIGN_KEYNAME = "cfg-oe-selftest" | ||
276 | FIT_SIGN_INDIVIDUAL = "1" | ||
277 | """ | ||
278 | self.write_config(config) | ||
279 | |||
280 | # The U-Boot fitImage is created as part of the U-Boot recipe | ||
281 | bitbake("virtual/bootloader") | ||
282 | |||
283 | deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE') | ||
284 | machine = get_bb_var('MACHINE') | ||
285 | fitimage_its_path = os.path.join(deploy_dir_image, | ||
286 | "u-boot-its-%s" % (machine,)) | ||
287 | fitimage_path = os.path.join(deploy_dir_image, | ||
288 | "u-boot-fitImage-%s" % (machine,)) | ||
289 | |||
290 | self.assertTrue(os.path.exists(fitimage_its_path), | ||
291 | "%s image tree source doesn't exist" % (fitimage_its_path)) | ||
292 | self.assertTrue(os.path.exists(fitimage_path), | ||
293 | "%s FIT image doesn't exist" % (fitimage_path)) | ||
294 | |||
295 | # Check that the type, load address, entrypoint address and default | ||
296 | # values for kernel and ramdisk in Image Tree Source are as expected. | ||
297 | # The order of fields in the below array is important. Not all the | ||
298 | # fields are tested, only the key fields that wont vary between | ||
299 | # different architectures. | ||
300 | its_field_check = [ | ||
301 | 'description = "A model description";', | ||
302 | 'type = "standalone";', | ||
303 | 'load = <0x80080000>;', | ||
304 | 'entry = <0x80080000>;', | ||
305 | 'default = "conf";', | ||
306 | 'loadables = "uboot";', | ||
307 | 'fdt = "fdt";' | ||
308 | ] | ||
309 | |||
310 | with open(fitimage_its_path) as its_file: | ||
311 | field_index = 0 | ||
312 | for line in its_file: | ||
313 | if field_index == len(its_field_check): | ||
314 | break | ||
315 | if its_field_check[field_index] in line: | ||
316 | field_index +=1 | ||
317 | |||
318 | if field_index != len(its_field_check): # if its equal, the test passed | ||
319 | self.assertTrue(field_index == len(its_field_check), | ||
320 | "Fields in Image Tree Source File %s did not match, error in finding %s" | ||
321 | % (fitimage_its_path, its_field_check[field_index])) | ||
322 | |||
323 | def test_uboot_sign_fit_image(self): | ||
324 | """ | ||
325 | Summary: Check if Uboot FIT image and Image Tree Source | ||
326 | (its) are built and the Image Tree Source has the | ||
327 | correct fields, in the scenario where the Kernel | ||
328 | is also creating/signing it's fitImage. | ||
329 | Expected: 1. u-boot-fitImage and u-boot-its can be built | ||
330 | 2. The type, load address, entrypoint address and | ||
331 | default values of U-boot image are correct in the | ||
332 | Image Tree Source. Not all the fields are tested, | ||
333 | only the key fields that wont vary between | ||
334 | different architectures. | ||
335 | Product: oe-core | ||
336 | Author: Klaus Heinrich Kiwi <klaus@linux.vnet.ibm.com> | ||
337 | based on work by Usama Arif <usama.arif@arm.com> | ||
338 | """ | ||
339 | config = """ | ||
340 | # We need at least CONFIG_SPL_LOAD_FIT and CONFIG_SPL_OF_CONTROL set | ||
341 | MACHINE = "qemuarm" | ||
342 | UBOOT_MACHINE = "am57xx_evm_defconfig" | ||
343 | SPL_BINARY = "MLO" | ||
344 | |||
345 | # Enable creation of the U-Boot fitImage | ||
346 | UBOOT_FITIMAGE_ENABLE = "1" | ||
347 | |||
348 | # (U-boot) fitImage properties | ||
349 | UBOOT_LOADADDRESS = "0x80080000" | ||
350 | UBOOT_ENTRYPOINT = "0x80080000" | ||
351 | UBOOT_FIT_DESC = "A model description" | ||
352 | KERNEL_IMAGETYPES += " fitImage " | ||
353 | KERNEL_CLASSES = " kernel-fitimage " | ||
354 | INHERIT += "test-mkimage-wrapper" | ||
355 | UBOOT_SIGN_ENABLE = "1" | ||
356 | FIT_GENERATE_KEYS = "1" | ||
357 | UBOOT_SIGN_KEYDIR = "${TOPDIR}/signing-keys" | ||
358 | UBOOT_SIGN_IMG_KEYNAME = "img-oe-selftest" | ||
359 | UBOOT_SIGN_KEYNAME = "cfg-oe-selftest" | ||
360 | FIT_SIGN_INDIVIDUAL = "1" | ||
361 | UBOOT_MKIMAGE_SIGN_ARGS = "-c 'a smart U-Boot comment'" | ||
362 | """ | ||
363 | self.write_config(config) | ||
364 | |||
365 | # The U-Boot fitImage is created as part of the U-Boot recipe | ||
366 | bitbake("virtual/bootloader") | ||
367 | |||
368 | deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE') | ||
369 | machine = get_bb_var('MACHINE') | ||
370 | fitimage_its_path = os.path.join(deploy_dir_image, | ||
371 | "u-boot-its-%s" % (machine,)) | ||
372 | fitimage_path = os.path.join(deploy_dir_image, | ||
373 | "u-boot-fitImage-%s" % (machine,)) | ||
374 | |||
375 | self.assertTrue(os.path.exists(fitimage_its_path), | ||
376 | "%s image tree source doesn't exist" % (fitimage_its_path)) | ||
377 | self.assertTrue(os.path.exists(fitimage_path), | ||
378 | "%s FIT image doesn't exist" % (fitimage_path)) | ||
379 | |||
380 | # Check that the type, load address, entrypoint address and default | ||
381 | # values for kernel and ramdisk in Image Tree Source are as expected. | ||
382 | # The order of fields in the below array is important. Not all the | ||
383 | # fields are tested, only the key fields that wont vary between | ||
384 | # different architectures. | ||
385 | its_field_check = [ | ||
386 | 'description = "A model description";', | ||
387 | 'type = "standalone";', | ||
388 | 'load = <0x80080000>;', | ||
389 | 'entry = <0x80080000>;', | ||
390 | 'default = "conf";', | ||
391 | 'loadables = "uboot";', | ||
392 | 'fdt = "fdt";' | ||
393 | ] | ||
394 | |||
395 | with open(fitimage_its_path) as its_file: | ||
396 | field_index = 0 | ||
397 | for line in its_file: | ||
398 | if field_index == len(its_field_check): | ||
399 | break | ||
400 | if its_field_check[field_index] in line: | ||
401 | field_index +=1 | ||
402 | |||
403 | if field_index != len(its_field_check): # if its equal, the test passed | ||
404 | self.assertTrue(field_index == len(its_field_check), | ||
405 | "Fields in Image Tree Source File %s did not match, error in finding %s" | ||
406 | % (fitimage_its_path, its_field_check[field_index])) | ||
407 | |||
408 | |||
409 | def test_sign_standalone_uboot_fit_image(self): | ||
410 | """ | ||
411 | Summary: Check if U-Boot FIT image and Image Tree Source (its) are | ||
412 | created and signed correctly for the scenario where only | ||
413 | the U-Boot proper fitImage is being created and signed. | ||
414 | Expected: 1) U-Boot its and FIT image are built successfully | ||
415 | 2) Scanning the its file indicates signing is enabled | ||
416 | as requested by SPL_SIGN_ENABLE (using keys generated | ||
417 | via UBOOT_FIT_GENERATE_KEYS) | ||
418 | 3) Dumping the FIT image indicates signature values | ||
419 | are present | ||
420 | 4) Examination of the do_uboot_assemble_fitimage | ||
421 | runfile/logfile indicate that UBOOT_MKIMAGE, UBOOT_MKIMAGE_SIGN | ||
422 | and SPL_MKIMAGE_SIGN_ARGS are working as expected. | ||
423 | Product: oe-core | ||
424 | Author: Klaus Heinrich Kiwi <klaus@linux.vnet.ibm.com> based upon | ||
425 | work by Paul Eggleton <paul.eggleton@microsoft.com> and | ||
426 | Usama Arif <usama.arif@arm.com> | ||
427 | """ | ||
428 | config = """ | ||
429 | # There's no U-boot deconfig with CONFIG_FIT_SIGNATURE yet, so we need at | ||
430 | # least CONFIG_SPL_LOAD_FIT and CONFIG_SPL_OF_CONTROL set | ||
431 | MACHINE = "qemuarm" | ||
432 | UBOOT_MACHINE = "am57xx_evm_defconfig" | ||
433 | SPL_BINARY = "MLO" | ||
434 | # The kernel-fitimage class is a dependency even if we're only | ||
435 | # creating/signing the U-Boot fitImage | ||
436 | KERNEL_CLASSES = " kernel-fitimage" | ||
437 | INHERIT += "test-mkimage-wrapper" | ||
438 | # Enable creation and signing of the U-Boot fitImage | ||
439 | UBOOT_FITIMAGE_ENABLE = "1" | ||
440 | SPL_SIGN_ENABLE = "1" | ||
441 | SPL_SIGN_KEYNAME = "spl-oe-selftest" | ||
442 | SPL_SIGN_KEYDIR = "${TOPDIR}/signing-keys" | ||
443 | UBOOT_DTB_BINARY = "u-boot.dtb" | ||
444 | UBOOT_ENTRYPOINT = "0x80000000" | ||
445 | UBOOT_LOADADDRESS = "0x80000000" | ||
446 | UBOOT_DTB_LOADADDRESS = "0x82000000" | ||
447 | UBOOT_ARCH = "arm" | ||
448 | SPL_MKIMAGE_DTCOPTS = "-I dts -O dtb -p 2000" | ||
449 | SPL_MKIMAGE_SIGN_ARGS = "-c 'a smart U-Boot comment'" | ||
450 | UBOOT_EXTLINUX = "0" | ||
451 | UBOOT_FIT_GENERATE_KEYS = "1" | ||
452 | UBOOT_FIT_HASH_ALG = "sha256" | ||
453 | """ | ||
454 | self.write_config(config) | ||
455 | |||
456 | # The U-Boot fitImage is created as part of the U-Boot recipe | ||
457 | bitbake("virtual/bootloader") | ||
458 | |||
459 | image_type = "core-image-minimal" | ||
460 | deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE') | ||
461 | machine = get_bb_var('MACHINE') | ||
462 | fitimage_its_path = os.path.join(deploy_dir_image, | ||
463 | "u-boot-its-%s" % (machine,)) | ||
464 | fitimage_path = os.path.join(deploy_dir_image, | ||
465 | "u-boot-fitImage-%s" % (machine,)) | ||
466 | |||
467 | self.assertTrue(os.path.exists(fitimage_its_path), | ||
468 | "%s image tree source doesn't exist" % (fitimage_its_path)) | ||
469 | self.assertTrue(os.path.exists(fitimage_path), | ||
470 | "%s FIT image doesn't exist" % (fitimage_path)) | ||
471 | |||
472 | req_itspaths = [ | ||
473 | ['/', 'images', 'uboot'], | ||
474 | ['/', 'images', 'uboot', 'signature'], | ||
475 | ['/', 'images', 'fdt'], | ||
476 | ['/', 'images', 'fdt', 'signature'], | ||
477 | ] | ||
478 | |||
479 | itspath = [] | ||
480 | itspaths = [] | ||
481 | linect = 0 | ||
482 | sigs = {} | ||
483 | with open(fitimage_its_path) as its_file: | ||
484 | linect += 1 | ||
485 | for line in its_file: | ||
486 | line = line.strip() | ||
487 | if line.endswith('};'): | ||
488 | itspath.pop() | ||
489 | elif line.endswith('{'): | ||
490 | itspath.append(line[:-1].strip()) | ||
491 | itspaths.append(itspath[:]) | ||
492 | elif itspath and itspath[-1] == 'signature': | ||
493 | itsdotpath = '.'.join(itspath) | ||
494 | if not itsdotpath in sigs: | ||
495 | sigs[itsdotpath] = {} | ||
496 | if not '=' in line or not line.endswith(';'): | ||
497 | self.fail('Unexpected formatting in %s sigs section line %d:%s' % (fitimage_its_path, linect, line)) | ||
498 | key, value = line.split('=', 1) | ||
499 | sigs[itsdotpath][key.rstrip()] = value.lstrip().rstrip(';') | ||
500 | |||
501 | for reqpath in req_itspaths: | ||
502 | if not reqpath in itspaths: | ||
503 | self.fail('Missing section in its file: %s' % reqpath) | ||
504 | |||
505 | reqsigvalues_image = { | ||
506 | 'algo': '"sha256,rsa2048"', | ||
507 | 'key-name-hint': '"spl-oe-selftest"', | ||
508 | } | ||
509 | |||
510 | for itspath, values in sigs.items(): | ||
511 | reqsigvalues = reqsigvalues_image | ||
512 | for reqkey, reqvalue in reqsigvalues.items(): | ||
513 | value = values.get(reqkey, None) | ||
514 | if value is None: | ||
515 | self.fail('Missing key "%s" in its file signature section %s' % (reqkey, itspath)) | ||
516 | self.assertEqual(value, reqvalue) | ||
517 | |||
518 | # Dump the image to see if it really got signed | ||
519 | bitbake("u-boot-tools-native -c addto_recipe_sysroot") | ||
520 | result = runCmd('bitbake -e u-boot-tools-native | grep ^RECIPE_SYSROOT_NATIVE=') | ||
521 | recipe_sysroot_native = result.output.split('=')[1].strip('"') | ||
522 | dumpimage_path = os.path.join(recipe_sysroot_native, 'usr', 'bin', 'dumpimage') | ||
523 | result = runCmd('%s -l %s' % (dumpimage_path, fitimage_path)) | ||
524 | in_signed = None | ||
525 | signed_sections = {} | ||
526 | for line in result.output.splitlines(): | ||
527 | if line.startswith((' Image')): | ||
528 | in_signed = re.search(r'\((.*)\)', line).groups()[0] | ||
529 | elif re.match(' \w', line): | ||
530 | in_signed = None | ||
531 | elif in_signed: | ||
532 | if not in_signed in signed_sections: | ||
533 | signed_sections[in_signed] = {} | ||
534 | key, value = line.split(':', 1) | ||
535 | signed_sections[in_signed][key.strip()] = value.strip() | ||
536 | self.assertIn('uboot', signed_sections) | ||
537 | self.assertIn('fdt', signed_sections) | ||
538 | for signed_section, values in signed_sections.items(): | ||
539 | value = values.get('Sign algo', None) | ||
540 | self.assertEqual(value, 'sha256,rsa2048:spl-oe-selftest', 'Signature algorithm for %s not expected value' % signed_section) | ||
541 | value = values.get('Sign value', None) | ||
542 | self.assertEqual(len(value), 512, 'Signature value for section %s not expected length' % signed_section) | ||
543 | |||
544 | # Check for SPL_MKIMAGE_SIGN_ARGS | ||
545 | result = runCmd('bitbake -e virtual/bootloader | grep ^T=') | ||
546 | tempdir = result.output.split('=', 1)[1].strip().strip('') | ||
547 | result = runCmd('grep "a smart U-Boot comment" %s/run.do_uboot_assemble_fitimage' % tempdir, ignore_status=True) | ||
548 | self.assertEqual(result.status, 0, 'SPL_MKIMAGE_SIGN_ARGS value did not get used') | ||
549 | |||
550 | # Check for evidence of test-mkimage-wrapper class | ||
551 | result = runCmd('grep "### uboot-mkimage wrapper message" %s/log.do_uboot_assemble_fitimage' % tempdir, ignore_status=True) | ||
552 | self.assertEqual(result.status, 0, 'UBOOT_MKIMAGE did not work') | ||
553 | result = runCmd('grep "### uboot-mkimage signing wrapper message" %s/log.do_uboot_assemble_fitimage' % tempdir, ignore_status=True) | ||
554 | self.assertEqual(result.status, 0, 'UBOOT_MKIMAGE_SIGN did not work') | ||
555 | |||
556 | def test_sign_cascaded_uboot_fit_image(self): | ||
557 | """ | ||
558 | Summary: Check if U-Boot FIT image and Image Tree Source (its) are | ||
559 | created and signed correctly for the scenario where both | ||
560 | U-Boot proper and Kernel fitImages are being created and | ||
561 | signed. | ||
562 | Expected: 1) U-Boot its and FIT image are built successfully | ||
563 | 2) Scanning the its file indicates signing is enabled | ||
564 | as requested by SPL_SIGN_ENABLE (using keys generated | ||
565 | via UBOOT_FIT_GENERATE_KEYS) | ||
566 | 3) Dumping the FIT image indicates signature values | ||
567 | are present | ||
568 | 4) Examination of the do_uboot_assemble_fitimage | ||
569 | runfile/logfile indicate that UBOOT_MKIMAGE, UBOOT_MKIMAGE_SIGN | ||
570 | and SPL_MKIMAGE_SIGN_ARGS are working as expected. | ||
571 | Product: oe-core | ||
572 | Author: Klaus Heinrich Kiwi <klaus@linux.vnet.ibm.com> based upon | ||
573 | work by Paul Eggleton <paul.eggleton@microsoft.com> and | ||
574 | Usama Arif <usama.arif@arm.com> | ||
575 | """ | ||
576 | config = """ | ||
577 | # There's no U-boot deconfig with CONFIG_FIT_SIGNATURE yet, so we need at | ||
578 | # least CONFIG_SPL_LOAD_FIT and CONFIG_SPL_OF_CONTROL set | ||
579 | MACHINE = "qemuarm" | ||
580 | UBOOT_MACHINE = "am57xx_evm_defconfig" | ||
581 | SPL_BINARY = "MLO" | ||
582 | # Enable creation and signing of the U-Boot fitImage | ||
583 | UBOOT_FITIMAGE_ENABLE = "1" | ||
584 | SPL_SIGN_ENABLE = "1" | ||
585 | SPL_SIGN_KEYNAME = "spl-cascaded-oe-selftest" | ||
586 | SPL_SIGN_KEYDIR = "${TOPDIR}/signing-keys" | ||
587 | UBOOT_DTB_BINARY = "u-boot.dtb" | ||
588 | UBOOT_ENTRYPOINT = "0x80000000" | ||
589 | UBOOT_LOADADDRESS = "0x80000000" | ||
590 | UBOOT_MKIMAGE_DTCOPTS = "-I dts -O dtb -p 2000" | ||
591 | UBOOT_MKIMAGE_SIGN_ARGS = "-c 'a smart cascaded Kernel comment'" | ||
592 | UBOOT_DTB_LOADADDRESS = "0x82000000" | ||
593 | UBOOT_ARCH = "arm" | ||
594 | SPL_MKIMAGE_DTCOPTS = "-I dts -O dtb -p 2000" | ||
595 | SPL_MKIMAGE_SIGN_ARGS = "-c 'a smart cascaded U-Boot comment'" | ||
596 | UBOOT_EXTLINUX = "0" | ||
597 | UBOOT_FIT_GENERATE_KEYS = "1" | ||
598 | UBOOT_FIT_HASH_ALG = "sha256" | ||
599 | KERNEL_IMAGETYPES += " fitImage " | ||
600 | KERNEL_CLASSES = " kernel-fitimage " | ||
601 | INHERIT += "test-mkimage-wrapper" | ||
602 | UBOOT_SIGN_ENABLE = "1" | ||
603 | FIT_GENERATE_KEYS = "1" | ||
604 | UBOOT_SIGN_KEYDIR = "${TOPDIR}/signing-keys" | ||
605 | UBOOT_SIGN_IMG_KEYNAME = "img-oe-selftest" | ||
606 | UBOOT_SIGN_KEYNAME = "cfg-oe-selftest" | ||
607 | FIT_SIGN_INDIVIDUAL = "1" | ||
608 | """ | ||
609 | self.write_config(config) | ||
610 | |||
611 | # The U-Boot fitImage is created as part of the U-Boot recipe | ||
612 | bitbake("virtual/bootloader") | ||
613 | |||
614 | image_type = "core-image-minimal" | ||
615 | deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE') | ||
616 | machine = get_bb_var('MACHINE') | ||
617 | fitimage_its_path = os.path.join(deploy_dir_image, | ||
618 | "u-boot-its-%s" % (machine,)) | ||
619 | fitimage_path = os.path.join(deploy_dir_image, | ||
620 | "u-boot-fitImage-%s" % (machine,)) | ||
621 | |||
622 | self.assertTrue(os.path.exists(fitimage_its_path), | ||
623 | "%s image tree source doesn't exist" % (fitimage_its_path)) | ||
624 | self.assertTrue(os.path.exists(fitimage_path), | ||
625 | "%s FIT image doesn't exist" % (fitimage_path)) | ||
626 | |||
627 | req_itspaths = [ | ||
628 | ['/', 'images', 'uboot'], | ||
629 | ['/', 'images', 'uboot', 'signature'], | ||
630 | ['/', 'images', 'fdt'], | ||
631 | ['/', 'images', 'fdt', 'signature'], | ||
632 | ] | ||
633 | |||
634 | itspath = [] | ||
635 | itspaths = [] | ||
636 | linect = 0 | ||
637 | sigs = {} | ||
638 | with open(fitimage_its_path) as its_file: | ||
639 | linect += 1 | ||
640 | for line in its_file: | ||
641 | line = line.strip() | ||
642 | if line.endswith('};'): | ||
643 | itspath.pop() | ||
644 | elif line.endswith('{'): | ||
645 | itspath.append(line[:-1].strip()) | ||
646 | itspaths.append(itspath[:]) | ||
647 | elif itspath and itspath[-1] == 'signature': | ||
648 | itsdotpath = '.'.join(itspath) | ||
649 | if not itsdotpath in sigs: | ||
650 | sigs[itsdotpath] = {} | ||
651 | if not '=' in line or not line.endswith(';'): | ||
652 | self.fail('Unexpected formatting in %s sigs section line %d:%s' % (fitimage_its_path, linect, line)) | ||
653 | key, value = line.split('=', 1) | ||
654 | sigs[itsdotpath][key.rstrip()] = value.lstrip().rstrip(';') | ||
655 | |||
656 | for reqpath in req_itspaths: | ||
657 | if not reqpath in itspaths: | ||
658 | self.fail('Missing section in its file: %s' % reqpath) | ||
659 | |||
660 | reqsigvalues_image = { | ||
661 | 'algo': '"sha256,rsa2048"', | ||
662 | 'key-name-hint': '"spl-cascaded-oe-selftest"', | ||
663 | } | ||
664 | |||
665 | for itspath, values in sigs.items(): | ||
666 | reqsigvalues = reqsigvalues_image | ||
667 | for reqkey, reqvalue in reqsigvalues.items(): | ||
668 | value = values.get(reqkey, None) | ||
669 | if value is None: | ||
670 | self.fail('Missing key "%s" in its file signature section %s' % (reqkey, itspath)) | ||
671 | self.assertEqual(value, reqvalue) | ||
672 | |||
673 | # Dump the image to see if it really got signed | ||
674 | bitbake("u-boot-tools-native -c addto_recipe_sysroot") | ||
675 | result = runCmd('bitbake -e u-boot-tools-native | grep ^RECIPE_SYSROOT_NATIVE=') | ||
676 | recipe_sysroot_native = result.output.split('=')[1].strip('"') | ||
677 | dumpimage_path = os.path.join(recipe_sysroot_native, 'usr', 'bin', 'dumpimage') | ||
678 | result = runCmd('%s -l %s' % (dumpimage_path, fitimage_path)) | ||
679 | in_signed = None | ||
680 | signed_sections = {} | ||
681 | for line in result.output.splitlines(): | ||
682 | if line.startswith((' Image')): | ||
683 | in_signed = re.search(r'\((.*)\)', line).groups()[0] | ||
684 | elif re.match(' \w', line): | ||
685 | in_signed = None | ||
686 | elif in_signed: | ||
687 | if not in_signed in signed_sections: | ||
688 | signed_sections[in_signed] = {} | ||
689 | key, value = line.split(':', 1) | ||
690 | signed_sections[in_signed][key.strip()] = value.strip() | ||
691 | self.assertIn('uboot', signed_sections) | ||
692 | self.assertIn('fdt', signed_sections) | ||
693 | for signed_section, values in signed_sections.items(): | ||
694 | value = values.get('Sign algo', None) | ||
695 | self.assertEqual(value, 'sha256,rsa2048:spl-cascaded-oe-selftest', 'Signature algorithm for %s not expected value' % signed_section) | ||
696 | value = values.get('Sign value', None) | ||
697 | self.assertEqual(len(value), 512, 'Signature value for section %s not expected length' % signed_section) | ||
698 | |||
699 | # Check for SPL_MKIMAGE_SIGN_ARGS | ||
700 | result = runCmd('bitbake -e virtual/bootloader | grep ^T=') | ||
701 | tempdir = result.output.split('=', 1)[1].strip().strip('') | ||
702 | result = runCmd('grep "a smart cascaded U-Boot comment" %s/run.do_uboot_assemble_fitimage' % tempdir, ignore_status=True) | ||
703 | self.assertEqual(result.status, 0, 'SPL_MKIMAGE_SIGN_ARGS value did not get used') | ||
704 | |||
705 | # Check for evidence of test-mkimage-wrapper class | ||
706 | result = runCmd('grep "### uboot-mkimage wrapper message" %s/log.do_uboot_assemble_fitimage' % tempdir, ignore_status=True) | ||
707 | self.assertEqual(result.status, 0, 'UBOOT_MKIMAGE did not work') | ||
708 | result = runCmd('grep "### uboot-mkimage signing wrapper message" %s/log.do_uboot_assemble_fitimage' % tempdir, ignore_status=True) | ||
709 | self.assertEqual(result.status, 0, 'UBOOT_MKIMAGE_SIGN did not work') | ||
710 | |||
711 | |||
712 | |||
234 | def test_initramfs_bundle(self): | 713 | def test_initramfs_bundle(self): |
235 | """ | 714 | """ |
236 | Summary: Verifies the content of the initramfs bundle node in the FIT Image Tree Source (its) | 715 | Summary: Verifies the content of the initramfs bundle node in the FIT Image Tree Source (its) |
@@ -264,9 +743,11 @@ UBOOT_LOADADDRESS = "0x80000000" | |||
264 | UBOOT_DTB_LOADADDRESS = "0x82000000" | 743 | UBOOT_DTB_LOADADDRESS = "0x82000000" |
265 | UBOOT_ARCH = "arm" | 744 | UBOOT_ARCH = "arm" |
266 | UBOOT_MKIMAGE_DTCOPTS = "-I dts -O dtb -p 2000" | 745 | UBOOT_MKIMAGE_DTCOPTS = "-I dts -O dtb -p 2000" |
746 | UBOOT_MKIMAGE_KERNEL_TYPE = "kernel" | ||
267 | UBOOT_EXTLINUX = "0" | 747 | UBOOT_EXTLINUX = "0" |
268 | FIT_GENERATE_KEYS = "1" | 748 | FIT_GENERATE_KEYS = "1" |
269 | KERNEL_IMAGETYPE_REPLACEMENT = "zImage" | 749 | KERNEL_IMAGETYPE_REPLACEMENT = "zImage" |
750 | FIT_KERNEL_COMP_ALG = "none" | ||
270 | FIT_HASH_ALG = "sha256" | 751 | FIT_HASH_ALG = "sha256" |
271 | """ | 752 | """ |
272 | self.write_config(config) | 753 | self.write_config(config) |
@@ -288,9 +769,9 @@ FIT_HASH_ALG = "sha256" | |||
288 | 769 | ||
289 | kernel_load = str(get_bb_var('UBOOT_LOADADDRESS')) | 770 | kernel_load = str(get_bb_var('UBOOT_LOADADDRESS')) |
290 | kernel_entry = str(get_bb_var('UBOOT_ENTRYPOINT')) | 771 | kernel_entry = str(get_bb_var('UBOOT_ENTRYPOINT')) |
291 | initramfs_bundle_format = str(get_bb_var('KERNEL_IMAGETYPE_REPLACEMENT')) | 772 | kernel_type = str(get_bb_var('UBOOT_MKIMAGE_KERNEL_TYPE')) |
773 | kernel_compression = str(get_bb_var('FIT_KERNEL_COMP_ALG')) | ||
292 | uboot_arch = str(get_bb_var('UBOOT_ARCH')) | 774 | uboot_arch = str(get_bb_var('UBOOT_ARCH')) |
293 | initramfs_bundle = "arch/" + uboot_arch + "/boot/" + initramfs_bundle_format + ".initramfs" | ||
294 | fit_hash_alg = str(get_bb_var('FIT_HASH_ALG')) | 775 | fit_hash_alg = str(get_bb_var('FIT_HASH_ALG')) |
295 | 776 | ||
296 | its_file = open(fitimage_its_path) | 777 | its_file = open(fitimage_its_path) |
@@ -300,11 +781,11 @@ FIT_HASH_ALG = "sha256" | |||
300 | exp_node_lines = [ | 781 | exp_node_lines = [ |
301 | 'kernel-1 {', | 782 | 'kernel-1 {', |
302 | 'description = "Linux kernel";', | 783 | 'description = "Linux kernel";', |
303 | 'data = /incbin/("' + initramfs_bundle + '");', | 784 | 'data = /incbin/("linux.bin");', |
304 | 'type = "kernel";', | 785 | 'type = "' + kernel_type + '";', |
305 | 'arch = "' + uboot_arch + '";', | 786 | 'arch = "' + uboot_arch + '";', |
306 | 'os = "linux";', | 787 | 'os = "linux";', |
307 | 'compression = "none";', | 788 | 'compression = "' + kernel_compression + '";', |
308 | 'load = <' + kernel_load + '>;', | 789 | 'load = <' + kernel_load + '>;', |
309 | 'entry = <' + kernel_entry + '>;', | 790 | 'entry = <' + kernel_entry + '>;', |
310 | 'hash-1 {', | 791 | 'hash-1 {', |