Allow a user to insert additional, arbitrary loadables in a FIT image.
The loadables can be specified through the FIT_LOADABLES variable as
a list, with parameters defined by flags on dedicated FIT_LOADABLE_*
variables; they will be included in all configurations.
Sensible defaults will be used for some parameters (type, compression,
description, arch, os) if the corresponding flag is not set, while
others (load address and entry point) will be omitted in the final FIT
image.
As an example, the following configuration can be specified to add as
loadables a TF-A BL31 firmware and a (compressed) TEE firmware, to be
loaded respectively at 0x204E0000 and 0x96000000:
FIT_LOADABLES = "atf tee"
FIT_LOADABLE_FILENAME[atf] = "bl31.bin"
FIT_LOADABLE_TYPE[atf] = "tfa-bl31"
FIT_LOADABLE_ARCH[atf] = "arm64"
FIT_LOADABLE_OS[atf] = "arm-trusted-firmware"
FIT_LOADABLE_LOADADDRESS[atf] = "0x204E0000"
FIT_LOADABLE_FILENAME[tee] = "tee.bin.gz"
FIT_LOADABLE_COMPRESSSION[tee] = "gzip"
FIT_LOADABLE_TYPE[tee] = "tee"
FIT_LOADABLE_OS[tee] = "tee"
FIT_LOADABLE_LOADADDRESS[tee] = "0x21000000"
Signed-off-by: Francesco Valla <francesco@valla.it>
Signed-off-by: Mathieu Dubois-Briand <mathieu.dubois-briand@bootlin.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
if providerdtb:
d.appendVarFlag('do_compile', 'depends', ' virtual/dtb:do_populate_sysroot')
d.setVar('EXTERNAL_KERNEL_DEVICETREE', "${RECIPE_SYSROOT}/boot/devicetree")
+
+ # Parse loadables config
+ loadables = d.getVar('FIT_LOADABLES')
+ if loadables:
+ # Check that the loadables configuration variables are not set directly
+ # directly, then assign them a synthetic value for testability purposes
+ for v in ['FIT_LOADABLE_ARCH', 'FIT_LOADABLE_COMPRESSION',
+ 'FIT_LOADABLE_DESCRIPTION', 'FIT_LOADABLE_ENTRYPOINT',
+ 'FIT_LOADABLE_FILENAME', 'FIT_LOADABLE_LOADADDRESS',
+ 'FIT_LOADABLE_OS', 'FIT_LOADABLE_TYPE']:
+ if d.getVar(v):
+ raise bb.parse.SkipRecipe("You cannot use %s as a variable, you can only set flags." % v)
+
+ synt_value = " ? ".join([ d.getVarFlag(v, loadable) or "" for loadable in loadables.split() ])
+ d.setVar(v, synt_value)
}
do_configure[noexec] = "1"
if not found:
bb.fatal("Could not find a valid initramfs type for %s, the supported types are: %s" % (d.getVar('INITRAMFS_IMAGE_NAME'), d.getVar('FIT_SUPPORTED_INITRAMFS_FSTYPES')))
+ #
+ # Prepare loadables sections
+ #
+ for loadable in d.getVar('FIT_LOADABLES').split():
+ loadable_file = d.getVarFlag('FIT_LOADABLE_FILENAME', loadable)
+ if not loadable_file:
+ bb.fatal("File for loadable %s not specified through FIT_LOADABLE_FILENAME[%s]" % (loadable, loadable))
+
+ loadable_loadaddress = d.getVarFlag('FIT_LOADABLE_LOADADDRESS', loadable)
+ if not loadable_loadaddress:
+ bb.fatal("Load address for loadable %s not specified through FIT_LOADABLE_LOADADDRESS[%s]" % (loadable, loadable))
+
+ # Optional parameters
+ loadable_arch = d.getVarFlag('FIT_LOADABLE_ARCH', loadable)
+ loadable_compression = d.getVarFlag('FIT_LOADABLE_COMPRESSION', loadable)
+ loadable_description = d.getVarFlag('FIT_LOADABLE_DESCRIPTION', loadable) or ("%s loadable" % loadable)
+ loadable_entrypoint = d.getVarFlag('FIT_LOADABLE_ENTRYPOINT', loadable)
+ loadable_os = d.getVarFlag('FIT_LOADABLE_OS', loadable)
+ loadable_type = d.getVarFlag('FIT_LOADABLE_TYPE', loadable)
+
+ # Check if loadable artifact exists
+ loadable_path = os.path.join(d.getVar("DEPLOY_DIR_IMAGE"), loadable_file)
+ if not os.path.exists(loadable_path):
+ bb.fatal("File for loadable %s not found at %s" % (loadable, loadable_path))
+
+ root_node.fitimage_emit_section_loadable(loadable,
+ loadable_path, loadable_type,
+ loadable_description,
+ loadable_compression,
+ loadable_arch, loadable_os,
+ loadable_loadaddress,
+ loadable_entrypoint)
+
# Generate the configuration section
root_node.fitimage_emit_section_config(d.getVar("FIT_CONF_DEFAULT_DTB"), d.getVar("FIT_CONF_MAPPINGS"))
# Machine configurations needing such a script file should include it in the
# SRC_URI of the kernel recipe and set the FIT_UBOOT_ENV parameter.
FIT_UBOOT_ENV ?= ""
+
+# Allow user to insert additional loadable images.
+# For each loadable, a number of parameters can be defined through additional
+# variable flags.
+# Example:
+# FIT_LOADABLES = "atf"
+# FIT_LOADABLE_FILENAME[atf] = "bl31.bin"
+# FIT_LOADABLE_COMPRESSSION[atf] = "none"
+# FIT_LOADABLE_DESCRIPTION[atf] = "TF-A firmware image"
+# FIT_LOADABLE_TYPE[atf] = "tfa-bl31"
+# FIT_LOADABLE_ARCH[atf] = "arm64"
+# FIT_LOADABLE_OS[atf] = "arm-trusted-firmware"
+# FIT_LOADABLE_LOADADDRESS[atf] = "0x204E0000"
+# FIT_LOADABLE_ENTRYPOINT[atf] = "0x204E0000"
+# Sensible defalts will be used for some parameters (compression, description,
+# arch, os) if the corresponding flag is not set, while others (load address
+# and entry point) will be omitted in the final FIT.
+FIT_LOADABLES ?= ""
self._ramdisk = None
self._bootscr = None
self._setup = None
+ self._loadables = []
def _sanitize_sign_config(self):
if self._sign_enable:
)
self._ramdisk = ramdisk_node
+ def fitimage_emit_section_loadable(self, name, filepath, type=None, description=None, compression=None, arch=None, os=None, load=None, entry=None):
+ """Emit one fitImage ITS loadable section"""
+ opt_props = {
+ "data": '/incbin/("' + filepath + '")',
+ "arch": arch if arch is not None else self._arch,
+ "os": os if os is not None else "linux",
+ }
+
+ if load:
+ opt_props["load"] = f"<{load}>"
+ if entry:
+ opt_props["entry"] = f"<{entry}>"
+
+ loadable_node = self.its_add_node_image(
+ name,
+ description if description is not None else name,
+ type if type is not None else "firmware",
+ compression if compression is not None else "none",
+ opt_props
+ )
+
+ self._loadables.append(loadable_node)
+
def _fitimage_emit_one_section_config(self, conf_node_name, dtb=None):
"""Emit the fitImage ITS configuration section"""
opt_props = {}
if self._sign_enable:
sign_entries.append("setup")
+ if len(self._loadables) > 0:
+ conf_desc.append("loadables")
+ opt_props["loadables"] = [ loadable.name for loadable in self._loadables ]
+ if self._sign_enable:
+ sign_entries.append("loadables")
+
# First added configuration is the default configuration
default_flag = "0"
if len(self.configurations.sub_nodes) == 0:
dtb_symlinks.append("am335x-bonegreen-ext-alias.dtb")
return (all_dtbs, dtb_symlinks)
+ @staticmethod
+ def _get_loadables(bb_vars):
+ """Return a list of loadable names"""
+ loadables = []
+ var_loadables = bb_vars.get('FIT_LOADABLES')
+ if var_loadables:
+ loadables += var_loadables.split()
+ return loadables
+
def _is_req_dict_in_dict(self, found_dict, req_dict):
"""
Check if all key-value pairs in the required dictionary are present in the found dictionary.
'FIT_DESC',
'FIT_HASH_ALG',
'FIT_KERNEL_COMP_ALG',
+ 'FIT_LOADABLES',
+ 'FIT_LOADABLE_ENTRYPOINT',
+ 'FIT_LOADABLE_LOADADDRESS',
'FIT_SIGN_ALG',
'FIT_SIGN_INDIVIDUAL',
'FIT_UBOOT_ENV',
fit_uboot_env = bb_vars['FIT_UBOOT_ENV']
initramfs_image = bb_vars['INITRAMFS_IMAGE']
initramfs_image_bundle = bb_vars['INITRAMFS_IMAGE_BUNDLE']
+ loadables = FitImageTestCase._get_loadables(bb_vars)
uboot_sign_enable = bb_vars.get('UBOOT_SIGN_ENABLE')
# image nodes
else:
not_images.append('ramdisk-1')
+ if loadables:
+ images += loadables
+
# configuration nodes (one per DTB, symlink, and mappings)
configurations = []
if dtb_files:
fit_uboot_env = bb_vars['FIT_UBOOT_ENV']
initramfs_image = bb_vars['INITRAMFS_IMAGE']
initramfs_image_bundle = bb_vars['INITRAMFS_IMAGE_BUNDLE']
+ loadables = FitImageTestCase._get_loadables(bb_vars)
uboot_sign_enable = bb_vars['UBOOT_SIGN_ENABLE']
uboot_sign_img_keyname = bb_vars['UBOOT_SIGN_IMG_KEYNAME']
uboot_sign_keyname = bb_vars['UBOOT_SIGN_KEYNAME']
"Load Address": bb_vars['UBOOT_RD_LOADADDRESS'],
"Entry Point": bb_vars['UBOOT_RD_ENTRYPOINT']
}
+ # Create one section per loadable
+ for index,loadable in enumerate(loadables):
+ loadaddress = bb_vars['FIT_LOADABLE_LOADADDRESS'].split("?")[index].strip()
+ req_sections[loadable] = { "Load Address": loadaddress }
+ entrypoint = bb_vars['FIT_LOADABLE_ENTRYPOINT'].split("?")[index].strip()
+ if entrypoint:
+ req_sections[loadable]['Entry Point'] = entrypoint
# Create a configuration section for each DTB
if dtb_files:
for dtb in dtb_files + dtb_symlinks:
}
if initramfs_image and initramfs_image_bundle != "1":
req_sections[conf_name]['Init Ramdisk'] = "ramdisk-1"
+ if loadables:
+ req_sections[conf_name]['Loadables'] = ",".join(loadables)
else:
conf_name = bb_vars['FIT_CONF_PREFIX'] + '1'
req_sections[conf_name] = {
}
if initramfs_image and initramfs_image_bundle != "1":
req_sections[conf_name]['Init Ramdisk'] = "ramdisk-1"
+ if loadables:
+ req_sections[conf_name]['Loadables'] = ",".join(loadables)
# Add signing related properties if needed
if uboot_sign_enable == "1":
in the Image Tree Source. Not all the fields are tested,
only the key fields that wont vary between different
architectures.
+ 3. The load address and (if defined) entrypoint address
+ of each loadable are as expected in the Image Tree Source.
Product: oe-core
Author: Usama Arif <usama.arif@arm.com>
"""
UBOOT_ENTRYPOINT = "0x80080000"
FIT_DESC = "A model description"
FIT_CONF_PREFIX = "foo-"
+# Use the linux.bin kernel image as loadable file to avoid building other components
+FIT_LOADABLES = "loadable1 loadable2"
+FIT_LOADABLE_FILENAME[loadable1] = "linux.bin"
+FIT_LOADABLE_LOADADDRESS[loadable1] = "0x86000000"
+FIT_LOADABLE_TYPE[loadable1] = "firmware"
+FIT_LOADABLE_FILENAME[loadable2] = "linux.bin"
+FIT_LOADABLE_LOADADDRESS[loadable2] = "0x87000000"
+FIT_LOADABLE_TYPE[loadable2] = "firmware"
"""
config = self._config_add_kernel_classes(config)
self.write_config(config)
'FIT_KEY_GENRSA_ARGS': "-F4",
'FIT_KEY_REQ_ARGS': "-batch -new",
'FIT_KEY_SIGN_PKCS': "-x509",
+ 'FIT_LOADABLES': "",
'FIT_LINUX_BIN': "linux.bin",
'FIT_PAD_ALG': "pkcs-1.5",
'FIT_SIGN_ALG': "rsa2048",
"core-image-minimal-initramfs",
bb_vars.get("UBOOT_RD_LOADADDRESS"), bb_vars.get("UBOOT_RD_ENTRYPOINT"))
+ loadables = FitImageTestCase._get_loadables(bb_vars)
+ for loadable in loadables:
+ root_node.fitimage_emit_section_loadable(loadable,
+ "a-dir/loadable-%s" % loadable,
+ "loadable-type")
+
root_node.fitimage_emit_section_config(bb_vars['FIT_CONF_DEFAULT_DTB'], bb_vars.get('FIT_CONF_MAPPINGS'))
root_node.write_its_file(fitimage_its_path)
with self.assertRaises(BBHandledException):
self._test_fitimage_py(bb_vars_overrides)
+ def test_fitimage_py_conf_loadables(self):
+ """Test FIT_LOADABLES basic functionality"""
+ bb_vars_overrides = {
+ 'FIT_LOADABLES': "my-loadable",
+ }
+ self._test_fitimage_py(bb_vars_overrides)
+
class UBootFitImageTests(FitImageTestCase):
"""Test cases for the uboot-sign bbclass"""