diff mbox series

[2/5] arm-systemready: Introduce the Arm SystemReady layer

Message ID 20231103094939.1290558-2-Debbie.Martin@arm.com
State New
Headers show
Series [1/5] arm/fvp-base: Update the default testsuites | expand

Commit Message

Debbie Martin Nov. 3, 2023, 9:49 a.m. UTC
Add the meta-arm-systemready layer. This provides the infrastructure to
load and run the Arm SystemReady IR ACS v2.0.0 prebuilt image and
analyze the results.

The recipes included are as follows:
1. arm-systemready-firmware: Enables the ARM_SYSTEMREADY_FIRMWARE machine
   conf variable to be used to specify which firmware packages to deploy.
2. arm-systemready-ir-acs: Runs the Arm SystemReady IR ACS tests from
   the pre-built images and checks the results adhere to the specification.
3. arm-systemready-linux-distros-[debian|opensuse]: Install the distro of
   choice from CD/DVD image to target disk image.

Signed-off-by: Debbie Martin <Debbie.Martin@arm.com>
Signed-off-by: Diego Sueiro <diego.sueiro@arm.com>
Signed-off-by: Peter Hoyes <Peter.Hoyes@arm.com>
Signed-off-by: Qi Feng <qi.feng@arm.com>
Signed-off-by: Robbie Cao <robbie.cao@arm.com>
Signed-off-by: Tomás González <tomasagustin.gonzalezorlando@arm.com
Signed-off-by: Vineeth Raveendran <vineeth.raveendran@arm.com>
---
 .../classes/arm-systemready-acs.bbclass       | 161 ++++++++++++++++++
 .../classes/extra_imagedepends_only.bbclass   |  25 +++
 meta-arm-systemready/conf/layer.conf          |  15 ++
 .../runtime/cases/arm_systemready_ir_acs.py   |  37 ++++
 .../arm-systemready-firmware.bb               |  14 ++
 .../python3-construct-native_2.10.68.bb       |  13 ++
 .../arm-systemready-ir-acs.bb                 |  61 +++++++
 .../arm-systemready-scripts-native.bb         |  31 ++++
 ...-Return-non-zero-exit-code-on-failur.patch |  37 ++++
 ...-sr-results-Device-tree-improvements.patch |  77 +++++++++
 .../edk2-test-parser-native.bb                |  26 +++
 .../arm-systemready-linux-distros-debian.bb   |  41 +++++
 .../arm-systemready-linux-distros-opensuse.bb |  69 ++++++++
 .../arm-systemready-linux-distros.inc         |  50 ++++++
 14 files changed, 657 insertions(+)
 create mode 100644 meta-arm-systemready/classes/arm-systemready-acs.bbclass
 create mode 100644 meta-arm-systemready/classes/extra_imagedepends_only.bbclass
 create mode 100644 meta-arm-systemready/conf/layer.conf
 create mode 100644 meta-arm-systemready/lib/oeqa/runtime/cases/arm_systemready_ir_acs.py
 create mode 100644 meta-arm-systemready/recipes-bsp/arm-systemready/arm-systemready-firmware.bb
 create mode 100644 meta-arm-systemready/recipes-devtools/python/python3-construct-native_2.10.68.bb
 create mode 100644 meta-arm-systemready/recipes-test/arm-systemready-acs/arm-systemready-ir-acs.bb
 create mode 100644 meta-arm-systemready/recipes-test/arm-systemready-acs/arm-systemready-scripts-native.bb
 create mode 100644 meta-arm-systemready/recipes-test/arm-systemready-acs/arm-systemready-scripts/0001-check-sr-results-Return-non-zero-exit-code-on-failur.patch
 create mode 100644 meta-arm-systemready/recipes-test/arm-systemready-acs/arm-systemready-scripts/0002-check-sr-results-Device-tree-improvements.patch
 create mode 100644 meta-arm-systemready/recipes-test/arm-systemready-acs/edk2-test-parser-native.bb
 create mode 100644 meta-arm-systemready/recipes-test/arm-systemready-linux-distros/arm-systemready-linux-distros-debian.bb
 create mode 100644 meta-arm-systemready/recipes-test/arm-systemready-linux-distros/arm-systemready-linux-distros-opensuse.bb
 create mode 100644 meta-arm-systemready/recipes-test/arm-systemready-linux-distros/arm-systemready-linux-distros.inc
diff mbox series

Patch

diff --git a/meta-arm-systemready/classes/arm-systemready-acs.bbclass b/meta-arm-systemready/classes/arm-systemready-acs.bbclass
new file mode 100644
index 00000000..e9888023
--- /dev/null
+++ b/meta-arm-systemready/classes/arm-systemready-acs.bbclass
@@ -0,0 +1,161 @@ 
+# This class contains the common logic to deploy the SystemReady ACS pre-built
+# image and set up the testimage environment. It is to be inherited by recipes
+# which contains the URI to download the SystemReady ACS image.
+# This class also contains a testimage "postfunc" called acs_logs_handle which
+# performs the following functions after the tests have completed:
+#   * Extract the acs_results directory from the Wic image to
+#     ${WORKDIR}/testimage
+#   * Create a symlink to the acs_results in ${TMPDIR}/log/oeqa for ease of
+#     access
+#   * Run the test parser, format results, and check results routines
+
+INHIBIT_DEFAULT_DEPS = "1"
+COMPATIBLE_HOST = "aarch64-*"
+PACKAGE_ARCH = "${MACHINE_ARCH}"
+inherit nopackages deploy rootfs-postcommands ${IMAGE_CLASSES} python3native
+
+do_configure[noexec] = "1"
+do_compile[noexec] = "1"
+do_install[noexec] = "1"
+do_testimage[depends] += "mtools-native:do_populate_sysroot"
+
+# Deploy with this suffix so it is picked up in the machine configuration
+IMAGE_DEPLOY_SUFFIX ?= ".wic"
+
+# Post-process commands may write to IMGDEPLOYDIR
+IMGDEPLOYDIR = "${DEPLOYDIR}"
+# Write the test data in IMAGE_POSTPROCESS_COMMAND
+IMAGE_POSTPROCESS_COMMAND += "write_image_test_data; "
+
+python do_deploy() {
+    deploydir = d.getVar('DEPLOYDIR')
+    suffix = d.getVar('IMAGE_DEPLOY_SUFFIX')
+    imgfile = os.path.join(d.getVar('WORKDIR'), d.getVar('IMAGE_FILENAME'))
+    deployfile = os.path.join(deploydir, d.getVar('IMAGE_NAME') + suffix)
+    linkfile = os.path.join(deploydir, d.getVar('IMAGE_LINK_NAME') + suffix)
+
+    # Install the image file in the deploy directory
+    import shutil
+    shutil.copyfile(imgfile, deployfile)
+    if os.path.lexists(linkfile):
+        os.remove(manifest_link)
+    os.symlink(os.path.basename(deployfile), linkfile)
+
+    # Run the image post-process commands
+    from oe.utils import execute_pre_post_process
+    post_process_cmds = d.getVar("IMAGE_POSTPROCESS_COMMAND")
+    execute_pre_post_process(d, post_process_cmds)
+
+    # Copy the report.txt to DEPLOYDIR
+    # The machine-specific implementation can optionally put the report file in
+    # ${WORKDIR}/report.txt. If there is no such file present, use the template.
+    workdir = d.getVar('WORKDIR')
+    report_file = os.path.join(workdir, "report.txt")
+    report_file_dest = os.path.join(deploydir, "report.txt")
+    if os.path.exists(report_file):
+        report_file_to_copy = report_file
+    else:
+        report_file_to_copy = os.path.join(workdir, "systemready-ir-template",
+                                            "report.txt")
+    shutil.copyfile(report_file_to_copy, report_file_dest)
+
+    # Ensure an empty rootfs manifest exists (required by testimage)
+    fname = os.path.join(deploydir, d.getVar('IMAGE_LINK_NAME') + ".manifest")
+    open(fname, 'w').close()
+}
+addtask deploy after do_install before do_image_complete
+
+do_image_complete() {
+    true
+}
+addtask image_complete after do_deploy before do_build
+do_image_complete[depends] += "arm-systemready-firmware:do_image_complete"
+
+ACS_LOG_NAME = "acs_results_${DATETIME}"
+ACS_LOG_NAME[vardepsexclude] += "DATETIME"
+ACS_LOG_DIR = "${TEST_LOG_DIR}/${ACS_LOG_NAME}"
+ACS_LOG_LINK = "${TEST_LOG_DIR}/acs_results"
+TEST_LOG_DIR = "${WORKDIR}/testimage"
+RM_WORK_EXCLUDE_ITEMS += "${@ os.path.basename(d.getVar('TEST_LOG_DIR')) }"
+
+do_testimage[postfuncs] += "acs_logs_handle"
+do_testimage[depends] += "edk2-test-parser-native:do_populate_sysroot \
+                          arm-systemready-scripts-native:do_populate_sysroot"
+
+# Process the logs
+python acs_logs_handle() {
+    import logging
+    from oeqa.utils import make_logger_bitbake_compatible
+    import shutil
+
+    deploy_dir_image = d.getVar('DEPLOY_DIR_IMAGE')
+    systemready_scripts_dir = os.path.join(d.getVar('STAGING_LIBDIR_NATIVE'),
+                                           "systemready_scripts")
+    edk2_test_parser_dir = os.path.join(d.getVar('STAGING_LIBDIR_NATIVE'),
+                                        "edk2_test_parser")
+    deployfile = os.path.join(deploy_dir_image, d.getVar('IMAGE_LINK_NAME')
+                              + d.getVar('IMAGE_DEPLOY_SUFFIX'))
+
+    testimage_dir = d.getVar('TEST_LOG_DIR')
+    logdir = d.getVar('ACS_LOG_DIR')
+    loglink = d.getVar('ACS_LOG_LINK')
+
+    # Copy the report.txt file from DEPLOY_DIR_IMAGE
+    report_file = os.path.join(deploy_dir_image, "report.txt")
+    report_file_dest = os.path.join(testimage_dir, "report.txt")
+    shutil.copyfile(report_file, report_file_dest)
+
+    # Extract the log files from the Wic image to the testimage logs directory
+    resultspath = deployfile + ':3/acs_results'
+    import subprocess
+    subprocess.run(['wic', 'cp', resultspath, logdir], check=True)
+
+    # Create a symlink to the acs_results directory
+    if os.path.lexists(loglink):
+        os.remove(loglink)
+    os.symlink(os.path.basename(logdir), loglink)
+
+    # Create a top-level symlink to the acs_results directory
+    top_logdir = os.path.join(get_testimage_json_result_dir(d), d.getVar("PN"))
+    log_name = d.getVar('ACS_LOG_NAME')
+    top_link = os.path.join(top_logdir, log_name)
+    log_target = os.path.relpath(logdir, top_logdir)
+    os.symlink(log_target, top_link)
+
+    # Parse the logs and generate results file
+    logger = make_logger_bitbake_compatible(logging.getLogger("BitBake"))
+
+    sct_log = os.path.join(logdir, 'sct_results', 'Overall', 'Summary.ekl')
+    sct_seq = os.path.join(logdir, 'sct_results', 'Sequence', 'EBBR.seq')
+
+    parser_path = os.path.join(edk2_test_parser_dir, "parser.py")
+    # format-sr-results.py needs the output file to be called "result.md"
+    subprocess.run([parser_path, sct_log, sct_seq, "--md",
+                   os.path.join(logdir, "result.md")], check=True)
+
+    scripts_path = os.path.join(systemready_scripts_dir,
+                                "format-sr-results.py")
+    summary_path = os.path.join(testimage_dir, "summary.md")
+    subprocess.run([scripts_path, "--dir", testimage_dir, "--md", summary_path],
+                   check=True)
+
+    # Symlink acs-console.log to default_log
+    subprocess.run(["ln", "-sf", os.path.join(testimage_dir, "default_log"),
+                    os.path.join(testimage_dir, "acs-console.log")], check=True)
+
+    # Run the check-sr-results.py systemready script to check the results
+    check_sr_results_log_path = os.path.join(testimage_dir,
+                                             "check_sr_results.log")
+    with open(check_sr_results_log_path, "w") as f:
+        check_sr_results_path = os.path.join(systemready_scripts_dir,
+                                            "check-sr-results.py")
+        try:
+            subprocess.run([check_sr_results_path, "--dir", testimage_dir,
+                            "--print-meta", "--debug"],
+                           stdout=f, stderr=f, text=True, check=True)
+        except subprocess.CalledProcessError:
+            logger.error(f"ACS run failed the check SystemReady results. See "
+                         f"{summary_path} and {check_sr_results_log_path} for "
+                         f"details of the error.")
+            raise bb.BBHandledException()
+}
diff --git a/meta-arm-systemready/classes/extra_imagedepends_only.bbclass b/meta-arm-systemready/classes/extra_imagedepends_only.bbclass
new file mode 100644
index 00000000..bf06a9f4
--- /dev/null
+++ b/meta-arm-systemready/classes/extra_imagedepends_only.bbclass
@@ -0,0 +1,25 @@ 
+# This class is to be inherited by recipes interested in only deploying what is
+# listed in the EXTRA_IMAGEDEPENDS.
+# It is inheriting the image.bbclass to make sure that the
+# image_license.manifest is generated.
+
+IMAGE_FSTYPES = ""
+
+inherit image
+
+IMAGE_FEATURES = ""
+EXTRA_IMAGE_FEATURES = ""
+
+INHIBIT_DEFAULT_DEPS = "1"
+DEPENDS = ""
+RDEPENDS = ""
+RRECOMMENDS = ""
+
+deltask do_prepare_recipe_sysroot
+deltask do_flush_pseudodb
+deltask do_image_qa
+do_rootfs[depends] = ""
+do_rootfs[noexec] = "1"
+do_image[noexec] = "1"
+do_image_complete[noexec] = "1"
+do_build[depends] = ""
diff --git a/meta-arm-systemready/conf/layer.conf b/meta-arm-systemready/conf/layer.conf
new file mode 100644
index 00000000..27bb568e
--- /dev/null
+++ b/meta-arm-systemready/conf/layer.conf
@@ -0,0 +1,15 @@ 
+# We have a conf and classes directory, add to BBPATH
+BBPATH .= ":${LAYERDIR}"
+
+# We have recipes-* directories, add to BBFILES
+BBFILES += "${LAYERDIR}/recipes-*/*/*.bb \
+            ${LAYERDIR}/recipes-*/*/*.bbappend"
+
+BBFILE_COLLECTIONS += "meta-arm-systemready"
+BBFILE_PATTERN_meta-arm-systemready = "^${LAYERDIR}/"
+
+LAYERSERIES_COMPAT_meta-arm-systemready = "nanbield"
+
+LAYERDEPENDS_meta-arm-systemready = "core"
+
+addpylib ${LAYERDIR}/lib oeqa
diff --git a/meta-arm-systemready/lib/oeqa/runtime/cases/arm_systemready_ir_acs.py b/meta-arm-systemready/lib/oeqa/runtime/cases/arm_systemready_ir_acs.py
new file mode 100644
index 00000000..518d1aa2
--- /dev/null
+++ b/meta-arm-systemready/lib/oeqa/runtime/cases/arm_systemready_ir_acs.py
@@ -0,0 +1,37 @@ 
+from oeqa.runtime.case import OERuntimeTestCase
+
+
+class SystemReadyACSTest(OERuntimeTestCase):
+    def setUp(self):
+        self.console = self.td.get('ARM_SYSTEMREADY_ACS_CONSOLE')
+        self.assertNotEqual(self.console, '',
+                            msg='ARM_SYSTEMREADY_ACS_CONSOLE is not set')
+
+    def test_acs(self):
+        """
+        The purpose of this test case is to detect any issues with the ACS
+        tests themselves. The intention is to fail only if there is an issue
+        running the tests, not if an ACS test fails
+        """
+        self.target.transition('on')
+        # The tests finish on a root shell
+        test_patterns = [r'([a-zA-Z0-9_ ]+): \[([a-zA-Z_ ]+)\]',
+                         'ACS run is completed'] # Signifies successful completion
+
+        while True:
+            match_id = self.target.expect(self.console, test_patterns,
+                                          timeout=10*60*60)
+            if match_id == 0:
+                # A test group's result has been printed
+                matches = self.target.match(self.console)
+                group_name = matches[1].decode().strip()
+                status = matches[2].decode().strip()
+                self.logger.info(f'Test Group ({group_name}): {status}')
+            elif match_id == 1:
+                break
+
+        # Workaround to ensure the model syncs the log files to disk
+        self.target.sendline(self.console, r'sync /mnt')
+        self.target.expect(self.console, r'root@generic-arm64:~#')
+
+        self.logger.info('Linux tests complete')
diff --git a/meta-arm-systemready/recipes-bsp/arm-systemready/arm-systemready-firmware.bb b/meta-arm-systemready/recipes-bsp/arm-systemready/arm-systemready-firmware.bb
new file mode 100644
index 00000000..54ffc859
--- /dev/null
+++ b/meta-arm-systemready/recipes-bsp/arm-systemready/arm-systemready-firmware.bb
@@ -0,0 +1,14 @@ 
+SUMMARY = "Arm SystemReady Firmware Image"
+DESCRIPTION = "This recipe ensures that all packages listed in \
+ARM_SYSTEMREADY_FIRMWARE variable (set at machine conf) are deployed."
+
+EXTRA_IMAGEDEPENDS = "${ARM_SYSTEMREADY_FIRMWARE}"
+
+inherit extra_imagedepends_only
+
+python() {
+    if not d.getVar("ARM_SYSTEMREADY_FIRMWARE"):
+        raise bb.parse.SkipRecipe("ARM_SYSTEMREADY_FIRMWARE needs to be set")
+}
+
+do_testimage[noexec] = "1"
diff --git a/meta-arm-systemready/recipes-devtools/python/python3-construct-native_2.10.68.bb b/meta-arm-systemready/recipes-devtools/python/python3-construct-native_2.10.68.bb
new file mode 100644
index 00000000..5e39ae72
--- /dev/null
+++ b/meta-arm-systemready/recipes-devtools/python/python3-construct-native_2.10.68.bb
@@ -0,0 +1,13 @@ 
+SUMMARY = "A powerful declarative symmetric parser/builder for binary data"
+HOMEPAGE = "https://github.com/construct/construct"
+
+LICENSE = "MIT"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=202b39559c1c79fe4715ce81e9e0ac02"
+
+PYPI_PACKAGE = "construct"
+
+SRC_URI[sha256sum] = "7b2a3fd8e5f597a5aa1d614c3bd516fa065db01704c72a1efaaeec6ef23d8b45"
+
+inherit pypi
+inherit setuptools3
+inherit native
diff --git a/meta-arm-systemready/recipes-test/arm-systemready-acs/arm-systemready-ir-acs.bb b/meta-arm-systemready/recipes-test/arm-systemready-acs/arm-systemready-ir-acs.bb
new file mode 100644
index 00000000..f9226c31
--- /dev/null
+++ b/meta-arm-systemready/recipes-test/arm-systemready-acs/arm-systemready-ir-acs.bb
@@ -0,0 +1,61 @@ 
+SUMMARY = "Arm SystemReady IR ACS"
+DESCRIPTION = "Arm SystemReady IR Architecture Compliance Suite prebuilt image"
+
+LICENSE = "AFL-2.1 & Apache-2.0 & BSD-2-Clause & BSD-2-Clause-Patent \
+           & BSD-3-Clause & BSD-4-Clause & bzip2-1.0.4 & bzip2-1.0.6 & CC-BY-SA-4.0 \
+           & curl & GPL-2.0-only & GPL-2.0-or-later & GPL-3.0-only \
+           & GPL-3.0-or-later & GPL-3.0-with-GCC-exception & ISC \
+           & LGPL-2.0-only & LGPL-2.0-or-later & LGPL-2.1-only \
+           & LGPL-2.1-or-later & LGPL-3.0-only & MIT & MPL-2.0 & PD & PSF-2.0 \
+           & Python-2.0 & Unicode-DFS-2016 & Unicode-TOU & Zlib"
+LIC_FILES_CHKSUM = "\
+file://${COMMON_LICENSE_DIR}/AFL-2.1;md5=e40039b90e182a056bcd9ad3e47ddd71 \
+file://${COMMON_LICENSE_DIR}/Apache-2.0;md5=89aea4e17d99a7cacdbeed46a0096b10 \
+file://${COMMON_LICENSE_DIR}/BSD-2-Clause;md5=cb641bc04cda31daea161b1bc15da69f \
+file://${COMMON_LICENSE_DIR}/BSD-2-Clause-Patent;md5=0518d409dae93098cca8dfa932f3ab1b \
+file://${COMMON_LICENSE_DIR}/BSD-3-Clause;md5=550794465ba0ec5312d6919e203a55f9 \
+file://${COMMON_LICENSE_DIR}/BSD-4-Clause;md5=624d9e67e8ac41a78f6b6c2c55a83a2b \
+file://${COMMON_LICENSE_DIR}/bzip2-1.0.4;md5=452e1b423688222dcfc3cb9462c92902 \
+file://${COMMON_LICENSE_DIR}/bzip2-1.0.6;md5=841c5495611ae95b13e80fa4a0627333 \
+file://${COMMON_LICENSE_DIR}/CC-BY-SA-4.0;md5=4084714af41157e38872e798eb3fe1b1 \
+file://${COMMON_LICENSE_DIR}/curl;md5=f7adb1397db248527ffed14d947e445c \
+file://${COMMON_LICENSE_DIR}/GPL-2.0-only;md5=801f80980d171dd6425610833a22dbe6 \
+file://${COMMON_LICENSE_DIR}/GPL-2.0-or-later;md5=fed54355545ffd980b814dab4a3b312c \
+file://${COMMON_LICENSE_DIR}/GPL-3.0-only;md5=c79ff39f19dfec6d293b95dea7b07891 \
+file://${COMMON_LICENSE_DIR}/GPL-3.0-or-later;md5=1c76c4cc354acaac30ed4d5eefea7245 \
+file://${COMMON_LICENSE_DIR}/GPL-3.0-with-GCC-exception;md5=aef5f35c9272f508be848cd99e0151df \
+file://${COMMON_LICENSE_DIR}/ISC;md5=f3b90e78ea0cffb20bf5cca7947a896d \
+file://${COMMON_LICENSE_DIR}/LGPL-2.0-only;md5=9427b8ccf5cf3df47c29110424c9641a \
+file://${COMMON_LICENSE_DIR}/LGPL-2.0-or-later;md5=6d2d9952d88b50a51a5c73dc431d06c7 \
+file://${COMMON_LICENSE_DIR}/LGPL-2.1-only;md5=1a6d268fd218675ffea8be556788b780 \
+file://${COMMON_LICENSE_DIR}/LGPL-2.1-or-later;md5=2a4f4fd2128ea2f65047ee63fbca9f68 \
+file://${COMMON_LICENSE_DIR}/LGPL-3.0-only;md5=bfccfe952269fff2b407dd11f2f3083b \
+file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302 \
+file://${COMMON_LICENSE_DIR}/MPL-2.0;md5=815ca599c9df247a0c7f619bab123dad \
+file://${COMMON_LICENSE_DIR}/PD;md5=b3597d12946881e13cb3b548d1173851 \
+file://${COMMON_LICENSE_DIR}/PSF-2.0;md5=76c1502273262a5ebefb50dfb20d7c4f \
+file://${COMMON_LICENSE_DIR}/Python-2.0;md5=a5c8025e305fb49e6d405769358851f6 \
+file://${COMMON_LICENSE_DIR}/Unicode-DFS-2016;md5=907371994d651afe53e98adc27824669 \
+file://${COMMON_LICENSE_DIR}/Unicode-TOU;md5=666362dc5dba74f477af0f44fb85bd22 \
+file://${COMMON_LICENSE_DIR}/Zlib;md5=87f239f408daca8a157858e192597633 \
+"
+IMAGE_CLASSES:remove = "license_image"
+
+COMPATIBLE_MACHINE = "fvp-*"
+
+TEST_SUITES = "arm_systemready_ir_acs"
+
+PV = "2.0.0"
+PV_DATE = "23.03"
+FULL_PV = "v${PV_DATE}_${PV}"
+ARM_SYSTEMREADY_IR_ACS_BRANCH ?= "main"
+IMAGE_FILENAME = "ir-acs-live-image-generic-arm64.wic"
+SRC_URI = " \
+    https://github.com/ARM-software/arm-systemready/raw/${ARM_SYSTEMREADY_IR_ACS_BRANCH}/IR/prebuilt_images/${FULL_PV}/${IMAGE_FILENAME}.xz;name=acs-img \
+    git://git.gitlab.arm.com/systemready/systemready-ir-template.git;protocol=https;nobranch=1;destsuffix=systemready-ir-template;name=sr-ir-template \
+"
+SRC_URI[acs-img.sha256sum] = "ea52f84dab44bde97de3e2d2224d883acaae35724dd8e2bdfb125de49040f9b3"
+# Revision pointing to v2023.04 tag
+SRCREV_sr-ir-template = "c714db178ddf72e5ae5017f15421095297d5bf0e"
+
+inherit arm-systemready-acs
diff --git a/meta-arm-systemready/recipes-test/arm-systemready-acs/arm-systemready-scripts-native.bb b/meta-arm-systemready/recipes-test/arm-systemready-acs/arm-systemready-scripts-native.bb
new file mode 100644
index 00000000..ccc87ed2
--- /dev/null
+++ b/meta-arm-systemready/recipes-test/arm-systemready-acs/arm-systemready-scripts-native.bb
@@ -0,0 +1,31 @@ 
+SUMMARY = "System Ready Scripts"
+DESCRIPTION = "A collection of scripts to help with SystemReady compliance."
+HOMEPAGE = "https://gitlab.arm.com/systemready/systemready-scripts"
+
+inherit native
+
+LICENSE = "BSD-3-Clause"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=85b7d439a311c22626c2e3f05daf628e"
+
+RDEPENDS:${PN} = "python3-packaging-native python3-pyyaml-native \
+python3-chardet-native python3-requests-native python3-construct-native \
+dtc-native python3-dtschema-wrapper-native"
+
+PV = "v2023.04"
+S = "${WORKDIR}/git"
+SRC_URI = "\
+        git://git.gitlab.arm.com/systemready/systemready-scripts.git;protocol=https;nobranch=1 \
+        file://0001-check-sr-results-Return-non-zero-exit-code-on-failur.patch \
+        file://0002-check-sr-results-Device-tree-improvements.patch \
+"
+
+# The SRCREV is at the v2023.04 tag
+SRCREV  = "f8244ab8da09f9e6005ceff81ebb234f35a2a698"
+
+do_install() {
+    install -d ${D}/${libdir}/systemready_scripts
+    cp -r ${S}/* ${D}/${libdir}/systemready_scripts
+}
+
+do_configure[noexec] = "1"
+do_compile[noexec] = "1"
diff --git a/meta-arm-systemready/recipes-test/arm-systemready-acs/arm-systemready-scripts/0001-check-sr-results-Return-non-zero-exit-code-on-failur.patch b/meta-arm-systemready/recipes-test/arm-systemready-acs/arm-systemready-scripts/0001-check-sr-results-Return-non-zero-exit-code-on-failur.patch
new file mode 100644
index 00000000..6a95881d
--- /dev/null
+++ b/meta-arm-systemready/recipes-test/arm-systemready-acs/arm-systemready-scripts/0001-check-sr-results-Return-non-zero-exit-code-on-failur.patch
@@ -0,0 +1,37 @@ 
+From ad8f2826f6e2cefb630f7fc2c7c99857f224e109 Mon Sep 17 00:00:00 2001
+From: Debbie Martin <Debbie.Martin@arm.com>
+Date: Tue, 5 Sep 2023 21:37:46 +0100
+Subject: [PATCH] check-sr-results: Return non-zero exit code on failure
+
+Return a non-zero exit code if there are any warnings or errors found.
+
+Upstream-Status: Pending
+Signed-off-by: Debbie Martin <Debbie.Martin@arm.com>
+---
+ check-sr-results.py | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/check-sr-results.py b/check-sr-results.py
+index 12b89cd..48658f0 100755
+--- a/check-sr-results.py
++++ b/check-sr-results.py
+@@ -185,6 +185,9 @@ class Stats:
+     def inc_error(self):
+         self._inc('error')
+ 
++    def has_warnings_or_errors(self):
++        return self.data['warning'] or self.data['error']
++
+ 
+ # Download (possibly large) file from URL.
+ # We raise an exception in case of issue.
+@@ -1519,3 +1522,6 @@ if __name__ == '__main__':
+     if args.print_meta:
+         print()
+         print_meta()
++
++    if stats.has_warnings_or_errors():
++        exit(1)
+-- 
+2.25.1
+
diff --git a/meta-arm-systemready/recipes-test/arm-systemready-acs/arm-systemready-scripts/0002-check-sr-results-Device-tree-improvements.patch b/meta-arm-systemready/recipes-test/arm-systemready-acs/arm-systemready-scripts/0002-check-sr-results-Device-tree-improvements.patch
new file mode 100644
index 00000000..f76a03ad
--- /dev/null
+++ b/meta-arm-systemready/recipes-test/arm-systemready-acs/arm-systemready-scripts/0002-check-sr-results-Device-tree-improvements.patch
@@ -0,0 +1,77 @@ 
+From 53ceb2d4167b05374678b966031b3d52fc5080a2 Mon Sep 17 00:00:00 2001
+From: Debbie Martin <Debbie.Martin@arm.com>
+Date: Fri, 29 Sep 2023 15:22:17 +0100
+Subject: [PATCH] check-sr-results: Device tree improvements
+
+Make check-sr-results.py accept 'extra_compat' configuration for
+devicetree files, and pass these in the compat list given to
+dt-parser.py.
+
+Update dt-parser.py to parse the GCC version line in the dtb log.
+
+Upstream-Status: Pending
+Signed-off-by: Debbie Martin <Debbie.Martin@arm.com>
+---
+ check-sr-results.py | 12 ++++++++++--
+ dt-parser.py        |  8 ++++++++
+ 2 files changed, 18 insertions(+), 2 deletions(-)
+
+diff --git a/check-sr-results.py b/check-sr-results.py
+index 48658f0..a207a39 100755
+--- a/check-sr-results.py
++++ b/check-sr-results.py
+@@ -598,7 +598,7 @@ def need_regen(filename, deps, margin=0):
+ # We run dtc and dt-validate to produce the log when needed.
+ # We add markers to the log, which will be ignored by dt-parser.py.
+ # We return a Stats object.
+-def check_devicetree(filename):
++def check_devicetree(filename, extra_compat=None):
+     logging.debug(f"Check Devicetree `{filename}'")
+     stats = Stats()
+     log = f"{filename}.log"
+@@ -644,6 +644,9 @@ def check_devicetree(filename):
+     # We use the compatible strings extracted from Linux bindings to filter out
+     # more false positive.
+     compat = get_compat()
++    if extra_compat:
++        with open(compat, "a") as compat_file:
++            compat_file.write("\n".join(extra_compat))
+     cp = run(f"{dt_parser} --compatibles '{compat}' '{log}'")
+
+     if cp.returncode:
+@@ -930,7 +933,12 @@ def check_file(conffile, filename):
+                 stats.add(check_uefi_capsule(filename))
+
+             if 'devicetree' in conffile:
+-                stats.add(check_devicetree(filename))
++                stats.add(
++                    check_devicetree(
++                        filename,
++                        extra_compat=conffile.get("extra_compat")
++                    )
++                )
+
+             if 'uefi-sniff' in conffile:
+                 stats.add(check_uefi_sniff(filename))
+diff --git a/dt-parser.py b/dt-parser.py
+index 3eccd74..c1c0031 100755
+--- a/dt-parser.py
++++ b/dt-parser.py
+@@ -181,6 +181,14 @@ def parse(filename):
+                 }
+                 continue
+
++            # line [GCC <version>]
++            m = re.match(r'\[GCC [0-9\.]+\]', line)
++            if m:
++                logging.debug(
++                    f"line {i}: GCC version (`{line}')"
++                )
++                continue
++
+             # If we could not parse the line we arrive here and complain.
+             logging.warning(f"Unparsed line {i}: `{line}'")
+
+--
+2.25.1
+
diff --git a/meta-arm-systemready/recipes-test/arm-systemready-acs/edk2-test-parser-native.bb b/meta-arm-systemready/recipes-test/arm-systemready-acs/edk2-test-parser-native.bb
new file mode 100644
index 00000000..ad93c41e
--- /dev/null
+++ b/meta-arm-systemready/recipes-test/arm-systemready-acs/edk2-test-parser-native.bb
@@ -0,0 +1,26 @@ 
+SUMMARY = "EDK2 Test Parser"
+DESCRIPTION = "EDK2 Test Parser for parsing the results of UEFI SCT tests"
+HOMEPAGE = "https://gitlab.arm.com/systemready/edk2-test-parser"
+
+inherit native
+
+LICENSE = "BSD-2-Clause"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=c0550be4b3b9c0223efd0eaa70dc9085"
+
+RDEPENDS:${PN} = "python3-packaging-native python3-pyyaml-native \
+                  python3-jsonschema-native"
+
+PV = "v2023.04"
+S = "${WORKDIR}/git"
+SRC_URI = "git://git.gitlab.arm.com/systemready/edk2-test-parser.git;protocol=https;nobranch=1"
+
+# The SRCREV is at the v2023.04 tag
+SRCREV  = "e8cdb692592d2a152cb87cf4d9fbd7ba2ae8b405"
+
+do_install() {
+    install -d ${D}/${libdir}/edk2_test_parser
+    cp -r ${S}/* ${D}/${libdir}/edk2_test_parser
+}
+
+do_configure[noexec] = "1"
+do_compile[noexec] = "1"
diff --git a/meta-arm-systemready/recipes-test/arm-systemready-linux-distros/arm-systemready-linux-distros-debian.bb b/meta-arm-systemready/recipes-test/arm-systemready-linux-distros/arm-systemready-linux-distros-debian.bb
new file mode 100644
index 00000000..04faa3a9
--- /dev/null
+++ b/meta-arm-systemready/recipes-test/arm-systemready-linux-distros/arm-systemready-linux-distros-debian.bb
@@ -0,0 +1,41 @@ 
+require arm-systemready-linux-distros.inc
+
+LICENSE = "GPL-1.0-only & GPL-1.0-or-later & GPL-2.0-only & GPL-2.0-or-later \
+           & GPL-3.0-only & GPL-3.0-or-later & LGPL-2.0-only \
+           & LGPL-2.0-or-later & LGPL-2.1-only & LGPL-2.1-or-later \
+           & LGPL-3.0-only & LGPL-3.0-or-later & BSD-3-Clause & BSD-4-Clause \
+           & Artistic-1.0-Perl & Apache-1.0 & Apache-1.1 & Apache-2.0 & Zlib \
+           & Python-2.0 & Ruby & PHP-3.01 & W3C-20150513 & OpenSSL & Sleepycat"
+LIC_FILES_CHKSUM = "\
+file://${COMMON_LICENSE_DIR}/GPL-1.0-only;md5=e9e36a9de734199567a4d769498f743d \
+file://${COMMON_LICENSE_DIR}/GPL-1.0-or-later;md5=30c0b8a5048cc2f4be5ff15ef0d8cf61 \
+file://${COMMON_LICENSE_DIR}/GPL-2.0-only;md5=801f80980d171dd6425610833a22dbe6 \
+file://${COMMON_LICENSE_DIR}/GPL-2.0-or-later;md5=fed54355545ffd980b814dab4a3b312c \
+file://${COMMON_LICENSE_DIR}/GPL-3.0-only;md5=c79ff39f19dfec6d293b95dea7b07891 \
+file://${COMMON_LICENSE_DIR}/GPL-3.0-or-later;md5=1c76c4cc354acaac30ed4d5eefea7245 \
+file://${COMMON_LICENSE_DIR}/LGPL-2.0-only;md5=9427b8ccf5cf3df47c29110424c9641a \
+file://${COMMON_LICENSE_DIR}/LGPL-2.0-or-later;md5=6d2d9952d88b50a51a5c73dc431d06c7 \
+file://${COMMON_LICENSE_DIR}/LGPL-2.1-only;md5=1a6d268fd218675ffea8be556788b780 \
+file://${COMMON_LICENSE_DIR}/LGPL-2.1-or-later;md5=2a4f4fd2128ea2f65047ee63fbca9f68 \
+file://${COMMON_LICENSE_DIR}/LGPL-3.0-only;md5=bfccfe952269fff2b407dd11f2f3083b \
+file://${COMMON_LICENSE_DIR}/LGPL-3.0-or-later;md5=c51d3eef3be114124d11349ca0d7e117 \
+file://${COMMON_LICENSE_DIR}/BSD-3-Clause;md5=550794465ba0ec5312d6919e203a55f9 \
+file://${COMMON_LICENSE_DIR}/BSD-4-Clause;md5=624d9e67e8ac41a78f6b6c2c55a83a2b \
+file://${COMMON_LICENSE_DIR}/Artistic-1.0-Perl;md5=8feedd169dbd5738981843bd7d931f9f \
+file://${COMMON_LICENSE_DIR}/Apache-1.0;md5=9f7a9503b805de9158a2a31a2cef4b70 \
+file://${COMMON_LICENSE_DIR}/Apache-1.1;md5=61cc638ff95ff4f38f243855bcec4317 \
+file://${COMMON_LICENSE_DIR}/Apache-2.0;md5=89aea4e17d99a7cacdbeed46a0096b10 \
+file://${COMMON_LICENSE_DIR}/Zlib;md5=87f239f408daca8a157858e192597633 \
+file://${COMMON_LICENSE_DIR}/Python-2.0;md5=a5c8025e305fb49e6d405769358851f6 \
+file://${COMMON_LICENSE_DIR}/Ruby;md5=105fc57d3f4d3122db32912f3e6107d0 \
+file://${COMMON_LICENSE_DIR}/PHP-3.01;md5=3363e286b5882ec667a6ebd86e0d9d91 \
+file://${COMMON_LICENSE_DIR}/W3C-20150513;md5=9ff23a699fca546a380855dd40d12d4f \
+file://${COMMON_LICENSE_DIR}/OpenSSL;md5=4eb1764f3e65fafa1a25057f9082f2ae \
+file://${COMMON_LICENSE_DIR}/Sleepycat;md5=1cbb64231c94198653282f3ccab88ffb \
+"
+
+PV = "11.7.0"
+# netinst, DVD-1
+ISO_TYPE = "netinst"
+SRC_URI = "https://cdimage.debian.org/mirror/cdimage/archive/${PV}/arm64/iso-cd/debian-${PV}-arm64-${ISO_TYPE}.iso;unpack=0;downloadfilename=${ISO_IMAGE_NAME}.iso"
+SRC_URI[sha256sum] = "174caba674fe3172938439257156b9cb8940bb5fd5ddf124256e81ec00ec460d"
diff --git a/meta-arm-systemready/recipes-test/arm-systemready-linux-distros/arm-systemready-linux-distros-opensuse.bb b/meta-arm-systemready/recipes-test/arm-systemready-linux-distros/arm-systemready-linux-distros-opensuse.bb
new file mode 100644
index 00000000..13e4355d
--- /dev/null
+++ b/meta-arm-systemready/recipes-test/arm-systemready-linux-distros/arm-systemready-linux-distros-opensuse.bb
@@ -0,0 +1,69 @@ 
+require arm-systemready-linux-distros.inc
+
+LICENSE = "AGPL-3.0-only & Apache-2.0 & Artistic-1.0 & Artistic-2.0 \
+           & BSD-2-Clause-Patent & BSD-2-Clause & BSD-3-Clause & BSD-4-Clause \
+           & CC-BY-3.0 & CC-BY-4.0 & CC-BY-SA-1.0 & CC-BY-SA-3.0 \
+           & CC-BY-SA-4.0 & CC0-1.0 & CDDL-1.0 & GFDL-1.1-only \
+           & GFDL-1.2-only & GFDL-1.3-only & GFDL-1.3-or-later \
+           & GPL-1.0-or-later & GPL-2.0-only & GPL-2.0-or-later \
+           & GPL-3.0-only & GPL-3.0-or-later & HPND & ICU & IPA \
+           & ISC & LGPL-2.0-only & LGPL-2.0-or-later & LGPL-2.1-only \
+           & LGPL-2.1-or-later & LGPL-3.0-only & LGPL-3.0-or-later \
+           & LPPL-1.3c & MIT & MPL-1.1 & MPL-2.0 & OFL-1.1 & OLDAP-2.8 \
+           & OpenSSL & Python-2.0 & Vim & W3C"
+
+LIC_FILES_CHKSUM = "\
+file://${COMMON_LICENSE_DIR}/AGPL-3.0-only;md5=73f1eb20517c55bf9493b7dd6e480788 \
+file://${COMMON_LICENSE_DIR}/Apache-2.0;md5=89aea4e17d99a7cacdbeed46a0096b10 \
+file://${COMMON_LICENSE_DIR}/Artistic-1.0;md5=cda03bbdc3c1951996392b872397b798 \
+file://${COMMON_LICENSE_DIR}/Artistic-2.0;md5=8bbc66f0ba93cec26ef526117e280266 \
+file://${COMMON_LICENSE_DIR}/BSD-2-Clause-Patent;md5=0518d409dae93098cca8dfa932f3ab1b \
+file://${COMMON_LICENSE_DIR}/BSD-2-Clause;md5=cb641bc04cda31daea161b1bc15da69f \
+file://${COMMON_LICENSE_DIR}/BSD-3-Clause;md5=550794465ba0ec5312d6919e203a55f9 \
+file://${COMMON_LICENSE_DIR}/BSD-4-Clause;md5=624d9e67e8ac41a78f6b6c2c55a83a2b \
+file://${COMMON_LICENSE_DIR}/CC-BY-3.0;md5=dfa02b5755629022e267f10b9c0a2ab7 \
+file://${COMMON_LICENSE_DIR}/CC-BY-4.0;md5=9b33bbd06fb58995fb0e299cd38d1838 \
+file://${COMMON_LICENSE_DIR}/CC-BY-SA-1.0;md5=681ffad43a0addd90f1bebf45675104e \
+file://${COMMON_LICENSE_DIR}/CC-BY-SA-3.0;md5=3248afbd148270ac7337a6f3e2558be5 \
+file://${COMMON_LICENSE_DIR}/CC-BY-SA-4.0;md5=4084714af41157e38872e798eb3fe1b1 \
+file://${COMMON_LICENSE_DIR}/CC0-1.0;md5=0ceb3372c9595f0a8067e55da801e4a1 \
+file://${COMMON_LICENSE_DIR}/CDDL-1.0;md5=d63dcc9297f2efd6c18d1e560b807bc6 \
+file://${COMMON_LICENSE_DIR}/GFDL-1.1-only;md5=03322744a1a73f36ebf29f98cced39a4 \
+file://${COMMON_LICENSE_DIR}/GFDL-1.2-only;md5=9f58808219e9a42ff1228309d6f83dc6 \
+file://${COMMON_LICENSE_DIR}/GFDL-1.3-only;md5=e0771ae6a62dc8a2e50b1d450fea66b7 \
+file://${COMMON_LICENSE_DIR}/GFDL-1.3-or-later;md5=e0771ae6a62dc8a2e50b1d450fea66b7 \
+file://${COMMON_LICENSE_DIR}/GPL-1.0-or-later;md5=30c0b8a5048cc2f4be5ff15ef0d8cf61 \
+file://${COMMON_LICENSE_DIR}/GPL-2.0-only;md5=801f80980d171dd6425610833a22dbe6 \
+file://${COMMON_LICENSE_DIR}/GPL-2.0-or-later;md5=fed54355545ffd980b814dab4a3b312c \
+file://${COMMON_LICENSE_DIR}/GPL-3.0-only;md5=c79ff39f19dfec6d293b95dea7b07891 \
+file://${COMMON_LICENSE_DIR}/GPL-3.0-or-later;md5=1c76c4cc354acaac30ed4d5eefea7245 \
+file://${COMMON_LICENSE_DIR}/HPND;md5=faa364b3e3c6db0f74cc0e704ddf6b9c \
+file://${COMMON_LICENSE_DIR}/ICU;md5=4d85ad1f393add71dc66bcf78e3ee584 \
+file://${COMMON_LICENSE_DIR}/IPA;md5=17b18da2d8b2c43c598aa7583229ef1b \
+file://${COMMON_LICENSE_DIR}/ISC;md5=f3b90e78ea0cffb20bf5cca7947a896d \
+file://${COMMON_LICENSE_DIR}/LGPL-2.0-only;md5=9427b8ccf5cf3df47c29110424c9641a \
+file://${COMMON_LICENSE_DIR}/LGPL-2.0-or-later;md5=6d2d9952d88b50a51a5c73dc431d06c7 \
+file://${COMMON_LICENSE_DIR}/LGPL-2.1-only;md5=1a6d268fd218675ffea8be556788b780 \
+file://${COMMON_LICENSE_DIR}/LGPL-2.1-or-later;md5=2a4f4fd2128ea2f65047ee63fbca9f68 \
+file://${COMMON_LICENSE_DIR}/LGPL-3.0-only;md5=bfccfe952269fff2b407dd11f2f3083b \
+file://${COMMON_LICENSE_DIR}/LGPL-3.0-or-later;md5=c51d3eef3be114124d11349ca0d7e117 \
+file://${COMMON_LICENSE_DIR}/LPPL-1.3c;md5=ba2fa6fe055623756de43a298d88a8b3 \
+file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302 \
+file://${COMMON_LICENSE_DIR}/MPL-1.1;md5=1d38e87ed8d522c49f04e1efe0fab3ab \
+file://${COMMON_LICENSE_DIR}/MPL-2.0;md5=815ca599c9df247a0c7f619bab123dad \
+file://${COMMON_LICENSE_DIR}/OFL-1.1;md5=fac3a519e5e9eb96316656e0ca4f2b90 \
+file://${COMMON_LICENSE_DIR}/OLDAP-2.8;md5=bb28ada4fbb5c3f52c233899b2e410a5 \
+file://${COMMON_LICENSE_DIR}/OpenSSL;md5=4eb1764f3e65fafa1a25057f9082f2ae \
+file://${COMMON_LICENSE_DIR}/Python-2.0;md5=a5c8025e305fb49e6d405769358851f6 \
+file://${COMMON_LICENSE_DIR}/Vim;md5=676d28582e2dca824e7e309a9865eeb1 \
+file://${COMMON_LICENSE_DIR}/W3C;md5=4b1d0384b406508a63e51f7c69687700 \
+"
+
+ARM_SYSTEMREADY_LINUX_DISTRO_INSTALL_SIZE = "6144"
+
+PV = "15.4"
+# possible value of ISO_TYPE: NET, DVD
+ISO_TYPE = "DVD"
+BUILD_NO = "243.2"
+SRC_URI = "https://download.opensuse.org/distribution/leap/${PV}/iso/openSUSE-Leap-${PV}-${ISO_TYPE}-aarch64-Build${BUILD_NO}-Media.iso;unpack=0;downloadfilename=${ISO_IMAGE_NAME}.iso"
+SRC_URI[sha256sum] = "d87f79b2b723f9baaeedd9e2be0365c04081e51a4f7f7f08c7ab3eee0c3e0fae"
diff --git a/meta-arm-systemready/recipes-test/arm-systemready-linux-distros/arm-systemready-linux-distros.inc b/meta-arm-systemready/recipes-test/arm-systemready-linux-distros/arm-systemready-linux-distros.inc
new file mode 100644
index 00000000..e247a427
--- /dev/null
+++ b/meta-arm-systemready/recipes-test/arm-systemready-linux-distros/arm-systemready-linux-distros.inc
@@ -0,0 +1,50 @@ 
+SUMMARY = "Arm SystemReady Linux distros installation"
+DESCRIPTION = "Arm SystemReady Linux distro CD/DVD images and installation \
+               target disk image"
+
+IMAGE_CLASSES:remove = "license_image testimage"
+
+INHIBIT_DEFAULT_DEPS = "1"
+COMPATIBLE_HOST = "aarch64-*"
+PACKAGE_ARCH = "${TARGET_ARCH}"
+
+inherit nopackages deploy rootfs-postcommands ${IMAGE_CLASSES}
+
+do_configure[noexec] = "1"
+do_compile[noexec] = "1"
+
+ISO_IMAGE_NAME = "${PN}-${PV}"
+IMAGE_LINK_NAME = "${PN}-${PV}-${MACHINE}"
+
+ARM_SYSTEMREADY_LINUX_DISTRO_ISO_IMAGE = \
+    "${DEPLOY_DIR_IMAGE}/${ISO_IMAGE_NAME}.iso"
+# Size of installation disk in MB
+ARM_SYSTEMREADY_LINUX_DISTRO_INSTALL_SIZE ?= "4096"
+
+do_image() {
+    dd if=/dev/zero of=${WORKDIR}/${IMAGE_LINK_NAME}.wic \
+        bs=1M count=${ARM_SYSTEMREADY_LINUX_DISTRO_INSTALL_SIZE} status=none
+}
+
+do_deploy() {
+    # Deploy the iso and installation target disk image to the deploy folder
+    install -m 644 ${WORKDIR}/${ISO_IMAGE_NAME}.iso ${DEPLOYDIR}
+    install -m 644 ${WORKDIR}/${IMAGE_LINK_NAME}.wic ${DEPLOYDIR}
+}
+
+addtask image before do_install
+addtask deploy after do_install before do_image_complete
+
+# Post-process commands may write to IMGDEPLOYDIR
+IMGDEPLOYDIR = "${DEPLOY_DIR_IMAGE}"
+
+python do_image_complete() {
+    # Run the image post-process commands
+    from oe.utils import execute_pre_post_process
+    post_process_cmds = d.getVar("IMAGE_POSTPROCESS_COMMAND")
+    execute_pre_post_process(d, post_process_cmds)
+}
+do_image_complete[nostamp] = "1"
+addtask image_complete after do_deploy before do_build
+
+do_install[depends] += "arm-systemready-firmware:do_image_complete"