مقایسه کامیتها
4
کامیتها
3cfe096d81
...
5ee716f38a
| مولف | SHA1 | تاریخ | |
|---|---|---|---|
|
|
5ee716f38a | ||
|
|
84789b3dad | ||
|
|
613828da54 | ||
|
|
ca7ae6df6c |
@@ -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
|
||||||
@@ -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"
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
name: Transfer U-Boot to RAM
|
name: Transfer, Write and Verify U-Boot
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
@@ -11,6 +11,6 @@ jobs:
|
|||||||
- name: Checkout Repository
|
- name: Checkout Repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Transfer firmware and verify RAM contents
|
- name: Transfer firmware, write SPI flash and verify read-back
|
||||||
run: |
|
run: |
|
||||||
/usr/bin/python3 scripts/serial_command.py transfer
|
/usr/bin/python3 scripts/serial_command.py transfer
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
Place `u-boot-sunxi-with-spl.bin` in this directory before running the
|
|
||||||
Transfer U-Boot to RAM workflow.
|
|
||||||
|
|
||||||
The existing TFTP server (`serverip` in U-Boot) must serve this directory
|
|
||||||
as its TFTP root, so the file is available as `u-boot-sunxi-with-spl.bin`.
|
|
||||||
Checking out this repository alone does not publish files over TFTP.
|
|
||||||
|
|
||||||
The workflow uses the current U-Boot network settings. It verifies the
|
|
||||||
transferred size and the first 32 bytes against this local file. It does
|
|
||||||
not erase or write SPI flash, save the environment, or boot the image.
|
|
||||||
دودویی (BIN)
فایل باینری نشان داده نشده است.
دودویی (BIN)
فایل باینری نشان داده نشده است.
دودویی (BIN)
فایل باینری نشان داده نشده است.
Executable
دودویی (BIN)
فایل باینری نشان داده نشده است.
@@ -82,12 +82,25 @@ class UBoot:
|
|||||||
return output
|
return output
|
||||||
|
|
||||||
|
|
||||||
def transfer(cli, firmware):
|
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()
|
image = firmware.read_bytes()
|
||||||
if not 32 <= len(image) <= 0x02000000:
|
if not dump_size <= len(image) <= limit:
|
||||||
raise RuntimeError("Firmware must contain at least 32 bytes and fit RAM at 0x42000000")
|
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(
|
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)
|
||||||
@@ -97,25 +110,49 @@ 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; no flash write performed.")
|
print(f"\nTransfer verified: size and first {dump_size} bytes match.")
|
||||||
|
cli.command("sf probe 0:0", r"^SF: Detected .+", timeout=20)
|
||||||
|
cli.command(
|
||||||
|
f"sf write {address:#x} {offset:#x} ${{filesize}}",
|
||||||
|
rf"^SF: {len(image)} bytes @ {offset:#x} Written: OK\s*$", timeout=120,
|
||||||
|
)
|
||||||
|
cli.command(
|
||||||
|
f"sf read 0x42800000 {offset:#x} ${{filesize}}",
|
||||||
|
rf"^SF: {len(image)} bytes @ {offset:#x} Read: OK\s*$", timeout=120,
|
||||||
|
)
|
||||||
|
output = cli.command(
|
||||||
|
f"cmp.b {address:#x} 0x42800000 ${{filesize}}",
|
||||||
|
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)
|
||||||
|
if compared != [str(len(image))]:
|
||||||
|
raise RuntimeError("Flash comparison byte count differs from firmware size")
|
||||||
|
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", "transfer-rootfs"), 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)
|
||||||
|
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()
|
args = parser.parse_args()
|
||||||
if args.mode == "transfer" and not args.firmware.is_file():
|
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 = "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", "transfer-rootfs") 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:
|
||||||
@@ -125,8 +162,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-rootfs"):
|
||||||
transfer(cli, args.firmware)
|
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
|
return
|
||||||
cli.command("version", r"^U-Boot \d")
|
cli.command("version", r"^U-Boot \d")
|
||||||
cli.command(
|
cli.command(
|
||||||
|
|||||||
مرجع در شماره جدید
مسدود کردن کاربر