From nobody Mon Feb 9 16:51:27 2026 Received: from mail-io1-f49.google.com (mail-io1-f49.google.com [209.85.166.49]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 44FBE327213 for ; Fri, 14 Nov 2025 14:28:10 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.166.49 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763130492; cv=none; b=ZZvGgsDiG7fmq7esImZuJOEmGzF8MRKiNfDoSVy2ad8+uDxBdLrLXKWBVHYt3a+lSIc+lyR8JGw28I0XXIsq3a2iXlIh43iLZnhHeMQLQ5gI2kprZHzk1keNJEyNhgt2cSCU0eiq85m0oI09cJyBPrHtXxMzkhcT2KtoCL7aLTo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763130492; c=relaxed/simple; bh=zBAjQh9JCzwABFilcP24spbYzKjpbpx0VEEAWxnlGS0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=BjyMk3NfcqDQpo3LsQyCgJC2qC8PkqDmPxhcOy5xut1sK6uJVo9ZmsRlpgDmwvOIRB81S8WoSW5pcay8F0f0LnH5lRHsXRwZ1FPQPPFeATDb01rX+kb0KUE3KpW8GGhHlsvwV3EMVm/QM5TzERXjR3n+jKFb3aQiI/vzpZdPpmo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=chromium.org; spf=pass smtp.mailfrom=chromium.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b=dQrDanze; arc=none smtp.client-ip=209.85.166.49 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=chromium.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="dQrDanze" Received: by mail-io1-f49.google.com with SMTP id ca18e2360f4ac-9489dc9845dso81363839f.0 for ; Fri, 14 Nov 2025 06:28:10 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; t=1763130489; x=1763735289; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=0Kcz22F2HSffVxv8SHD4ALbiSJ858QNwAp4RJw9tXbw=; b=dQrDanzeanmNIP5kFNS23XhSOfrUgLK/M+7emVniRQYgkqSrexkWXwXihzOsUilywY yhrXAMpnG20jcyUdzvxYDx2wD/4FyoBd9fmDJVqsaMuw9nS2JQcpMSNRkdCNFWOcdpv7 Dfi12c7vB4FE3f7zytlhQdd2OSm2SUUPg3iNo= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1763130489; x=1763735289; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=0Kcz22F2HSffVxv8SHD4ALbiSJ858QNwAp4RJw9tXbw=; b=AzkUn11J1rLEsD4RjkAZDQukyt841H4+XuZzp5/eRn8VBzShiKKF+JEAZaTUuZoFhR l3uez6MuejS1tUoiGL7XLuiqYzRHtbAu4+vGQk1U00XSTA9PmF5fAWnBG+4Fr4slLyan ptyrjz8o7LkYJfKVLqb/ecSCz69qJ0gkIAKcxR4tXk+6aauJRSP9i7jE/LrMHpLfMnnk Veo5oGLglaOc5Y0A4LdjAQAtoO7K29VT4y8jeny1QWplubSsxZsefkaJpob28RGL4i51 zfI1vh65bRa40TV8/0BVOVI4Ydl0tQRjlBWo/VjPTVsFOkJzmEC/1Q3/AXcUolJv2TbT HdTg== X-Forwarded-Encrypted: i=1; AJvYcCVcxtUHdV8oOW+N0W0/V5pDgCeSBlZtrKqwzKWQYhpKZa5RJBjAaU+38X8VaJCBDicKoKu0pgW/gzpZbzU=@vger.kernel.org X-Gm-Message-State: AOJu0Yzdky4Hk4LVQqFu/wq05Eg/r6kJptl6nXZiBs4JLrDWAHNv0QyA wAnCwbSCxOI4HEsRKbA8sjBZ8Mu2rWDCpOYlDQ/Rwhv8ozcNHdg0oAmeckGCb3vqTg== X-Gm-Gg: ASbGncsVm1uUcPrdXe+oDagk0QcxhKdAPtMvSsbykTiF53DClDNNwliXd8CU/k64HtR Nm7LaQyb3JOPTE/T7U2XNJKl0xSX21avVbohCoz2OgEpZwZP7QdWRZjBosEy7rvye1yX42AlR/Q xfXba5/XI5zCH+peuoxxorBt0MFymA5HFGQOLgAApVZGA8LOGsuW20t6yO+ch2VPoD7lEUg8EuO 0HhRxflRSGpMVF+WVdjPsQVjxIe1xWK6qArfVhE9NDHWFgwvTr7s00FQIZugPaB5yWQg5r/afzv 8sil3nzKSycKv6UL5IX1YBU2w8JQWE4oscSUS4q0ls4omVijIHDNLZxfGkqxGeWTKFrex2VMw8I RoNOJJYTT0cjX1lZzR5gQlO5wGVifC1lBb9kVXfsOwKxhjjagIrrYCOi05e71TwUjmOrfM68u9Y M6ApQD X-Google-Smtp-Source: AGHT+IFHOZJj2lH8HRzO4I7qi0KILDpyFlaNnMyv9yoDbXQXY3BIaEqV9liLUCD0alvtY81aHaZwsg== X-Received: by 2002:a05:6e02:258b:b0:434:6ef2:a43d with SMTP id e9e14a558f8ab-4348c938f48mr42073985ab.19.1763130489362; Fri, 14 Nov 2025 06:28:09 -0800 (PST) Received: from chromium.org ([73.34.74.121]) by smtp.gmail.com with ESMTPSA id e9e14a558f8ab-434839cdb10sm27500205ab.32.2025.11.14.06.28.07 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 14 Nov 2025 06:28:07 -0800 (PST) From: Simon Glass To: linux-arm-kernel@lists.infradead.org Cc: Nicolas Schier , Masahiro Yamada , Chen-Yu Tsai , Tom Rini , Ahmad Fatoum , =?UTF-8?q?J=20=2E=20Neusch=C3=A4fer?= , Simon Glass , Nicolas Schier , linux-kernel@vger.kernel.org Subject: [PATCH v5 4/8] scripts/make_fit: Provide a way to add built modules Date: Fri, 14 Nov 2025 07:27:30 -0700 Message-ID: <20251114142741.1919072-5-sjg@chromium.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251114142741.1919072-1-sjg@chromium.org> References: <20251114142741.1919072-1-sjg@chromium.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Provide arguments to support building a ramdisk from a directory tree of modules. This is a convenient way to try out a kernel with its modules. This makes use of the cpio tool rather than attempting to use a python module or our own code. The list of modules is provided in a file. Signed-off-by: Simon Glass Reviewed-by: Nicolas Schier Suggested-by: Ahmad Fatoum --- (no changes since v4) Changes in v4: - Provide the list of modules from the Makefile - Reduce verbosity (don't print every module filename) Changes in v3: - Add a way to add built modules into the FIT scripts/make_fit.py | 98 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 90 insertions(+), 8 deletions(-) diff --git a/scripts/make_fit.py b/scripts/make_fit.py index 1a74a9dcd85e..3db129f40b20 100755 --- a/scripts/make_fit.py +++ b/scripts/make_fit.py @@ -13,11 +13,17 @@ Usage: -r /boot/initrd.img-6.14.0-27-generic @arch/arm64/boot/dts/dtbs-li= st -E -c gzip =20 + # Build with modules ramdisk instead of external ramdisk: + make_fit.py -A arm64 -n 'Linux-6.17' -O linux + -o arch/arm64/boot/image.fit -k /tmp/kern/arch/arm64/boot/image.itk + -m module1.ko module2.ko module3.ko @arch/arm64/boot/dts/dtbs-list + Creates a FIT containing the supplied kernel, an optional ramdisk, and a s= et of devicetree files, either specified individually or listed in a file (with = an '@' prefix). =20 Use -r to specify an existing ramdisk/initrd file. +Use -m to build a ramdisk from specified kernel module files. =20 Use -E to generate an external FIT (where the data is placed after the FIT data structure). This allows parsing of the data without loading @@ -38,6 +44,7 @@ as U-Boot, Linuxboot, Tianocore, etc. import argparse import collections import os +import shutil import subprocess import sys import tempfile @@ -83,8 +90,14 @@ def parse_args(): help=3D'Specifies the operating system') parser.add_argument('-k', '--kernel', type=3Dstr, required=3DTrue, help=3D'Specifies the (uncompressed) kernel input file (.itk)') - parser.add_argument('-r', '--ramdisk', type=3Dstr, + + # Create mutually exclusive group for ramdisk options + rd_group =3D parser.add_mutually_exclusive_group() + rd_group.add_argument('-r', '--ramdisk', type=3Dstr, help=3D'Specifies the ramdisk/initrd input file') + rd_group.add_argument('-m', '--modules', type=3Dstr, nargs=3D'+', + help=3D'List of module filenames to include in ramdisk') + parser.add_argument('-v', '--verbose', action=3D'store_true', help=3D'Enable verbose output') parser.add_argument('dtbs', type=3Dstr, nargs=3D'*', @@ -240,6 +253,60 @@ def output_dtb(fsw, seq, fname, arch, compress): fsw.property('data', compressed) =20 =20 +def build_ramdisk(args, tmpdir): + """Build a cpio ramdisk containing kernel modules + + Similar to mkinitramfs, this creates a compressed cpio-archive contain= ing + the kernel modules for the current kernel version. + + Args: + args (Namespace): Program arguments + tmpdir (str): Temporary directory to use for modules installation + + Returns: + tuple: + bytes: Compressed cpio data containing modules + int: total uncompressed size + """ + suppress =3D None if args.verbose else subprocess.DEVNULL + + if args.verbose: + print(f'Copying {len(args.modules)} modules to ramdisk') + + # Create output-directory structure + outdir =3D os.path.join(tmpdir, 'initramfs') + modules_dir =3D os.path.join(outdir, 'usr', 'lib', 'modules') + os.makedirs(modules_dir, exist_ok=3DTrue) + + # Copy in the specified modules + for module in args.modules: + dest_path =3D os.path.join(modules_dir, os.path.basename(module)) + shutil.copy2(module, dest_path) + + if args.verbose: + print(f'Creating cpio archive from {outdir}') + + with tempfile.NamedTemporaryFile() as cpio_file: + # Change to initramfs directory and create cpio archive + with subprocess.Popen(['find', '.', '-print0'], cwd=3Doutdir, + stdout=3Dsubprocess.PIPE) as find: + with subprocess.Popen(['cpio', '-o', '-0', '-H', 'newc'], + stdin=3Dfind.stdout, stdout=3Dcpio_file, + stderr=3Dsuppress, cwd=3Doutdir) as cpio: + find.stdout.close() + cpio.wait() + find.wait() + + if cpio.returncode !=3D 0: + raise RuntimeError('Failed to create cpio archive') + + cpio_file.seek(0) # Reset to beginning for reading + if args.verbose: + print('Reading ramdisk...' if args.compress =3D=3D 'none' else + f'Compressing ramdisk with {args.compress}...') + return compress_data(cpio_file, args.compress), cpio_file.tell() + + def process_dtb(fname, args): """Process an input DTB, decomposing it if requested and is possible =20 @@ -318,11 +385,12 @@ def _process_dtbs(args, fsw, entries, fdts): return seq, size =20 =20 -def build_fit(args): +def build_fit(args, tmpdir): """Build the FIT from the provided files and arguments =20 Args: args (Namespace): Program arguments + tmpdir (str): Temporary directory for any temporary files =20 Returns: tuple: @@ -344,20 +412,29 @@ def build_fit(args): =20 # Handle the ramdisk if provided. Compression is not supported as it is # already compressed. + ramdisk_data =3D None if args.ramdisk: with open(args.ramdisk, 'rb') as inf: - data =3D inf.read() - size +=3D len(data) - write_ramdisk(fsw, data, args) + ramdisk_data =3D inf.read() + size +=3D len(ramdisk_data) + elif args.modules: + if args.verbose: + print('Building modules ramdisk...') + ramdisk_data, uncomp_size =3D build_ramdisk(args, tmpdir) + size +=3D uncomp_size + + if ramdisk_data: + write_ramdisk(fsw, ramdisk_data, args) =20 count, fdt_size =3D _process_dtbs(args, fsw, entries, fdts) size +=3D fdt_size =20 - finish_fit(fsw, entries, bool(args.ramdisk)) + finish_fit(fsw, entries, has_ramdisk=3Dbool(ramdisk_data)) =20 - # Include the kernel itself in the returned file count fdt =3D fsw.as_fdt() fdt.pack() + + # Count FDT files, kernel, plus ramdisk if present return fdt.as_bytearray(), count + 1 + bool(args.ramdisk), size =20 =20 @@ -365,7 +442,12 @@ def run_make_fit(): """Run the tool's main logic""" args =3D parse_args() =20 - out_data, count, size =3D build_fit(args) + tmpdir =3D tempfile.mkdtemp(prefix=3D'make_fit_') + try: + out_data, count, size =3D build_fit(args, tmpdir) + finally: + shutil.rmtree(tmpdir) + with open(args.output, 'wb') as outf: outf.write(out_data) =20 --=20 2.43.0