1*4882a593Smuzhiyun# 2*4882a593Smuzhiyun# SPDX-License-Identifier: MIT 3*4882a593Smuzhiyun# 4*4882a593Smuzhiyun 5*4882a593Smuzhiyunfrom oeqa.selftest.case import OESelftestTestCase 6*4882a593Smuzhiyunfrom oeqa.utils.commands import runCmd, bitbake, get_bb_var 7*4882a593Smuzhiyunimport os 8*4882a593Smuzhiyunimport re 9*4882a593Smuzhiyun 10*4882a593Smuzhiyunclass FitImageTests(OESelftestTestCase): 11*4882a593Smuzhiyun 12*4882a593Smuzhiyun def test_fit_image(self): 13*4882a593Smuzhiyun """ 14*4882a593Smuzhiyun Summary: Check if FIT image and Image Tree Source (its) are built 15*4882a593Smuzhiyun and the Image Tree Source has the correct fields. 16*4882a593Smuzhiyun Expected: 1. fitImage and fitImage-its can be built 17*4882a593Smuzhiyun 2. The type, load address, entrypoint address and 18*4882a593Smuzhiyun default values of kernel and ramdisk are as expected 19*4882a593Smuzhiyun in the Image Tree Source. Not all the fields are tested, 20*4882a593Smuzhiyun only the key fields that wont vary between different 21*4882a593Smuzhiyun architectures. 22*4882a593Smuzhiyun Product: oe-core 23*4882a593Smuzhiyun Author: Usama Arif <usama.arif@arm.com> 24*4882a593Smuzhiyun """ 25*4882a593Smuzhiyun config = """ 26*4882a593Smuzhiyun# Enable creation of fitImage 27*4882a593SmuzhiyunKERNEL_IMAGETYPE = "Image" 28*4882a593SmuzhiyunKERNEL_IMAGETYPES += " fitImage " 29*4882a593SmuzhiyunKERNEL_CLASSES = " kernel-fitimage " 30*4882a593Smuzhiyun 31*4882a593Smuzhiyun# RAM disk variables including load address and entrypoint for kernel and RAM disk 32*4882a593SmuzhiyunIMAGE_FSTYPES += "cpio.gz" 33*4882a593SmuzhiyunINITRAMFS_IMAGE = "core-image-minimal" 34*4882a593SmuzhiyunUBOOT_RD_LOADADDRESS = "0x88000000" 35*4882a593SmuzhiyunUBOOT_RD_ENTRYPOINT = "0x88000000" 36*4882a593SmuzhiyunUBOOT_LOADADDRESS = "0x80080000" 37*4882a593SmuzhiyunUBOOT_ENTRYPOINT = "0x80080000" 38*4882a593SmuzhiyunFIT_DESC = "A model description" 39*4882a593Smuzhiyun""" 40*4882a593Smuzhiyun self.write_config(config) 41*4882a593Smuzhiyun 42*4882a593Smuzhiyun # fitImage is created as part of linux recipe 43*4882a593Smuzhiyun bitbake("virtual/kernel") 44*4882a593Smuzhiyun 45*4882a593Smuzhiyun image_type = "core-image-minimal" 46*4882a593Smuzhiyun deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE') 47*4882a593Smuzhiyun machine = get_bb_var('MACHINE') 48*4882a593Smuzhiyun fitimage_its_path = os.path.join(deploy_dir_image, 49*4882a593Smuzhiyun "fitImage-its-%s-%s-%s" % (image_type, machine, machine)) 50*4882a593Smuzhiyun fitimage_path = os.path.join(deploy_dir_image, 51*4882a593Smuzhiyun "fitImage-%s-%s-%s" % (image_type, machine, machine)) 52*4882a593Smuzhiyun 53*4882a593Smuzhiyun self.assertTrue(os.path.exists(fitimage_its_path), 54*4882a593Smuzhiyun "%s image tree source doesn't exist" % (fitimage_its_path)) 55*4882a593Smuzhiyun self.assertTrue(os.path.exists(fitimage_path), 56*4882a593Smuzhiyun "%s FIT image doesn't exist" % (fitimage_path)) 57*4882a593Smuzhiyun 58*4882a593Smuzhiyun # Check that the type, load address, entrypoint address and default 59*4882a593Smuzhiyun # values for kernel and ramdisk in Image Tree Source are as expected. 60*4882a593Smuzhiyun # The order of fields in the below array is important. Not all the 61*4882a593Smuzhiyun # fields are tested, only the key fields that wont vary between 62*4882a593Smuzhiyun # different architectures. 63*4882a593Smuzhiyun its_field_check = [ 64*4882a593Smuzhiyun 'description = "A model description";', 65*4882a593Smuzhiyun 'type = "kernel";', 66*4882a593Smuzhiyun 'load = <0x80080000>;', 67*4882a593Smuzhiyun 'entry = <0x80080000>;', 68*4882a593Smuzhiyun 'type = "ramdisk";', 69*4882a593Smuzhiyun 'load = <0x88000000>;', 70*4882a593Smuzhiyun 'entry = <0x88000000>;', 71*4882a593Smuzhiyun 'default = "conf-1";', 72*4882a593Smuzhiyun 'kernel = "kernel-1";', 73*4882a593Smuzhiyun 'ramdisk = "ramdisk-1";' 74*4882a593Smuzhiyun ] 75*4882a593Smuzhiyun 76*4882a593Smuzhiyun with open(fitimage_its_path) as its_file: 77*4882a593Smuzhiyun field_index = 0 78*4882a593Smuzhiyun for line in its_file: 79*4882a593Smuzhiyun if field_index == len(its_field_check): 80*4882a593Smuzhiyun break 81*4882a593Smuzhiyun if its_field_check[field_index] in line: 82*4882a593Smuzhiyun field_index +=1 83*4882a593Smuzhiyun 84*4882a593Smuzhiyun if field_index != len(its_field_check): # if its equal, the test passed 85*4882a593Smuzhiyun self.assertTrue(field_index == len(its_field_check), 86*4882a593Smuzhiyun "Fields in Image Tree Source File %s did not match, error in finding %s" 87*4882a593Smuzhiyun % (fitimage_its_path, its_field_check[field_index])) 88*4882a593Smuzhiyun 89*4882a593Smuzhiyun 90*4882a593Smuzhiyun def test_sign_fit_image(self): 91*4882a593Smuzhiyun """ 92*4882a593Smuzhiyun Summary: Check if FIT image and Image Tree Source (its) are created 93*4882a593Smuzhiyun and signed correctly. 94*4882a593Smuzhiyun Expected: 1) its and FIT image are built successfully 95*4882a593Smuzhiyun 2) Scanning the its file indicates signing is enabled 96*4882a593Smuzhiyun as requested by UBOOT_SIGN_ENABLE (using keys generated 97*4882a593Smuzhiyun via FIT_GENERATE_KEYS) 98*4882a593Smuzhiyun 3) Dumping the FIT image indicates signature values 99*4882a593Smuzhiyun are present (including for images as enabled via 100*4882a593Smuzhiyun FIT_SIGN_INDIVIDUAL) 101*4882a593Smuzhiyun 4) Examination of the do_assemble_fitimage runfile/logfile 102*4882a593Smuzhiyun indicate that UBOOT_MKIMAGE, UBOOT_MKIMAGE_SIGN and 103*4882a593Smuzhiyun UBOOT_MKIMAGE_SIGN_ARGS are working as expected. 104*4882a593Smuzhiyun Product: oe-core 105*4882a593Smuzhiyun Author: Paul Eggleton <paul.eggleton@microsoft.com> based upon 106*4882a593Smuzhiyun work by Usama Arif <usama.arif@arm.com> 107*4882a593Smuzhiyun """ 108*4882a593Smuzhiyun config = """ 109*4882a593Smuzhiyun# Enable creation of fitImage 110*4882a593SmuzhiyunMACHINE = "beaglebone-yocto" 111*4882a593SmuzhiyunKERNEL_IMAGETYPES += " fitImage " 112*4882a593SmuzhiyunKERNEL_CLASSES = " kernel-fitimage test-mkimage-wrapper " 113*4882a593SmuzhiyunUBOOT_SIGN_ENABLE = "1" 114*4882a593SmuzhiyunFIT_GENERATE_KEYS = "1" 115*4882a593SmuzhiyunUBOOT_SIGN_KEYDIR = "${TOPDIR}/signing-keys" 116*4882a593SmuzhiyunUBOOT_SIGN_IMG_KEYNAME = "img-oe-selftest" 117*4882a593SmuzhiyunUBOOT_SIGN_KEYNAME = "cfg-oe-selftest" 118*4882a593SmuzhiyunFIT_SIGN_INDIVIDUAL = "1" 119*4882a593SmuzhiyunUBOOT_MKIMAGE_SIGN_ARGS = "-c 'a smart comment'" 120*4882a593Smuzhiyun""" 121*4882a593Smuzhiyun self.write_config(config) 122*4882a593Smuzhiyun 123*4882a593Smuzhiyun # fitImage is created as part of linux recipe 124*4882a593Smuzhiyun bitbake("virtual/kernel") 125*4882a593Smuzhiyun 126*4882a593Smuzhiyun image_type = "core-image-minimal" 127*4882a593Smuzhiyun deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE') 128*4882a593Smuzhiyun machine = get_bb_var('MACHINE') 129*4882a593Smuzhiyun fitimage_its_path = os.path.join(deploy_dir_image, 130*4882a593Smuzhiyun "fitImage-its-%s" % (machine,)) 131*4882a593Smuzhiyun fitimage_path = os.path.join(deploy_dir_image, 132*4882a593Smuzhiyun "fitImage-%s.bin" % (machine,)) 133*4882a593Smuzhiyun 134*4882a593Smuzhiyun self.assertTrue(os.path.exists(fitimage_its_path), 135*4882a593Smuzhiyun "%s image tree source doesn't exist" % (fitimage_its_path)) 136*4882a593Smuzhiyun self.assertTrue(os.path.exists(fitimage_path), 137*4882a593Smuzhiyun "%s FIT image doesn't exist" % (fitimage_path)) 138*4882a593Smuzhiyun 139*4882a593Smuzhiyun req_itspaths = [ 140*4882a593Smuzhiyun ['/', 'images', 'kernel-1'], 141*4882a593Smuzhiyun ['/', 'images', 'kernel-1', 'signature-1'], 142*4882a593Smuzhiyun ['/', 'images', 'fdt-am335x-boneblack.dtb'], 143*4882a593Smuzhiyun ['/', 'images', 'fdt-am335x-boneblack.dtb', 'signature-1'], 144*4882a593Smuzhiyun ['/', 'configurations', 'conf-am335x-boneblack.dtb'], 145*4882a593Smuzhiyun ['/', 'configurations', 'conf-am335x-boneblack.dtb', 'signature-1'], 146*4882a593Smuzhiyun ] 147*4882a593Smuzhiyun 148*4882a593Smuzhiyun itspath = [] 149*4882a593Smuzhiyun itspaths = [] 150*4882a593Smuzhiyun linect = 0 151*4882a593Smuzhiyun sigs = {} 152*4882a593Smuzhiyun with open(fitimage_its_path) as its_file: 153*4882a593Smuzhiyun linect += 1 154*4882a593Smuzhiyun for line in its_file: 155*4882a593Smuzhiyun line = line.strip() 156*4882a593Smuzhiyun if line.endswith('};'): 157*4882a593Smuzhiyun itspath.pop() 158*4882a593Smuzhiyun elif line.endswith('{'): 159*4882a593Smuzhiyun itspath.append(line[:-1].strip()) 160*4882a593Smuzhiyun itspaths.append(itspath[:]) 161*4882a593Smuzhiyun elif itspath and itspath[-1] == 'signature-1': 162*4882a593Smuzhiyun itsdotpath = '.'.join(itspath) 163*4882a593Smuzhiyun if not itsdotpath in sigs: 164*4882a593Smuzhiyun sigs[itsdotpath] = {} 165*4882a593Smuzhiyun if not '=' in line or not line.endswith(';'): 166*4882a593Smuzhiyun self.fail('Unexpected formatting in %s sigs section line %d:%s' % (fitimage_its_path, linect, line)) 167*4882a593Smuzhiyun key, value = line.split('=', 1) 168*4882a593Smuzhiyun sigs[itsdotpath][key.rstrip()] = value.lstrip().rstrip(';') 169*4882a593Smuzhiyun 170*4882a593Smuzhiyun for reqpath in req_itspaths: 171*4882a593Smuzhiyun if not reqpath in itspaths: 172*4882a593Smuzhiyun self.fail('Missing section in its file: %s' % reqpath) 173*4882a593Smuzhiyun 174*4882a593Smuzhiyun reqsigvalues_image = { 175*4882a593Smuzhiyun 'algo': '"sha256,rsa2048"', 176*4882a593Smuzhiyun 'key-name-hint': '"img-oe-selftest"', 177*4882a593Smuzhiyun } 178*4882a593Smuzhiyun reqsigvalues_config = { 179*4882a593Smuzhiyun 'algo': '"sha256,rsa2048"', 180*4882a593Smuzhiyun 'key-name-hint': '"cfg-oe-selftest"', 181*4882a593Smuzhiyun 'sign-images': '"kernel", "fdt"', 182*4882a593Smuzhiyun } 183*4882a593Smuzhiyun 184*4882a593Smuzhiyun for itspath, values in sigs.items(): 185*4882a593Smuzhiyun if 'conf-' in itspath: 186*4882a593Smuzhiyun reqsigvalues = reqsigvalues_config 187*4882a593Smuzhiyun else: 188*4882a593Smuzhiyun reqsigvalues = reqsigvalues_image 189*4882a593Smuzhiyun for reqkey, reqvalue in reqsigvalues.items(): 190*4882a593Smuzhiyun value = values.get(reqkey, None) 191*4882a593Smuzhiyun if value is None: 192*4882a593Smuzhiyun self.fail('Missing key "%s" in its file signature section %s' % (reqkey, itspath)) 193*4882a593Smuzhiyun self.assertEqual(value, reqvalue) 194*4882a593Smuzhiyun 195*4882a593Smuzhiyun # Dump the image to see if it really got signed 196*4882a593Smuzhiyun bitbake("u-boot-tools-native -c addto_recipe_sysroot") 197*4882a593Smuzhiyun result = runCmd('bitbake -e u-boot-tools-native | grep ^RECIPE_SYSROOT_NATIVE=') 198*4882a593Smuzhiyun recipe_sysroot_native = result.output.split('=')[1].strip('"') 199*4882a593Smuzhiyun dumpimage_path = os.path.join(recipe_sysroot_native, 'usr', 'bin', 'dumpimage') 200*4882a593Smuzhiyun result = runCmd('%s -l %s' % (dumpimage_path, fitimage_path)) 201*4882a593Smuzhiyun in_signed = None 202*4882a593Smuzhiyun signed_sections = {} 203*4882a593Smuzhiyun for line in result.output.splitlines(): 204*4882a593Smuzhiyun if line.startswith((' Configuration', ' Image')): 205*4882a593Smuzhiyun in_signed = re.search('\((.*)\)', line).groups()[0] 206*4882a593Smuzhiyun elif re.match('^ *', line) in (' ', ''): 207*4882a593Smuzhiyun in_signed = None 208*4882a593Smuzhiyun elif in_signed: 209*4882a593Smuzhiyun if not in_signed in signed_sections: 210*4882a593Smuzhiyun signed_sections[in_signed] = {} 211*4882a593Smuzhiyun key, value = line.split(':', 1) 212*4882a593Smuzhiyun signed_sections[in_signed][key.strip()] = value.strip() 213*4882a593Smuzhiyun self.assertIn('kernel-1', signed_sections) 214*4882a593Smuzhiyun self.assertIn('fdt-am335x-boneblack.dtb', signed_sections) 215*4882a593Smuzhiyun self.assertIn('conf-am335x-boneblack.dtb', signed_sections) 216*4882a593Smuzhiyun for signed_section, values in signed_sections.items(): 217*4882a593Smuzhiyun value = values.get('Sign algo', None) 218*4882a593Smuzhiyun if signed_section.startswith("conf"): 219*4882a593Smuzhiyun self.assertEqual(value, 'sha256,rsa2048:cfg-oe-selftest', 'Signature algorithm for %s not expected value' % signed_section) 220*4882a593Smuzhiyun else: 221*4882a593Smuzhiyun self.assertEqual(value, 'sha256,rsa2048:img-oe-selftest', 'Signature algorithm for %s not expected value' % signed_section) 222*4882a593Smuzhiyun value = values.get('Sign value', None) 223*4882a593Smuzhiyun self.assertEqual(len(value), 512, 'Signature value for section %s not expected length' % signed_section) 224*4882a593Smuzhiyun 225*4882a593Smuzhiyun # Check for UBOOT_MKIMAGE_SIGN_ARGS 226*4882a593Smuzhiyun result = runCmd('bitbake -e virtual/kernel | grep ^T=') 227*4882a593Smuzhiyun tempdir = result.output.split('=', 1)[1].strip().strip('') 228*4882a593Smuzhiyun result = runCmd('grep "a smart comment" %s/run.do_assemble_fitimage' % tempdir, ignore_status=True) 229*4882a593Smuzhiyun self.assertEqual(result.status, 0, 'UBOOT_MKIMAGE_SIGN_ARGS value did not get used') 230*4882a593Smuzhiyun 231*4882a593Smuzhiyun # Check for evidence of test-mkimage-wrapper class 232*4882a593Smuzhiyun result = runCmd('grep "### uboot-mkimage wrapper message" %s/log.do_assemble_fitimage' % tempdir, ignore_status=True) 233*4882a593Smuzhiyun self.assertEqual(result.status, 0, 'UBOOT_MKIMAGE did not work') 234*4882a593Smuzhiyun result = runCmd('grep "### uboot-mkimage signing wrapper message" %s/log.do_assemble_fitimage' % tempdir, ignore_status=True) 235*4882a593Smuzhiyun self.assertEqual(result.status, 0, 'UBOOT_MKIMAGE_SIGN did not work') 236*4882a593Smuzhiyun 237*4882a593Smuzhiyun def test_uboot_fit_image(self): 238*4882a593Smuzhiyun """ 239*4882a593Smuzhiyun Summary: Check if Uboot FIT image and Image Tree Source 240*4882a593Smuzhiyun (its) are built and the Image Tree Source has the 241*4882a593Smuzhiyun correct fields. 242*4882a593Smuzhiyun Expected: 1. u-boot-fitImage and u-boot-its can be built 243*4882a593Smuzhiyun 2. The type, load address, entrypoint address and 244*4882a593Smuzhiyun default values of U-boot image are correct in the 245*4882a593Smuzhiyun Image Tree Source. Not all the fields are tested, 246*4882a593Smuzhiyun only the key fields that wont vary between 247*4882a593Smuzhiyun different architectures. 248*4882a593Smuzhiyun Product: oe-core 249*4882a593Smuzhiyun Author: Klaus Heinrich Kiwi <klaus@linux.vnet.ibm.com> 250*4882a593Smuzhiyun based on work by Usama Arif <usama.arif@arm.com> 251*4882a593Smuzhiyun """ 252*4882a593Smuzhiyun config = """ 253*4882a593Smuzhiyun# We need at least CONFIG_SPL_LOAD_FIT and CONFIG_SPL_OF_CONTROL set 254*4882a593SmuzhiyunMACHINE = "qemuarm" 255*4882a593SmuzhiyunUBOOT_MACHINE = "am57xx_evm_defconfig" 256*4882a593SmuzhiyunSPL_BINARY = "MLO" 257*4882a593Smuzhiyun 258*4882a593Smuzhiyun# Enable creation of the U-Boot fitImage 259*4882a593SmuzhiyunUBOOT_FITIMAGE_ENABLE = "1" 260*4882a593Smuzhiyun 261*4882a593Smuzhiyun# (U-boot) fitImage properties 262*4882a593SmuzhiyunUBOOT_LOADADDRESS = "0x80080000" 263*4882a593SmuzhiyunUBOOT_ENTRYPOINT = "0x80080000" 264*4882a593SmuzhiyunUBOOT_FIT_DESC = "A model description" 265*4882a593Smuzhiyun 266*4882a593Smuzhiyun# Enable creation of Kernel fitImage 267*4882a593SmuzhiyunKERNEL_IMAGETYPES += " fitImage " 268*4882a593SmuzhiyunKERNEL_CLASSES = " kernel-fitimage" 269*4882a593SmuzhiyunUBOOT_SIGN_ENABLE = "1" 270*4882a593SmuzhiyunFIT_GENERATE_KEYS = "1" 271*4882a593SmuzhiyunUBOOT_SIGN_KEYDIR = "${TOPDIR}/signing-keys" 272*4882a593SmuzhiyunUBOOT_SIGN_IMG_KEYNAME = "img-oe-selftest" 273*4882a593SmuzhiyunUBOOT_SIGN_KEYNAME = "cfg-oe-selftest" 274*4882a593SmuzhiyunFIT_SIGN_INDIVIDUAL = "1" 275*4882a593Smuzhiyun""" 276*4882a593Smuzhiyun self.write_config(config) 277*4882a593Smuzhiyun 278*4882a593Smuzhiyun # The U-Boot fitImage is created as part of linux recipe 279*4882a593Smuzhiyun bitbake("virtual/kernel") 280*4882a593Smuzhiyun 281*4882a593Smuzhiyun deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE') 282*4882a593Smuzhiyun machine = get_bb_var('MACHINE') 283*4882a593Smuzhiyun fitimage_its_path = os.path.join(deploy_dir_image, 284*4882a593Smuzhiyun "u-boot-its-%s" % (machine,)) 285*4882a593Smuzhiyun fitimage_path = os.path.join(deploy_dir_image, 286*4882a593Smuzhiyun "u-boot-fitImage-%s" % (machine,)) 287*4882a593Smuzhiyun 288*4882a593Smuzhiyun self.assertTrue(os.path.exists(fitimage_its_path), 289*4882a593Smuzhiyun "%s image tree source doesn't exist" % (fitimage_its_path)) 290*4882a593Smuzhiyun self.assertTrue(os.path.exists(fitimage_path), 291*4882a593Smuzhiyun "%s FIT image doesn't exist" % (fitimage_path)) 292*4882a593Smuzhiyun 293*4882a593Smuzhiyun # Check that the type, load address, entrypoint address and default 294*4882a593Smuzhiyun # values for kernel and ramdisk in Image Tree Source are as expected. 295*4882a593Smuzhiyun # The order of fields in the below array is important. Not all the 296*4882a593Smuzhiyun # fields are tested, only the key fields that wont vary between 297*4882a593Smuzhiyun # different architectures. 298*4882a593Smuzhiyun its_field_check = [ 299*4882a593Smuzhiyun 'description = "A model description";', 300*4882a593Smuzhiyun 'type = "standalone";', 301*4882a593Smuzhiyun 'load = <0x80080000>;', 302*4882a593Smuzhiyun 'entry = <0x80080000>;', 303*4882a593Smuzhiyun 'default = "conf";', 304*4882a593Smuzhiyun 'loadables = "uboot";', 305*4882a593Smuzhiyun 'fdt = "fdt";' 306*4882a593Smuzhiyun ] 307*4882a593Smuzhiyun 308*4882a593Smuzhiyun with open(fitimage_its_path) as its_file: 309*4882a593Smuzhiyun field_index = 0 310*4882a593Smuzhiyun for line in its_file: 311*4882a593Smuzhiyun if field_index == len(its_field_check): 312*4882a593Smuzhiyun break 313*4882a593Smuzhiyun if its_field_check[field_index] in line: 314*4882a593Smuzhiyun field_index +=1 315*4882a593Smuzhiyun 316*4882a593Smuzhiyun if field_index != len(its_field_check): # if its equal, the test passed 317*4882a593Smuzhiyun self.assertTrue(field_index == len(its_field_check), 318*4882a593Smuzhiyun "Fields in Image Tree Source File %s did not match, error in finding %s" 319*4882a593Smuzhiyun % (fitimage_its_path, its_field_check[field_index])) 320*4882a593Smuzhiyun 321*4882a593Smuzhiyun def test_uboot_sign_fit_image(self): 322*4882a593Smuzhiyun """ 323*4882a593Smuzhiyun Summary: Check if Uboot FIT image and Image Tree Source 324*4882a593Smuzhiyun (its) are built and the Image Tree Source has the 325*4882a593Smuzhiyun correct fields, in the scenario where the Kernel 326*4882a593Smuzhiyun is also creating/signing it's fitImage. 327*4882a593Smuzhiyun Expected: 1. u-boot-fitImage and u-boot-its can be built 328*4882a593Smuzhiyun 2. The type, load address, entrypoint address and 329*4882a593Smuzhiyun default values of U-boot image are correct in the 330*4882a593Smuzhiyun Image Tree Source. Not all the fields are tested, 331*4882a593Smuzhiyun only the key fields that wont vary between 332*4882a593Smuzhiyun different architectures. 333*4882a593Smuzhiyun Product: oe-core 334*4882a593Smuzhiyun Author: Klaus Heinrich Kiwi <klaus@linux.vnet.ibm.com> 335*4882a593Smuzhiyun based on work by Usama Arif <usama.arif@arm.com> 336*4882a593Smuzhiyun """ 337*4882a593Smuzhiyun config = """ 338*4882a593Smuzhiyun# We need at least CONFIG_SPL_LOAD_FIT and CONFIG_SPL_OF_CONTROL set 339*4882a593SmuzhiyunMACHINE = "qemuarm" 340*4882a593SmuzhiyunUBOOT_MACHINE = "am57xx_evm_defconfig" 341*4882a593SmuzhiyunSPL_BINARY = "MLO" 342*4882a593Smuzhiyun 343*4882a593Smuzhiyun# Enable creation of the U-Boot fitImage 344*4882a593SmuzhiyunUBOOT_FITIMAGE_ENABLE = "1" 345*4882a593Smuzhiyun 346*4882a593Smuzhiyun# (U-boot) fitImage properties 347*4882a593SmuzhiyunUBOOT_LOADADDRESS = "0x80080000" 348*4882a593SmuzhiyunUBOOT_ENTRYPOINT = "0x80080000" 349*4882a593SmuzhiyunUBOOT_FIT_DESC = "A model description" 350*4882a593SmuzhiyunKERNEL_IMAGETYPES += " fitImage " 351*4882a593SmuzhiyunKERNEL_CLASSES = " kernel-fitimage test-mkimage-wrapper " 352*4882a593SmuzhiyunUBOOT_SIGN_ENABLE = "1" 353*4882a593SmuzhiyunFIT_GENERATE_KEYS = "1" 354*4882a593SmuzhiyunUBOOT_SIGN_KEYDIR = "${TOPDIR}/signing-keys" 355*4882a593SmuzhiyunUBOOT_SIGN_IMG_KEYNAME = "img-oe-selftest" 356*4882a593SmuzhiyunUBOOT_SIGN_KEYNAME = "cfg-oe-selftest" 357*4882a593SmuzhiyunFIT_SIGN_INDIVIDUAL = "1" 358*4882a593SmuzhiyunUBOOT_MKIMAGE_SIGN_ARGS = "-c 'a smart U-Boot comment'" 359*4882a593Smuzhiyun""" 360*4882a593Smuzhiyun self.write_config(config) 361*4882a593Smuzhiyun 362*4882a593Smuzhiyun # The U-Boot fitImage is created as part of linux recipe 363*4882a593Smuzhiyun bitbake("virtual/kernel") 364*4882a593Smuzhiyun 365*4882a593Smuzhiyun deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE') 366*4882a593Smuzhiyun machine = get_bb_var('MACHINE') 367*4882a593Smuzhiyun fitimage_its_path = os.path.join(deploy_dir_image, 368*4882a593Smuzhiyun "u-boot-its-%s" % (machine,)) 369*4882a593Smuzhiyun fitimage_path = os.path.join(deploy_dir_image, 370*4882a593Smuzhiyun "u-boot-fitImage-%s" % (machine,)) 371*4882a593Smuzhiyun 372*4882a593Smuzhiyun self.assertTrue(os.path.exists(fitimage_its_path), 373*4882a593Smuzhiyun "%s image tree source doesn't exist" % (fitimage_its_path)) 374*4882a593Smuzhiyun self.assertTrue(os.path.exists(fitimage_path), 375*4882a593Smuzhiyun "%s FIT image doesn't exist" % (fitimage_path)) 376*4882a593Smuzhiyun 377*4882a593Smuzhiyun # Check that the type, load address, entrypoint address and default 378*4882a593Smuzhiyun # values for kernel and ramdisk in Image Tree Source are as expected. 379*4882a593Smuzhiyun # The order of fields in the below array is important. Not all the 380*4882a593Smuzhiyun # fields are tested, only the key fields that wont vary between 381*4882a593Smuzhiyun # different architectures. 382*4882a593Smuzhiyun its_field_check = [ 383*4882a593Smuzhiyun 'description = "A model description";', 384*4882a593Smuzhiyun 'type = "standalone";', 385*4882a593Smuzhiyun 'load = <0x80080000>;', 386*4882a593Smuzhiyun 'entry = <0x80080000>;', 387*4882a593Smuzhiyun 'default = "conf";', 388*4882a593Smuzhiyun 'loadables = "uboot";', 389*4882a593Smuzhiyun 'fdt = "fdt";' 390*4882a593Smuzhiyun ] 391*4882a593Smuzhiyun 392*4882a593Smuzhiyun with open(fitimage_its_path) as its_file: 393*4882a593Smuzhiyun field_index = 0 394*4882a593Smuzhiyun for line in its_file: 395*4882a593Smuzhiyun if field_index == len(its_field_check): 396*4882a593Smuzhiyun break 397*4882a593Smuzhiyun if its_field_check[field_index] in line: 398*4882a593Smuzhiyun field_index +=1 399*4882a593Smuzhiyun 400*4882a593Smuzhiyun if field_index != len(its_field_check): # if its equal, the test passed 401*4882a593Smuzhiyun self.assertTrue(field_index == len(its_field_check), 402*4882a593Smuzhiyun "Fields in Image Tree Source File %s did not match, error in finding %s" 403*4882a593Smuzhiyun % (fitimage_its_path, its_field_check[field_index])) 404*4882a593Smuzhiyun 405*4882a593Smuzhiyun 406*4882a593Smuzhiyun def test_sign_standalone_uboot_fit_image(self): 407*4882a593Smuzhiyun """ 408*4882a593Smuzhiyun Summary: Check if U-Boot FIT image and Image Tree Source (its) are 409*4882a593Smuzhiyun created and signed correctly for the scenario where only 410*4882a593Smuzhiyun the U-Boot proper fitImage is being created and signed. 411*4882a593Smuzhiyun Expected: 1) U-Boot its and FIT image are built successfully 412*4882a593Smuzhiyun 2) Scanning the its file indicates signing is enabled 413*4882a593Smuzhiyun as requested by SPL_SIGN_ENABLE (using keys generated 414*4882a593Smuzhiyun via UBOOT_FIT_GENERATE_KEYS) 415*4882a593Smuzhiyun 3) Dumping the FIT image indicates signature values 416*4882a593Smuzhiyun are present 417*4882a593Smuzhiyun 4) Examination of the do_uboot_assemble_fitimage 418*4882a593Smuzhiyun runfile/logfile indicate that UBOOT_MKIMAGE, UBOOT_MKIMAGE_SIGN 419*4882a593Smuzhiyun and SPL_MKIMAGE_SIGN_ARGS are working as expected. 420*4882a593Smuzhiyun Product: oe-core 421*4882a593Smuzhiyun Author: Klaus Heinrich Kiwi <klaus@linux.vnet.ibm.com> based upon 422*4882a593Smuzhiyun work by Paul Eggleton <paul.eggleton@microsoft.com> and 423*4882a593Smuzhiyun Usama Arif <usama.arif@arm.com> 424*4882a593Smuzhiyun """ 425*4882a593Smuzhiyun config = """ 426*4882a593Smuzhiyun# There's no U-boot deconfig with CONFIG_FIT_SIGNATURE yet, so we need at 427*4882a593Smuzhiyun# least CONFIG_SPL_LOAD_FIT and CONFIG_SPL_OF_CONTROL set 428*4882a593SmuzhiyunMACHINE = "qemuarm" 429*4882a593SmuzhiyunUBOOT_MACHINE = "am57xx_evm_defconfig" 430*4882a593SmuzhiyunSPL_BINARY = "MLO" 431*4882a593Smuzhiyun# The kernel-fitimage class is a dependency even if we're only 432*4882a593Smuzhiyun# creating/signing the U-Boot fitImage 433*4882a593SmuzhiyunKERNEL_CLASSES = " kernel-fitimage test-mkimage-wrapper " 434*4882a593Smuzhiyun# Enable creation and signing of the U-Boot fitImage 435*4882a593SmuzhiyunUBOOT_FITIMAGE_ENABLE = "1" 436*4882a593SmuzhiyunSPL_SIGN_ENABLE = "1" 437*4882a593SmuzhiyunSPL_SIGN_KEYNAME = "spl-oe-selftest" 438*4882a593SmuzhiyunSPL_SIGN_KEYDIR = "${TOPDIR}/signing-keys" 439*4882a593SmuzhiyunUBOOT_DTB_BINARY = "u-boot.dtb" 440*4882a593SmuzhiyunUBOOT_ENTRYPOINT = "0x80000000" 441*4882a593SmuzhiyunUBOOT_LOADADDRESS = "0x80000000" 442*4882a593SmuzhiyunUBOOT_DTB_LOADADDRESS = "0x82000000" 443*4882a593SmuzhiyunUBOOT_ARCH = "arm" 444*4882a593SmuzhiyunSPL_MKIMAGE_DTCOPTS = "-I dts -O dtb -p 2000" 445*4882a593SmuzhiyunSPL_MKIMAGE_SIGN_ARGS = "-c 'a smart U-Boot comment'" 446*4882a593SmuzhiyunUBOOT_EXTLINUX = "0" 447*4882a593SmuzhiyunUBOOT_FIT_GENERATE_KEYS = "1" 448*4882a593SmuzhiyunUBOOT_FIT_HASH_ALG = "sha256" 449*4882a593Smuzhiyun""" 450*4882a593Smuzhiyun self.write_config(config) 451*4882a593Smuzhiyun 452*4882a593Smuzhiyun # The U-Boot fitImage is created as part of linux recipe 453*4882a593Smuzhiyun bitbake("virtual/kernel") 454*4882a593Smuzhiyun 455*4882a593Smuzhiyun image_type = "core-image-minimal" 456*4882a593Smuzhiyun deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE') 457*4882a593Smuzhiyun machine = get_bb_var('MACHINE') 458*4882a593Smuzhiyun fitimage_its_path = os.path.join(deploy_dir_image, 459*4882a593Smuzhiyun "u-boot-its-%s" % (machine,)) 460*4882a593Smuzhiyun fitimage_path = os.path.join(deploy_dir_image, 461*4882a593Smuzhiyun "u-boot-fitImage-%s" % (machine,)) 462*4882a593Smuzhiyun 463*4882a593Smuzhiyun self.assertTrue(os.path.exists(fitimage_its_path), 464*4882a593Smuzhiyun "%s image tree source doesn't exist" % (fitimage_its_path)) 465*4882a593Smuzhiyun self.assertTrue(os.path.exists(fitimage_path), 466*4882a593Smuzhiyun "%s FIT image doesn't exist" % (fitimage_path)) 467*4882a593Smuzhiyun 468*4882a593Smuzhiyun req_itspaths = [ 469*4882a593Smuzhiyun ['/', 'images', 'uboot'], 470*4882a593Smuzhiyun ['/', 'images', 'uboot', 'signature'], 471*4882a593Smuzhiyun ['/', 'images', 'fdt'], 472*4882a593Smuzhiyun ['/', 'images', 'fdt', 'signature'], 473*4882a593Smuzhiyun ] 474*4882a593Smuzhiyun 475*4882a593Smuzhiyun itspath = [] 476*4882a593Smuzhiyun itspaths = [] 477*4882a593Smuzhiyun linect = 0 478*4882a593Smuzhiyun sigs = {} 479*4882a593Smuzhiyun with open(fitimage_its_path) as its_file: 480*4882a593Smuzhiyun linect += 1 481*4882a593Smuzhiyun for line in its_file: 482*4882a593Smuzhiyun line = line.strip() 483*4882a593Smuzhiyun if line.endswith('};'): 484*4882a593Smuzhiyun itspath.pop() 485*4882a593Smuzhiyun elif line.endswith('{'): 486*4882a593Smuzhiyun itspath.append(line[:-1].strip()) 487*4882a593Smuzhiyun itspaths.append(itspath[:]) 488*4882a593Smuzhiyun elif itspath and itspath[-1] == 'signature': 489*4882a593Smuzhiyun itsdotpath = '.'.join(itspath) 490*4882a593Smuzhiyun if not itsdotpath in sigs: 491*4882a593Smuzhiyun sigs[itsdotpath] = {} 492*4882a593Smuzhiyun if not '=' in line or not line.endswith(';'): 493*4882a593Smuzhiyun self.fail('Unexpected formatting in %s sigs section line %d:%s' % (fitimage_its_path, linect, line)) 494*4882a593Smuzhiyun key, value = line.split('=', 1) 495*4882a593Smuzhiyun sigs[itsdotpath][key.rstrip()] = value.lstrip().rstrip(';') 496*4882a593Smuzhiyun 497*4882a593Smuzhiyun for reqpath in req_itspaths: 498*4882a593Smuzhiyun if not reqpath in itspaths: 499*4882a593Smuzhiyun self.fail('Missing section in its file: %s' % reqpath) 500*4882a593Smuzhiyun 501*4882a593Smuzhiyun reqsigvalues_image = { 502*4882a593Smuzhiyun 'algo': '"sha256,rsa2048"', 503*4882a593Smuzhiyun 'key-name-hint': '"spl-oe-selftest"', 504*4882a593Smuzhiyun } 505*4882a593Smuzhiyun 506*4882a593Smuzhiyun for itspath, values in sigs.items(): 507*4882a593Smuzhiyun reqsigvalues = reqsigvalues_image 508*4882a593Smuzhiyun for reqkey, reqvalue in reqsigvalues.items(): 509*4882a593Smuzhiyun value = values.get(reqkey, None) 510*4882a593Smuzhiyun if value is None: 511*4882a593Smuzhiyun self.fail('Missing key "%s" in its file signature section %s' % (reqkey, itspath)) 512*4882a593Smuzhiyun self.assertEqual(value, reqvalue) 513*4882a593Smuzhiyun 514*4882a593Smuzhiyun # Dump the image to see if it really got signed 515*4882a593Smuzhiyun bitbake("u-boot-tools-native -c addto_recipe_sysroot") 516*4882a593Smuzhiyun result = runCmd('bitbake -e u-boot-tools-native | grep ^RECIPE_SYSROOT_NATIVE=') 517*4882a593Smuzhiyun recipe_sysroot_native = result.output.split('=')[1].strip('"') 518*4882a593Smuzhiyun dumpimage_path = os.path.join(recipe_sysroot_native, 'usr', 'bin', 'dumpimage') 519*4882a593Smuzhiyun result = runCmd('%s -l %s' % (dumpimage_path, fitimage_path)) 520*4882a593Smuzhiyun in_signed = None 521*4882a593Smuzhiyun signed_sections = {} 522*4882a593Smuzhiyun for line in result.output.splitlines(): 523*4882a593Smuzhiyun if line.startswith((' Image')): 524*4882a593Smuzhiyun in_signed = re.search('\((.*)\)', line).groups()[0] 525*4882a593Smuzhiyun elif re.match(' \w', line): 526*4882a593Smuzhiyun in_signed = None 527*4882a593Smuzhiyun elif in_signed: 528*4882a593Smuzhiyun if not in_signed in signed_sections: 529*4882a593Smuzhiyun signed_sections[in_signed] = {} 530*4882a593Smuzhiyun key, value = line.split(':', 1) 531*4882a593Smuzhiyun signed_sections[in_signed][key.strip()] = value.strip() 532*4882a593Smuzhiyun self.assertIn('uboot', signed_sections) 533*4882a593Smuzhiyun self.assertIn('fdt', signed_sections) 534*4882a593Smuzhiyun for signed_section, values in signed_sections.items(): 535*4882a593Smuzhiyun value = values.get('Sign algo', None) 536*4882a593Smuzhiyun self.assertEqual(value, 'sha256,rsa2048:spl-oe-selftest', 'Signature algorithm for %s not expected value' % signed_section) 537*4882a593Smuzhiyun value = values.get('Sign value', None) 538*4882a593Smuzhiyun self.assertEqual(len(value), 512, 'Signature value for section %s not expected length' % signed_section) 539*4882a593Smuzhiyun 540*4882a593Smuzhiyun # Check for SPL_MKIMAGE_SIGN_ARGS 541*4882a593Smuzhiyun result = runCmd('bitbake -e virtual/kernel | grep ^T=') 542*4882a593Smuzhiyun tempdir = result.output.split('=', 1)[1].strip().strip('') 543*4882a593Smuzhiyun result = runCmd('grep "a smart U-Boot comment" %s/run.do_uboot_assemble_fitimage' % tempdir, ignore_status=True) 544*4882a593Smuzhiyun self.assertEqual(result.status, 0, 'SPL_MKIMAGE_SIGN_ARGS value did not get used') 545*4882a593Smuzhiyun 546*4882a593Smuzhiyun # Check for evidence of test-mkimage-wrapper class 547*4882a593Smuzhiyun result = runCmd('grep "### uboot-mkimage wrapper message" %s/log.do_uboot_assemble_fitimage' % tempdir, ignore_status=True) 548*4882a593Smuzhiyun self.assertEqual(result.status, 0, 'UBOOT_MKIMAGE did not work') 549*4882a593Smuzhiyun result = runCmd('grep "### uboot-mkimage signing wrapper message" %s/log.do_uboot_assemble_fitimage' % tempdir, ignore_status=True) 550*4882a593Smuzhiyun self.assertEqual(result.status, 0, 'UBOOT_MKIMAGE_SIGN did not work') 551*4882a593Smuzhiyun 552*4882a593Smuzhiyun def test_sign_cascaded_uboot_fit_image(self): 553*4882a593Smuzhiyun """ 554*4882a593Smuzhiyun Summary: Check if U-Boot FIT image and Image Tree Source (its) are 555*4882a593Smuzhiyun created and signed correctly for the scenario where both 556*4882a593Smuzhiyun U-Boot proper and Kernel fitImages are being created and 557*4882a593Smuzhiyun signed. 558*4882a593Smuzhiyun Expected: 1) U-Boot its and FIT image are built successfully 559*4882a593Smuzhiyun 2) Scanning the its file indicates signing is enabled 560*4882a593Smuzhiyun as requested by SPL_SIGN_ENABLE (using keys generated 561*4882a593Smuzhiyun via UBOOT_FIT_GENERATE_KEYS) 562*4882a593Smuzhiyun 3) Dumping the FIT image indicates signature values 563*4882a593Smuzhiyun are present 564*4882a593Smuzhiyun 4) Examination of the do_uboot_assemble_fitimage 565*4882a593Smuzhiyun runfile/logfile indicate that UBOOT_MKIMAGE, UBOOT_MKIMAGE_SIGN 566*4882a593Smuzhiyun and SPL_MKIMAGE_SIGN_ARGS are working as expected. 567*4882a593Smuzhiyun Product: oe-core 568*4882a593Smuzhiyun Author: Klaus Heinrich Kiwi <klaus@linux.vnet.ibm.com> based upon 569*4882a593Smuzhiyun work by Paul Eggleton <paul.eggleton@microsoft.com> and 570*4882a593Smuzhiyun Usama Arif <usama.arif@arm.com> 571*4882a593Smuzhiyun """ 572*4882a593Smuzhiyun config = """ 573*4882a593Smuzhiyun# There's no U-boot deconfig with CONFIG_FIT_SIGNATURE yet, so we need at 574*4882a593Smuzhiyun# least CONFIG_SPL_LOAD_FIT and CONFIG_SPL_OF_CONTROL set 575*4882a593SmuzhiyunMACHINE = "qemuarm" 576*4882a593SmuzhiyunUBOOT_MACHINE = "am57xx_evm_defconfig" 577*4882a593SmuzhiyunSPL_BINARY = "MLO" 578*4882a593Smuzhiyun# Enable creation and signing of the U-Boot fitImage 579*4882a593SmuzhiyunUBOOT_FITIMAGE_ENABLE = "1" 580*4882a593SmuzhiyunSPL_SIGN_ENABLE = "1" 581*4882a593SmuzhiyunSPL_SIGN_KEYNAME = "spl-cascaded-oe-selftest" 582*4882a593SmuzhiyunSPL_SIGN_KEYDIR = "${TOPDIR}/signing-keys" 583*4882a593SmuzhiyunUBOOT_DTB_BINARY = "u-boot.dtb" 584*4882a593SmuzhiyunUBOOT_ENTRYPOINT = "0x80000000" 585*4882a593SmuzhiyunUBOOT_LOADADDRESS = "0x80000000" 586*4882a593SmuzhiyunUBOOT_MKIMAGE_DTCOPTS = "-I dts -O dtb -p 2000" 587*4882a593SmuzhiyunUBOOT_MKIMAGE_SIGN_ARGS = "-c 'a smart cascaded Kernel comment'" 588*4882a593SmuzhiyunUBOOT_DTB_LOADADDRESS = "0x82000000" 589*4882a593SmuzhiyunUBOOT_ARCH = "arm" 590*4882a593SmuzhiyunSPL_MKIMAGE_DTCOPTS = "-I dts -O dtb -p 2000" 591*4882a593SmuzhiyunSPL_MKIMAGE_SIGN_ARGS = "-c 'a smart cascaded U-Boot comment'" 592*4882a593SmuzhiyunUBOOT_EXTLINUX = "0" 593*4882a593SmuzhiyunUBOOT_FIT_GENERATE_KEYS = "1" 594*4882a593SmuzhiyunUBOOT_FIT_HASH_ALG = "sha256" 595*4882a593SmuzhiyunKERNEL_IMAGETYPES += " fitImage " 596*4882a593SmuzhiyunKERNEL_CLASSES = " kernel-fitimage test-mkimage-wrapper " 597*4882a593SmuzhiyunUBOOT_SIGN_ENABLE = "1" 598*4882a593SmuzhiyunFIT_GENERATE_KEYS = "1" 599*4882a593SmuzhiyunUBOOT_SIGN_KEYDIR = "${TOPDIR}/signing-keys" 600*4882a593SmuzhiyunUBOOT_SIGN_IMG_KEYNAME = "img-oe-selftest" 601*4882a593SmuzhiyunUBOOT_SIGN_KEYNAME = "cfg-oe-selftest" 602*4882a593SmuzhiyunFIT_SIGN_INDIVIDUAL = "1" 603*4882a593Smuzhiyun""" 604*4882a593Smuzhiyun self.write_config(config) 605*4882a593Smuzhiyun 606*4882a593Smuzhiyun # The U-Boot fitImage is created as part of linux recipe 607*4882a593Smuzhiyun bitbake("virtual/kernel") 608*4882a593Smuzhiyun 609*4882a593Smuzhiyun image_type = "core-image-minimal" 610*4882a593Smuzhiyun deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE') 611*4882a593Smuzhiyun machine = get_bb_var('MACHINE') 612*4882a593Smuzhiyun fitimage_its_path = os.path.join(deploy_dir_image, 613*4882a593Smuzhiyun "u-boot-its-%s" % (machine,)) 614*4882a593Smuzhiyun fitimage_path = os.path.join(deploy_dir_image, 615*4882a593Smuzhiyun "u-boot-fitImage-%s" % (machine,)) 616*4882a593Smuzhiyun 617*4882a593Smuzhiyun self.assertTrue(os.path.exists(fitimage_its_path), 618*4882a593Smuzhiyun "%s image tree source doesn't exist" % (fitimage_its_path)) 619*4882a593Smuzhiyun self.assertTrue(os.path.exists(fitimage_path), 620*4882a593Smuzhiyun "%s FIT image doesn't exist" % (fitimage_path)) 621*4882a593Smuzhiyun 622*4882a593Smuzhiyun req_itspaths = [ 623*4882a593Smuzhiyun ['/', 'images', 'uboot'], 624*4882a593Smuzhiyun ['/', 'images', 'uboot', 'signature'], 625*4882a593Smuzhiyun ['/', 'images', 'fdt'], 626*4882a593Smuzhiyun ['/', 'images', 'fdt', 'signature'], 627*4882a593Smuzhiyun ] 628*4882a593Smuzhiyun 629*4882a593Smuzhiyun itspath = [] 630*4882a593Smuzhiyun itspaths = [] 631*4882a593Smuzhiyun linect = 0 632*4882a593Smuzhiyun sigs = {} 633*4882a593Smuzhiyun with open(fitimage_its_path) as its_file: 634*4882a593Smuzhiyun linect += 1 635*4882a593Smuzhiyun for line in its_file: 636*4882a593Smuzhiyun line = line.strip() 637*4882a593Smuzhiyun if line.endswith('};'): 638*4882a593Smuzhiyun itspath.pop() 639*4882a593Smuzhiyun elif line.endswith('{'): 640*4882a593Smuzhiyun itspath.append(line[:-1].strip()) 641*4882a593Smuzhiyun itspaths.append(itspath[:]) 642*4882a593Smuzhiyun elif itspath and itspath[-1] == 'signature': 643*4882a593Smuzhiyun itsdotpath = '.'.join(itspath) 644*4882a593Smuzhiyun if not itsdotpath in sigs: 645*4882a593Smuzhiyun sigs[itsdotpath] = {} 646*4882a593Smuzhiyun if not '=' in line or not line.endswith(';'): 647*4882a593Smuzhiyun self.fail('Unexpected formatting in %s sigs section line %d:%s' % (fitimage_its_path, linect, line)) 648*4882a593Smuzhiyun key, value = line.split('=', 1) 649*4882a593Smuzhiyun sigs[itsdotpath][key.rstrip()] = value.lstrip().rstrip(';') 650*4882a593Smuzhiyun 651*4882a593Smuzhiyun for reqpath in req_itspaths: 652*4882a593Smuzhiyun if not reqpath in itspaths: 653*4882a593Smuzhiyun self.fail('Missing section in its file: %s' % reqpath) 654*4882a593Smuzhiyun 655*4882a593Smuzhiyun reqsigvalues_image = { 656*4882a593Smuzhiyun 'algo': '"sha256,rsa2048"', 657*4882a593Smuzhiyun 'key-name-hint': '"spl-cascaded-oe-selftest"', 658*4882a593Smuzhiyun } 659*4882a593Smuzhiyun 660*4882a593Smuzhiyun for itspath, values in sigs.items(): 661*4882a593Smuzhiyun reqsigvalues = reqsigvalues_image 662*4882a593Smuzhiyun for reqkey, reqvalue in reqsigvalues.items(): 663*4882a593Smuzhiyun value = values.get(reqkey, None) 664*4882a593Smuzhiyun if value is None: 665*4882a593Smuzhiyun self.fail('Missing key "%s" in its file signature section %s' % (reqkey, itspath)) 666*4882a593Smuzhiyun self.assertEqual(value, reqvalue) 667*4882a593Smuzhiyun 668*4882a593Smuzhiyun # Dump the image to see if it really got signed 669*4882a593Smuzhiyun bitbake("u-boot-tools-native -c addto_recipe_sysroot") 670*4882a593Smuzhiyun result = runCmd('bitbake -e u-boot-tools-native | grep ^RECIPE_SYSROOT_NATIVE=') 671*4882a593Smuzhiyun recipe_sysroot_native = result.output.split('=')[1].strip('"') 672*4882a593Smuzhiyun dumpimage_path = os.path.join(recipe_sysroot_native, 'usr', 'bin', 'dumpimage') 673*4882a593Smuzhiyun result = runCmd('%s -l %s' % (dumpimage_path, fitimage_path)) 674*4882a593Smuzhiyun in_signed = None 675*4882a593Smuzhiyun signed_sections = {} 676*4882a593Smuzhiyun for line in result.output.splitlines(): 677*4882a593Smuzhiyun if line.startswith((' Image')): 678*4882a593Smuzhiyun in_signed = re.search('\((.*)\)', line).groups()[0] 679*4882a593Smuzhiyun elif re.match(' \w', line): 680*4882a593Smuzhiyun in_signed = None 681*4882a593Smuzhiyun elif in_signed: 682*4882a593Smuzhiyun if not in_signed in signed_sections: 683*4882a593Smuzhiyun signed_sections[in_signed] = {} 684*4882a593Smuzhiyun key, value = line.split(':', 1) 685*4882a593Smuzhiyun signed_sections[in_signed][key.strip()] = value.strip() 686*4882a593Smuzhiyun self.assertIn('uboot', signed_sections) 687*4882a593Smuzhiyun self.assertIn('fdt', signed_sections) 688*4882a593Smuzhiyun for signed_section, values in signed_sections.items(): 689*4882a593Smuzhiyun value = values.get('Sign algo', None) 690*4882a593Smuzhiyun self.assertEqual(value, 'sha256,rsa2048:spl-cascaded-oe-selftest', 'Signature algorithm for %s not expected value' % signed_section) 691*4882a593Smuzhiyun value = values.get('Sign value', None) 692*4882a593Smuzhiyun self.assertEqual(len(value), 512, 'Signature value for section %s not expected length' % signed_section) 693*4882a593Smuzhiyun 694*4882a593Smuzhiyun # Check for SPL_MKIMAGE_SIGN_ARGS 695*4882a593Smuzhiyun result = runCmd('bitbake -e virtual/kernel | grep ^T=') 696*4882a593Smuzhiyun tempdir = result.output.split('=', 1)[1].strip().strip('') 697*4882a593Smuzhiyun result = runCmd('grep "a smart cascaded U-Boot comment" %s/run.do_uboot_assemble_fitimage' % tempdir, ignore_status=True) 698*4882a593Smuzhiyun self.assertEqual(result.status, 0, 'SPL_MKIMAGE_SIGN_ARGS value did not get used') 699*4882a593Smuzhiyun 700*4882a593Smuzhiyun # Check for evidence of test-mkimage-wrapper class 701*4882a593Smuzhiyun result = runCmd('grep "### uboot-mkimage wrapper message" %s/log.do_uboot_assemble_fitimage' % tempdir, ignore_status=True) 702*4882a593Smuzhiyun self.assertEqual(result.status, 0, 'UBOOT_MKIMAGE did not work') 703*4882a593Smuzhiyun result = runCmd('grep "### uboot-mkimage signing wrapper message" %s/log.do_uboot_assemble_fitimage' % tempdir, ignore_status=True) 704*4882a593Smuzhiyun self.assertEqual(result.status, 0, 'UBOOT_MKIMAGE_SIGN did not work') 705*4882a593Smuzhiyun 706*4882a593Smuzhiyun 707*4882a593Smuzhiyun 708*4882a593Smuzhiyun def test_initramfs_bundle(self): 709*4882a593Smuzhiyun """ 710*4882a593Smuzhiyun Summary: Verifies the content of the initramfs bundle node in the FIT Image Tree Source (its) 711*4882a593Smuzhiyun The FIT settings are set by the test case. 712*4882a593Smuzhiyun The machine used is beaglebone-yocto. 713*4882a593Smuzhiyun Expected: 1. The ITS is generated with initramfs bundle support 714*4882a593Smuzhiyun 2. All the fields in the kernel node are as expected (matching the 715*4882a593Smuzhiyun conf settings) 716*4882a593Smuzhiyun 3. The kernel is included in all the available configurations and 717*4882a593Smuzhiyun its hash is included in the configuration signature 718*4882a593Smuzhiyun 719*4882a593Smuzhiyun Product: oe-core 720*4882a593Smuzhiyun Author: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com> 721*4882a593Smuzhiyun """ 722*4882a593Smuzhiyun 723*4882a593Smuzhiyun config = """ 724*4882a593SmuzhiyunDISTRO="poky" 725*4882a593SmuzhiyunMACHINE = "beaglebone-yocto" 726*4882a593SmuzhiyunINITRAMFS_IMAGE_BUNDLE = "1" 727*4882a593SmuzhiyunINITRAMFS_IMAGE = "core-image-minimal-initramfs" 728*4882a593SmuzhiyunINITRAMFS_SCRIPTS = "" 729*4882a593SmuzhiyunUBOOT_MACHINE = "am335x_evm_defconfig" 730*4882a593SmuzhiyunKERNEL_CLASSES = " kernel-fitimage " 731*4882a593SmuzhiyunKERNEL_IMAGETYPES = "fitImage" 732*4882a593SmuzhiyunUBOOT_SIGN_ENABLE = "1" 733*4882a593SmuzhiyunUBOOT_SIGN_KEYNAME = "beaglebonekey" 734*4882a593SmuzhiyunUBOOT_SIGN_KEYDIR ?= "${DEPLOY_DIR_IMAGE}" 735*4882a593SmuzhiyunUBOOT_DTB_BINARY = "u-boot.dtb" 736*4882a593SmuzhiyunUBOOT_ENTRYPOINT = "0x80000000" 737*4882a593SmuzhiyunUBOOT_LOADADDRESS = "0x80000000" 738*4882a593SmuzhiyunUBOOT_DTB_LOADADDRESS = "0x82000000" 739*4882a593SmuzhiyunUBOOT_ARCH = "arm" 740*4882a593SmuzhiyunUBOOT_MKIMAGE_DTCOPTS = "-I dts -O dtb -p 2000" 741*4882a593SmuzhiyunUBOOT_MKIMAGE_KERNEL_TYPE = "kernel" 742*4882a593SmuzhiyunUBOOT_EXTLINUX = "0" 743*4882a593SmuzhiyunFIT_GENERATE_KEYS = "1" 744*4882a593SmuzhiyunKERNEL_IMAGETYPE_REPLACEMENT = "zImage" 745*4882a593SmuzhiyunFIT_KERNEL_COMP_ALG = "none" 746*4882a593SmuzhiyunFIT_HASH_ALG = "sha256" 747*4882a593Smuzhiyun""" 748*4882a593Smuzhiyun self.write_config(config) 749*4882a593Smuzhiyun 750*4882a593Smuzhiyun # fitImage is created as part of linux recipe 751*4882a593Smuzhiyun bitbake("virtual/kernel") 752*4882a593Smuzhiyun 753*4882a593Smuzhiyun image_type = get_bb_var('INITRAMFS_IMAGE') 754*4882a593Smuzhiyun deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE') 755*4882a593Smuzhiyun machine = get_bb_var('MACHINE') 756*4882a593Smuzhiyun fitimage_its_path = os.path.join(deploy_dir_image, 757*4882a593Smuzhiyun "fitImage-its-%s-%s-%s" % (image_type, machine, machine)) 758*4882a593Smuzhiyun fitimage_path = os.path.join(deploy_dir_image,"fitImage") 759*4882a593Smuzhiyun 760*4882a593Smuzhiyun self.assertTrue(os.path.exists(fitimage_its_path), 761*4882a593Smuzhiyun "%s image tree source doesn't exist" % (fitimage_its_path)) 762*4882a593Smuzhiyun self.assertTrue(os.path.exists(fitimage_path), 763*4882a593Smuzhiyun "%s FIT image doesn't exist" % (fitimage_path)) 764*4882a593Smuzhiyun 765*4882a593Smuzhiyun kernel_load = str(get_bb_var('UBOOT_LOADADDRESS')) 766*4882a593Smuzhiyun kernel_entry = str(get_bb_var('UBOOT_ENTRYPOINT')) 767*4882a593Smuzhiyun kernel_type = str(get_bb_var('UBOOT_MKIMAGE_KERNEL_TYPE')) 768*4882a593Smuzhiyun kernel_compression = str(get_bb_var('FIT_KERNEL_COMP_ALG')) 769*4882a593Smuzhiyun uboot_arch = str(get_bb_var('UBOOT_ARCH')) 770*4882a593Smuzhiyun fit_hash_alg = str(get_bb_var('FIT_HASH_ALG')) 771*4882a593Smuzhiyun 772*4882a593Smuzhiyun its_file = open(fitimage_its_path) 773*4882a593Smuzhiyun 774*4882a593Smuzhiyun its_lines = [line.strip() for line in its_file.readlines()] 775*4882a593Smuzhiyun 776*4882a593Smuzhiyun exp_node_lines = [ 777*4882a593Smuzhiyun 'kernel-1 {', 778*4882a593Smuzhiyun 'description = "Linux kernel";', 779*4882a593Smuzhiyun 'data = /incbin/("linux.bin");', 780*4882a593Smuzhiyun 'type = "' + kernel_type + '";', 781*4882a593Smuzhiyun 'arch = "' + uboot_arch + '";', 782*4882a593Smuzhiyun 'os = "linux";', 783*4882a593Smuzhiyun 'compression = "' + kernel_compression + '";', 784*4882a593Smuzhiyun 'load = <' + kernel_load + '>;', 785*4882a593Smuzhiyun 'entry = <' + kernel_entry + '>;', 786*4882a593Smuzhiyun 'hash-1 {', 787*4882a593Smuzhiyun 'algo = "' + fit_hash_alg +'";', 788*4882a593Smuzhiyun '};', 789*4882a593Smuzhiyun '};' 790*4882a593Smuzhiyun ] 791*4882a593Smuzhiyun 792*4882a593Smuzhiyun node_str = exp_node_lines[0] 793*4882a593Smuzhiyun 794*4882a593Smuzhiyun test_passed = False 795*4882a593Smuzhiyun 796*4882a593Smuzhiyun print ("checking kernel node\n") 797*4882a593Smuzhiyun 798*4882a593Smuzhiyun if node_str in its_lines: 799*4882a593Smuzhiyun node_start_idx = its_lines.index(node_str) 800*4882a593Smuzhiyun node = its_lines[node_start_idx:(node_start_idx + len(exp_node_lines))] 801*4882a593Smuzhiyun if node == exp_node_lines: 802*4882a593Smuzhiyun print("kernel node verified") 803*4882a593Smuzhiyun else: 804*4882a593Smuzhiyun self.assertTrue(test_passed == True,"kernel node does not match expectation") 805*4882a593Smuzhiyun 806*4882a593Smuzhiyun rx_configs = re.compile("^conf-.*") 807*4882a593Smuzhiyun its_configs = list(filter(rx_configs.match, its_lines)) 808*4882a593Smuzhiyun 809*4882a593Smuzhiyun for cfg_str in its_configs: 810*4882a593Smuzhiyun cfg_start_idx = its_lines.index(cfg_str) 811*4882a593Smuzhiyun line_idx = cfg_start_idx + 2 812*4882a593Smuzhiyun node_end = False 813*4882a593Smuzhiyun while node_end == False: 814*4882a593Smuzhiyun if its_lines[line_idx] == "};" and its_lines[line_idx-1] == "};" : 815*4882a593Smuzhiyun node_end = True 816*4882a593Smuzhiyun line_idx = line_idx + 1 817*4882a593Smuzhiyun 818*4882a593Smuzhiyun node = its_lines[cfg_start_idx:line_idx] 819*4882a593Smuzhiyun print("checking configuration " + cfg_str.rstrip(" {")) 820*4882a593Smuzhiyun rx_desc_line = re.compile("^description.*1 Linux kernel.*") 821*4882a593Smuzhiyun if len(list(filter(rx_desc_line.match, node))) != 1: 822*4882a593Smuzhiyun self.assertTrue(test_passed == True,"kernel keyword not found in the description line") 823*4882a593Smuzhiyun break 824*4882a593Smuzhiyun else: 825*4882a593Smuzhiyun print("kernel keyword found in the description line") 826*4882a593Smuzhiyun 827*4882a593Smuzhiyun if 'kernel = "kernel-1";' not in node: 828*4882a593Smuzhiyun self.assertTrue(test_passed == True,"kernel line not found") 829*4882a593Smuzhiyun break 830*4882a593Smuzhiyun else: 831*4882a593Smuzhiyun print("kernel line found") 832*4882a593Smuzhiyun 833*4882a593Smuzhiyun rx_sign_line = re.compile("^sign-images.*kernel.*") 834*4882a593Smuzhiyun if len(list(filter(rx_sign_line.match, node))) != 1: 835*4882a593Smuzhiyun self.assertTrue(test_passed == True,"kernel hash not signed") 836*4882a593Smuzhiyun break 837*4882a593Smuzhiyun else: 838*4882a593Smuzhiyun print("kernel hash signed") 839*4882a593Smuzhiyun 840*4882a593Smuzhiyun test_passed = True 841*4882a593Smuzhiyun self.assertTrue(test_passed == True,"Initramfs bundle test success") 842