Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/1.2/patches/2224435/?format=api
{ "id": 2224435, "url": "http://patchwork.ozlabs.org/api/1.2/patches/2224435/?format=api", "web_url": "http://patchwork.ozlabs.org/project/uboot/patch/20260417120951.3454249-6-aswin.murugan@oss.qualcomm.com/", "project": { "id": 18, "url": "http://patchwork.ozlabs.org/api/1.2/projects/18/?format=api", "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, "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<20260417120951.3454249-6-aswin.murugan@oss.qualcomm.com>", "list_archive_url": null, "date": "2026-04-17T12:09:49", "name": "[v3,5/7] mkimage: add fatfs image type for FAT partition images", "commit_ref": null, "pull_url": null, "state": "changes-requested", "archived": false, "hash": "2a634751c7389c2f8891c4c33a0a4f4b95ffb520", "submitter": { "id": 90811, "url": "http://patchwork.ozlabs.org/api/1.2/people/90811/?format=api", "name": "Aswin Murugan", "email": "aswin.murugan@oss.qualcomm.com" }, "delegate": { "id": 3651, "url": "http://patchwork.ozlabs.org/api/1.2/users/3651/?format=api", "username": "trini", "first_name": "Tom", "last_name": "Rini", "email": "trini@ti.com" }, "mbox": "http://patchwork.ozlabs.org/project/uboot/patch/20260417120951.3454249-6-aswin.murugan@oss.qualcomm.com/mbox/", "series": [ { "id": 500319, "url": "http://patchwork.ozlabs.org/api/1.2/series/500319/?format=api", "web_url": "http://patchwork.ozlabs.org/project/uboot/list/?series=500319", "date": "2026-04-17T12:09:44", "name": "Add FIT multi-DTB selection for Qualcomm platforms", "version": 3, "mbox": "http://patchwork.ozlabs.org/series/500319/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/2224435/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/2224435/checks/", "tags": {}, "related": [], "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\tdkim=pass (2048-bit key;\n unprotected) header.d=qualcomm.com header.i=@qualcomm.com header.a=rsa-sha256\n header.s=qcppdkim1 header.b=o6GuMWhc;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com\n header.a=rsa-sha256 header.s=google header.b=CLgUpnw2;\n\tdkim-atps=neutral", "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de\n (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; 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=oss.qualcomm.com", "phobos.denx.de;\n spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de", "phobos.denx.de;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=qualcomm.com header.i=@qualcomm.com\n header.b=\"o6GuMWhc\";\n\tdkim=pass (2048-bit key;\n unprotected) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com\n header.b=\"CLgUpnw2\";\n\tdkim-atps=neutral", "phobos.denx.de; dmarc=none (p=none dis=none)\n header.from=oss.qualcomm.com", "phobos.denx.de;\n spf=pass smtp.mailfrom=aswin.murugan@oss.qualcomm.com" ], "Received": [ "from phobos.denx.de (phobos.denx.de\n [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4fxtz96mZDz1yD3\n\tfor <incoming@patchwork.ozlabs.org>; Fri, 17 Apr 2026 22:11:49 +1000 (AEST)", "from h2850616.stratoserver.net (localhost [IPv6:::1])\n\tby phobos.denx.de (Postfix) with ESMTP id 70B4A8428C;\n\tFri, 17 Apr 2026 14:11:28 +0200 (CEST)", "by phobos.denx.de (Postfix, from userid 109)\n id EBAEC8428C; Fri, 17 Apr 2026 14:11:26 +0200 (CEST)", "from mx0b-0031df01.pphosted.com (mx0b-0031df01.pphosted.com\n [205.220.180.131])\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 5E92D842A4\n for <u-boot@lists.denx.de>; Fri, 17 Apr 2026 14:11:24 +0200 (CEST)", "from pps.filterd (m0279868.ppops.net [127.0.0.1])\n by mx0a-0031df01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id\n 63H80L8t1872640\n for <u-boot@lists.denx.de>; Fri, 17 Apr 2026 12:11:23 GMT", "from mail-pf1-f199.google.com (mail-pf1-f199.google.com\n [209.85.210.199])\n by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 4dk2knby0s-1\n (version=TLSv1.3 cipher=TLS_AES_128_GCM_SHA256 bits=128 verify=NOT)\n for <u-boot@lists.denx.de>; Fri, 17 Apr 2026 12:11:22 +0000 (GMT)", "by mail-pf1-f199.google.com with SMTP id\n d2e1a72fcca58-82f0f2b2641so440942b3a.3\n for <u-boot@lists.denx.de>; Fri, 17 Apr 2026 05:11:22 -0700 (PDT)", "from hu-aswinm-blr.qualcomm.com\n (blr-bdr-fw-01_GlobalNAT_AllZones-Outside.qualcomm.com. [103.229.18.19])\n by smtp.gmail.com with ESMTPSA id\n d2e1a72fcca58-82f8e9cbb28sm1744641b3a.13.2026.04.17.05.11.12\n (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n Fri, 17 Apr 2026 05:11:20 -0700 (PDT)" ], "X-Spam-Checker-Version": "SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de", "X-Spam-Level": "", "X-Spam-Status": "No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED,\n DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_BLOCKED,\n RCVD_IN_VALIDITY_CERTIFIED_BLOCKED,RCVD_IN_VALIDITY_RPBL_BLOCKED,\n SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.2", "DKIM-Signature": [ "v=1; a=rsa-sha256; c=relaxed/relaxed; d=qualcomm.com; h=\n content-transfer-encoding:date:from:in-reply-to:message-id\n :mime-version:references:subject:to; s=qcppdkim1; bh=p2ECGlyWwxS\n gIvsL0wEOoDmQMzp6g2LREOsPUY/1mM4=; b=o6GuMWhcLnWqbd1uagfri421Mb5\n hbGi7BMHrqGXHUNXcf00wLy4JqTLq8PrLcpBW7JRON4jVJaCjR+kdQG3qNth8OQt\n oI+Z1M2PNSZWTzqAnlmAnQPvAWzr6c6wNm74gvz+t8mbNqlEEKxoFrnBKkebSr9A\n M5+r6yh3IU9SjUtBPebxPvWPvwkdDPwqAQ/jYdGr1VNDn27FDdXUOvyjk7Ef9P1T\n sP7CuFmQfdJ4fJTACKco2xd/+SEIQV3Usj7Cc9Si6rPJDpfv6ugx/GdJFc/KltC2\n dkWVdtblLjxMG6/kxZwB9RWSfTR5OPsx0lUTcX8CPNP4jpvhBDR1IoBVFkA==", "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=oss.qualcomm.com; s=google; t=1776427882; x=1777032682; darn=lists.denx.de;\n h=content-transfer-encoding:mime-version:references:in-reply-to\n :message-id:date:subject:to:from:from:to:cc:subject:date:message-id\n :reply-to; bh=p2ECGlyWwxSgIvsL0wEOoDmQMzp6g2LREOsPUY/1mM4=;\n b=CLgUpnw2GdsPYhS/XDAltCL8cQ2xXohcHLms84KrrVdyj3QgQwLezmdIc5MVnH/ltR\n X/qbQuNwnnaCeIEtCHI3v8M4/pyvbszs96KF/JDcbLnjVWJwU3jfzPsOScblTiin8m05\n 0zhj+2FrBgwfIxnVjjGW31CLChxrYHu8aOJUTkjMmbYP2XUCoseFc/WTrjuo5tVLc+v8\n lOLAfAC/ok6oLz3gk0Cln3JJwfxrxdlDVCKqxBujvpqVNqCDCl7mc5LCQd2odUsD2bOG\n v+JSyHAYMfZFcKKbl4/68ohOXab70ZB0jU0LlwhD8Z7rAokrswkV8B4uyzP7PWYR9ZQH\n RewA==" ], "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20251104; t=1776427882; x=1777032682;\n h=content-transfer-encoding:mime-version:references:in-reply-to\n :message-id:date:subject:to:from:x-gm-gg:x-gm-message-state:from:to\n :cc:subject:date:message-id:reply-to;\n bh=p2ECGlyWwxSgIvsL0wEOoDmQMzp6g2LREOsPUY/1mM4=;\n b=Tdv/Qqguo/NdFyz5SBf+SX3HQZjD1L6d5pTrE9hxl31YFlaA/c+Nfbh4xoKRzBUNav\n 1CTdpKZJAiCBaJ0NIvpRmfYHDHUsuDszdjactlqr+UTyvYSU/BPCO9liGh4syljlgUTC\n zgruPIpAGT3q9G4Jthoa4QlcK4OmPNKwPkk2K+l09bEYGZXk7JiLlCIupkjGMuHI2Ene\n jN6ebVJiBf7pEYM0c1WbDYSEPMASCrwB10ZmeGiEw3apvSxrV5g06yylfLzlJyHHd2WJ\n QCEZk2DgQd6E7TMcgqZXUGziCUGr4FVOKjJsYpiO/VN8YiFouKyeiAadz42HFoUxmkHZ\n qKhQ==", "X-Forwarded-Encrypted": "i=1;\n AFNElJ+ogBx9Sy3j5fIN0C3zOvR1JWx8NBSF/1ZbnzekmYvqrUdl/bJb2AZG0L+GfStRzms1Tywdgms=@lists.denx.de", "X-Gm-Message-State": "AOJu0YxpTkmxU0+44G8nGu6xEZROOz6APUEEDnjges/SufbhMuqCsIJV\n WKWYLpees06iLrgkUfibzTDgGrLFTl8uR5zpZBK8I/ppB61HDxP2xgiouwNVhQwULFsb5rDzWa8\n gyVV+REXpzBOg9JMKdGvZTVTIOY+mHj8VvghZpeQ4VIHAI5vf6nBnvu4R", "X-Gm-Gg": "AeBDieuufa8O2r0Xivo/tM0MfZiWqfFn6OOWH+/+eUvvAKHXjMphgg1BTcIZSFrqJeu\n o7sa9u4DuVGBvj1IW6XBoB1vlnLN6y7+cd6Li+/jYiRJMrBmKrE79rL0n7xhdMqctOKl2Aa2xqp\n i7ICYNA7xCKLmdez2pQjiNy9c3AuWs1V+30/S8H3NWFQef1rlB+fODO/mXdU8IYpwPvbsPqx5ib\n tXl5I8st8mcpB79qa6hI0myUAgEjXnysJnyK5vJF7oKAN2n1Dem3IrimImLAPZGTXSHl3FKhdzc\n AkQ3PEJHIwNPLHxvwoNv4y3RicjiRkCVxG4JNKQNF8lJ/bvKomwl/lmKQTi84wP2QmTaqnBiP/v\n ClWBT8SCfTbaBM073nPzF9CIN60Drun4pqHMsXvRRrKKz8FO1hkJMk3eO4DNQ5u8L4S3Veit3Nk\n KXNzGiKCM/l53uO8U9WORwsaGdasDGy577AuoVMFfpjto57q0hUIE=", "X-Received": [ "by 2002:a05:6a00:90a8:b0:82c:7eb1:4d61 with SMTP id\n d2e1a72fcca58-82f8c8bb03amr2376597b3a.32.1776427881366;\n Fri, 17 Apr 2026 05:11:21 -0700 (PDT)", "by 2002:a05:6a00:90a8:b0:82c:7eb1:4d61 with SMTP id\n d2e1a72fcca58-82f8c8bb03amr2376549b3a.32.1776427880757;\n Fri, 17 Apr 2026 05:11:20 -0700 (PDT)" ], "From": "Aswin Murugan <aswin.murugan@oss.qualcomm.com>", "To": "trini@konsulko.com, casey.connolly@linaro.org, neil.armstrong@linaro.org,\n sumit.garg@kernel.org, aswin.murugan@oss.qualcomm.com,\n sughosh.ganu@arm.com, ilias.apalodimas@linaro.org, gchan9527@gmail.com,\n mchitale@ventanamicro.com, maximmosk4@gmail.com, jonas@kwiboo.se,\n marek.vasut@mailbox.org, quentin.schulz@cherry.de, peng.fan@nxp.com,\n sajattack@postmarketos.org, balaji.selvanathan@oss.qualcomm.com,\n wolfgang.wallner@at.abb.com, e@freeshell.de, yangshiji66@outlook.com,\n jan.kiszka@siemens.com, funderscore@postmarketos.org, hs@nabladev.com,\n kory.maincent@bootlin.com, jj251510319013@gmail.com,\n carlos.lopezr4096@gmail.com, u-boot-qcom@groups.io, u-boot@lists.denx.de", "Subject": "[PATCH v3 5/7] mkimage: add fatfs image type for FAT partition images", "Date": "Fri, 17 Apr 2026 17:39:49 +0530", "Message-Id": "<20260417120951.3454249-6-aswin.murugan@oss.qualcomm.com>", "X-Mailer": "git-send-email 2.34.1", "In-Reply-To": "<20260417120951.3454249-1-aswin.murugan@oss.qualcomm.com>", "References": "<20260417120951.3454249-1-aswin.murugan@oss.qualcomm.com>", "MIME-Version": "1.0", "Content-Transfer-Encoding": "8bit", "X-Proofpoint-GUID": "9guJCkTujK2BCnxjF4SsvTOKHv-X1EWC", "X-Authority-Analysis": "v=2.4 cv=XNoAjwhE c=1 sm=1 tr=0 ts=69e2236a cx=c_pps\n a=WW5sKcV1LcKqjgzy2JUPuA==:117 a=Ou0eQOY4+eZoSc0qltEV5Q==:17\n a=A5OVakUREuEA:10 a=s4-Qcg_JpJYA:10 a=VkNPw1HP01LnGYTKEx00:22\n a=u7WPNUs3qKkmUXheDGA7:22 a=ZpdpYltYx_vBUK5n70dp:22 a=EUspDBNiAAAA:8\n a=KD3lojeL17VxHfHb3aMA:9 a=OpyuDcXvxspvyRM73sMx:22", "X-Proofpoint-ORIG-GUID": "9guJCkTujK2BCnxjF4SsvTOKHv-X1EWC", "X-Proofpoint-Spam-Details-Enc": "AW1haW4tMjYwNDE3MDEyMiBTYWx0ZWRfX+PEoFuyWtjzt\n xlDdteVi7Xa2KPOlGMDgf5WSuD5g3aYHyIEsCGnzLTr7ZppzT7Tp/GdTtl4pLD0SDiibyfDzhaw\n 5UKbpgJgXa6v20mrGvUnM2sy3d+VbELCBLaYK0V5OsGLHYIqOzUqDvpvXx5vBVXKv/E4iEtnvIy\n ZaDHqgEr4zGVcZ08rA51RNWQwUS+gTqK4s/F3Qaz1GpvU563Sc6BDY+d+CVazsJof4jZD3aefmL\n bYU8K3zM2j5UXJck8cBE1ZMsf9t5FJqNQrDURD7gEyzEXecAstqLXjUV825xuJl0Np9YTkH532f\n Lc6D4kW3dwJKYoIX+xiv/BZy4MviODOUX8LwLhEW4xqIuF06ntIOKqjV7oaAP2MZZvnkYtLdqis\n mQVMCWuFLUjeBhhbyCXRM0Z911Ge93GaZlheNt9YlqbY/pL8uUfCiqRWprg8mgdwwZCgtXmxfNe\n ICjx6W69rv1r42ySfyw==", "X-Proofpoint-Virus-Version": "vendor=baseguard\n engine=ICAP:2.0.293,Aquarius:18.0.1143,Hydra:6.1.51,FMLib:17.12.100.49\n definitions=2026-04-17_01,2026-04-17_01,2025-10-01_01", "X-Proofpoint-Spam-Details": "rule=outbound_notspam policy=outbound score=0\n malwarescore=0 impostorscore=0 priorityscore=1501 suspectscore=0 spamscore=0\n phishscore=0 clxscore=1015 lowpriorityscore=0 adultscore=0 bulkscore=0\n classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0\n reason=mlx scancount=1 engine=8.22.0-2604070000 definitions=main-2604170122", "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 a new mkimage image type 'fatfs' that creates a raw FAT\nfilesystem partition image from a directory of files.\n\nThe image handler (fatimage.c) uses mkfs.vfat (dosfstools)\nto format the image and mcopy (mtools) to populate it. The\nimage size is calculated automatically from the input\ndirectory size plus FAT metadata overhead.\n\nNew long options added to mkimage:\n --fat-extra-space <KB> extra padding (default: 512 KB)\n --fat-type <0|12|16|32> FAT type (0 = auto-detect)\n --fat-volume-id <label> volume label (default: BOOT)\n --fat-mkfs-opts <opts> extra mkfs.vfat options\n\nUsage:\n mkimage -T fatfs -d <input-dir> \\\n --fat-extra-space 512 \\\n --fat-volume-id \"MYBOOT\" \\\n --fat-mkfs-opts \"-S 512 -a\" \\\n output.img\n\nSigned-off-by: Aswin Murugan <aswin.murugan@oss.qualcomm.com>\n---\n tools/Makefile | 1 +\n tools/fatimage.c | 495 +++++++++++++++++++++++++++++++++++++++++++++++\n tools/fatimage.h | 25 +++\n tools/mkimage.c | 21 ++\n tools/mkimage.h | 15 ++\n 5 files changed, 557 insertions(+)\n create mode 100644 tools/fatimage.c\n create mode 100644 tools/fatimage.h", "diff": "diff --git a/tools/Makefile b/tools/Makefile\nindex 1a5f425ecda..2f6c9363209 100644\n--- a/tools/Makefile\n+++ b/tools/Makefile\n@@ -112,6 +112,7 @@ ROCKCHIP_OBS = generated/lib/rc4.o rkcommon.o rkimage.o rksd.o rkspi.o\n dumpimage-mkimage-objs := aisimage.o \\\n \t\t\tamlimage.o \\\n \t\t\tatmelimage.o \\\n+\t\t\tfatimage.o \\\n \t\t\t$(FIT_OBJS-y) \\\n \t\t\t$(FIT_SIG_OBJS-y) \\\n \t\t\t$(FIT_CIPHER_OBJS-y) \\\ndiff --git a/tools/fatimage.c b/tools/fatimage.c\nnew file mode 100644\nindex 00000000000..6a199c70f5b\n--- /dev/null\n+++ b/tools/fatimage.c\n@@ -0,0 +1,495 @@\n+// SPDX-License-Identifier: GPL-2.0\n+/*\n+ * FAT Filesystem Image support for mkimage\n+ *\n+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries\n+ *\n+ * This tool creates FAT filesystem images from a directory of files.\n+ * It uses system tools (mkfs.vfat and mcopy from mtools) to create\n+ * the filesystem image.\n+ */\n+\n+#include \"imagetool.h\"\n+#include \"mkimage.h\"\n+#include \"fatimage.h\"\n+#include <image.h>\n+#include <sys/stat.h>\n+#include <dirent.h>\n+#include <errno.h>\n+\n+static struct fatimage_params fatparams = {\n+\t.input_dir = NULL,\n+\t.extra_space = 512,\n+\t.fat_type = 0,\n+\t.volume_id = \"BOOT\",\n+\t.mkfs_opts = \"-S 512\",\n+};\n+\n+/* Cached image size to avoid recalculation between vrec_header and set_header */\n+static int cached_image_size_kb = -1;\n+\n+/**\n+ * get_directory_size_kb() - Return the total disk usage of a directory in KB\n+ * @path: Path to the directory\n+ *\n+ * Runs 'du -sk' to measure the on-disk size of all files under @path.\n+ *\n+ * Return: size in KB on success, -1 on error\n+ */\n+static int get_directory_size_kb(const char *path)\n+{\n+\tchar cmd[1024];\n+\tFILE *fp;\n+\tint size_kb = 0;\n+\n+\tsnprintf(cmd, sizeof(cmd), \"du -sk \\\"%s\\\" 2>/dev/null | cut -f1\", path);\n+\n+\tfp = popen(cmd, \"r\");\n+\tif (!fp) {\n+\t\tfprintf(stderr, \"Error: Failed to execute du command\\n\");\n+\t\treturn -1;\n+\t}\n+\n+\tif (fscanf(fp, \"%d\", &size_kb) != 1) {\n+\t\tfprintf(stderr, \"Error: Failed to read directory size\\n\");\n+\t\tpclose(fp);\n+\t\treturn -1;\n+\t}\n+\n+\tpclose(fp);\n+\treturn size_kb;\n+}\n+\n+/**\n+ * count_entries() - Recursively count files and subdirectories under a path\n+ * @path: Directory to scan\n+ * @files: Incremented for each regular file found\n+ * @dirs: Incremented for each subdirectory found\n+ *\n+ * Used to estimate FAT directory entry overhead when sizing the image.\n+ *\n+ * Return: 0 on success, -1 if the directory cannot be opened\n+ */\n+static int count_entries(const char *path, int *files, int *dirs)\n+{\n+\tDIR *dir;\n+\tstruct dirent *entry;\n+\tstruct stat st;\n+\tchar full_path[1024];\n+\n+\tdir = opendir(path);\n+\tif (!dir) {\n+\t\tfprintf(stderr, \"Error: Cannot open directory %s: %s\\n\",\n+\t\t\tpath, strerror(errno));\n+\t\treturn -1;\n+\t}\n+\n+\twhile ((entry = readdir(dir)) != NULL) {\n+\t\tif (strcmp(entry->d_name, \".\") == 0 ||\n+\t\t strcmp(entry->d_name, \"..\") == 0)\n+\t\t\tcontinue;\n+\n+\t\tsnprintf(full_path, sizeof(full_path), \"%s/%s\", path, entry->d_name);\n+\n+\t\tif (stat(full_path, &st) < 0) {\n+\t\t\tfprintf(stderr, \"Warning: Cannot stat %s: %s\\n\",\n+\t\t\t\tfull_path, strerror(errno));\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tif (S_ISDIR(st.st_mode)) {\n+\t\t\t(*dirs)++;\n+\t\t\tcount_entries(full_path, files, dirs);\n+\t\t} else {\n+\t\t\t(*files)++;\n+\t\t}\n+\t}\n+\n+\tclosedir(dir);\n+\treturn 0;\n+}\n+\n+/**\n+ * calculate_image_size() - Compute the required FAT image size in KB\n+ * @input_dir: Directory whose contents will be packed into the image\n+ * @extra_space: Additional padding in KB to add beyond the data size\n+ * @fat_type: Requested FAT type (0=auto, 12, 16, 32)\n+ *\n+ * Calculates the minimum image size needed to hold all files in @input_dir\n+ * plus FAT metadata overhead (directory entries, two FAT copies) and\n+ * @extra_space KB of padding. The result is cached in cached_image_size_kb\n+ * so that vrec_header and set_header agree on the same value.\n+ *\n+ * Return: image size in KB on success, -1 on error\n+ */\n+static int calculate_image_size(const char *input_dir, int extra_space,\n+\t\t\t\t int fat_type)\n+{\n+\tint data_kb;\n+\tint sectors;\n+\tint files = 0, dirs = 0;\n+\tint dir_bytes, fat_bytes;\n+\tint dir_sectors, fat_sectors;\n+\tint fat_entry_size;\n+\tint total_sectors;\n+\tint blocks;\n+\n+\tif (cached_image_size_kb > 0)\n+\t\treturn cached_image_size_kb;\n+\n+\tdata_kb = get_directory_size_kb(input_dir);\n+\tif (data_kb < 0)\n+\t\treturn -1;\n+\n+\tsectors = data_kb * 2;\n+\n+\tif (count_entries(input_dir, &files, &dirs) < 0)\n+\t\treturn -1;\n+\n+\tdir_bytes = (files + dirs) * DIR_ENTRY_SIZE;\n+\tdir_bytes += dirs * DIR_ENTRY_SIZE;\n+\n+\tif (fat_type == 32) {\n+\t\tfat_entry_size = FAT_ENTRY_SIZE_FAT32;\n+\t\tif ((sectors / 2 + extra_space) < 32 * 1024) {\n+\t\t\tfprintf(stderr, \"Warning: Image size %d KB may be too small for FAT32\\n\",\n+\t\t\t\t(sectors / 2 + extra_space));\n+\t\t\tfprintf(stderr, \" FAT32 works best with images >= 32 MB\\n\");\n+\t\t\tfprintf(stderr, \" Consider using auto-detect or FAT16 instead\\n\");\n+\t\t}\n+\t} else if (fat_type == 0) {\n+\t\tif ((sectors / 2 + extra_space) > 512 * 1024)\n+\t\t\tfat_entry_size = FAT_ENTRY_SIZE_FAT32;\n+\t\telse\n+\t\t\tfat_entry_size = FAT_ENTRY_SIZE_FAT16;\n+\t} else if (fat_type == 16) {\n+\t\tfat_entry_size = FAT_ENTRY_SIZE_FAT16;\n+\t} else if (fat_type == 12) {\n+\t\tfat_entry_size = FAT_ENTRY_SIZE_FAT12;\n+\t} else {\n+\t\tfat_entry_size = FAT_ENTRY_SIZE_FAT16;\n+\t}\n+\n+\tfat_bytes = sectors * fat_entry_size;\n+\tfat_bytes += dirs * fat_entry_size;\n+\n+\tdir_sectors = (dir_bytes + SECTOR_SIZE - 1) / SECTOR_SIZE;\n+\tfat_sectors = ((fat_bytes + SECTOR_SIZE - 1) / SECTOR_SIZE) * 2;\n+\n+\ttotal_sectors = sectors + dir_sectors + fat_sectors;\n+\tblocks = (total_sectors / 2) + extra_space;\n+\n+\tprintf(\"FAT image size calculation:\\n\");\n+\tprintf(\" Data size: %d KB (%d sectors)\\n\", data_kb, sectors);\n+\tprintf(\" Files: %d, Directories: %d\\n\", files, dirs);\n+\tprintf(\" Directory overhead: %d sectors\\n\", dir_sectors);\n+\tprintf(\" FAT overhead: %d sectors (2 FATs)\\n\", fat_sectors);\n+\tprintf(\" Extra padding: %d KB\\n\", extra_space);\n+\tprintf(\" Total image size: %d KB\\n\", blocks);\n+\n+\tcached_image_size_kb = blocks;\n+\n+\treturn blocks;\n+}\n+\n+/**\n+ * create_fat_image() - Format a FAT image file and populate it with files\n+ * @input_dir: Source directory; all contents are copied into the image\n+ * @output_file: Path of the FAT image file to create\n+ * @blocks: Image size in KB (passed to mkfs.vfat as the block count)\n+ * @fat_type: FAT type to use (0=auto, 12, 16, 32)\n+ * @volume_id: FAT volume label string\n+ * @mkfs_opts: Additional options forwarded to mkfs.vfat\n+ *\n+ * Calls mkfs.vfat to format @output_file as a FAT filesystem, then uses\n+ * mcopy to copy all files from @input_dir into the image root.\n+ *\n+ * Return: 0 on success, -1 on error\n+ */\n+static int create_fat_image(const char *input_dir, const char *output_file,\n+\t\t\t int blocks, int fat_type, const char *volume_id,\n+\t\t\t const char *mkfs_opts)\n+{\n+\tchar cmd[2048];\n+\tint ret;\n+\n+\tunlink(output_file);\n+\n+\tif (fat_type > 0) {\n+\t\tsnprintf(cmd, sizeof(cmd),\n+\t\t\t \"mkfs.vfat -F %d %s -n \\\"%s\\\" -C \\\"%s\\\" %d\",\n+\t\t\t fat_type, mkfs_opts ? mkfs_opts : \"\",\n+\t\t\t volume_id, output_file, blocks);\n+\t} else {\n+\t\tif (blocks > 512 * 1024) {\n+\t\t\tsnprintf(cmd, sizeof(cmd),\n+\t\t\t\t \"mkfs.vfat -F 32 %s -n \\\"%s\\\" -C \\\"%s\\\" %d\",\n+\t\t\t\t mkfs_opts ? mkfs_opts : \"\",\n+\t\t\t\t volume_id, output_file, blocks);\n+\t\t} else {\n+\t\t\tsnprintf(cmd, sizeof(cmd),\n+\t\t\t\t \"mkfs.vfat %s -n \\\"%s\\\" -C \\\"%s\\\" %d\",\n+\t\t\t\t mkfs_opts ? mkfs_opts : \"\",\n+\t\t\t\t volume_id, output_file, blocks);\n+\t\t}\n+\t}\n+\n+\tprintf(\"Creating FAT filesystem: %s\\n\", cmd);\n+\tret = system(cmd);\n+\tif (ret != 0) {\n+\t\tfprintf(stderr, \"Error: mkfs.vfat failed with code %d\\n\", ret);\n+\t\tfprintf(stderr, \"Make sure mkfs.vfat (dosfstools) is installed\\n\");\n+\t\treturn -1;\n+\t}\n+\n+\tsnprintf(cmd, sizeof(cmd),\n+\t\t \"MTOOLS_SKIP_CHECK=1 mcopy -i \\\"%s\\\" -s \\\"%s\\\"/* ::/\",\n+\t\t output_file, input_dir);\n+\n+\tprintf(\"Copying files: %s\\n\", cmd);\n+\tret = system(cmd);\n+\tif (ret != 0) {\n+\t\tfprintf(stderr, \"Error: mcopy failed with code %d\\n\", ret);\n+\t\tfprintf(stderr, \"Make sure mcopy (mtools) is installed\\n\");\n+\t\treturn -1;\n+\t}\n+\n+\tprintf(\"FAT image created successfully: %s\\n\", output_file);\n+\treturn 0;\n+}\n+\n+/**\n+ * fatimage_check_params() - Validate mkimage parameters for the fatfs type\n+ * @params: mkimage tool parameters (unused; input dir is in fatparams)\n+ *\n+ * Verifies that an input directory has been specified via fatimage_set_dir()\n+ * and that it exists and is a directory.\n+ *\n+ * Return: 0 if parameters are valid, -1 on error\n+ */\n+static int fatimage_check_params(struct image_tool_params *params)\n+{\n+\tif (!fatparams.input_dir) {\n+\t\tfprintf(stderr, \"Error: Input directory not specified\\n\");\n+\t\tfprintf(stderr, \"Use -d <directory> to specify input directory\\n\");\n+\t\treturn -1;\n+\t}\n+\n+\tstruct stat st;\n+\tif (stat(fatparams.input_dir, &st) < 0) {\n+\t\tfprintf(stderr, \"Error: Input directory '%s' does not exist: %s\\n\",\n+\t\t\tfatparams.input_dir, strerror(errno));\n+\t\treturn -1;\n+\t}\n+\n+\tif (!S_ISDIR(st.st_mode)) {\n+\t\tfprintf(stderr, \"Error: '%s' is not a directory\\n\",\n+\t\t\tfatparams.input_dir);\n+\t\treturn -1;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * fatimage_check_image_type() - Report whether this handler owns a given type\n+ * @type: IH_TYPE_* value to check\n+ *\n+ * Return: EXIT_SUCCESS if @type == IH_TYPE_FATFS, EXIT_FAILURE otherwise\n+ */\n+static int fatimage_check_image_type(uint8_t type)\n+{\n+\tif (type == IH_TYPE_FATFS)\n+\t\treturn EXIT_SUCCESS;\n+\treturn EXIT_FAILURE;\n+}\n+\n+/**\n+ * fatimage_verify_header() - Verify that a buffer contains a valid FAT image\n+ * @ptr: Pointer to the start of the image data\n+ * @image_size: Total size of the image in bytes\n+ * @params: mkimage tool parameters (unused)\n+ *\n+ * Checks for the FAT boot sector signature (0x55AA) at bytes 510-511.\n+ *\n+ * Return: 0 if the signature is present, -1 otherwise\n+ */\n+static int fatimage_verify_header(unsigned char *ptr, int image_size,\n+\t\t\t\t struct image_tool_params *params)\n+{\n+\tif (image_size < 512)\n+\t\treturn -1;\n+\n+\tif (ptr[510] != 0x55 || ptr[511] != 0xAA) {\n+\t\tfprintf(stderr, \"Error: Not a valid FAT filesystem image\\n\");\n+\t\treturn -1;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * fatimage_print_header() - Print human-readable FAT image information\n+ * @ptr: Pointer to the start of the image data\n+ * @params: mkimage tool parameters (unused)\n+ *\n+ * Prints the boot signature, detected FAT type (FAT32 vs FAT12/16),\n+ * and volume label read from the BPB.\n+ */\n+static void fatimage_print_header(const void *ptr,\n+\t\t\t\t struct image_tool_params *params)\n+{\n+\tconst unsigned char *buf = ptr;\n+\n+\tprintf(\"FAT Filesystem Image\\n\");\n+\tprintf(\" Boot signature: 0x%02X%02X\\n\", buf[511], buf[510]);\n+\n+\tif (buf[82] == 'F' && buf[83] == 'A' && buf[84] == 'T' &&\n+\t buf[85] == '3' && buf[86] == '2') {\n+\t\tprintf(\" Filesystem: FAT32\\n\");\n+\t\tprintf(\" Volume label: %.11s\\n\", &buf[71]);\n+\t} else {\n+\t\tprintf(\" Filesystem: FAT12/FAT16\\n\");\n+\t\tprintf(\" Volume label: %.11s\\n\", &buf[43]);\n+\t}\n+}\n+\n+/**\n+ * fatimage_vrec_header() - Allocate the output buffer for the FAT image\n+ * @params: mkimage tool parameters\n+ * @tparams: image type parameters; hdr and header_size are set on success\n+ *\n+ * Called before set_header to pre-allocate a buffer large enough for the\n+ * complete FAT image. The size is calculated from the input directory and\n+ * cached for reuse by fatimage_set_header().\n+ *\n+ * Return: 0 on success, -1 on error\n+ */\n+static int fatimage_vrec_header(struct image_tool_params *params,\n+\t\t\t\tstruct image_type_params *tparams)\n+{\n+\tint blocks;\n+\tint image_size_bytes;\n+\n+\tblocks = calculate_image_size(fatparams.input_dir,\n+\t\t\t\t fatparams.extra_space,\n+\t\t\t\t fatparams.fat_type);\n+\tif (blocks < 0) {\n+\t\tfprintf(stderr, \"Error: Failed to calculate image size\\n\");\n+\t\treturn -1;\n+\t}\n+\n+\timage_size_bytes = blocks * 1024;\n+\n+\ttparams->hdr = malloc(image_size_bytes);\n+\tif (!tparams->hdr) {\n+\t\tfprintf(stderr, \"Error: Failed to allocate %d bytes for FAT image\\n\",\n+\t\t\timage_size_bytes);\n+\t\treturn -1;\n+\t}\n+\n+\ttparams->header_size = image_size_bytes;\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * fatimage_set_header() - Create the FAT image and load it into the buffer\n+ * @ptr: Output buffer (allocated by fatimage_vrec_header)\n+ * @sbuf: stat of the output file (unused)\n+ * @ifd: file descriptor of the output file (unused)\n+ * @params: mkimage tool parameters; imagefile is used for the temp file name\n+ *\n+ * Creates the FAT image in a temporary file using mkfs.vfat and mcopy,\n+ * reads the result into @ptr, then removes the temporary file.\n+ *\n+ * Return: 0 on success, -1 on error\n+ */\n+static int fatimage_set_header(void *ptr, struct stat *sbuf, int ifd,\n+\t\t\t struct image_tool_params *params)\n+{\n+\tint blocks;\n+\tint ret;\n+\tchar temp_file[256];\n+\tFILE *fp;\n+\tsize_t bytes_read;\n+\n+\tsnprintf(temp_file, sizeof(temp_file), \"%s.tmp\", params->imagefile);\n+\n+\tblocks = calculate_image_size(fatparams.input_dir,\n+\t\t\t\t fatparams.extra_space,\n+\t\t\t\t fatparams.fat_type);\n+\tif (blocks < 0) {\n+\t\tfprintf(stderr, \"Error: Failed to calculate image size\\n\");\n+\t\treturn -1;\n+\t}\n+\n+\tret = create_fat_image(fatparams.input_dir, temp_file,\n+\t\t\t blocks, fatparams.fat_type,\n+\t\t\t fatparams.volume_id, fatparams.mkfs_opts);\n+\tif (ret < 0) {\n+\t\tfprintf(stderr, \"Error: Failed to create FAT image\\n\");\n+\t\treturn -1;\n+\t}\n+\n+\tfp = fopen(temp_file, \"rb\");\n+\tif (!fp) {\n+\t\tfprintf(stderr, \"Error: Failed to open temporary file %s: %s\\n\",\n+\t\t\ttemp_file, strerror(errno));\n+\t\tunlink(temp_file);\n+\t\treturn -1;\n+\t}\n+\n+\tbytes_read = fread(ptr, 1, blocks * 1024, fp);\n+\tfclose(fp);\n+\tunlink(temp_file);\n+\n+\tif (bytes_read != (size_t)(blocks * 1024)) {\n+\t\tfprintf(stderr, \"Error: Failed to read FAT image (read %zu, expected %d)\\n\",\n+\t\t\tbytes_read, blocks * 1024);\n+\t\treturn -1;\n+\t}\n+\n+\tprintf(\"FAT image created successfully in buffer\\n\");\n+\treturn 0;\n+}\n+\n+U_BOOT_IMAGE_TYPE(\n+\tfatfsimage,\n+\t\"FAT Filesystem Image\",\n+\t0,\n+\tNULL,\n+\tfatimage_check_params,\n+\tfatimage_verify_header,\n+\tfatimage_print_header,\n+\tfatimage_set_header,\n+\tNULL,\n+\tfatimage_check_image_type,\n+\tNULL,\n+\tfatimage_vrec_header\n+);\n+\n+void fatimage_set_dir(const char *dir)\n+{\n+\tfatparams.input_dir = strdup(dir);\n+}\n+\n+void fatimage_set_extra_space(int space_kb)\n+{\n+\tfatparams.extra_space = space_kb;\n+}\n+\n+void fatimage_set_fat_type(int type)\n+{\n+\tfatparams.fat_type = type;\n+}\n+\n+void fatimage_set_volume_id(const char *volid)\n+{\n+\tfatparams.volume_id = strdup(volid);\n+}\n+\n+void fatimage_set_mkfs_opts(const char *opts)\n+{\n+\tfatparams.mkfs_opts = strdup(opts);\n+}\ndiff --git a/tools/fatimage.h b/tools/fatimage.h\nnew file mode 100644\nindex 00000000000..8822724925c\n--- /dev/null\n+++ b/tools/fatimage.h\n@@ -0,0 +1,25 @@\n+/* SPDX-License-Identifier: GPL-2.0 */\n+/*\n+ * FAT Filesystem Image support for mkimage\n+ *\n+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries\n+ */\n+\n+#ifndef _FATIMAGE_H_\n+#define _FATIMAGE_H_\n+\n+#define SECTOR_SIZE 512\n+#define DIR_ENTRY_SIZE 32\n+#define FAT_ENTRY_SIZE_FAT32 4\n+#define FAT_ENTRY_SIZE_FAT16 2\n+#define FAT_ENTRY_SIZE_FAT12 2 /* Rounded up from 1.5 bytes */\n+\n+struct fatimage_params {\n+\tchar *input_dir;\n+\tint extra_space; /* Extra padding space in KB (default: 512) */\n+\tint fat_type; /* FAT type: 0=auto, 12/16/32 */\n+\tchar *volume_id; /* Volume label (default: \"BOOT\") */\n+\tchar *mkfs_opts; /* Extra mkfs.vfat options (default: \"-S 512\") */\n+};\n+\n+#endif /* _FATIMAGE_H_ */\ndiff --git a/tools/mkimage.c b/tools/mkimage.c\nindex 3c43962807d..9fbc9b52957 100644\n--- a/tools/mkimage.c\n+++ b/tools/mkimage.c\n@@ -204,6 +204,10 @@ static const struct option longopts[] = {\n \t{ \"tfa-bl31-addr\", no_argument, NULL, 'Y' },\n \t{ \"tee-file\", no_argument, NULL, 'z' },\n \t{ \"tee-addr\", no_argument, NULL, 'Z' },\n+{ \"fat-extra-space\", required_argument, NULL, OPT_FAT_EXTRA },\n+\t{ \"fat-type\", required_argument, NULL, OPT_FAT_TYPE },\n+\t{ \"fat-volume-id\", required_argument, NULL, OPT_FAT_VOLID },\n+\t{ \"fat-mkfs-opts\", required_argument, NULL, OPT_FAT_MKFS },\n \t{ /* sentinel */ },\n };\n \n@@ -397,6 +401,18 @@ static void process_args(int argc, char **argv)\n \t\t\t\texit(EXIT_FAILURE);\n \t\t\t}\n \t\t\tbreak;\n+\t\tcase OPT_FAT_EXTRA:\n+\t\t\tfatimage_set_extra_space(atoi(optarg));\n+\t\t\tbreak;\n+\t\tcase OPT_FAT_TYPE:\n+\t\t\tfatimage_set_fat_type(atoi(optarg));\n+\t\t\tbreak;\n+\t\tcase OPT_FAT_VOLID:\n+\t\t\tfatimage_set_volume_id(optarg);\n+\t\t\tbreak;\n+\t\tcase OPT_FAT_MKFS:\n+\t\t\tfatimage_set_mkfs_opts(optarg);\n+\t\t\tbreak;\n \t\tdefault:\n \t\t\tusage(\"Invalid option\");\n \t\t}\n@@ -433,6 +449,11 @@ static void process_args(int argc, char **argv)\n \t\tparams.type = type;\n \t}\n \n+\tif (params.type == IH_TYPE_FATFS && params.datafile) {\n+\t\tfatimage_set_dir(params.datafile);\n+\t\tparams.skipcpy = 1;\n+\t}\n+\n \tif (!params.imagefile)\n \t\tusage(\"Missing output filename\");\n }\ndiff --git a/tools/mkimage.h b/tools/mkimage.h\nindex 5d6bcc9301a..599f92e617f 100644\n--- a/tools/mkimage.h\n+++ b/tools/mkimage.h\n@@ -53,4 +53,19 @@ static inline ulong map_to_sysmem(const void *ptr)\n #define MKIMAGE_DEFAULT_DTC_OPTIONS\t\"-I dts -O dtb -p 500\"\n #define MKIMAGE_MAX_DTC_CMDLINE_LEN\t2 * MKIMAGE_MAX_TMPFILE_LEN + 35\n \n+/* Long option values for mkimage */\n+enum {\n+\tOPT_FAT_EXTRA = 512,\n+\tOPT_FAT_TYPE,\n+\tOPT_FAT_VOLID,\n+\tOPT_FAT_MKFS,\n+};\n+\n+/* FAT image functions */\n+void fatimage_set_dir(const char *dir);\n+void fatimage_set_extra_space(int space_kb);\n+void fatimage_set_fat_type(int type);\n+void fatimage_set_volume_id(const char *volid);\n+void fatimage_set_mkfs_opts(const char *opts);\n+\n #endif /* _MKIIMAGE_H_ */\n", "prefixes": [ "v3", "5/7" ] }