blob: 19b9f53ee4600c0703a714958570afbe80197e23 [file] [log] [blame]
Andrew Geisslerc723b722021-01-08 16:14:09 -06001#
2# SPDX-License-Identifier: MIT
3#
4
5from oeqa.selftest.case import OESelftestTestCase
6from oeqa.utils.commands import runCmd, bitbake, get_bb_var, runqemu
7import os
8import json
9import re
10
11class FitImageTests(OESelftestTestCase):
12
13 def test_fit_image(self):
14 """
15 Summary: Check if FIT image and Image Tree Source (its) are built
16 and the Image Tree Source has the correct fields.
17 Expected: 1. fitImage and fitImage-its can be built
18 2. The type, load address, entrypoint address and
19 default values of kernel and ramdisk are as expected
20 in the Image Tree Source. Not all the fields are tested,
21 only the key fields that wont vary between different
22 architectures.
23 Product: oe-core
24 Author: Usama Arif <usama.arif@arm.com>
25 """
26 config = """
27# Enable creation of fitImage
28KERNEL_IMAGETYPE = "Image"
29KERNEL_IMAGETYPES += " fitImage "
30KERNEL_CLASSES = " kernel-fitimage "
31
32# RAM disk variables including load address and entrypoint for kernel and RAM disk
33IMAGE_FSTYPES += "cpio.gz"
34INITRAMFS_IMAGE = "core-image-minimal"
35UBOOT_RD_LOADADDRESS = "0x88000000"
36UBOOT_RD_ENTRYPOINT = "0x88000000"
37UBOOT_LOADADDRESS = "0x80080000"
38UBOOT_ENTRYPOINT = "0x80080000"
39FIT_DESC = "A model description"
40"""
41 self.write_config(config)
42
43 # fitImage is created as part of linux recipe
44 bitbake("virtual/kernel")
45
46 image_type = "core-image-minimal"
47 deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE')
48 machine = get_bb_var('MACHINE')
49 fitimage_its_path = os.path.join(deploy_dir_image,
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
54 self.assertTrue(os.path.exists(fitimage_its_path),
55 "%s image tree source doesn't exist" % (fitimage_its_path))
56 self.assertTrue(os.path.exists(fitimage_path),
57 "%s FIT image doesn't exist" % (fitimage_path))
58
59 # Check that the type, load address, entrypoint address and default
60 # values for kernel and ramdisk in Image Tree Source are as expected.
61 # The order of fields in the below array is important. Not all the
62 # fields are tested, only the key fields that wont vary between
63 # different architectures.
64 its_field_check = [
65 'description = "A model description";',
66 'type = "kernel";',
67 'load = <0x80080000>;',
68 'entry = <0x80080000>;',
69 'type = "ramdisk";',
70 'load = <0x88000000>;',
71 'entry = <0x88000000>;',
72 'default = "conf@1";',
73 'kernel = "kernel@1";',
74 'ramdisk = "ramdisk@1";'
75 ]
76
77 with open(fitimage_its_path) as its_file:
78 field_index = 0
79 for line in its_file:
80 if field_index == len(its_field_check):
81 break
82 if its_field_check[field_index] in line:
83 field_index +=1
84
85 if field_index != len(its_field_check): # if its equal, the test passed
86 self.assertTrue(field_index == len(its_field_check),
87 "Fields in Image Tree Source File %s did not match, error in finding %s"
88 % (fitimage_its_path, its_field_check[field_index]))
89
90
91 def test_sign_fit_image(self):
92 """
93 Summary: Check if FIT image and Image Tree Source (its) are created
94 and signed correctly.
95 Expected: 1) its and FIT image are built successfully
96 2) Scanning the its file indicates signing is enabled
97 as requested by UBOOT_SIGN_ENABLE (using keys generated
98 via FIT_GENERATE_KEYS)
99 3) Dumping the FIT image indicates signature values
100 are present (including for images as enabled via
101 FIT_SIGN_INDIVIDUAL)
102 4) Examination of the do_assemble_fitimage runfile/logfile
103 indicate that UBOOT_MKIMAGE, UBOOT_MKIMAGE_SIGN and
104 UBOOT_MKIMAGE_SIGN_ARGS are working as expected.
105 Product: oe-core
106 Author: Paul Eggleton <paul.eggleton@microsoft.com> based upon
107 work by Usama Arif <usama.arif@arm.com>
108 """
109 config = """
110# Enable creation of fitImage
111MACHINE = "beaglebone-yocto"
112KERNEL_IMAGETYPES += " fitImage "
113KERNEL_CLASSES = " kernel-fitimage test-mkimage-wrapper "
114UBOOT_SIGN_ENABLE = "1"
115FIT_GENERATE_KEYS = "1"
116UBOOT_SIGN_KEYDIR = "${TOPDIR}/signing-keys"
117UBOOT_SIGN_KEYNAME = "oe-selftest"
118FIT_SIGN_INDIVIDUAL = "1"
119UBOOT_MKIMAGE_SIGN_ARGS = "-c 'a smart comment'"
120"""
121 self.write_config(config)
122
123 # fitImage is created as part of linux recipe
124 bitbake("virtual/kernel")
125
126 image_type = "core-image-minimal"
127 deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE')
128 machine = get_bb_var('MACHINE')
129 fitimage_its_path = os.path.join(deploy_dir_image,
130 "fitImage-its-%s" % (machine,))
131 fitimage_path = os.path.join(deploy_dir_image,
132 "fitImage-%s.bin" % (machine,))
133
134 self.assertTrue(os.path.exists(fitimage_its_path),
135 "%s image tree source doesn't exist" % (fitimage_its_path))
136 self.assertTrue(os.path.exists(fitimage_path),
137 "%s FIT image doesn't exist" % (fitimage_path))
138
139 req_itspaths = [
140 ['/', 'images', 'kernel@1'],
141 ['/', 'images', 'kernel@1', 'signature@1'],
142 ['/', 'images', 'fdt@am335x-boneblack.dtb'],
143 ['/', 'images', 'fdt@am335x-boneblack.dtb', 'signature@1'],
144 ['/', 'configurations', 'conf@am335x-boneblack.dtb'],
145 ['/', 'configurations', 'conf@am335x-boneblack.dtb', 'signature@1'],
146 ]
147
148 itspath = []
149 itspaths = []
150 linect = 0
151 sigs = {}
152 with open(fitimage_its_path) as its_file:
153 linect += 1
154 for line in its_file:
155 line = line.strip()
156 if line.endswith('};'):
157 itspath.pop()
158 elif line.endswith('{'):
159 itspath.append(line[:-1].strip())
160 itspaths.append(itspath[:])
161 elif itspath and itspath[-1] == 'signature@1':
162 itsdotpath = '.'.join(itspath)
163 if not itsdotpath in sigs:
164 sigs[itsdotpath] = {}
165 if not '=' in line or not line.endswith(';'):
166 self.fail('Unexpected formatting in %s sigs section line %d:%s' % (fitimage_its_path, linect, line))
167 key, value = line.split('=', 1)
168 sigs[itsdotpath][key.rstrip()] = value.lstrip().rstrip(';')
169
170 for reqpath in req_itspaths:
171 if not reqpath in itspaths:
172 self.fail('Missing section in its file: %s' % reqpath)
173
174 reqsigvalues_image = {
175 'algo': '"sha256,rsa2048"',
176 'key-name-hint': '"oe-selftest"',
177 }
178 reqsigvalues_config = {
179 'algo': '"sha256,rsa2048"',
180 'key-name-hint': '"oe-selftest"',
181 'sign-images': '"kernel", "fdt"',
182 }
183
184 for itspath, values in sigs.items():
185 if 'conf@' in itspath:
186 reqsigvalues = reqsigvalues_config
187 else:
188 reqsigvalues = reqsigvalues_image
189 for reqkey, reqvalue in reqsigvalues.items():
190 value = values.get(reqkey, None)
191 if value is None:
192 self.fail('Missing key "%s" in its file signature section %s' % (reqkey, itspath))
193 self.assertEqual(value, reqvalue)
194
195 # Dump the image to see if it really got signed
196 bitbake("u-boot-tools-native -c addto_recipe_sysroot")
197 result = runCmd('bitbake -e u-boot-tools-native | grep ^RECIPE_SYSROOT_NATIVE=')
198 recipe_sysroot_native = result.output.split('=')[1].strip('"')
199 dumpimage_path = os.path.join(recipe_sysroot_native, 'usr', 'bin', 'dumpimage')
200 result = runCmd('%s -l %s' % (dumpimage_path, fitimage_path))
201 in_signed = None
202 signed_sections = {}
203 for line in result.output.splitlines():
204 if line.startswith((' Configuration', ' Image')):
205 in_signed = re.search('\((.*)\)', line).groups()[0]
206 elif re.match('^ *', line) in (' ', ''):
207 in_signed = None
208 elif in_signed:
209 if not in_signed in signed_sections:
210 signed_sections[in_signed] = {}
211 key, value = line.split(':', 1)
212 signed_sections[in_signed][key.strip()] = value.strip()
213 self.assertIn('kernel@1', signed_sections)
214 self.assertIn('fdt@am335x-boneblack.dtb', signed_sections)
215 self.assertIn('conf@am335x-boneblack.dtb', signed_sections)
216 for signed_section, values in signed_sections.items():
217 value = values.get('Sign algo', None)
218 self.assertEqual(value, 'sha256,rsa2048:oe-selftest', 'Signature algorithm for %s not expected value' % signed_section)
219 value = values.get('Sign value', None)
220 self.assertEqual(len(value), 512, 'Signature value for section %s not expected length' % signed_section)
221
222 # Check for UBOOT_MKIMAGE_SIGN_ARGS
223 result = runCmd('bitbake -e virtual/kernel | grep ^T=')
224 tempdir = result.output.split('=', 1)[1].strip().strip('')
225 result = runCmd('grep "a smart comment" %s/run.do_assemble_fitimage' % tempdir, ignore_status=True)
226 self.assertEqual(result.status, 0, 'UBOOT_MKIMAGE_SIGN_ARGS value did not get used')
227
228 # Check for evidence of test-mkimage-wrapper class
229 result = runCmd('grep "### uboot-mkimage wrapper message" %s/log.do_assemble_fitimage' % tempdir, ignore_status=True)
230 self.assertEqual(result.status, 0, 'UBOOT_MKIMAGE did not work')
231 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')
233