{"id":2218919,"url":"http://patchwork.ozlabs.org/api/1.0/patches/2218919/?format=json","project":{"id":18,"url":"http://patchwork.ozlabs.org/api/1.0/projects/18/?format=json","name":"U-Boot","link_name":"uboot","list_id":"u-boot.lists.denx.de","list_email":"u-boot@lists.denx.de","web_url":null,"scm_url":null,"webscm_url":null},"msgid":"<6cc0f6ccf692d97dafc073e08195e54b712882b4.1775099118.git.daniel@makrotopia.org>","date":"2026-04-02T03:08:57","name":"[2/4] boot: fit: support generating DM verity cmdline parameters","commit_ref":null,"pull_url":null,"state":"new","archived":false,"hash":"1ae185b48f8ea6a174733739918416d33d572908","submitter":{"id":64091,"url":"http://patchwork.ozlabs.org/api/1.0/people/64091/?format=json","name":"Daniel Golle","email":"daniel@makrotopia.org"},"delegate":{"id":3651,"url":"http://patchwork.ozlabs.org/api/1.0/users/3651/?format=json","username":"trini","first_name":"Tom","last_name":"Rini","email":"trini@ti.com"},"mbox":"http://patchwork.ozlabs.org/project/uboot/patch/6cc0f6ccf692d97dafc073e08195e54b712882b4.1775099118.git.daniel@makrotopia.org/mbox/","series":[{"id":498423,"url":"http://patchwork.ozlabs.org/api/1.0/series/498423/?format=json","date":"2026-04-02T03:08:27","name":"fit: dm-verity support","version":1,"mbox":"http://patchwork.ozlabs.org/series/498423/mbox/"}],"check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/2218919/checks/","tags":{},"headers":{"Return-Path":"<u-boot-bounces@lists.denx.de>","X-Original-To":"incoming@patchwork.ozlabs.org","Delivered-To":"patchwork-incoming@legolas.ozlabs.org","Authentication-Results":["legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de\n (client-ip=85.214.62.61; helo=phobos.denx.de;\n envelope-from=u-boot-bounces@lists.denx.de; receiver=patchwork.ozlabs.org)","phobos.denx.de;\n dmarc=none (p=none dis=none) header.from=makrotopia.org","phobos.denx.de;\n spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de","phobos.denx.de; dmarc=none (p=none dis=none)\n header.from=makrotopia.org","phobos.denx.de;\n spf=pass smtp.mailfrom=daniel@makrotopia.org"],"Received":["from phobos.denx.de (phobos.denx.de [85.214.62.61])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4fmRfK53Wdz1yFv\n\tfor <incoming@patchwork.ozlabs.org>; Thu, 02 Apr 2026 14:09:29 +1100 (AEDT)","from h2850616.stratoserver.net (localhost [IPv6:::1])\n\tby phobos.denx.de (Postfix) with ESMTP id 3CB7584099;\n\tThu,  2 Apr 2026 05:09:26 +0200 (CEST)","by phobos.denx.de (Postfix, from userid 109)\n id 6DDA984099; Thu,  2 Apr 2026 05:09:24 +0200 (CEST)","from pidgin.makrotopia.org (pidgin.makrotopia.org\n [IPv6:2a07:2ec0:3002::65])\n (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits))\n (No client certificate requested)\n by phobos.denx.de (Postfix) with ESMTPS id 1990A84132\n for <u-boot@lists.denx.de>; Thu,  2 Apr 2026 05:09:16 +0200 (CEST)","from local\n by pidgin.makrotopia.org with esmtpsa (TLS1.3:TLS_AES_256_GCM_SHA384:256)\n (Exim 4.99) (envelope-from <daniel@makrotopia.org>)\n id 1w88QW-000000007h2-3vZ0; Thu, 02 Apr 2026 03:09:01 +0000"],"X-Spam-Checker-Version":"SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de","X-Spam-Level":"","X-Spam-Status":"No, score=-1.9 required=5.0 tests=BAYES_00,\n RCVD_IN_DNSWL_BLOCKED,SPF_HELO_NONE,SPF_PASS autolearn=ham\n autolearn_force=no version=3.4.2","Date":"Thu, 2 Apr 2026 04:08:57 +0100","From":"Daniel Golle <daniel@makrotopia.org>","To":"Tom Rini <trini@konsulko.com>, Quentin Schulz <quentin.schulz@cherry.de>,\n Kory Maincent <kory.maincent@bootlin.com>, Simon Glass <sjg@chromium.org>,\n Mattijs Korpershoek <mkorpershoek@kernel.org>, Peng Fan <peng.fan@nxp.com>,\n Marek Vasut <marek.vasut+renesas@mailbox.org>,\n Daniel Golle <daniel@makrotopia.org>, Martin Schwan <m.schwan@phytec.de>,\n Anshul Dalal <anshuld@ti.com>,\n Ilias Apalodimas <ilias.apalodimas@linaro.org>,\n Sughosh Ganu <sughosh.ganu@arm.com>,\n =?utf-8?b?54mbIOW/l+Wujw==?= <Zone.Niuzh@hotmail.com>,\n Benjamin ROBIN <dev@benjarobin.fr>, Aristo Chen <jj251510319013@gmail.com>,\n James Hilliard <james.hilliard1@gmail.com>,\n Frank Wunderlich <frank-w@public-files.de>,\n Mayuresh Chitale <mchitale@ventanamicro.com>,\n Neil Armstrong <neil.armstrong@linaro.org>,\n Wolfgang Wallner <wolfgang.wallner@at.abb.com>,\n Rasmus Villemoes <ravi@prevas.dk>, Francois Berder <fberder@outlook.fr>,\n Shiji Yang <yangshiji66@outlook.com>, u-boot@lists.denx.de","Subject":"[PATCH 2/4] boot: fit: support generating DM verity cmdline\n parameters","Message-ID":"\n <6cc0f6ccf692d97dafc073e08195e54b712882b4.1775099118.git.daniel@makrotopia.org>","References":"<cover.1775099118.git.daniel@makrotopia.org>","MIME-Version":"1.0","Content-Type":"text/plain; charset=us-ascii","Content-Disposition":"inline","In-Reply-To":"<cover.1775099118.git.daniel@makrotopia.org>","X-BeenThere":"u-boot@lists.denx.de","X-Mailman-Version":"2.1.39","Precedence":"list","List-Id":"U-Boot discussion <u-boot.lists.denx.de>","List-Unsubscribe":"<https://lists.denx.de/options/u-boot>,\n <mailto:u-boot-request@lists.denx.de?subject=unsubscribe>","List-Archive":"<https://lists.denx.de/pipermail/u-boot/>","List-Post":"<mailto:u-boot@lists.denx.de>","List-Help":"<mailto:u-boot-request@lists.denx.de?subject=help>","List-Subscribe":"<https://lists.denx.de/listinfo/u-boot>,\n <mailto:u-boot-request@lists.denx.de?subject=subscribe>","Errors-To":"u-boot-bounces@lists.denx.de","Sender":"\"U-Boot\" <u-boot-bounces@lists.denx.de>","X-Virus-Scanned":"clamav-milter 0.103.8 at phobos.denx.de","X-Virus-Status":"Clean"},"content":"Add fit_verity_build_cmdline(): when a FILESYSTEM loadable carries a\ndm-verity subnode, construct the dm-mod.create= kernel cmdline parameter\nfrom the verity metadata (block-size, data-blocks, algo, root-hash,\nsalt) and append it to bootargs.\n\nAlso add dm-mod.waitfor=/dev/fit0[,/dev/fitN] for each dm-verity device\nso the kernel waits for the underlying FIT block device to appear before\nsetting up device-mapper targets. This is needed when the block driver\nprobes late, e.g. because it depends on NVMEM calibration data.\n\nThe dm-verity target references /dev/fitN where N is the loadable's\nindex in the configuration -- matching the order Linux's FIT block\ndriver assigns block devices.  hash-start-block is read directly from\nthe FIT dm-verity node; mkimage ensures its value equals num-data-blocks\nby invoking veritysetup with --no-superblock.\n\nSigned-off-by: Daniel Golle <daniel@makrotopia.org>\n---\n boot/Kconfig       |  21 +++\n boot/bootm.c       |   7 +\n boot/image-board.c |   5 +\n boot/image-fit.c   | 336 +++++++++++++++++++++++++++++++++++++++++++++\n include/image.h    |  80 ++++++++++-\n 5 files changed, 448 insertions(+), 1 deletion(-)","diff":"diff --git a/boot/Kconfig b/boot/Kconfig\nindex ab31b8f40ed..5895763c378 100644\n--- a/boot/Kconfig\n+++ b/boot/Kconfig\n@@ -142,6 +142,27 @@ config FIT_CIPHER\n \t  Enable the feature of data ciphering/unciphering in the tool mkimage\n \t  and in the u-boot support of the FIT image.\n \n+config FIT_VERITY\n+\tbool \"dm-verity boot parameter generation from FIT metadata\"\n+\tdepends on FIT && OF_LIBFDT\n+\thelp\n+\t  When a FIT configuration contains loadable sub-images of type\n+\t  IH_TYPE_FILESYSTEM with a dm-verity subnode, this option enables\n+\t  building the dm-mod.create= and dm-mod.waitfor= kernel\n+\t  command-line parameters from the verity metadata\n+\t  (data-block-size, hash-block-size, num-data-blocks,\n+\t  hash-start-block, algorithm, digest, salt) stored in the FIT.\n+\n+\t  The generated parameters reference /dev/fitN block devices that\n+\t  Linux's uImage.FIT block driver assigns to loadable sub-images.\n+\n+\t  During FIT parsing (BOOTM_STATE_FINDOTHER), verity cmdline\n+\t  fragments are stored in struct bootm_headers and automatically\n+\t  appended to the bootargs environment variable during\n+\t  BOOTM_STATE_OS_PREP.  This works from both the bootm command\n+\t  and BOOTSTD bootmeths.\n+\n+\n config FIT_VERBOSE\n \tbool \"Show verbose messages when FIT images fail\"\n \thelp\ndiff --git a/boot/bootm.c b/boot/bootm.c\nindex 4bdca22ea8c..00625e1fb48 100644\n--- a/boot/bootm.c\n+++ b/boot/bootm.c\n@@ -242,6 +242,7 @@ static int boot_get_kernel(const char *addr_fit, struct bootm_headers *images,\n \n static int bootm_start(void)\n {\n+\tfit_verity_free(&images);\n \tmemset((void *)&images, 0, sizeof(images));\n \timages.verify = env_get_yesno(\"verify\");\n \n@@ -1070,6 +1071,12 @@ int bootm_run_states(struct bootm_info *bmi, int states)\n \t\t/* For Linux OS do all substitutions at console processing */\n \t\tif (images->os.os == IH_OS_LINUX)\n \t\t\tflags = BOOTM_CL_ALL;\n+\t\tret = fit_verity_apply_bootargs(images);\n+\t\tif (ret) {\n+\t\t\tprintf(\"dm-verity bootargs failed (err=%d)\\n\", ret);\n+\t\t\tret = CMD_RET_FAILURE;\n+\t\t\tgoto err;\n+\t\t}\n \t\tret = bootm_process_cmdline_env(flags);\n \t\tif (ret) {\n \t\t\tprintf(\"Cmdline setup failed (err=%d)\\n\", ret);\ndiff --git a/boot/image-board.c b/boot/image-board.c\nindex 005d60caf5c..265f29d44ff 100644\n--- a/boot/image-board.c\n+++ b/boot/image-board.c\n@@ -810,6 +810,11 @@ int boot_get_loadable(struct bootm_headers *images)\n \n \t\t\tfit_loadable_process(img_type, img_data, img_len);\n \t\t}\n+\n+\t\tfit_img_result = fit_verity_build_cmdline(buf, conf_noffset,\n+\t\t\t\t\t\t\t  images);\n+\t\tif (fit_img_result < 0)\n+\t\t\treturn fit_img_result;\n \t\tbreak;\n \tdefault:\n \t\tprintf(\"The given image format is not supported (corrupt?)\\n\");\ndiff --git a/boot/image-fit.c b/boot/image-fit.c\nindex 067ad236081..ae500747f46 100644\n--- a/boot/image-fit.c\n+++ b/boot/image-fit.c\n@@ -22,7 +22,9 @@ extern void *aligned_alloc(size_t alignment, size_t size);\n #else\n #include <linux/compiler.h>\n #include <linux/sizes.h>\n+#include <env.h>\n #include <errno.h>\n+#include <hexdump.h>\n #include <log.h>\n #include <mapmem.h>\n #include <asm/io.h>\n@@ -243,6 +245,39 @@ static void fit_image_print_data(const void *fit, int noffset, const char *p,\n \t}\n }\n \n+static __maybe_unused void fit_image_print_dm_verity(const void *fit,\n+\t\t\t\t\t\t     int noffset,\n+\t\t\t\t\t\t     const char *p)\n+{\n+#if defined(USE_HOSTCC) || CONFIG_IS_ENABLED(FIT_VERITY)\n+\tconst char *algo;\n+\tconst u8 *bin;\n+\tint len, i;\n+\n+\talgo = fdt_getprop(fit, noffset, FIT_VERITY_ALGO_PROP, NULL);\n+\tif (algo)\n+\t\tprintf(\"%s  Verity algo:  %s\\n\", p, algo);\n+\n+\tbin = fdt_getprop(fit, noffset, FIT_VERITY_DIGEST_PROP,\n+\t\t\t  &len);\n+\tif (bin && len > 0) {\n+\t\tprintf(\"%s  Verity hash:  \", p);\n+\t\tfor (i = 0; i < len; i++)\n+\t\t\tprintf(\"%02x\", bin[i]);\n+\t\tprintf(\"\\n\");\n+\t}\n+\n+\tbin = fdt_getprop(fit, noffset, FIT_VERITY_SALT_PROP,\n+\t\t\t  &len);\n+\tif (bin && len > 0) {\n+\t\tprintf(\"%s  Verity salt:  \", p);\n+\t\tfor (i = 0; i < len; i++)\n+\t\t\tprintf(\"%02x\", bin[i]);\n+\t\tprintf(\"\\n\");\n+\t}\n+#endif\n+}\n+\n /**\n  * fit_image_print_verification_data() - prints out the hash/signature details\n  * @fit: pointer to the FIT format image header\n@@ -271,6 +306,11 @@ static void fit_image_print_verification_data(const void *fit, int noffset,\n \t\t\t\tstrlen(FIT_SIG_NODENAME))) {\n \t\tfit_image_print_data(fit, noffset, p, \"Sign\");\n \t}\n+#if defined(USE_HOSTCC) || CONFIG_IS_ENABLED(FIT_VERITY)\n+\telse if (!strcmp(name, FIT_VERITY_NODENAME)) {\n+\t\tfit_image_print_dm_verity(fit, noffset, p);\n+\t}\n+#endif\n }\n \n /**\n@@ -2642,3 +2682,299 @@ out:\n \treturn fdt_noffset;\n }\n #endif\n+\n+#if !defined(USE_HOSTCC) && CONFIG_IS_ENABLED(FIT_VERITY)\n+\n+static const char *const verity_opt_props[] = {\n+\tFIT_VERITY_OPT_RESTART,\n+\tFIT_VERITY_OPT_PANIC,\n+\tFIT_VERITY_OPT_RERR,\n+\tFIT_VERITY_OPT_PERR,\n+\tFIT_VERITY_OPT_ONCE,\n+};\n+\n+/**\n+ * fit_verity_build_target() - build one dm-verity target specification\n+ * @fit:\tpointer to the FIT blob\n+ * @img_noffset:\timage node offset containing the dm-verity subnode\n+ * @loadable_idx:\tindex of this loadable (for /dev/fitN)\n+ * @uname:\tunit name of the image\n+ * @separator:\ttrue if a \";\" prefix is needed (not the first target)\n+ * @buf:\toutput buffer, or NULL to measure only\n+ * @bufsize:\tsize of @buf (ignored when @buf is NULL)\n+ *\n+ * Parses all dm-verity properties from the image's ``dm-verity`` child\n+ * node and writes (or measures) a dm target specification string of the\n+ * form used by the ``dm-mod.create`` kernel parameter.\n+ *\n+ * Return: number of characters that would be written (excluding '\\0'),\n+ *\t   or -ve errno on error (e.g. missing mandatory property)\n+ */\n+static int fit_verity_build_target(const void *fit, int img_noffset,\n+\t\t\t\t   int loadable_idx, const char *uname,\n+\t\t\t\t   bool separator, char *buf, int bufsize)\n+{\n+\tconst char *algorithm;\n+\tconst u8 *digest_raw, *salt_raw;\n+\tconst fdt32_t *val;\n+\tchar *digest_hex = NULL, *salt_hex = NULL, *opt_buf = NULL;\n+\tint verity_node;\n+\tint data_block_size, hash_block_size;\n+\tint num_data_blocks, hash_start_block;\n+\tu64 data_sectors;\n+\tint digest_len, salt_len;\n+\tint opt_count, opt_off, opt_buf_size;\n+\tint len;\n+\tint i;\n+\n+\tverity_node = fdt_subnode_offset(fit, img_noffset, FIT_VERITY_NODENAME);\n+\tif (verity_node < 0)\n+\t\treturn -ENOENT;\n+\n+\t/* Mandatory u32 properties */\n+\tval = fdt_getprop(fit, verity_node, FIT_VERITY_DBS_PROP, NULL);\n+\tif (!val)\n+\t\treturn -EINVAL;\n+\tdata_block_size = fdt32_to_cpu(*val);\n+\n+\tval = fdt_getprop(fit, verity_node, FIT_VERITY_HBS_PROP, NULL);\n+\tif (!val)\n+\t\treturn -EINVAL;\n+\thash_block_size = fdt32_to_cpu(*val);\n+\n+\tval = fdt_getprop(fit, verity_node, FIT_VERITY_NBLK_PROP, NULL);\n+\tif (!val)\n+\t\treturn -EINVAL;\n+\tnum_data_blocks = fdt32_to_cpu(*val);\n+\n+\tval = fdt_getprop(fit, verity_node, FIT_VERITY_HBLK_PROP, NULL);\n+\tif (!val)\n+\t\treturn -EINVAL;\n+\thash_start_block = fdt32_to_cpu(*val);\n+\n+\tif (!data_block_size || data_block_size < 512 ||\n+\t    !hash_block_size || hash_block_size < 512 ||\n+\t    !num_data_blocks)\n+\t\treturn -EINVAL;\n+\n+\t/* Mandatory string */\n+\talgorithm = fdt_getprop(fit, verity_node, FIT_VERITY_ALGO_PROP, NULL);\n+\tif (!algorithm)\n+\t\treturn -EINVAL;\n+\n+\t/* Mandatory byte arrays */\n+\tdigest_raw = fdt_getprop(fit, verity_node, FIT_VERITY_DIGEST_PROP,\n+\t\t\t\t &digest_len);\n+\tif (!digest_raw || digest_len <= 0)\n+\t\treturn -EINVAL;\n+\n+\tsalt_raw = fdt_getprop(fit, verity_node, FIT_VERITY_SALT_PROP,\n+\t\t\t       &salt_len);\n+\tif (!salt_raw || salt_len <= 0)\n+\t\treturn -EINVAL;\n+\n+\t/* Hex-encode digest and salt into dynamically sized buffers */\n+\tdigest_hex = malloc(digest_len * 2 + 1);\n+\tsalt_hex = malloc(salt_len * 2 + 1);\n+\tif (!digest_hex || !salt_hex) {\n+\t\tlen = -ENOMEM;\n+\t\tgoto out;\n+\t}\n+\t*bin2hex(digest_hex, digest_raw, digest_len) = '\\0';\n+\t*bin2hex(salt_hex, salt_raw, salt_len) = '\\0';\n+\n+\tdata_sectors = (u64)num_data_blocks * ((u64)data_block_size / 512);\n+\n+\t/* Compute space needed for optional boolean properties */\n+\topt_buf_size = 1; /* NUL terminator */\n+\tfor (i = 0; i < ARRAY_SIZE(verity_opt_props); i++)\n+\t\topt_buf_size += strlen(verity_opt_props[i]) + 1;\n+\topt_buf = malloc(opt_buf_size);\n+\tif (!opt_buf) {\n+\t\tlen = -ENOMEM;\n+\t\tgoto out;\n+\t}\n+\n+\t/* Collect optional boolean properties */\n+\topt_count = 0;\n+\topt_off = 0;\n+\topt_buf[0] = '\\0';\n+\tfor (i = 0; i < ARRAY_SIZE(verity_opt_props); i++) {\n+\t\tif (fdt_getprop(fit, verity_node,\n+\t\t\t\tverity_opt_props[i], NULL)) {\n+\t\t\tconst char *s = verity_opt_props[i];\n+\t\t\tint slen = strlen(s);\n+\n+\t\t\tif (opt_off)\n+\t\t\t\topt_buf[opt_off++] = ' ';\n+\t\t\t/* Copy with hyphen-to-underscore conversion */\n+\t\t\twhile (slen-- > 0) {\n+\t\t\t\topt_buf[opt_off++] =\n+\t\t\t\t\t(*s == '-') ? '_' : *s;\n+\t\t\t\ts++;\n+\t\t\t}\n+\t\t\topt_buf[opt_off] = '\\0';\n+\t\t\topt_count++;\n+\t\t}\n+\t}\n+\n+\t/* Emit (or measure) the target spec */\n+\tlen = snprintf(buf, buf ? bufsize : 0,\n+\t\t       \"%s%s,,, ro,0 %llu verity 1 /dev/fit%d /dev/fit%d %d %d %d %d %s %s %s\",\n+\t\t       separator ? \";\" : \"\", uname,\n+\t\t       (unsigned long long)data_sectors, loadable_idx, loadable_idx,\n+\t\t       data_block_size, hash_block_size,\n+\t\t       num_data_blocks, hash_start_block,\n+\t\t       algorithm, digest_hex, salt_hex);\n+\tif (opt_count) {\n+\t\tint extra = snprintf(buf ? buf + len : NULL,\n+\t\t\t\t     buf ? bufsize - len : 0,\n+\t\t\t\t     \" %d %s\", opt_count, opt_buf);\n+\t\tlen += extra;\n+\t}\n+\n+out:\n+\tfree(digest_hex);\n+\tfree(salt_hex);\n+\tfree(opt_buf);\n+\treturn len;\n+}\n+\n+int fit_verity_build_cmdline(const void *fit, int conf_noffset,\n+\t\t\t     struct bootm_headers *images)\n+{\n+\tint images_noffset;\n+\tint dm_create_len = 0, dm_waitfor_len = 0;\n+\tchar *dm_create = NULL, *dm_waitfor = NULL;\n+\tconst char *uname;\n+\tint loadable_idx;\n+\tint found = 0;\n+\tint ret = 0;\n+\n+\timages_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH);\n+\tif (images_noffset < 0)\n+\t\treturn 0;\n+\n+\tfor (loadable_idx = 0;\n+\t     (uname = fdt_stringlist_get(fit, conf_noffset,\n+\t\t\t\t\t FIT_LOADABLE_PROP,\n+\t\t\t\t\t loadable_idx, NULL));\n+\t     loadable_idx++) {\n+\t\tint img_noffset, need;\n+\t\tu8 img_type;\n+\t\tchar *tmp;\n+\n+\t\timg_noffset = fdt_subnode_offset(fit, images_noffset, uname);\n+\t\tif (img_noffset < 0)\n+\t\t\tcontinue;\n+\n+\t\tif (fit_image_get_type(fit, img_noffset, &img_type) ||\n+\t\t    img_type != IH_TYPE_FILESYSTEM)\n+\t\t\tcontinue;\n+\n+\t\t/* Measure first, then allocate and write */\n+\t\tneed = fit_verity_build_target(fit, img_noffset,\n+\t\t\t\t\t       loadable_idx, uname,\n+\t\t\t\t\t       found > 0, NULL, 0);\n+\t\tif (need == -ENOENT)\n+\t\t\tcontinue;\t/* no dm-verity subnode -- fine */\n+\t\tif (need < 0) {\n+\t\t\tprintf(\"FIT: broken dm-verity metadata in '%s'\\n\",\n+\t\t\t       uname);\n+\t\t\tret = need;\n+\t\t\tgoto err;\n+\t\t}\n+\n+\t\ttmp = realloc(dm_create, dm_create_len + need + 1);\n+\t\tif (!tmp) {\n+\t\t\tret = -ENOMEM;\n+\t\t\tgoto err;\n+\t\t}\n+\t\tdm_create = tmp;\n+\t\tfit_verity_build_target(fit, img_noffset, loadable_idx,\n+\t\t\t\t\tuname, found > 0,\n+\t\t\t\t\tdm_create + dm_create_len,\n+\t\t\t\t\tneed + 1);\n+\t\tdm_create_len += need;\n+\n+\t\t/* Grow dm_waitfor buffer */\n+\t\tneed = snprintf(NULL, 0, \"%s/dev/fit%d\",\n+\t\t\t\tdm_waitfor_len ? \",\" : \"\",\n+\t\t\t\tloadable_idx);\n+\t\ttmp = realloc(dm_waitfor, dm_waitfor_len + need + 1);\n+\t\tif (!tmp) {\n+\t\t\tret = -ENOMEM;\n+\t\t\tgoto err;\n+\t\t}\n+\t\tdm_waitfor = tmp;\n+\t\tsprintf(dm_waitfor + dm_waitfor_len, \"%s/dev/fit%d\",\n+\t\t\tdm_waitfor_len ? \",\" : \"\",\n+\t\t\tloadable_idx);\n+\t\tdm_waitfor_len += need;\n+\n+\t\tfound++;\n+\t}\n+\n+\tif (found) {\n+\t\t/* Transfer ownership to the bootm_headers */\n+\t\timages->dm_mod_create = dm_create;\n+\t\timages->dm_mod_waitfor = dm_waitfor;\n+\t} else {\n+\t\tfree(dm_create);\n+\t\tfree(dm_waitfor);\n+\t}\n+\n+\treturn found;\n+\n+err:\n+\tfree(dm_create);\n+\tfree(dm_waitfor);\n+\treturn ret;\n+}\n+\n+/**\n+ * fmt used by both the measurement and the actual write of bootargs.\n+ * Shared to guarantee they stay in sync.\n+ */\n+#define VERITY_BOOTARGS_FMT\t\"%s%sdm-mod.create=\\\"%s\\\" dm-mod.waitfor=\\\"%s\\\"\"\n+\n+int fit_verity_apply_bootargs(const struct bootm_headers *images)\n+{\n+\tconst char *existing;\n+\tchar *newargs;\n+\tint len;\n+\n+\tif (!images->dm_mod_create)\n+\t\treturn 0;\n+\n+\texisting = env_get(\"bootargs\");\n+\tif (!existing)\n+\t\texisting = \"\";\n+\n+\t/* Measure */\n+\tlen = snprintf(NULL, 0, VERITY_BOOTARGS_FMT,\n+\t\t       existing, existing[0] ? \" \" : \"\",\n+\t\t       images->dm_mod_create, images->dm_mod_waitfor);\n+\n+\tnewargs = malloc(len + 1);\n+\tif (!newargs)\n+\t\treturn -ENOMEM;\n+\n+\tsnprintf(newargs, len + 1, VERITY_BOOTARGS_FMT,\n+\t\t existing, existing[0] ? \" \" : \"\",\n+\t\t images->dm_mod_create, images->dm_mod_waitfor);\n+\n+\tenv_set(\"bootargs\", newargs);\n+\tfree(newargs);\n+\n+\treturn 0;\n+}\n+\n+void fit_verity_free(struct bootm_headers *images)\n+{\n+\tfree(images->dm_mod_create);\n+\tfree(images->dm_mod_waitfor);\n+\timages->dm_mod_create = NULL;\n+\timages->dm_mod_waitfor = NULL;\n+}\n+#endif /* FIT_VERITY */\ndiff --git a/include/image.h b/include/image.h\nindex 482446a8115..0bd0bd4fc5c 100644\n--- a/include/image.h\n+++ b/include/image.h\n@@ -396,7 +396,19 @@ struct bootm_headers {\n \tulong\t\tcmdline_start;\n \tulong\t\tcmdline_end;\n \tstruct bd_info\t\t*kbd;\n-#endif\n+\n+#if CONFIG_IS_ENABLED(FIT_VERITY)\n+\t/*\n+\t * dm-verity kernel command-line fragments, populated during FIT\n+\t * parsing by fit_verity_build_cmdline().  Bootmeths can check\n+\t * fit_verity_active() between bootm states, and\n+\t * fit_verity_apply_bootargs() appends these to the \"bootargs\"\n+\t * env var during BOOTM_STATE_OS_PREP.\n+\t */\n+\tchar *dm_mod_create;\n+\tchar *dm_mod_waitfor;\n+#endif /* FIT_VERITY */\n+#endif /* !USE_HOSTCC */\n \n \tint\t\tverify;\t\t/* env_get(\"verify\")[0] != 'n' */\n \n@@ -756,6 +768,72 @@ int fit_image_load(struct bootm_headers *images, ulong addr,\n \t\t   int arch, int image_ph_type, int bootstage_id,\n \t\t   enum fit_load_op load_op, ulong *datap, ulong *lenp);\n \n+#if !defined(USE_HOSTCC) && CONFIG_IS_ENABLED(FIT_VERITY)\n+/**\n+ * fit_verity_build_cmdline() - build dm-verity cmdline from FIT metadata\n+ * @fit:\t\tpointer to the FIT blob\n+ * @conf_noffset:\tconfiguration node offset in @fit\n+ * @images:\t\tbootm headers; dm_mod_create / dm_mod_waitfor are\n+ *\t\t\tpopulated on success\n+ *\n+ * Called automatically from boot_get_loadable() during FIT parsing.\n+ * For each IH_TYPE_FILESYSTEM loadable with a dm-verity subnode,\n+ * builds the corresponding dm target specification.\n+ *\n+ * Return: number of verity targets found (>=0), or -ve errno\n+ */\n+int fit_verity_build_cmdline(const void *fit, int conf_noffset,\n+\t\t\t     struct bootm_headers *images);\n+\n+/**\n+ * fit_verity_apply_bootargs() - append dm-verity params to bootargs env\n+ * @images:\tbootm headers with dm-verity cmdline fragments\n+ *\n+ * Called from BOOTM_STATE_OS_PREP before bootm_process_cmdline_env().\n+ *\n+ * Return: 0 on success, -ve errno on error\n+ */\n+int fit_verity_apply_bootargs(const struct bootm_headers *images);\n+\n+/**\n+ * fit_verity_active() - check whether dm-verity targets were found\n+ * @images:\tbootm headers\n+ *\n+ * Return: true if at least one dm-verity target was built\n+ */\n+static inline bool fit_verity_active(const struct bootm_headers *images)\n+{\n+\treturn !!images->dm_mod_create;\n+}\n+\n+/**\n+ * fit_verity_free() - free dm-verity cmdline allocations\n+ * @images:\tbootm headers\n+ */\n+void fit_verity_free(struct bootm_headers *images);\n+\n+#else /* !FIT_VERITY */\n+\n+static inline int fit_verity_build_cmdline(const void *fit, int conf_noffset,\n+\t\t\t\t\t   struct bootm_headers *images)\n+{\n+\treturn 0;\n+}\n+\n+static inline int fit_verity_apply_bootargs(const struct bootm_headers *images)\n+{\n+\treturn 0;\n+}\n+\n+static inline bool fit_verity_active(const struct bootm_headers *images)\n+{\n+\treturn false;\n+}\n+\n+static inline void fit_verity_free(struct bootm_headers *images) {}\n+\n+#endif /* FIT_VERITY */\n+\n /**\n  * image_locate_script() - Locate the raw script in an image\n  *\n","prefixes":["2/4"]}