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
64LICENSE ?= "MIT"
65
66inherit deploy kernel-artifact-names image-artifact-names kernel-arch nopackages
67
68do_patch[noexec] = "1"
69do_compile[noexec] = "1"
70do_install[noexec] = "1"
71deltask do_populate_sysroot
72
73INHIBIT_DEFAULT_DEPS = "1"
74
75DEPENDS = "u-boot-mkimage-native dtc-native"
76
77FITIMAGE_SIGN ?= "0"
78FITIMAGE_SIGN[doc] = "Enable FIT image signing"
79FITIMAGE_SIGN_KEYDIR ?= ""
80FITIMAGE_SIGN_KEYDIR[doc] = "Key directory or pkcs#11 URI to use for signing configuration"
81FITIMAGE_MKIMAGE_EXTRA_ARGS[doc] = "Extra arguemnts to pass to uboot-mkimage call"
82FITIMAGE_HASH_ALGO ?= "sha256"
83FITIMAGE_HASH_ALGO[doc] = "Hash algorithm to use"
84FITIMAGE_ENCRYPT_ALGO ?= "rsa2048"
85FITIMAGE_ENCRYPT_ALGO[doc] = "Signature algorithm to use"
86FITIMAGE_CONFIG_PREFIX ?= "conf-"
87FITIMAGE_CONFIG_PREFIX[doc] = "Prefix to use for FIT configuration node name"
88
89FITIMAGE_LOADADDRESS ??= ""
90FITIMAGE_ENTRYPOINT  ??= ""
91FITIMAGE_DTB_LOADADDRESS ??= ""
92FITIMAGE_DTB_OVERLAY_LOADADDRESS ??= ""
93FITIMAGE_RD_LOADADDRESS ??= ""
94FITIMAGE_RD_ENTRYPOINT ??= ""
95
96PACKAGE_ARCH = "${MACHINE_ARCH}"
97
98# Create dependency list from images
99python __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
130S = "${WORKDIR}/sources"
131UNPACKDIR = "${S}"
132B = "${WORKDIR}/build"
133
134#
135# Emit the fitImage ITS header
136#
137def 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#
145def fitimage_emit_fit_footer(d, fd):
146    fd.write('};\n')
147
148#
149# Emit the fitImage section
150#
151def fitimage_emit_section_start(d, fd, section):
152    fd.write(f'\t{section} {{\n')
153
154#
155# Emit the fitImage section end
156#
157def fitimage_emit_section_end(d, fd):
158    fd.write('\t};\n')
159
160def 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#
188def _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
208def 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#
216def 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#
225def 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
250def 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
268def 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#
288def 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 f'{conf_prefix}{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#
338def 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
354python 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
491do_configure[postfuncs] += "write_manifest"
492
493do_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}
505addtask fitimage after do_configure
506
507ITS_NAME ?= "${PN}-${KERNEL_ARTIFACT_NAME}"
508ITS_LINK_NAME ?= "${PN}-${KERNEL_ARTIFACT_LINK_NAME}"
509FITIMAGE_IMAGE_NAME ?= "fitImage-${PN}-${KERNEL_FIT_NAME}${KERNEL_FIT_BIN_EXT}"
510FITIMAGE_IMAGE_LINK_NAME ?= "fitImage-${PN}-${KERNEL_FIT_LINK_NAME}"
511
512SSTATE_SKIP_CREATION:task-deploy = '1'
513
514do_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}
530addtask deploy after do_fitimage before do_build
531