diff options
| -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 | ||
