[meta-oe,2/2] oeqa/selftest/imagefeatures: adding fitImage testcases for initramfs bundle and boot script

Submitted by abdellatif.elkhlifi@arm.com on Oct. 13, 2020, 11:32 a.m. | Patch ID: 177184

Details

Message ID 20201013113232.29228-3-abdellatif.elkhlifi@arm.com
State Master Next
Commit 254c26d1495a5e10b27ffa89954b8db7f6fd7261
Headers show

Commit Message

abdellatif.elkhlifi@arm.com Oct. 13, 2020, 11:32 a.m.
From: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>

- This commit allows to test the initramfs bundle feature through a new testcase that  checks
if FIT image and Image Tree Source (ITS) are built and the Image Tree Source has the correct
initramfs bundle fields.
The FIT settings are automatically read from the current machine conf file or from local.conf.

This testcase can be run through the following command:

oe-selftest -r imagefeatures.ImageFeatures.test_signed_fit_image_initramfs

- This commit also allows to test the u-boot script feature through a new testcase that checks
if FIT image and Image Tree Source are built and the Image Tree Source has the correct
uboot script fields.
The FIT settings are automatically read from the current machine conf file or from local.conf.

This testcase can be run through the following command:

oe-selftest -r imagefeatures.ImageFeatures.test_signed_fit_image_bootscr

Change-Id: I2d4e670ca9cd4971194edccf9fa6c5ede6627f31
Signed-off-by: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
---
 meta/lib/oeqa/selftest/cases/imagefeatures.py | 215 ++++++++++++++++++
 1 file changed, 215 insertions(+)

Patch hide | download patch | download mbox

diff --git a/meta/lib/oeqa/selftest/cases/imagefeatures.py b/meta/lib/oeqa/selftest/cases/imagefeatures.py
index f7a2533746..69c4313c5e 100644
--- a/meta/lib/oeqa/selftest/cases/imagefeatures.py
+++ b/meta/lib/oeqa/selftest/cases/imagefeatures.py
@@ -7,6 +7,7 @@  from oeqa.utils.commands import runCmd, bitbake, get_bb_var, runqemu
 from oeqa.utils.sshcontrol import SSHControl
 import os
 import json
+import re
 
 class ImageFeatures(OESelftestTestCase):
 
@@ -278,6 +279,7 @@  PNBLACKLIST[busybox] = "Don't build this"
         """
         config = """
 # Enable creation of fitImage
+
 KERNEL_IMAGETYPE = "Image"
 KERNEL_IMAGETYPES += " fitImage "
 KERNEL_CLASSES = " kernel-fitimage "
@@ -337,6 +339,219 @@  UBOOT_ENTRYPOINT = "0x80080000"
                 "Fields in Image Tree Source File %s did not match, error in finding %s"
                 % (fitimage_its_path, its_field_check[field_index]))
 
+    def test_signed_fit_image_initramfs(self):
+        """
+        Summary:     Check if FIT image and Image Tree Source (its) are built
+                     and the Image Tree Source has the correct initramfs bundle fields.
+                     The FIT settings are automatically read from the current machine
+                     conf file or from local.conf , no need to set values in this function
+        Expected:    1. fitImage and fitImage ITS are built with initramfs bundle support
+                     2. All the fields in the kernel node are as expected (matching the
+                        conf settings)
+                     3. The kernel is included in all the available configurations and
+                        its hash is included in the configuration signature
+        Usage:      Set the following variables in the machine conf file:
+
+                    INITRAMFS_IMAGE_BUNDLE = "1"
+                    INITRAMFS_IMAGE = "<the initramfs image>"
+                    UBOOT_CONFIG ??= "FIT"
+                    UBOOT_CONFIG[FIT] = "<machine>_defconfig"
+                    KERNEL_CLASSES = " kernel-fitimage "
+                    KERNEL_IMAGETYPES = "fitImage"
+                    UBOOT_SIGN_ENABLE = "1"
+                    UBOOT_SIGN_KEYNAME = "<key name>"
+                    UBOOT_SIGN_KEYDIR ?= "${DEPLOY_DIR_IMAGE}"
+                    UBOOT_DTB_BINARY = "u-boot.dtb"
+                    UBOOT_ENTRYPOINT  = "<initramfs bundle address in RAM>"
+                    UBOOT_LOADADDRESS = "<initramfs bundle address in RAM>"
+                    UBOOT_DTB_LOADADDRESS = "<DTB address in RAM>"
+                    UBOOT_ARCH = "arm"
+                    UBOOT_MKIMAGE_DTCOPTS = "-I dts -O dtb -p 2000"
+                    UBOOT_EXTLINUX = "0"
+                    KERNEL_IMAGETYPE_REPLACEMENT = "<the value set in the kernel-fitimage.bbclass>"
+                    FIT_HASH_ALG = "<sha algorithm>"
+
+        Product:     oe-core
+        Author:      Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
+        """
+
+        # fitImage is created as part of linux recipe
+        bitbake("virtual/kernel")
+
+        image_type = get_bb_var('INITRAMFS_IMAGE')
+        deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE')
+        machine = get_bb_var('MACHINE')
+        fitimage_its_path = os.path.join(deploy_dir_image,
+                    "fitImage-its-%s-%s-%s" % (image_type, machine, machine))
+        fitimage_path = os.path.join(deploy_dir_image,"fitImage")
+
+        self.assertTrue(os.path.exists(fitimage_its_path),
+            "%s image tree source doesn't exist" % (fitimage_its_path))
+        self.assertTrue(os.path.exists(fitimage_path),
+            "%s FIT image doesn't exist" % (fitimage_path))
+
+        kernel_load = str(get_bb_var('UBOOT_LOADADDRESS'))
+        kernel_entry = str(get_bb_var('UBOOT_ENTRYPOINT'))
+        initramfs_bundle_format = str(get_bb_var('KERNEL_IMAGETYPE_REPLACEMENT'))
+        uboot_arch = str(get_bb_var('UBOOT_ARCH'))
+        initramfs_bundle = "arch/" + uboot_arch + "/boot/" + initramfs_bundle_format + ".initramfs"
+        fit_hash_alg = str(get_bb_var('FIT_HASH_ALG'))
+
+        its_file = open(fitimage_its_path)
+
+        its_lines = [line.strip() for line in its_file.readlines()]
+
+        exp_node_lines = [
+            'kernel@1 {',
+            'description = "Linux kernel";',
+            'data = /incbin/("' + initramfs_bundle + '");',
+            'type = "kernel";',
+            'arch = "' + uboot_arch + '";',
+            'os = "linux";',
+            'compression = "none";',
+            'load = <' + kernel_load + '>;',
+            'entry = <' + kernel_entry + '>;',
+            'hash@1 {',
+            'algo = "' + fit_hash_alg +'";',
+            '};',
+            '};'
+        ]
+
+        node_str = exp_node_lines[0]
+
+        test_passed = False
+
+        if node_str in its_lines:
+            node_start_idx = its_lines.index(node_str)
+            node = its_lines[node_start_idx:(node_start_idx + len(exp_node_lines))]
+            if node != exp_node_lines:
+                self.assertTrue(test_passed == True,"kernel node does not match expectation")
+
+        rx_configs = re.compile("^conf@.*")
+        its_configs = list(filter(rx_configs.match, its_lines))
+
+        for cfg_str in its_configs:
+            cfg_start_idx = its_lines.index(cfg_str)
+            line_idx = cfg_start_idx + 2
+            node_end = False
+            while node_end == False:
+                if its_lines[line_idx] == "};" and its_lines[line_idx-1] == "};" :
+                    node_end = True
+                line_idx = line_idx + 1
+
+            node = its_lines[cfg_start_idx:line_idx]
+            rx_desc_line = re.compile("^description.*1 Linux kernel.*")
+            if len(list(filter(rx_desc_line.match, node))) != 1:
+                self.assertTrue(test_passed == True,"kernel keyword not found in the description line")
+                break
+
+            if 'kernel = "kernel@1";' not in node:
+                self.assertTrue(test_passed == True,"kernel line not found")
+                break
+
+            rx_sign_line = re.compile("^sign-images.*kernel.*")
+            if len(list(filter(rx_sign_line.match, node))) != 1:
+                self.assertTrue(test_passed == True,"kernel hash not signed")
+                break
+
+            test_passed = True
+
+    def test_signed_fit_image_bootscr(self):
+        """
+        Summary:     Check if FIT image and Image Tree Source (its) are built
+                     and the Image Tree Source has the correct uboot script fields.
+                     The FIT settings are automatically read from the current machine
+                     conf file or from local.conf , no need to set values in this function
+        Expected:    1. fitImage and fitImage ITS are built with uboot script support
+                     2. All the fields in the uboot script node are as expected (matching the
+                        conf settings)
+                     3. The uboot script is included in all the available configurations and
+                        its hash is included in the configuration signature
+        Usage:      In addition to the settings related to the FIT, make sure the
+                    following variables are set in the machine conf file:
+
+                    UBOOT_ENV_SUFFIX = "scr"
+                    UBOOT_ENV_BINARY = "${UBOOT_ENV}.${UBOOT_ENV_SUFFIX}"
+
+        Product:     oe-core
+        Author:      Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
+        """
+
+        # fitImage is created as part of linux recipe
+        bitbake("virtual/kernel")
+
+        image_type = get_bb_var('INITRAMFS_IMAGE')
+        deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE')
+        machine = get_bb_var('MACHINE')
+        fitimage_its_path = os.path.join(deploy_dir_image,
+                    "fitImage-its-%s-%s-%s" % (image_type, machine, machine))
+        fitimage_path = os.path.join(deploy_dir_image,"fitImage")
+
+        self.assertTrue(os.path.exists(fitimage_its_path),
+            "%s image tree source doesn't exist" % (fitimage_its_path))
+        self.assertTrue(os.path.exists(fitimage_path),
+            "%s FIT image doesn't exist" % (fitimage_path))
+
+        uboot_arch = str(get_bb_var('UBOOT_ARCH'))
+        fit_hash_alg = str(get_bb_var('FIT_HASH_ALG'))
+        uboot_env_bin = str(get_bb_var('UBOOT_ENV_BINARY'))
+
+        its_file = open(fitimage_its_path)
+
+        its_lines = [line.strip() for line in its_file.readlines()]
+
+        exp_node_lines = [
+            'bootscr@' + uboot_env_bin + ' {',
+            'description = "U-boot script";',
+            'data = /incbin/("' + uboot_env_bin + '");',
+            'type = "script";',
+            'arch = "' + uboot_arch + '";',
+            'compression = "none";',
+            'hash@1 {',
+            'algo = "' + fit_hash_alg +'";',
+            '};',
+            '};'
+        ]
+
+        node_str = exp_node_lines[0]
+
+        test_passed = False
+
+        if node_str in its_lines:
+            node_start_idx = its_lines.index(node_str)
+            node = its_lines[node_start_idx:(node_start_idx + len(exp_node_lines))]
+            if node != exp_node_lines:
+                self.assertTrue(test_passed == True,"uboot script node does not match expectation")
+
+        rx_configs = re.compile("^conf@.*")
+        its_configs = list(filter(rx_configs.match, its_lines))
+
+        for cfg_str in its_configs:
+            cfg_start_idx = its_lines.index(cfg_str)
+            line_idx = cfg_start_idx + 2
+            node_end = False
+            while node_end == False:
+                if its_lines[line_idx] == "};" and its_lines[line_idx-1] == "};" :
+                    node_end = True
+                line_idx = line_idx + 1
+
+            node = its_lines[cfg_start_idx:line_idx]
+            rx_desc_line = re.compile("^description.*u-boot script.*")
+            if len(list(filter(rx_desc_line.match, node))) != 1:
+                self.assertTrue(test_passed == True,"uboot script keyword not found in the description line")
+                break
+
+            if 'bootscr = "bootscr@' + uboot_env_bin + '";' not in node:
+                self.assertTrue(test_passed == True,"uboot script line not found")
+                break
+
+            rx_sign_line = re.compile("^sign-images.*bootscr.*")
+            if len(list(filter(rx_sign_line.match, node))) != 1:
+                self.assertTrue(test_passed == True,"uboot script hash not signed")
+                break
+
+            test_passed = True
+
     def test_image_gen_debugfs(self):
         """
         Summary:     Check debugfs generation