ورک فلو فلش dts و kernel

This commit is contained in:
2026-11-09 20:51:13 +03:30
والد ca7ae6df6c
کامیت 613828da54
4فایلهای تغییر یافته به همراه72 افزوده شده و 22 حذف شده
@@ -0,0 +1,16 @@
name: Transfer, Write and Verify DTB
on:
workflow_dispatch:
jobs:
dtb-transfer:
runs-on: serial-runner
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Transfer DTB, write SPI flash and verify read-back
run: |
/usr/bin/python3 scripts/serial_command.py transfer-dtb
@@ -0,0 +1,16 @@
name: Transfer, Write and Verify Kernel
on:
workflow_dispatch:
jobs:
kernel-transfer:
runs-on: serial-runner
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Transfer Kernel, write SPI flash and verify read-back
run: |
/usr/bin/python3 scripts/serial_command.py transfer-kernel
+9
مشاهده پرونده
@@ -10,3 +10,12 @@ with the local file, probes SPI flash, writes at offset 0, reads back to
No erase, reboot or saveenv command is issued. Any failed or unverified No erase, reboot or saveenv command is issued. Any failed or unverified
command stops execution; flash writes are never automatically retried. command stops execution; flash writes are never automatically retried.
For the DTB workflow, place `sun8i-v3s-licheepi-zero-dock.dtb` here.
It uses the same checks, with maximum size 0x110000, RAM address
0x41000000 and flash offset 0x200000. Read-back uses 0x42800000.
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.
+31 -22
مشاهده پرونده
@@ -82,14 +82,19 @@ class UBoot:
return output return output
def transfer(cli, firmware): def transfer(cli, firmware, *, dtb=False, kernel=False):
address = 0x41000000 if dtb 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")
image = firmware.read_bytes() image = firmware.read_bytes()
if not 32 <= len(image) <= 0x200000: if not dump_size <= len(image) <= limit:
raise RuntimeError("Firmware size must be between 32 and 0x200000 bytes") raise RuntimeError(f"Firmware size must be between {dump_size} and {limit:#x} bytes")
# Invalidate any previous transfer length before attempting a new transfer. # Invalidate any previous transfer length before attempting a new transfer.
cli.command("setenv filesize") cli.command("setenv filesize")
output = cli.command( output = cli.command(
"tftp 0x42000000 u-boot-sunxi-with-spl.bin", f"tftp {address:#x} {filename}",
r"^Bytes transferred = \d+", timeout=120, r"^Bytes transferred = \d+", timeout=120,
) )
transferred = re.findall(r"^Bytes transferred = (\d+)", output, re.MULTILINE) transferred = re.findall(r"^Bytes transferred = (\d+)", output, re.MULTILINE)
@@ -99,42 +104,46 @@ def transfer(cli, firmware):
sizes = re.findall(r"^([0-9a-fA-F]+)$", output, re.MULTILINE) sizes = re.findall(r"^([0-9a-fA-F]+)$", output, re.MULTILINE)
if len(sizes) != 1 or int(sizes[0], 16) != len(image): if len(sizes) != 1 or int(sizes[0], 16) != len(image):
raise RuntimeError("U-Boot filesize differs from the local firmware file") raise RuntimeError("U-Boot filesize differs from the local firmware file")
output = cli.command("md.b 0x42000000 0x20", r"^42000000:") output = cli.command(f"md.b {address:#x} {dump_size:#x}", rf"^{address:08x}:")
dumped = bytearray() dumped = bytearray()
for address in ("42000000", "42000010"): for row_offset in range(0, dump_size, 16):
rows = re.findall(r"^" + address + r":((?: [0-9a-fA-F]{2}){16})(?:\s|$)", output, re.MULTILINE) row_address = f"{address + row_offset:08x}"
rows = re.findall(r"^" + row_address + r":((?: [0-9a-fA-F]{2}){16})(?:\s|$)", output, re.MULTILINE)
if len(rows) != 1: if len(rows) != 1:
raise RuntimeError("Missing or invalid memory dump at " + address) raise RuntimeError("Missing or invalid memory dump at " + row_address)
dumped.extend(bytes.fromhex(rows[0])) dumped.extend(bytes.fromhex(rows[0]))
if dumped != image[:32]: if dumped != image[:dump_size]:
raise RuntimeError("First 32 bytes in RAM differ from the local firmware file") raise RuntimeError(f"First {dump_size} bytes in RAM differ from the local firmware file")
print("\nTransfer verified: size and first 32 bytes match.") print(f"\nTransfer verified: size and first {dump_size} bytes match.")
cli.command("sf probe 0:0", r"^SF: Detected .+", timeout=20) cli.command("sf probe 0:0", r"^SF: Detected .+", timeout=20)
cli.command( cli.command(
"sf write 0x42000000 0x0 ${filesize}", f"sf write {address:#x} {offset:#x} ${{filesize}}",
rf"^SF: {len(image)} bytes @ 0x0 Written: OK\s*$", timeout=120, rf"^SF: {len(image)} bytes @ {offset:#x} Written: OK\s*$", timeout=120,
) )
cli.command( cli.command(
"sf read 0x42800000 0x0 ${filesize}", f"sf read 0x42800000 {offset:#x} ${{filesize}}",
rf"^SF: {len(image)} bytes @ 0x0 Read: OK\s*$", timeout=120, rf"^SF: {len(image)} bytes @ {offset:#x} Read: OK\s*$", timeout=120,
) )
output = cli.command( output = cli.command(
"cmp.b 0x42000000 0x42800000 ${filesize}", f"cmp.b {address:#x} 0x42800000 ${{filesize}}",
r"^Total of \d+ byte\(s\) were the same", timeout=60, r"^Total of \d+ byte\(s\) were the same", timeout=60,
) )
compared = re.findall(r"^Total of (\d+) byte\(s\) were the same", output, re.MULTILINE) compared = re.findall(r"^Total of (\d+) byte\(s\) were the same", output, re.MULTILINE)
if compared != [str(len(image))]: if compared != [str(len(image))]:
raise RuntimeError("Flash comparison byte count differs from firmware size") raise RuntimeError("Flash comparison byte count differs from firmware size")
print("\nU-Boot flash write and full read-back comparison verified.") print("\nFirmware flash write and full read-back comparison verified.")
def main(): def main():
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument("mode", choices=("check", "configure", "transfer"), default="check", nargs="?") parser.add_argument("mode", choices=("check", "configure", "transfer", "transfer-dtb", "transfer-kernel"), default="check", nargs="?")
parser.add_argument("--port", default="/dev/ttyUSB0") parser.add_argument("--port", default="/dev/ttyUSB0")
parser.add_argument("--firmware", type=Path, default=Path(__file__).resolve().parent.parent / "firmware" / "u-boot-sunxi-with-spl.bin") parser.add_argument("--firmware", type=Path, default=None)
args = parser.parse_args() args = parser.parse_args()
if args.mode == "transfer" and not args.firmware.is_file(): 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")
args.firmware = Path(__file__).resolve().parent.parent / "firmware" / filename
if args.mode in ("transfer", "transfer-dtb", "transfer-kernel") and not args.firmware.is_file():
raise RuntimeError("Firmware file not found: " + str(args.firmware)) raise RuntimeError("Firmware file not found: " + str(args.firmware))
# Shared by both workflows: fail rather than interleave serial commands. # Shared by both workflows: fail rather than interleave serial commands.
with open("/tmp/uboot-serial.lock", "w") as lock: with open("/tmp/uboot-serial.lock", "w") as lock:
@@ -144,8 +153,8 @@ def main():
cli.detect() cli.detect()
if args.mode == "check": if args.mode == "check":
return return
if args.mode == "transfer": if args.mode in ("transfer", "transfer-dtb", "transfer-kernel"):
transfer(cli, args.firmware) transfer(cli, args.firmware, dtb=args.mode == "transfer-dtb", kernel=args.mode == "transfer-kernel")
return return
cli.command("version", r"^U-Boot \d") cli.command("version", r"^U-Boot \d")
cli.command( cli.command(