diff options
author | Marco Felsch <m.felsch@pengutronix.de> | 2024-01-26 14:16:31 +0100 |
---|---|---|
committer | Khem Raj <raj.khem@gmail.com> | 2024-10-09 15:47:23 -0700 |
commit | b20be52a4ee5867cd0a21dc9891605e189c48219 (patch) | |
tree | c6489c23e3a5098ee68c44d08a2faa9254962bd8 | |
parent | a090cd3e0ef554d7171eb84488661599d72fa3e9 (diff) | |
download | meta-openembedded-b20be52a4ee5867cd0a21dc9891605e189c48219.tar.gz |
fitimage: add support to build arbitrary FIT images
The FIT image support in OE is quite limited:
1) No support to build an arbitrary number of FIT images since the FIT
image generation is tightly coupled to the kernel image.
2) A lot of U_BOOT-specific variables which may not be necessary for
other bootloaders.
3) No usage of the meta-oe signing.bbclass for signed FIT images.
This alternative class is added to solve the above-mentioned problems:
1) The class can be inherited by an arbitrary number of
<fit-image-name>.bb recipes to generate FIT images
2) No U_BOOT-specific variables are used
3) <fit-image-name>.bb recipes can prepend the do_fitimage() to
provide the key using the signing.bbclass e.g.:
do_fitimage:prepend() {
signing_prepare
signing_use_role "${FITIMAGE_SIGNING_KEY_ROLE}"
}
Then enable and configure signing as follows:
FITIMAGE_SIGN = "1"
FITIMAGE_MKIMAGE_EXTRA_ARGS = "--engine pkcs11"
FITIMAGE_SIGN_KEYDIR = "${PKCS11_URI}
This class is inspired by the meta-phytec fitimage.bbclass [1].
[1] https://git.phytec.de/meta-phytec/tree/classes/fitimage.bbclass
Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
Signed-off-by: Enrico Jörns <ejo@pengutronix.de>
Signed-off-by: Khem Raj <raj.khem@gmail.com>
-rw-r--r-- | meta-oe/classes/fitimage.bbclass | 530 |
1 files changed, 530 insertions, 0 deletions
diff --git a/meta-oe/classes/fitimage.bbclass b/meta-oe/classes/fitimage.bbclass new file mode 100644 index 0000000000..78e30eca33 --- /dev/null +++ b/meta-oe/classes/fitimage.bbclass | |||
@@ -0,0 +1,530 @@ | |||
1 | # SPDX-License-Identifier: MIT | ||
2 | # | ||
3 | # Copyright PHYTEC Messtechnik GmbH | ||
4 | # Copyright (C) 2024 Pengutronix, <yocto@pengutronix.de> | ||
5 | # | ||
6 | # Class for creating (signed) FIT images | ||
7 | # Description: | ||
8 | # | ||
9 | # You have to define the 'images' to put in the FIT image in your recipe file | ||
10 | # following this example: | ||
11 | # | ||
12 | # FITIMAGE_IMAGES ?= "kernel fdt fdto setup ramdisk bootscript" | ||
13 | # | ||
14 | # FITIMAGE_IMAGE_kernel ?= "virtual/kernel" | ||
15 | # FITIMAGE_IMAGE_kernel[type] ?= "kernel" | ||
16 | # | ||
17 | # FITIMAGE_IMAGE_fdt ?= "virtual/dtb" # or "virtual/kernel" | ||
18 | # FITIMAGE_IMAGE_fdt[type] ?= "fdt" | ||
19 | # #FITIMAGE_IMAGE_fdt[file] ?= "hw-name.dtb" | ||
20 | # | ||
21 | # FITIMAGE_IMAGE_fdto ?= "virtual/kernel" | ||
22 | # FITIMAGE_IMAGE_fdto[type] ?= "fdto" | ||
23 | # FITIMAGE_IMAGE_fdto[file] ?= <list of all dtbo files from KERNEL_DEVICETREE> | ||
24 | # | ||
25 | # Add a devicetree created on-thy-fly of a base dtb and serveral dtbo's | ||
26 | # FITIMAGE_IMAGE_fdtapply ?= "virtual/kernel" | ||
27 | # FITIMAGE_IMAGE_fdtapply[type] ?= "fdtapply" | ||
28 | # FITIMAGE_IMAGE_fdtapply[file] ?= "base.dtb overlay-1.dtbo overlay-2.dtbo" | ||
29 | # FITIMAGE_IMAGE_fdtapply[name] ?= "<name for new generated fdt>" | ||
30 | # | ||
31 | # FITIMAGE_IMAGE_ramdisk ?= "core-image-minimal" | ||
32 | # FITIMAGE_IMAGE_ramdisk[type] ?= "ramdisk" | ||
33 | # FITIMAGE_IMAGE_ramdisk[fstype] ?= "cpio.gz" | ||
34 | # | ||
35 | # FITIMAGE_IMAGE_bootscript ?= "bootscript" | ||
36 | # FITIMAGE_IMAGE_bootscript[type] ?= "bootscript" | ||
37 | # FITIMAGE_IMAGE_bootscript[file] ?= "boot.scr" | ||
38 | # | ||
39 | # Valid options for the [type] varflag are: "kernel", "fdt", "fdto", "fdtapply", "ramdisk", "bootscript". | ||
40 | # | ||
41 | # To enable signing, set | ||
42 | # | ||
43 | # FITIMAGE_SIGN = "1" | ||
44 | # | ||
45 | # and configure FITIMAGE_SIGN_KEYDIR (and FITIMAGE_SIGN_KEYNAME) according to | ||
46 | # your needs. | ||
47 | # | ||
48 | # For signing via PKCS#11 URIs provided by the meta-oe signing.bbclass, add: | ||
49 | # | ||
50 | # inherit signing | ||
51 | # | ||
52 | # FITIMAGE_SIGNING_KEY_ROLE = "fit" | ||
53 | # | ||
54 | # do_fitimage:prepend() { | ||
55 | # signing_prepare | ||
56 | # signing_use_role "${FITIMAGE_SIGNING_KEY_ROLE}" | ||
57 | # } | ||
58 | # | ||
59 | # FITIMAGE_SIGN = "1" | ||
60 | # FITIMAGE_MKIMAGE_EXTRA_ARGS = "--engine pkcs11" | ||
61 | # FITIMAGE_SIGN_KEYDIR = "${PKCS11_URI}" | ||
62 | |||
63 | |||
64 | LICENSE ?= "MIT" | ||
65 | |||
66 | inherit deploy kernel-artifact-names image-artifact-names kernel-arch nopackages | ||
67 | |||
68 | do_patch[noexec] = "1" | ||
69 | do_compile[noexec] = "1" | ||
70 | do_install[noexec] = "1" | ||
71 | deltask do_populate_sysroot | ||
72 | |||
73 | INHIBIT_DEFAULT_DEPS = "1" | ||
74 | |||
75 | DEPENDS = "u-boot-mkimage-native dtc-native" | ||
76 | |||
77 | FITIMAGE_SIGN ?= "0" | ||
78 | FITIMAGE_SIGN[doc] = "Enable FIT image signing" | ||
79 | FITIMAGE_SIGN_KEYDIR ?= "" | ||
80 | FITIMAGE_SIGN_KEYDIR[doc] = "Key directory or pkcs#11 URI to use for signing configuration" | ||
81 | FITIMAGE_MKIMAGE_EXTRA_ARGS[doc] = "Extra arguemnts to pass to uboot-mkimage call" | ||
82 | FITIMAGE_HASH_ALGO ?= "sha256" | ||
83 | FITIMAGE_HASH_ALGO[doc] = "Hash algorithm to use" | ||
84 | FITIMAGE_ENCRYPT_ALGO ?= "rsa2048" | ||
85 | FITIMAGE_ENCRYPT_ALGO[doc] = "Signature algorithm to use" | ||
86 | FITIMAGE_CONFIG_PREFIX ?= "conf-" | ||
87 | FITIMAGE_CONFIG_PREFIX[doc] = "Prefix to use for FIT configuration node name" | ||
88 | |||
89 | FITIMAGE_LOADADDRESS ??= "" | ||
90 | FITIMAGE_ENTRYPOINT ??= "" | ||
91 | FITIMAGE_DTB_LOADADDRESS ??= "" | ||
92 | FITIMAGE_DTB_OVERLAY_LOADADDRESS ??= "" | ||
93 | FITIMAGE_RD_LOADADDRESS ??= "" | ||
94 | FITIMAGE_RD_ENTRYPOINT ??= "" | ||
95 | |||
96 | PACKAGE_ARCH = "${MACHINE_ARCH}" | ||
97 | |||
98 | # Create dependency list from images | ||
99 | python __anonymous() { | ||
100 | for image in (d.getVar('FITIMAGE_IMAGES') or "").split(): | ||
101 | imageflags = d.getVarFlags('FITIMAGE_IMAGE_%s' % image, expand=['type', 'depends']) or {} | ||
102 | imgtype = imageflags.get('type') | ||
103 | if not imgtype: | ||
104 | bb.debug(1, "No [type] given for image '%s', defaulting to 'kernel'" % image) | ||
105 | imgtype = 'kernel' | ||
106 | recipe = d.getVar('FITIMAGE_IMAGE_%s' % image) | ||
107 | |||
108 | if not recipe: | ||
109 | bb.error("No recipe set for image '%s'. Specify via 'FITIMAGE_IMAGE_%s = \"<recipe-name>\"'" % (recipe, image)) | ||
110 | return | ||
111 | |||
112 | d.appendVarFlag('do_unpack', 'vardeps', ' FITIMAGE_IMAGE_%s' % image) | ||
113 | depends = imageflags.get('depends') | ||
114 | if depends: | ||
115 | d.appendVarFlag('do_unpack', 'depends', ' ' + depends) | ||
116 | continue | ||
117 | |||
118 | if imgtype == 'ramdisk': | ||
119 | d.appendVarFlag('do_unpack', 'depends', ' ' + recipe + ':do_image_complete') | ||
120 | elif 'fdt' in imgtype: | ||
121 | d.appendVarFlag('do_unpack', 'depends', ' ' + recipe + ':do_populate_sysroot') | ||
122 | d.appendVarFlag('do_unpack', 'depends', ' ' + recipe + ':do_deploy') | ||
123 | else: | ||
124 | d.appendVarFlag('do_unpack', 'depends', ' ' + recipe + ':do_deploy') | ||
125 | |||
126 | if 'fdt' in imgtype and d.getVar('PREFERRED_PROVIDER_virtual/dtb'): | ||
127 | d.setVar('EXTERNAL_KERNEL_DEVICETREE', '${RECIPE_SYSROOT}/boot/devicetree') | ||
128 | } | ||
129 | |||
130 | S = "${WORKDIR}/sources" | ||
131 | UNPACKDIR = "${S}" | ||
132 | B = "${WORKDIR}/build" | ||
133 | |||
134 | # | ||
135 | # Emit the fitImage ITS header | ||
136 | # | ||
137 | def fitimage_emit_fit_header(d, fd): | ||
138 | fd.write('/dts-v1/;\n\n/ {\n') | ||
139 | fd.write(d.expand('\tdescription = "fitImage for ${DISTRO_NAME}/${PV}/${MACHINE}";\n')) | ||
140 | fd.write('\t#address-cells = <1>;\n') | ||
141 | |||
142 | # | ||
143 | # Emit the fitImage ITS footer | ||
144 | # | ||
145 | def fitimage_emit_fit_footer(d, fd): | ||
146 | fd.write('};\n') | ||
147 | |||
148 | # | ||
149 | # Emit the fitImage section | ||
150 | # | ||
151 | def fitimage_emit_section_start(d, fd, section): | ||
152 | fd.write(f'\t{section} {{\n') | ||
153 | |||
154 | # | ||
155 | # Emit the fitImage section end | ||
156 | # | ||
157 | def fitimage_emit_section_end(d, fd): | ||
158 | fd.write('\t};\n') | ||
159 | |||
160 | def fitimage_emit_section_kernel(d, fd, imgpath, imgsource, imgcomp): | ||
161 | kernelcount = 1 | ||
162 | kernel_csum = d.getVar("FITIMAGE_HASH_ALGO") | ||
163 | arch = d.getVar("ARCH") | ||
164 | loadaddr = d.getVar("FITIMAGE_LOADADDRESS") | ||
165 | entryaddr = d.getVar("FITIMAGE_ENTRYPOINT") | ||
166 | |||
167 | bb.note(f"Adding kernel-{kernelcount} section to ITS file") | ||
168 | |||
169 | fd.write(f'\t\tkernel-{kernelcount} {{\n') | ||
170 | fd.write('\t\t\tdescription = "Linux kernel";\n') | ||
171 | fd.write(f'\t\t\tdata = /incbin/("{imgpath}/{imgsource}");\n') | ||
172 | fd.write('\t\t\ttype = "kernel";\n') | ||
173 | fd.write(f'\t\t\tarch = "{arch}";\n') | ||
174 | fd.write('\t\t\tos = "linux";\n') | ||
175 | fd.write(f'\t\t\tcompression = "{imgcomp}";\n') | ||
176 | if (loadaddr): | ||
177 | fd.write(f'\t\t\tload = <{loadaddr}>;\n') | ||
178 | if (entryaddr): | ||
179 | fd.write(f'\t\t\tentry = <{entryaddr}>;\n') | ||
180 | fd.write('\t\t\thash-1 {\n') | ||
181 | fd.write(f'\t\t\t\talgo = "{kernel_csum}";\n') | ||
182 | fd.write('\t\t\t};\n') | ||
183 | fd.write('\t\t};\n') | ||
184 | |||
185 | # | ||
186 | # Emit the fitImage ITS DTB section | ||
187 | # | ||
188 | def _fitimage_emit_section_dtb(d, fd, dtb_file, dtb_path, loadaddr, desc): | ||
189 | dtb_csum = d.getVar("FITIMAGE_HASH_ALGO") | ||
190 | arch = d.getVar("ARCH") | ||
191 | |||
192 | bb.note(f"Adding fdt-{dtb_file} section to ITS file") | ||
193 | |||
194 | fd.write(f'\t\tfdt-{dtb_file} {{\n') | ||
195 | fd.write(f'\t\t\tdescription = "{desc}";\n') | ||
196 | fd.write(f'\t\t\tdata = /incbin/("{dtb_path}/{dtb_file}");\n') | ||
197 | fd.write('\t\t\ttype = "flat_dt";\n') | ||
198 | fd.write(f'\t\t\tarch = "{arch}";\n') | ||
199 | fd.write('\t\t\tcompression = "none";\n') | ||
200 | if loadaddr: | ||
201 | fd.write(f'\t\t\tload = <{loadaddr}>;\n') | ||
202 | fd.write('\t\t\thash-1 {\n') | ||
203 | fd.write(f'\t\t\t\talgo = "{dtb_csum}";\n') | ||
204 | fd.write('\t\t\t};\n') | ||
205 | fd.write('\t\t};\n') | ||
206 | |||
207 | |||
208 | def fitimage_emit_section_dtb(d, fd, dtb_file, dtb_path): | ||
209 | loadaddr = d.getVar("FITIMAGE_DTB_LOADADDRESS") | ||
210 | |||
211 | _fitimage_emit_section_dtb(d, fd, dtb_file, dtb_path, loadaddr, "Flattened Device Tree blob") | ||
212 | |||
213 | # | ||
214 | # Emit the fitImage ITS DTB overlay section | ||
215 | # | ||
216 | def fitimage_emit_section_dtb_overlay(d, fd, dtb_file, dtb_path): | ||
217 | loadaddr = d.getVar("FITIMAGE_DTB_OVERLAY_LOADADDRESS") | ||
218 | |||
219 | _fitimage_emit_section_dtb(d, fd, dtb_file, dtb_path, loadaddr, "Flattened Device Tree Overlay blob") | ||
220 | |||
221 | |||
222 | # | ||
223 | # Emit the fitImage ITS ramdisk section | ||
224 | # | ||
225 | def fitimage_emit_section_ramdisk(d, fd, img_file, img_path): | ||
226 | ramdisk_count = "1" | ||
227 | ramdisk_csum = d.getVar("FITIMAGE_HASH_ALGO") | ||
228 | arch = d.getVar("ARCH") | ||
229 | loadaddr = d.getVar("FITIMAGE_RD_LOADADDRESS") | ||
230 | entryaddr = d.getVar("FITIMAGE_RD_ENTRYPOINT") | ||
231 | |||
232 | bb.note(f"Adding ramdisk-{ramdisk_count} section to ITS file") | ||
233 | |||
234 | fd.write(f'\t\tramdisk-{ramdisk_count} {{\n') | ||
235 | fd.write(f'\t\t\tdescription = "{img_file}";\n') | ||
236 | fd.write(f'\t\t\tdata = /incbin/("{img_path}/{img_file}");\n') | ||
237 | fd.write('\t\t\ttype = "ramdisk";\n') | ||
238 | fd.write(f'\t\t\tarch = "{arch}";\n') | ||
239 | fd.write('\t\t\tos = "linux";\n') | ||
240 | fd.write('\t\t\tcompression = "none";\n') | ||
241 | if (loadaddr): | ||
242 | fd.write(f'\t\t\tload = <{loadaddr}>;\n') | ||
243 | if (entryaddr): | ||
244 | fd.write(f'\t\t\tentry = <{entryaddr}>;\n') | ||
245 | fd.write('\t\t\thash-1 {\n') | ||
246 | fd.write(f'\t\t\t\talgo = "{ramdisk_csum}";\n') | ||
247 | fd.write('\t\t\t};\n') | ||
248 | fd.write('\t\t};\n') | ||
249 | |||
250 | def fitimage_emit_section_bootscript(d, fd, imgpath, imgsource): | ||
251 | hash_algo = d.getVar("FITIMAGE_HASH_ALGO") | ||
252 | arch = d.getVar("ARCH") | ||
253 | |||
254 | bb.note(f"Adding bootscr-{imgsource} section to ITS file") | ||
255 | |||
256 | fd.write(f'\t\tbootscr-{imgsource} {{\n') | ||
257 | fd.write('\t\t\tdescription = "U-boot script";\n') | ||
258 | fd.write(f'\t\t\tdata = /incbin/("{imgpath}/{imgsource}");\n') | ||
259 | fd.write('\t\t\ttype = "script";\n') | ||
260 | fd.write(f'\t\t\tarch = "{arch}";\n') | ||
261 | fd.write('\t\t\tos = "linux";\n') | ||
262 | fd.write('\t\t\tcompression = "none";\n') | ||
263 | fd.write('\t\t\thash-1 {\n') | ||
264 | fd.write(f'\t\t\t\talgo = "{hash_algo}";\n') | ||
265 | fd.write('\t\t\t};\n') | ||
266 | fd.write('\t\t};\n') | ||
267 | |||
268 | def fitimage_emit_subsection_signature(d, fd, sign_images_list): | ||
269 | hash_algo = d.getVar("FITIMAGE_HASH_ALGO") | ||
270 | encrypt_algo = d.getVar("FITIMAGE_ENCRYPT_ALGO") or "" | ||
271 | conf_sign_keyname = d.getVar("FITIMAGE_SIGN_KEYNAME") | ||
272 | signer_name = d.getVar("FITIMAGE_SIGNER") | ||
273 | signer_version = d.getVar("FITIMAGE_SIGNER_VERSION") | ||
274 | sign_images = ", ".join(f'"{s}"' for s in sign_images_list) | ||
275 | |||
276 | fd.write('\t\t\tsignature-1 {\n') | ||
277 | fd.write(f'\t\t\t\talgo = "{hash_algo},{encrypt_algo}";\n') | ||
278 | if conf_sign_keyname: | ||
279 | fd.write(f'\t\t\t\tkey-name-hint = {conf_sign_keyname}";\n') | ||
280 | fd.write(f'\t\t\t\tsign-images = {sign_images};\n') | ||
281 | fd.write(f'\t\t\t\tsigner-name = "{signer_name}";\n') | ||
282 | fd.write(f'\t\t\t\tsigner-version = "{signer_version}";\n') | ||
283 | fd.write('\t\t\t};\n') | ||
284 | |||
285 | # | ||
286 | # Emit the fitImage ITS configuration section | ||
287 | # | ||
288 | def fitimage_emit_section_config(d, fd, dtb, kernelcount, ramdiskcount, setupcount, bootscriptid, compatible, dtbcount): | ||
289 | sign = d.getVar("FITIMAGE_SIGN") | ||
290 | conf_default = None | ||
291 | conf_prefix = d.getVar('FITIMAGE_CONFIG_PREFIX', True) or "" | ||
292 | |||
293 | bb.note(f"Adding {dtb} section to ITS file") | ||
294 | |||
295 | conf_desc="Linux kernel" | ||
296 | if dtb: | ||
297 | conf_desc += ", FDT blob" | ||
298 | if ramdiskcount: | ||
299 | conf_desc += ", ramdisk" | ||
300 | if setupcount: | ||
301 | conf_desc += ", setup" | ||
302 | if bootscriptid: | ||
303 | conf_desc += ", u-boot script" | ||
304 | if dtbcount == 1: | ||
305 | conf_default = d.getVar('FITIMAGE_DEFAULT_CONFIG', True) or dtb | ||
306 | |||
307 | if conf_default: | ||
308 | fd.write(f'\t\tdefault = "{conf_default}";\n') | ||
309 | fd.write(f'\t\t{conf_prefix}{dtb} {{\n') | ||
310 | fd.write(f'\t\t\tdescription = "{dtbcount} {conf_desc}";\n') | ||
311 | if kernelcount: | ||
312 | fd.write('\t\t\tkernel = "kernel-1";\n') | ||
313 | fd.write(f'\t\t\tfdt = "fdt-{dtb}";\n') | ||
314 | if ramdiskcount: | ||
315 | fd.write(f'\t\t\tramdisk = "ramdisk-{ramdiskcount}";\n') | ||
316 | if bootscriptid: | ||
317 | fd.write(f'\t\t\tbootscr = "bootscr-{bootscriptid}";\n') | ||
318 | if compatible: | ||
319 | fd.write(f'\t\t\tcompatible = "{compatible}";\n') | ||
320 | |||
321 | if sign == "1": | ||
322 | sign_images = ["kernel"] | ||
323 | if dtb: | ||
324 | sign_images.append("fdt") | ||
325 | if ramdiskcount: | ||
326 | sign_images.append("ramdisk") | ||
327 | if setupcount: | ||
328 | sign_images.append("setup") | ||
329 | if bootscriptid: | ||
330 | sign_images.append("bootscr") | ||
331 | fitimage_emit_subsection_signature(d, fd, sign_images) | ||
332 | |||
333 | fd.write('\t\t' + '};\n') | ||
334 | |||
335 | # | ||
336 | # Emits a device tree overlay config section | ||
337 | # | ||
338 | def fitimage_emit_section_config_fdto(d, fd, dtb, compatible): | ||
339 | sign = d.getVar("FITIMAGE_SIGN") | ||
340 | bb.note("Adding overlay config section to ITS file") | ||
341 | |||
342 | fd.write(f'\t\t{dtb} {{\n') | ||
343 | fd.write(f'\t\t\tdescription = "Device Tree Overlay";\n') | ||
344 | fd.write(f'\t\t\tfdt = "fdt-{dtb}";') | ||
345 | if compatible: | ||
346 | fd.write(f'\t\t\tcompatible = "{compatible}";') | ||
347 | |||
348 | if sign == "1": | ||
349 | sign_images = ["fdt"] | ||
350 | fitimage_emit_subsection_signature(d, fd, sign_images) | ||
351 | |||
352 | fd.write('\t\t' + '};\n') | ||
353 | |||
354 | python write_manifest() { | ||
355 | machine = d.getVar('MACHINE') | ||
356 | kernelcount=1 | ||
357 | DTBS = "" | ||
358 | DTBOS = "" | ||
359 | ramdiskcount = "" | ||
360 | setupcount = "" | ||
361 | bootscriptid = "" | ||
362 | compatible = "" | ||
363 | |||
364 | def get_dtbs(d, dtb_suffix): | ||
365 | sysroot = d.getVar('RECIPE_SYSROOT') | ||
366 | deploydir = d.getVar('DEPLOY_DIR_IMAGE') | ||
367 | |||
368 | dtbs = (d.getVar('KERNEL_DEVICETREE') or '').split() | ||
369 | dtbs = [os.path.basename(x) for x in dtbs if x.endswith(dtb_suffix)] | ||
370 | ext_dtbs = os.listdir(d.getVar('EXTERNAL_KERNEL_DEVICETREE')) if d.getVar('EXTERNAL_KERNEL_DEVICETREE') else [] | ||
371 | ext_dtbs = [x for x in ext_dtbs if x.endswith(dtb_suffix)] | ||
372 | |||
373 | result = [] | ||
374 | # Prefer BSP dts if BSP and kernel provide the same dts | ||
375 | for d in sorted(set(dtbs + ext_dtbs)): | ||
376 | dtbpath = f'{sysroot}/boot/devicetree/{d}' if d in ext_dtbs else f'{deploydir}/{d}' | ||
377 | result.append(dtbpath) | ||
378 | |||
379 | return " ".join(result) | ||
380 | |||
381 | with open('%s/manifest.its' % d.getVar('B'), 'w') as fd: | ||
382 | images = d.getVar('FITIMAGE_IMAGES') | ||
383 | if not images: | ||
384 | bb.warn("No images specified in FITIMAGE_IMAGES. Generated FIT image will be empty") | ||
385 | |||
386 | fitimage_emit_fit_header(d, fd) | ||
387 | fitimage_emit_section_start(d, fd, 'images') | ||
388 | |||
389 | for image in (images or "").split(): | ||
390 | imageflags = d.getVarFlags('FITIMAGE_IMAGE_%s' % image, expand=['file', 'fstype', 'type', 'comp']) or {} | ||
391 | imgtype = imageflags.get('type', '') | ||
392 | if imgtype == 'kernel': | ||
393 | default = "%s-%s%s" % (d.getVar('KERNEL_IMAGETYPE'), machine, d.getVar('KERNEL_IMAGE_BIN_EXT')) | ||
394 | imgsource = imageflags.get('file', default) | ||
395 | imgcomp = imageflags.get('comp', 'none') | ||
396 | imgpath = d.getVar("DEPLOY_DIR_IMAGE") | ||
397 | fitimage_emit_section_kernel(d, fd, imgpath, imgsource, imgcomp) | ||
398 | elif imgtype == 'fdt': | ||
399 | default = get_dtbs(d, "dtb") | ||
400 | dtbfiles = imageflags.get('file', default) | ||
401 | if not dtbfiles: | ||
402 | bb.fatal(f"No dtb file found for image '{image}'. Set KERNEL_DEVICETREE, [file] varflag, or reference devicetree.bbclass-based recipe.") | ||
403 | for dtb in dtbfiles.split(): | ||
404 | dtb_path, dtb_file = os.path.split(dtb) | ||
405 | DTBS += f" {dtb}" | ||
406 | fitimage_emit_section_dtb(d, fd, dtb_file, dtb_path) | ||
407 | elif imgtype == 'fdto': | ||
408 | default = get_dtbs(d, "dtbo") | ||
409 | dtbofiles = imageflags.get('file', default) | ||
410 | if not dtbofiles: | ||
411 | bb.fatal(f"No dtbo file found for image '{image}'. Set KERNEL_DEVICETREE, [file] varflag, or reference devicetree.bbclass-based recipe.") | ||
412 | for dtb in dtbofiles.split(): | ||
413 | dtb_path, dtb_file = os.path.split(dtb) | ||
414 | DTBOS = DTBOS + " " + dtb | ||
415 | fitimage_emit_section_dtb_overlay(d, fd, dtb_file, dtb_path) | ||
416 | elif imgtype == 'fdtapply': | ||
417 | import subprocess | ||
418 | dtbofiles = imageflags.get('file', None) | ||
419 | if not dtbofiles: | ||
420 | bb.fatal(f"No dtbo file found for image '{image}'. Set via [file] varflag.") | ||
421 | dtboutname = imageflags.get('name', None) | ||
422 | if not dtboutname: | ||
423 | bb.fatal(f"No dtb output name found for image '{image}'. Set via [name] varflag.") | ||
424 | dtbresult = "%s/%s" % (d.getVar('B'), dtboutname) | ||
425 | dtbcommand = "" | ||
426 | for dtb in dtbofiles.split(): | ||
427 | dtb_path, dtb_file = os.path.split(dtb) | ||
428 | if not dtb_path: | ||
429 | dtb_path = d.getVar("DEPLOY_DIR_IMAGE") | ||
430 | if not dtbcommand: | ||
431 | if not dtb_file.endswith('.dtb'): | ||
432 | bb.fatal(f"fdtapply failed: Expected (non-overlay) .dtb file as first element, but got {dtb_file}") | ||
433 | dtbcommand = f"fdtoverlay -i {dtb_path}/{dtb_file} -o {dtbresult}" | ||
434 | else: | ||
435 | if not dtb_file.endswith('.dtbo'): | ||
436 | bb.fatal(f"fdtapply failed: Expected .dtbo file, but got {dtb_file}") | ||
437 | dtbcommand += f" {dtb_path}/{dtb_file}" | ||
438 | result = subprocess.run(dtbcommand, stderr=subprocess.PIPE, shell=True, text=True) | ||
439 | if result.returncode != 0: | ||
440 | bb.fatal(f"Running {dtbcommand} failed: {result.stderr}") | ||
441 | dtb_path, dtb_file = os.path.split(dtbresult) | ||
442 | DTBS += f" {dtbresult}" | ||
443 | fitimage_emit_section_dtb(d, fd, dtb_file, dtb_path) | ||
444 | elif imgtype == 'ramdisk': | ||
445 | ramdiskcount = "1" | ||
446 | default_imgfstype = d.getVar('INITRAMFS_FSTYPES' or "").split()[0] | ||
447 | img_fstype = imageflags.get('fstype', default_imgfstype) | ||
448 | img_file = "%s%s.%s" % (d.getVar('FITIMAGE_IMAGE_%s' % image), d.getVar('IMAGE_MACHINE_SUFFIX'), img_fstype) | ||
449 | img_path = d.getVar("DEPLOY_DIR_IMAGE") | ||
450 | fitimage_emit_section_ramdisk(d, fd, img_file, img_path) | ||
451 | elif imgtype == 'bootscript': | ||
452 | if bootscriptid: | ||
453 | bb.fatal("Only a single boot script is supported (already set to: %s)" % bootscriptid) | ||
454 | imgsource = imageflags.get('file', None) | ||
455 | imgpath = d.getVar("DEPLOY_DIR_IMAGE") | ||
456 | bootscriptid = imgsource | ||
457 | fitimage_emit_section_bootscript(d, fd, imgpath, imgsource) | ||
458 | fitimage_emit_section_end(d, fd) | ||
459 | # | ||
460 | # Step 5: Prepare a configurations section | ||
461 | # | ||
462 | fitimage_emit_section_start(d, fd, 'configurations') | ||
463 | dtbcount = 1 | ||
464 | for dtb in (DTBS or "").split(): | ||
465 | import subprocess | ||
466 | try: | ||
467 | cmd = "fdtget -t s {} / compatible".format(dtb) | ||
468 | compatible = subprocess.check_output(cmd, shell=True, text=True).split()[0] | ||
469 | except subprocess.CalledProcessError: | ||
470 | bb.fatal("Failed to find root-node compatible string in (%s)" % dtb) | ||
471 | |||
472 | dtb_path, dtb_file = os.path.split(dtb) | ||
473 | fitimage_emit_section_config(d, fd, dtb_file, kernelcount, ramdiskcount, setupcount, bootscriptid, compatible, dtbcount) | ||
474 | dtbcount += 1 | ||
475 | for dtb in (DTBOS or "").split(): | ||
476 | import subprocess | ||
477 | try: | ||
478 | cmd = "fdtget -t s {} / compatible".format(dtb) | ||
479 | compatible = subprocess.check_output(cmd, shell=True, text=True).split()[0] | ||
480 | except subprocess.CalledProcessError: | ||
481 | bb.note("Failed to find root-node compatible string in (%s)" % dtb) | ||
482 | compatible = None | ||
483 | |||
484 | dtb_path, dtb_file = os.path.split(dtb) | ||
485 | fitimage_emit_section_config_fdto(d, fd, dtb_file, compatible) | ||
486 | |||
487 | fitimage_emit_section_end(d, fd) | ||
488 | fitimage_emit_fit_footer(d, fd) | ||
489 | } | ||
490 | |||
491 | do_configure[postfuncs] += "write_manifest" | ||
492 | |||
493 | do_fitimage () { | ||
494 | if [ "${FITIMAGE_SIGN}" = "1" ]; then | ||
495 | uboot-mkimage ${FITIMAGE_MKIMAGE_EXTRA_ARGS} \ | ||
496 | -k ${FITIMAGE_SIGN_KEYDIR} -r \ | ||
497 | -f "${B}/manifest.its" \ | ||
498 | "${B}/fitImage" | ||
499 | else | ||
500 | uboot-mkimage ${FITIMAGE_MKIMAGE_EXTRA_ARGS} \ | ||
501 | -f "${B}/manifest.its" \ | ||
502 | "${B}/fitImage" | ||
503 | fi | ||
504 | } | ||
505 | addtask fitimage after do_configure | ||
506 | |||
507 | ITS_NAME ?= "${PN}-${KERNEL_ARTIFACT_NAME}" | ||
508 | ITS_LINK_NAME ?= "${PN}-${KERNEL_ARTIFACT_LINK_NAME}" | ||
509 | FITIMAGE_IMAGE_NAME ?= "fitImage-${PN}-${KERNEL_FIT_NAME}${KERNEL_FIT_BIN_EXT}" | ||
510 | FITIMAGE_IMAGE_LINK_NAME ?= "fitImage-${PN}-${KERNEL_FIT_LINK_NAME}" | ||
511 | |||
512 | SSTATE_SKIP_CREATION:task-deploy = '1' | ||
513 | |||
514 | do_deploy() { | ||
515 | bbnote 'Copying fit-image.its source file...' | ||
516 | install -m 0644 ${B}/manifest.its ${DEPLOYDIR}/${ITS_NAME}.its | ||
517 | |||
518 | bbnote 'Copying all created fdt from type fdtapply' | ||
519 | for DTB_FILE in `find ${B} -maxdepth 1 -name *.dtb`; do | ||
520 | install -m 0644 ${DTB_FILE} ${DEPLOYDIR}/ | ||
521 | done | ||
522 | |||
523 | bbnote 'Copying fitImage file...' | ||
524 | install -m 0644 ${B}/fitImage ${DEPLOYDIR}/${FITIMAGE_IMAGE_NAME} | ||
525 | |||
526 | cd ${DEPLOYDIR} | ||
527 | ln -sf ${ITS_NAME}.its ${ITS_LINK_NAME}.its | ||
528 | ln -sf ${FITIMAGE_IMAGE_NAME} ${FITIMAGE_IMAGE_LINK_NAME} | ||
529 | } | ||
530 | addtask deploy after do_fitimage before do_build | ||