summaryrefslogtreecommitdiffstats
path: root/meta/classes-recipe
diff options
context:
space:
mode:
authorAdrian Freihofer <adrian.freihofer@siemens.com>2025-06-03 10:23:22 +0200
committerRichard Purdie <richard.purdie@linuxfoundation.org>2025-06-05 11:02:21 +0100
commit36bea94fe7d01b572f6802683dba8b8e84f426e8 (patch)
tree9aaff25df8d81be9cf7bc1cf81e43477e0f555c1 /meta/classes-recipe
parentceee2575537cfeabb99f76057416701d6cf0fc8b (diff)
downloadpoky-36bea94fe7d01b572f6802683dba8b8e84f426e8.tar.gz
kernel-fit-image.bbclass: add a new FIT image implementation
The new recipe linux-yocto-fitimage.bb and the new kernel-fit-image.bbclass are intended to become successors of the kernel-fitimage.bbclass. Instead of injecting the FIT image related build steps into the kernel recipe, the new recipe takes the kernel artifacts from the kernel recipe and creates the FIT image as an independent task. This solves some basic problems: * sstate does not work well when a fitImage contains an initramfs. The kernel is rebuilt from scratch if the build runs from an empty TMPDIR. * A fitImage kernel is not available as a package, but all other kernel image types are. * The task dependencies in the kernel are very complex and difficult to debug if something goes wrong. As a separate, downstream recipe, this is now much easier. The recipe takes the kernel artifacts from the deploy folder. There was also a test implementation passing the kernel artifacts via sysroot directory. This requires changes on the kernel.bbclass to make it copying the artifacts also to the sysroot directory while the same artifacts are already in the sstate-cached deploy directory. The new class kernel-fit-extra-artifacts.bbclass generates and deploys the kernel binary intended for inclusion in a FIT image. Note that the kernel used in a FIT image is a stripped (and optionally compressed) vmlinux ELF binary - not a self-extracting format like zImage, which is already available in the deploy directory if needed separately. The kernel-fit-extra-artifacts.bbclass can be used like this: KERNEL_CLASSES += "kernel-fit-extra-artifacts" (if uImage support is not needed, or with :append otherwise) The long story about this issue is here: [YOCTO #12912] (From OE-Core rev: 05d0c7342d7638dbe8a9f2fd3d1c709ee87d6579) Signed-off-by: Adrian Freihofer <adrian.freihofer@siemens.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'meta/classes-recipe')
-rw-r--r--meta/classes-recipe/kernel-fit-extra-artifacts.bbclass19
-rw-r--r--meta/classes-recipe/kernel-fit-image.bbclass187
2 files changed, 206 insertions, 0 deletions
diff --git a/meta/classes-recipe/kernel-fit-extra-artifacts.bbclass b/meta/classes-recipe/kernel-fit-extra-artifacts.bbclass
new file mode 100644
index 0000000000..385fe9895a
--- /dev/null
+++ b/meta/classes-recipe/kernel-fit-extra-artifacts.bbclass
@@ -0,0 +1,19 @@
1#
2# Copyright OpenEmbedded Contributors
3#
4# SPDX-License-Identifier: MIT
5#
6
7# Generate and deploy additional artifacts required for FIT image creation.
8# To use this class, add it to the KERNEL_CLASSES variable.
9
10inherit kernel-uboot
11
12kernel_do_deploy:append() {
13 # Provide the kernel artifacts to post processing recipes e.g. for creating a FIT image
14 uboot_prep_kimage "$deployDir"
15 # For x86 a setup.bin needs to be include"d in a fitImage as well
16 if [ -e ${KERNEL_OUTPUT_DIR}/setup.bin ]; then
17 install -D "${B}/${KERNEL_OUTPUT_DIR}/setup.bin" "$deployDir/"
18 fi
19}
diff --git a/meta/classes-recipe/kernel-fit-image.bbclass b/meta/classes-recipe/kernel-fit-image.bbclass
new file mode 100644
index 0000000000..6d80cd4bb4
--- /dev/null
+++ b/meta/classes-recipe/kernel-fit-image.bbclass
@@ -0,0 +1,187 @@
1
2inherit kernel-arch kernel-artifact-names uboot-config deploy
3require conf/image-fitimage.conf
4
5S = "${WORKDIR}/sources"
6UNPACKDIR = "${S}"
7
8PACKAGE_ARCH = "${MACHINE_ARCH}"
9
10DEPENDS += "\
11 u-boot-tools-native dtc-native \
12 ${@'kernel-signing-keys-native' if d.getVar('FIT_GENERATE_KEYS') == '1' else ''} \
13"
14
15python () {
16 image = d.getVar('INITRAMFS_IMAGE')
17 if image and d.getVar('INITRAMFS_IMAGE_BUNDLE') != '1':
18 if d.getVar('INITRAMFS_MULTICONFIG'):
19 mc = d.getVar('BB_CURRENT_MC')
20 d.appendVarFlag('do_compile', 'mcdepends', ' mc:' + mc + ':${INITRAMFS_MULTICONFIG}:${INITRAMFS_IMAGE}:do_image_complete')
21 else:
22 d.appendVarFlag('do_compile', 'depends', ' ${INITRAMFS_IMAGE}:do_image_complete')
23
24 #check if there are any dtb providers
25 providerdtb = d.getVar("PREFERRED_PROVIDER_virtual/dtb")
26 if providerdtb:
27 d.appendVarFlag('do_compile', 'depends', ' virtual/dtb:do_populate_sysroot')
28 d.setVar('EXTERNAL_KERNEL_DEVICETREE', "${RECIPE_SYSROOT}/boot/devicetree")
29}
30
31do_configure[noexec] = "1"
32
33UBOOT_MKIMAGE_KERNEL_TYPE ?= "kernel"
34KERNEL_IMAGEDEST ?= "/boot"
35
36python do_compile() {
37 import shutil
38 import oe.fitimage
39
40 itsfile = "fit-image.its"
41 fitname = "fitImage"
42 kernel_deploydir = d.getVar('DEPLOY_DIR_IMAGE')
43 kernel_deploysubdir = d.getVar('KERNEL_DEPLOYSUBDIR')
44 if kernel_deploysubdir:
45 kernel_deploydir = os.path.join(kernel_deploydir, kernel_deploysubdir)
46
47 # Collect all the its nodes before the its file is generated and mkimage gets executed
48 root_node = oe.fitimage.ItsNodeRootKernel(
49 d.getVar("FIT_DESC"), d.getVar("FIT_ADDRESS_CELLS"),
50 d.getVar('HOST_PREFIX'), d.getVar('UBOOT_ARCH'), d.getVar("FIT_CONF_PREFIX"),
51 oe.types.boolean(d.getVar('UBOOT_SIGN_ENABLE')), d.getVar("UBOOT_SIGN_KEYDIR"),
52 d.getVar("UBOOT_MKIMAGE"), d.getVar("UBOOT_MKIMAGE_DTCOPTS"),
53 d.getVar("UBOOT_MKIMAGE_SIGN"), d.getVar("UBOOT_MKIMAGE_SIGN_ARGS"),
54 d.getVar('FIT_HASH_ALG'), d.getVar('FIT_SIGN_ALG'), d.getVar('FIT_PAD_ALG'),
55 d.getVar('UBOOT_SIGN_KEYNAME'),
56 oe.types.boolean(d.getVar('FIT_SIGN_INDIVIDUAL')), d.getVar('UBOOT_SIGN_IMG_KEYNAME')
57 )
58
59 # Prepare a kernel image section.
60 shutil.copyfile(os.path.join(kernel_deploydir, "linux.bin"), "linux.bin")
61 with open(os.path.join(kernel_deploydir, "linux_comp")) as linux_comp_f:
62 linux_comp = linux_comp_f.read()
63 root_node.fitimage_emit_section_kernel("kernel-1", "linux.bin", linux_comp,
64 d.getVar('UBOOT_LOADADDRESS'), d.getVar('UBOOT_ENTRYPOINT'),
65 d.getVar('UBOOT_MKIMAGE_KERNEL_TYPE'), d.getVar("UBOOT_ENTRYSYMBOL"))
66
67 # Prepare a DTB image section
68 kernel_devicetree = d.getVar('KERNEL_DEVICETREE')
69 external_kernel_devicetree = d.getVar("EXTERNAL_KERNEL_DEVICETREE")
70 if kernel_devicetree:
71 for dtb in kernel_devicetree.split():
72 # In deploy_dir the DTBs are without sub-directories also with KERNEL_DTBVENDORED = "1"
73 dtb_name = os.path.basename(dtb)
74
75 # Skip DTB if it's also provided in EXTERNAL_KERNEL_DEVICETREE directory
76 if external_kernel_devicetree:
77 ext_dtb_path = os.path.join(external_kernel_devicetree, dtb_name)
78 if os.path.exists(ext_dtb_path) and os.path.getsize(ext_dtb_path) > 0:
79 continue
80
81 # Copy the dtb or dtbo file into the FIT image assembly directory
82 shutil.copyfile(os.path.join(kernel_deploydir, dtb_name), dtb_name)
83 root_node.fitimage_emit_section_dtb(dtb_name, dtb_name,
84 d.getVar("UBOOT_DTB_LOADADDRESS"), d.getVar("UBOOT_DTBO_LOADADDRESS"))
85
86 if external_kernel_devicetree:
87 # iterate over all .dtb and .dtbo files in the external kernel devicetree directory
88 # and copy them to the FIT image assembly directory
89 for dtb_name in sorted(os.listdir(external_kernel_devicetree)):
90 if dtb_name.endswith('.dtb') or dtb_name.endswith('.dtbo'):
91 dtb_path = os.path.join(external_kernel_devicetree, dtb_name)
92
93 # For symlinks, add a configuration node that refers to the DTB image node to which the symlink points
94 symlink_target = oe.fitimage.symlink_points_below(dtb_name, external_kernel_devicetree)
95 if symlink_target:
96 root_node.fitimage_emit_section_dtb_alias(dtb_name, symlink_target, True)
97 # For real DTB files add an image node and a configuration node
98 else:
99 shutil.copyfile(dtb_path, dtb_name)
100 root_node.fitimage_emit_section_dtb(dtb_name, dtb_name,
101 d.getVar("UBOOT_DTB_LOADADDRESS"), d.getVar("UBOOT_DTBO_LOADADDRESS"), True)
102
103 # Prepare a u-boot script section
104 fit_uboot_env = d.getVar("FIT_UBOOT_ENV")
105 if fit_uboot_env:
106 root_node.fitimage_emit_section_boot_script("bootscr-"+fit_uboot_env , fit_uboot_env)
107
108 # Prepare a setup section (For x86)
109 setup_bin_path = os.path.join(kernel_deploydir, "setup.bin")
110 if os.path.exists(setup_bin_path):
111 shutil.copyfile(setup_bin_path, "setup.bin")
112 root_node.fitimage_emit_section_setup("setup-1", "setup.bin")
113
114 # Prepare a ramdisk section.
115 initramfs_image = d.getVar('INITRAMFS_IMAGE')
116 if initramfs_image and d.getVar("INITRAMFS_IMAGE_BUNDLE") != '1':
117 # Find and use the first initramfs image archive type we find
118 found = False
119 for img in d.getVar("FIT_SUPPORTED_INITRAMFS_FSTYPES").split():
120 initramfs_path = os.path.join(d.getVar("DEPLOY_DIR_IMAGE"), "%s.%s" % (d.getVar('INITRAMFS_IMAGE_NAME'), img))
121 if os.path.exists(initramfs_path):
122 bb.note("Found initramfs image: " + initramfs_path)
123 found = True
124 root_node.fitimage_emit_section_ramdisk("ramdisk-1", initramfs_path,
125 initramfs_image,
126 d.getVar("UBOOT_RD_LOADADDRESS"),
127 d.getVar("UBOOT_RD_ENTRYPOINT"))
128 break
129 else:
130 bb.note("Did not find initramfs image: " + initramfs_path)
131
132 if not found:
133 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')))
134
135 # Generate the configuration section
136 root_node.fitimage_emit_section_config(d.getVar("FIT_CONF_DEFAULT_DTB"))
137
138 # Write the its file
139 root_node.write_its_file(itsfile)
140
141 # Assemble the FIT image
142 root_node.run_mkimage_assemble(itsfile, fitname)
143
144 # Sign the FIT image if required
145 root_node.run_mkimage_sign(fitname)
146}
147do_compile[depends] += "virtual/kernel:do_deploy"
148
149do_install() {
150 install -d "${D}/${KERNEL_IMAGEDEST}"
151 install -m 0644 "${B}/fitImage" "${D}/${KERNEL_IMAGEDEST}/fitImage"
152}
153
154FILES:${PN} = "${KERNEL_IMAGEDEST}"
155
156
157do_deploy() {
158 deploy_dir="${DEPLOYDIR}"
159 if [ -n "${KERNEL_DEPLOYSUBDIR}" ]; then
160 deploy_dir="${DEPLOYDIR}/${KERNEL_DEPLOYSUBDIR}"
161 fi
162 install -d "$deploy_dir"
163 install -m 0644 "${B}/fitImage" "$deploy_dir/fitImage"
164 install -m 0644 "${B}/fit-image.its" "$deploy_dir/fit-image.its"
165
166 if [ "${INITRAMFS_IMAGE_BUNDLE}" != "1" ]; then
167 ln -snf fit-image.its "$deploy_dir/fitImage-its-${KERNEL_FIT_NAME}.its"
168 if [ -n "${KERNEL_FIT_LINK_NAME}" ] ; then
169 ln -snf fit-image.its "$deploy_dir/fitImage-its-${KERNEL_FIT_LINK_NAME}"
170 fi
171 fi
172
173 if [ -n "${INITRAMFS_IMAGE}" ]; then
174 ln -snf fit-image-its "$deploy_dir/fitImage-its-${INITRAMFS_IMAGE_NAME}-${KERNEL_FIT_NAME}.its"
175 if [ -n "${KERNEL_FIT_LINK_NAME}" ]; then
176 ln -snf fit-image.its "$deploy_dir/fitImage-its-${INITRAMFS_IMAGE_NAME}-${KERNEL_FIT_LINK_NAME}"
177 fi
178
179 if [ "${INITRAMFS_IMAGE_BUNDLE}" != "1" ]; then
180 ln -snf fitImage "$deploy_dir/fitImage-${INITRAMFS_IMAGE_NAME}-${KERNEL_FIT_NAME}${KERNEL_FIT_BIN_EXT}"
181 if [ -n "${KERNEL_FIT_LINK_NAME}" ] ; then
182 ln -snf fitImage "$deploy_dir/fitImage-${INITRAMFS_IMAGE_NAME}-${KERNEL_FIT_LINK_NAME}"
183 fi
184 fi
185 fi
186}
187addtask deploy after do_compile before do_build