From 84789b3dad7ab3fe6c55ff3ecb34f9e7e9d4c840 Mon Sep 17 00:00:00 2001 From: nearology Date: Mon, 9 Nov 2026 20:53:02 +0330 Subject: [PATCH] =?UTF-8?q?=D9=88=D8=B1=DA=A9=20=D9=81=D9=84=D9=88=20?= =?UTF-8?q?=D9=81=D9=84=D8=B4=20rootfs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitea/workflows/rootfs-transfer.yml | 23 +++++++++++++++++++++++ firmware/README.md | 8 ++++++++ scripts/serial_command.py | 23 ++++++++++++++++------- 3 files changed, 47 insertions(+), 7 deletions(-) create mode 100644 .gitea/workflows/rootfs-transfer.yml diff --git a/.gitea/workflows/rootfs-transfer.yml b/.gitea/workflows/rootfs-transfer.yml new file mode 100644 index 0000000..8930dc6 --- /dev/null +++ b/.gitea/workflows/rootfs-transfer.yml @@ -0,0 +1,23 @@ +name: Transfer, Write and Verify RootFS + +on: + workflow_dispatch: + inputs: + rootfs_size: + description: 'Actual RootFS partition size in bytes (decimal or 0x-prefixed hex)' + required: true + type: string + +jobs: + rootfs-transfer: + runs-on: serial-runner + + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + + - name: Transfer RootFS, write SPI flash and verify read-back + env: + ROOTFS_PARTITION_SIZE: ${{ inputs.rootfs_size }} + run: | + /usr/bin/python3 scripts/serial_command.py transfer-rootfs --rootfs-size "$ROOTFS_PARTITION_SIZE" diff --git a/firmware/README.md b/firmware/README.md index e14ce4d..9f05126 100644 --- a/firmware/README.md +++ b/firmware/README.md @@ -19,3 +19,11 @@ For the Kernel workflow, place `zImage` here. It uses maximum size 0x500000, RAM address 0x42000000 and flash offset 0x310000. The first 64 bytes are checked against the local file; full read-back comparison uses 0x42800000. The same stale-filesize and transfer checks apply. + +For the RootFS workflow, place `rootfs.squashfs` here and supply the actual +RootFS partition size in bytes as the required `rootfs_size` workflow input +(decimal or 0x-prefixed hex). Determine it from the real board partition map; +the workflow does not infer it from flash capacity or a presumed layout. +It uses RAM 0x41000000, flash offset 0x810000, a 64-byte header comparison, +and read-back RAM 0x42800000. Files must fit the specified partition and +the non-overlapping RAM buffers (maximum 0x1800000 bytes). diff --git a/scripts/serial_command.py b/scripts/serial_command.py index 016802e..175a379 100644 --- a/scripts/serial_command.py +++ b/scripts/serial_command.py @@ -82,15 +82,21 @@ class UBoot: return output -def transfer(cli, firmware, *, dtb=False, kernel=False): - address = 0x41000000 if dtb else 0x42000000 +def transfer(cli, firmware, *, dtb=False, kernel=False, rootfs=False, rootfs_size=None): + address = 0x41000000 if (dtb or rootfs) else 0x42000000 offset = 0x310000 if kernel else (0x200000 if dtb else 0) limit = 0x500000 if kernel else (0x110000 if dtb else 0x200000) dump_size = 64 if kernel else 32 filename = "zImage" if kernel else ("sun8i-v3s-licheepi-zero-dock.dtb" if dtb else "u-boot-sunxi-with-spl.bin") + if rootfs: + if rootfs_size is None or rootfs_size < 64: + raise RuntimeError("Actual RootFS partition size is required (at least 64 bytes)") + offset, limit, dump_size, filename = 0x810000, rootfs_size, 64, "rootfs.squashfs" image = firmware.read_bytes() if not dump_size <= len(image) <= limit: raise RuntimeError(f"Firmware size must be between {dump_size} and {limit:#x} bytes") + if rootfs and len(image) > 0x1800000: + raise RuntimeError("RootFS exceeds the non-overlapping RAM buffer capacity (0x1800000)") # Invalidate any previous transfer length before attempting a new transfer. cli.command("setenv filesize") output = cli.command( @@ -136,14 +142,17 @@ def transfer(cli, firmware, *, dtb=False, kernel=False): def main(): parser = argparse.ArgumentParser() - parser.add_argument("mode", choices=("check", "configure", "transfer", "transfer-dtb", "transfer-kernel"), default="check", nargs="?") + parser.add_argument("mode", choices=("check", "configure", "transfer", "transfer-dtb", "transfer-kernel", "transfer-rootfs"), default="check", nargs="?") parser.add_argument("--port", default="/dev/ttyUSB0") parser.add_argument("--firmware", type=Path, default=None) + parser.add_argument("--rootfs-size", type=lambda value: int(value, 0), help="Actual RootFS partition size in bytes (decimal or 0x-prefixed hex)") args = parser.parse_args() + if args.mode == "transfer-rootfs" and (args.rootfs_size is None or args.rootfs_size < 64): + parser.error("--rootfs-size must specify the actual RootFS partition size (at least 64 bytes)") if args.firmware is None: - filename = "zImage" if args.mode == "transfer-kernel" else ("sun8i-v3s-licheepi-zero-dock.dtb" if args.mode == "transfer-dtb" else "u-boot-sunxi-with-spl.bin") + filename = "rootfs.squashfs" if args.mode == "transfer-rootfs" else "zImage" if args.mode == "transfer-kernel" else ("sun8i-v3s-licheepi-zero-dock.dtb" if args.mode == "transfer-dtb" else "u-boot-sunxi-with-spl.bin") args.firmware = Path(__file__).resolve().parent.parent / "firmware" / filename - if args.mode in ("transfer", "transfer-dtb", "transfer-kernel") and not args.firmware.is_file(): + if args.mode in ("transfer", "transfer-dtb", "transfer-kernel", "transfer-rootfs") and not args.firmware.is_file(): raise RuntimeError("Firmware file not found: " + str(args.firmware)) # Shared by both workflows: fail rather than interleave serial commands. with open("/tmp/uboot-serial.lock", "w") as lock: @@ -153,8 +162,8 @@ def main(): cli.detect() if args.mode == "check": return - if args.mode in ("transfer", "transfer-dtb", "transfer-kernel"): - transfer(cli, args.firmware, dtb=args.mode == "transfer-dtb", kernel=args.mode == "transfer-kernel") + if args.mode in ("transfer", "transfer-dtb", "transfer-kernel", "transfer-rootfs"): + transfer(cli, args.firmware, dtb=args.mode == "transfer-dtb", kernel=args.mode == "transfer-kernel", rootfs=args.mode == "transfer-rootfs", rootfs_size=args.rootfs_size) return cli.command("version", r"^U-Boot \d") cli.command(