diff options
Diffstat (limited to 'meta-oe/classes/fitimage.bbclass')
-rw-r--r-- | meta-oe/classes/fitimage.bbclass | 540 |
1 files changed, 540 insertions, 0 deletions
diff --git a/meta-oe/classes/fitimage.bbclass b/meta-oe/classes/fitimage.bbclass new file mode 100644 index 0000000000..03fa2fcd57 --- /dev/null +++ b/meta-oe/classes/fitimage.bbclass | |||
@@ -0,0 +1,540 @@ | |||
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.fatal(f"No recipe set for image '{image}'. Specify via 'FITIMAGE_IMAGE_{image} = \"<recipe-name>\"'") | ||
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 = "${UNPACKDIR}" | ||
131 | B = "${WORKDIR}/build" | ||
132 | |||
133 | # | ||
134 | # Emit the fitImage ITS header | ||
135 | # | ||
136 | def fitimage_emit_fit_header(d, fd): | ||
137 | fd.write('/dts-v1/;\n\n/ {\n') | ||
138 | fd.write(d.expand('\tdescription = "fitImage for ${DISTRO_NAME}/${PV}/${MACHINE}";\n')) | ||
139 | fd.write('\t#address-cells = <1>;\n') | ||
140 | |||
141 | # | ||
142 | # Emit the fitImage ITS footer | ||
143 | # | ||
144 | def fitimage_emit_fit_footer(d, fd): | ||
145 | fd.write('};\n') | ||
146 | |||
147 | # | ||
148 | # Emit the fitImage section | ||
149 | # | ||
150 | def fitimage_emit_section_start(d, fd, section): | ||
151 | fd.write(f'\t{section} {{\n') | ||
152 | |||
153 | # | ||
154 | # Emit the fitImage section end | ||
155 | # | ||
156 | def fitimage_emit_section_end(d, fd): | ||
157 | fd.write('\t};\n') | ||
158 | |||
159 | def fitimage_emit_section_kernel(d, fd, imgpath, imgsource, imgcomp): | ||
160 | kernelcount = 1 | ||
161 | kernel_csum = d.getVar("FITIMAGE_HASH_ALGO") | ||
162 | arch = d.getVar("ARCH") | ||
163 | loadaddr = d.getVar("FITIMAGE_LOADADDRESS") | ||
164 | entryaddr = d.getVar("FITIMAGE_ENTRYPOINT") | ||
165 | |||
166 | bb.note(f"Adding kernel-{kernelcount} section to ITS file") | ||
167 | |||
168 | fd.write(f'\t\tkernel-{kernelcount} {{\n') | ||
169 | fd.write('\t\t\tdescription = "Linux kernel";\n') | ||
170 | fd.write(f'\t\t\tdata = /incbin/("{imgpath}/{imgsource}");\n') | ||
171 | fd.write('\t\t\ttype = "kernel";\n') | ||
172 | fd.write(f'\t\t\tarch = "{arch}";\n') | ||
173 | fd.write('\t\t\tos = "linux";\n') | ||
174 | fd.write(f'\t\t\tcompression = "{imgcomp}";\n') | ||
175 | if (loadaddr): | ||
176 | fd.write(f'\t\t\tload = <{loadaddr}>;\n') | ||
177 | if (entryaddr): | ||
178 | fd.write(f'\t\t\tentry = <{entryaddr}>;\n') | ||
179 | fd.write('\t\t\thash-1 {\n') | ||
180 | fd.write(f'\t\t\t\talgo = "{kernel_csum}";\n') | ||
181 | fd.write('\t\t\t};\n') | ||
182 | fd.write('\t\t};\n') | ||
183 | |||
184 | # | ||
185 | # Emit the fitImage ITS DTB section | ||
186 | # | ||
187 | def _fitimage_emit_section_dtb(d, fd, dtb_file, dtb_path, loadaddr, desc): | ||
188 | dtb_csum = d.getVar("FITIMAGE_HASH_ALGO") | ||
189 | arch = d.getVar("ARCH") | ||
190 | |||
191 | bb.note(f"Adding fdt-{dtb_file} section to ITS file") | ||
192 | |||
193 | fd.write(f'\t\tfdt-{dtb_file} {{\n') | ||
194 | fd.write(f'\t\t\tdescription = "{desc}";\n') | ||
195 | fd.write(f'\t\t\tdata = /incbin/("{dtb_path}/{dtb_file}");\n') | ||
196 | fd.write('\t\t\ttype = "flat_dt";\n') | ||
197 | fd.write(f'\t\t\tarch = "{arch}";\n') | ||
198 | fd.write('\t\t\tcompression = "none";\n') | ||
199 | if loadaddr: | ||
200 | fd.write(f'\t\t\tload = <{loadaddr}>;\n') | ||
201 | fd.write('\t\t\thash-1 {\n') | ||
202 | fd.write(f'\t\t\t\talgo = "{dtb_csum}";\n') | ||
203 | fd.write('\t\t\t};\n') | ||
204 | fd.write('\t\t};\n') | ||
205 | |||
206 | |||
207 | def fitimage_emit_section_dtb(d, fd, dtb_file, dtb_path): | ||
208 | loadaddr = d.getVar("FITIMAGE_DTB_LOADADDRESS") | ||
209 | |||
210 | _fitimage_emit_section_dtb(d, fd, dtb_file, dtb_path, loadaddr, "Flattened Device Tree blob") | ||
211 | |||
212 | # | ||
213 | # Emit the fitImage ITS DTB overlay section | ||
214 | # | ||
215 | def fitimage_emit_section_dtb_overlay(d, fd, dtb_file, dtb_path): | ||
216 | loadaddr = d.getVar("FITIMAGE_DTB_OVERLAY_LOADADDRESS") | ||
217 | |||
218 | _fitimage_emit_section_dtb(d, fd, dtb_file, dtb_path, loadaddr, "Flattened Device Tree Overlay blob") | ||
219 | |||
220 | |||
221 | # | ||
222 | # Emit the fitImage ITS ramdisk section | ||
223 | # | ||
224 | def fitimage_emit_section_ramdisk(d, fd, img_file, img_path): | ||
225 | ramdisk_count = "1" | ||
226 | ramdisk_csum = d.getVar("FITIMAGE_HASH_ALGO") | ||
227 | arch = d.getVar("ARCH") | ||
228 | loadaddr = d.getVar("FITIMAGE_RD_LOADADDRESS") | ||
229 | entryaddr = d.getVar("FITIMAGE_RD_ENTRYPOINT") | ||
230 | |||
231 | bb.note(f"Adding ramdisk-{ramdisk_count} section to ITS file") | ||
232 | |||
233 | fd.write(f'\t\tramdisk-{ramdisk_count} {{\n') | ||
234 | fd.write(f'\t\t\tdescription = "{img_file}";\n') | ||
235 | fd.write(f'\t\t\tdata = /incbin/("{img_path}/{img_file}");\n') | ||
236 | fd.write('\t\t\ttype = "ramdisk";\n') | ||
237 | fd.write(f'\t\t\tarch = "{arch}";\n') | ||
238 | fd.write('\t\t\tos = "linux";\n') | ||
239 | fd.write('\t\t\tcompression = "none";\n') | ||
240 | if (loadaddr): | ||
241 | fd.write(f'\t\t\tload = <{loadaddr}>;\n') | ||
242 | if (entryaddr): | ||
243 | fd.write(f'\t\t\tentry = <{entryaddr}>;\n') | ||
244 | fd.write('\t\t\thash-1 {\n') | ||
245 | fd.write(f'\t\t\t\talgo = "{ramdisk_csum}";\n') | ||
246 | fd.write('\t\t\t};\n') | ||
247 | fd.write('\t\t};\n') | ||
248 | |||
249 | def fitimage_emit_section_bootscript(d, fd, imgpath, imgsource): | ||
250 | hash_algo = d.getVar("FITIMAGE_HASH_ALGO") | ||
251 | arch = d.getVar("ARCH") | ||
252 | |||
253 | bb.note(f"Adding bootscr-{imgsource} section to ITS file") | ||
254 | |||
255 | fd.write(f'\t\tbootscr-{imgsource} {{\n') | ||
256 | fd.write('\t\t\tdescription = "U-boot script";\n') | ||
257 | fd.write(f'\t\t\tdata = /incbin/("{imgpath}/{imgsource}");\n') | ||
258 | fd.write('\t\t\ttype = "script";\n') | ||
259 | fd.write(f'\t\t\tarch = "{arch}";\n') | ||
260 | fd.write('\t\t\tos = "linux";\n') | ||
261 | fd.write('\t\t\tcompression = "none";\n') | ||
262 | fd.write('\t\t\thash-1 {\n') | ||
263 | fd.write(f'\t\t\t\talgo = "{hash_algo}";\n') | ||
264 | fd.write('\t\t\t};\n') | ||
265 | fd.write('\t\t};\n') | ||
266 | |||
267 | def fitimage_emit_subsection_signature(d, fd, sign_images_list): | ||
268 | hash_algo = d.getVar("FITIMAGE_HASH_ALGO") | ||
269 | encrypt_algo = d.getVar("FITIMAGE_ENCRYPT_ALGO") or "" | ||
270 | conf_sign_keyname = d.getVar("FITIMAGE_SIGN_KEYNAME") | ||
271 | signer_name = d.getVar("FITIMAGE_SIGNER") | ||
272 | signer_version = d.getVar("FITIMAGE_SIGNER_VERSION") | ||
273 | sign_images = ", ".join(f'"{s}"' for s in sign_images_list) | ||
274 | |||
275 | fd.write('\t\t\tsignature-1 {\n') | ||
276 | fd.write(f'\t\t\t\talgo = "{hash_algo},{encrypt_algo}";\n') | ||
277 | if conf_sign_keyname: | ||
278 | fd.write(f'\t\t\t\tkey-name-hint = "{conf_sign_keyname}";\n') | ||
279 | fd.write(f'\t\t\t\tsign-images = {sign_images};\n') | ||
280 | fd.write(f'\t\t\t\tsigner-name = "{signer_name}";\n') | ||
281 | fd.write(f'\t\t\t\tsigner-version = "{signer_version}";\n') | ||
282 | fd.write('\t\t\t};\n') | ||
283 | |||
284 | # | ||
285 | # Emit the fitImage ITS configuration section | ||
286 | # | ||
287 | def fitimage_emit_section_config(d, fd, dtb, kernelcount, ramdiskcount, setupcount, bootscriptid, compatible, dtbcount): | ||
288 | sign = d.getVar("FITIMAGE_SIGN") | ||
289 | conf_default = None | ||
290 | conf_prefix = d.getVar('FITIMAGE_CONFIG_PREFIX') or "" | ||
291 | |||
292 | bb.note(f"Adding {conf_prefix}{dtb} section to ITS file") | ||
293 | |||
294 | conf_desc="Linux kernel" | ||
295 | if dtb: | ||
296 | conf_desc += ", FDT blob" | ||
297 | if ramdiskcount: | ||
298 | conf_desc += ", ramdisk" | ||
299 | if setupcount: | ||
300 | conf_desc += ", setup" | ||
301 | if bootscriptid: | ||
302 | conf_desc += ", u-boot script" | ||
303 | if dtbcount == 1: | ||
304 | conf_default = d.getVar('FITIMAGE_DEFAULT_CONFIG') or f'{conf_prefix}{dtb}' | ||
305 | |||
306 | if conf_default: | ||
307 | fd.write(f'\t\tdefault = "{conf_default}";\n') | ||
308 | fd.write(f'\t\t{conf_prefix}{dtb} {{\n') | ||
309 | fd.write(f'\t\t\tdescription = "{dtbcount} {conf_desc}";\n') | ||
310 | if kernelcount: | ||
311 | fd.write('\t\t\tkernel = "kernel-1";\n') | ||
312 | fd.write(f'\t\t\tfdt = "fdt-{dtb}";\n') | ||
313 | if ramdiskcount: | ||
314 | fd.write(f'\t\t\tramdisk = "ramdisk-{ramdiskcount}";\n') | ||
315 | if bootscriptid: | ||
316 | fd.write(f'\t\t\tbootscr = "bootscr-{bootscriptid}";\n') | ||
317 | if compatible: | ||
318 | fd.write(f'\t\t\tcompatible = "{compatible}";\n') | ||
319 | |||
320 | if sign == "1": | ||
321 | sign_images = ["kernel"] | ||
322 | if dtb: | ||
323 | sign_images.append("fdt") | ||
324 | if ramdiskcount: | ||
325 | sign_images.append("ramdisk") | ||
326 | if setupcount: | ||
327 | sign_images.append("setup") | ||
328 | if bootscriptid: | ||
329 | sign_images.append("bootscr") | ||
330 | fitimage_emit_subsection_signature(d, fd, sign_images) | ||
331 | |||
332 | fd.write('\t\t' + '};\n') | ||
333 | |||
334 | # | ||
335 | # Emits a device tree overlay config section | ||
336 | # | ||
337 | def fitimage_emit_section_config_fdto(d, fd, dtb, compatible): | ||
338 | sign = d.getVar("FITIMAGE_SIGN") | ||
339 | bb.note("Adding overlay config section to ITS file") | ||
340 | |||
341 | fd.write(f'\t\t{dtb} {{\n') | ||
342 | fd.write(f'\t\t\tdescription = "Device Tree Overlay";\n') | ||
343 | fd.write(f'\t\t\tfdt = "fdt-{dtb}";\n') | ||
344 | if compatible: | ||
345 | fd.write(f'\t\t\tcompatible = "{compatible}";\n') | ||
346 | |||
347 | if sign == "1": | ||
348 | sign_images = ["fdt"] | ||
349 | fitimage_emit_subsection_signature(d, fd, sign_images) | ||
350 | |||
351 | fd.write('\t\t' + '};\n') | ||
352 | |||
353 | python write_manifest() { | ||
354 | machine = d.getVar('MACHINE') | ||
355 | kernelcount=1 | ||
356 | DTBS = "" | ||
357 | DTBOS = "" | ||
358 | ramdiskcount = "" | ||
359 | setupcount = "" | ||
360 | bootscriptid = "" | ||
361 | compatible = "" | ||
362 | |||
363 | def get_dtbs(d, dtb_suffix): | ||
364 | sysroot = d.getVar('RECIPE_SYSROOT') | ||
365 | deploydir = d.getVar('DEPLOY_DIR_IMAGE') | ||
366 | |||
367 | dtbs = (d.getVar('KERNEL_DEVICETREE') or '').split() | ||
368 | dtbs = [os.path.basename(x) for x in dtbs if x.endswith(dtb_suffix)] | ||
369 | ext_dtbs = os.listdir(d.getVar('EXTERNAL_KERNEL_DEVICETREE')) if d.getVar('EXTERNAL_KERNEL_DEVICETREE') else [] | ||
370 | ext_dtbs = [x for x in ext_dtbs if x.endswith(dtb_suffix)] | ||
371 | |||
372 | result = [] | ||
373 | # Prefer BSP dts if BSP and kernel provide the same dts | ||
374 | for d in sorted(set(dtbs + ext_dtbs)): | ||
375 | dtbpath = f'{sysroot}/boot/devicetree/{d}' if d in ext_dtbs else f'{deploydir}/{d}' | ||
376 | result.append(dtbpath) | ||
377 | |||
378 | return " ".join(result) | ||
379 | |||
380 | with open('%s/manifest.its' % d.getVar('B'), 'w') as fd: | ||
381 | images = d.getVar('FITIMAGE_IMAGES') | ||
382 | if not images: | ||
383 | bb.warn("No images specified in FITIMAGE_IMAGES. Generated FIT image will be empty") | ||
384 | |||
385 | fitimage_emit_fit_header(d, fd) | ||
386 | fitimage_emit_section_start(d, fd, 'images') | ||
387 | |||
388 | for image in (images or "").split(): | ||
389 | imageflags = d.getVarFlags('FITIMAGE_IMAGE_%s' % image, expand=['file', 'fstype', 'type', 'comp']) or {} | ||
390 | imgtype = imageflags.get('type', 'kernel') | ||
391 | if imgtype == 'kernel': | ||
392 | if d.getVar('KERNEL_IMAGETYPE') not in ('zImage', 'Image') and not imageflags.get('comp'): | ||
393 | bb.warn(f"KERNEL_IMAGETYPE is '{d.getVar('KERNEL_IMAGETYPE')}' but FITIMAGE_IMAGE_kernel[comp] is not set.") | ||
394 | default = "%s-%s%s" % (d.getVar('KERNEL_IMAGETYPE'), machine, d.getVar('KERNEL_IMAGE_BIN_EXT')) | ||
395 | imgsource = imageflags.get('file', default) | ||
396 | imgcomp = imageflags.get('comp', 'none') | ||
397 | imgpath = d.getVar("DEPLOY_DIR_IMAGE") | ||
398 | fitimage_emit_section_kernel(d, fd, imgpath, imgsource, imgcomp) | ||
399 | elif imgtype == 'fdt': | ||
400 | default = get_dtbs(d, "dtb") | ||
401 | dtbfiles = imageflags.get('file', default) | ||
402 | if not dtbfiles: | ||
403 | bb.fatal(f"No dtb file found for image '{image}'. Set KERNEL_DEVICETREE, [file] varflag, or reference devicetree.bbclass-based recipe.") | ||
404 | for dtb in dtbfiles.split(): | ||
405 | dtb_path, dtb_file = os.path.split(dtb) | ||
406 | DTBS += f" {dtb}" | ||
407 | fitimage_emit_section_dtb(d, fd, dtb_file, dtb_path) | ||
408 | elif imgtype == 'fdto': | ||
409 | default = get_dtbs(d, "dtbo") | ||
410 | dtbofiles = imageflags.get('file', default) | ||
411 | if not dtbofiles: | ||
412 | bb.fatal(f"No dtbo file found for image '{image}'. Set KERNEL_DEVICETREE, [file] varflag, or reference devicetree.bbclass-based recipe.") | ||
413 | for dtb in dtbofiles.split(): | ||
414 | dtb_path, dtb_file = os.path.split(dtb) | ||
415 | DTBOS = DTBOS + " " + dtb | ||
416 | fitimage_emit_section_dtb_overlay(d, fd, dtb_file, dtb_path) | ||
417 | elif imgtype == 'fdtapply': | ||
418 | import subprocess | ||
419 | dtbofiles = imageflags.get('file', None) | ||
420 | if not dtbofiles: | ||
421 | bb.fatal(f"No dtbo file found for image '{image}'. Set via [file] varflag.") | ||
422 | dtboutname = imageflags.get('name', None) | ||
423 | if not dtboutname: | ||
424 | bb.fatal(f"No dtb output name found for image '{image}'. Set via [name] varflag.") | ||
425 | dtbresult = "%s/%s" % (d.getVar('B'), dtboutname) | ||
426 | dtbcommand = "" | ||
427 | for dtb in dtbofiles.split(): | ||
428 | dtb_path, dtb_file = os.path.split(dtb) | ||
429 | if not dtb_path: | ||
430 | dtb_path = d.getVar("DEPLOY_DIR_IMAGE") | ||
431 | if not dtbcommand: | ||
432 | if not dtb_file.endswith('.dtb'): | ||
433 | bb.fatal(f"fdtapply failed: Expected (non-overlay) .dtb file as first element, but got {dtb_file}") | ||
434 | dtbcommand = f"fdtoverlay -i {dtb_path}/{dtb_file} -o {dtbresult}" | ||
435 | else: | ||
436 | if not dtb_file.endswith('.dtbo'): | ||
437 | bb.fatal(f"fdtapply failed: Expected .dtbo file, but got {dtb_file}") | ||
438 | dtbcommand += f" {dtb_path}/{dtb_file}" | ||
439 | result = subprocess.run(dtbcommand, stderr=subprocess.PIPE, shell=True, text=True) | ||
440 | if result.returncode != 0: | ||
441 | bb.fatal(f"Running {dtbcommand} failed: {result.stderr}") | ||
442 | dtb_path, dtb_file = os.path.split(dtbresult) | ||
443 | DTBS += f" {dtbresult}" | ||
444 | fitimage_emit_section_dtb(d, fd, dtb_file, dtb_path) | ||
445 | elif imgtype == 'ramdisk': | ||
446 | ramdiskcount = "1" | ||
447 | default_imgfstype = d.getVar('INITRAMFS_FSTYPES' or "").split()[0] | ||
448 | img_fstype = imageflags.get('fstype', default_imgfstype) | ||
449 | img_file = "%s%s.%s" % (d.getVar('FITIMAGE_IMAGE_%s' % image), d.getVar('IMAGE_MACHINE_SUFFIX'), img_fstype) | ||
450 | img_path = d.getVar("DEPLOY_DIR_IMAGE") | ||
451 | fitimage_emit_section_ramdisk(d, fd, img_file, img_path) | ||
452 | elif imgtype == 'bootscript': | ||
453 | if bootscriptid: | ||
454 | bb.fatal("Only a single boot script is supported (already set to: %s)" % bootscriptid) | ||
455 | imgsource = imageflags.get('file', None) | ||
456 | imgpath = d.getVar("DEPLOY_DIR_IMAGE") | ||
457 | bootscriptid = imgsource | ||
458 | fitimage_emit_section_bootscript(d, fd, imgpath, imgsource) | ||
459 | else: | ||
460 | bb.fatal(f"Unsupported image type: '{imgtype}'") | ||
461 | fitimage_emit_section_end(d, fd) | ||
462 | # | ||
463 | # Step 5: Prepare a configurations section | ||
464 | # | ||
465 | fitimage_emit_section_start(d, fd, 'configurations') | ||
466 | confcount = 0 | ||
467 | dtbcount = 1 | ||
468 | for dtb in (DTBS or "").split(): | ||
469 | import subprocess | ||
470 | try: | ||
471 | cmd = "fdtget -t s {} / compatible".format(dtb) | ||
472 | compatible = subprocess.check_output(cmd, shell=True, text=True).split()[0] | ||
473 | except subprocess.CalledProcessError: | ||
474 | bb.fatal("Failed to find root-node compatible string in (%s)" % dtb) | ||
475 | |||
476 | dtb_path, dtb_file = os.path.split(dtb) | ||
477 | fitimage_emit_section_config(d, fd, dtb_file, kernelcount, ramdiskcount, setupcount, bootscriptid, compatible, dtbcount) | ||
478 | dtbcount += 1 | ||
479 | confcount += 1 | ||
480 | for dtb in (DTBOS or "").split(): | ||
481 | import subprocess | ||
482 | try: | ||
483 | cmd = "fdtget -t s {} / compatible".format(dtb) | ||
484 | compatible = subprocess.check_output(cmd, shell=True, text=True).split()[0] | ||
485 | except subprocess.CalledProcessError: | ||
486 | bb.note("Failed to find root-node compatible string in (%s)" % dtb) | ||
487 | compatible = None | ||
488 | |||
489 | dtb_path, dtb_file = os.path.split(dtb) | ||
490 | fitimage_emit_section_config_fdto(d, fd, dtb_file, compatible) | ||
491 | confcount += 1 | ||
492 | |||
493 | fitimage_emit_section_end(d, fd) | ||
494 | |||
495 | if confcount == 0: | ||
496 | bb.fatal("Empty 'configurations' node generated! At least one 'fdt' or 'fdto' type is required.") | ||
497 | |||
498 | fitimage_emit_fit_footer(d, fd) | ||
499 | } | ||
500 | |||
501 | do_configure[postfuncs] += "write_manifest" | ||
502 | |||
503 | do_fitimage () { | ||
504 | if [ "${FITIMAGE_SIGN}" = "1" ]; then | ||
505 | uboot-mkimage ${FITIMAGE_MKIMAGE_EXTRA_ARGS} \ | ||
506 | -k "${FITIMAGE_SIGN_KEYDIR}" -r \ | ||
507 | -f "${B}/manifest.its" \ | ||
508 | "${B}/fitImage" | ||
509 | else | ||
510 | uboot-mkimage ${FITIMAGE_MKIMAGE_EXTRA_ARGS} \ | ||
511 | -f "${B}/manifest.its" \ | ||
512 | "${B}/fitImage" | ||
513 | fi | ||
514 | } | ||
515 | addtask fitimage after do_configure | ||
516 | |||
517 | ITS_NAME ?= "${PN}-${KERNEL_ARTIFACT_NAME}" | ||
518 | ITS_LINK_NAME ?= "${PN}-${KERNEL_ARTIFACT_LINK_NAME}" | ||
519 | FITIMAGE_IMAGE_NAME ?= "fitImage-${PN}-${KERNEL_FIT_NAME}${KERNEL_FIT_BIN_EXT}" | ||
520 | FITIMAGE_IMAGE_LINK_NAME ?= "fitImage-${PN}-${KERNEL_FIT_LINK_NAME}" | ||
521 | |||
522 | SSTATE_SKIP_CREATION:task-deploy = '1' | ||
523 | |||
524 | do_deploy() { | ||
525 | bbnote 'Copying fit-image.its source file...' | ||
526 | install -m 0644 ${B}/manifest.its ${DEPLOYDIR}/${ITS_NAME}.its | ||
527 | |||
528 | bbnote 'Copying all created fdt from type fdtapply' | ||
529 | for DTB_FILE in `find ${B} -maxdepth 1 -name *.dtb`; do | ||
530 | install -m 0644 ${DTB_FILE} ${DEPLOYDIR}/ | ||
531 | done | ||
532 | |||
533 | bbnote 'Copying fitImage file...' | ||
534 | install -m 0644 ${B}/fitImage ${DEPLOYDIR}/${FITIMAGE_IMAGE_NAME} | ||
535 | |||
536 | cd ${DEPLOYDIR} | ||
537 | ln -sf ${ITS_NAME}.its ${ITS_LINK_NAME}.its | ||
538 | ln -sf ${FITIMAGE_IMAGE_NAME} ${FITIMAGE_IMAGE_LINK_NAME} | ||
539 | } | ||
540 | addtask deploy after do_fitimage before do_build | ||