اضافه شدن قابلیت تشخیص حافظه

This commit is contained in:
2026-11-09 21:05:20 +03:30
والد b452fceb82
کامیت 793504fc78
4فایلهای تغییر یافته به همراه64 افزوده شده و 29 حذف شده
@@ -1,4 +1,4 @@
name: Erase Entire 32 MiB SPI Flash
name: Detect and Erase Entire SPI Flash
on:
workflow_dispatch:
@@ -2,11 +2,6 @@ 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:
@@ -16,8 +11,6 @@ jobs:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Transfer RootFS, write SPI flash and verify read-back
env:
ROOTFS_PARTITION_SIZE: ${{ inputs.rootfs_size }}
- name: Detect flash, transfer RootFS and verify read-back
run: |
/usr/bin/python3 scripts/serial_command.py transfer-rootfs --rootfs-size "$ROOTFS_PARTITION_SIZE"
/usr/bin/python3 scripts/serial_command.py transfer-rootfs
+28 -5
مشاهده پرونده
@@ -1,6 +1,29 @@
Place firmware files here and serve this directory as the existing TFTP
server root. Checkout alone does not publish files over TFTP.
The separate `Erase Entire 32 MiB SPI Flash` workflow erases offsets
0x0 through 0x1ffffff, including all firmware and any saved environment.
It requires a successful 32 MiB flash probe, checks the erase/read command
results, and verifies that the first 256 bytes are FF. This sample does
not verify every byte of the flash. No automatic retries are performed.
Every transfer starts with sf probe 0:0. The reported total capacity must
be exactly 16 or 32 MiB; an unknown or ambiguous result stops execution.
The selected offsets and maximum sizes (hex bytes) are:
| File | 16 MiB offset / maximum | 32 MiB offset / maximum |
| --- | --- | --- |
| u-boot-sunxi-with-spl.bin | 0 / 0x100000 | 0 / 0x200000 |
| sun8i-v3s-licheepi-zero-dock.dtb | 0x100000 / 0x10000 | 0x200000 / 0x110000 |
| zImage | 0x110000 / 0x500000 | 0x310000 / 0x500000 |
| rootfs.squashfs | 0x610000 / 0x900000 | 0x810000 / 0x17f0000 |
The 32 MiB layout allocates the remainder of flash to RootFS. These are
selected project layouts, not partition tables read from the chip. DTB
partitions and bootcmd must match the selected layout. A smaller actual
RootFS region can be specified with --rootfs-size; larger overrides fail.
Transfers reset and verify filesize=0 before TFTP, require successful
transfer output and status, and compare the hexadecimal filesize with the
local file and transfer count. First 32 bytes (U-Boot/DTB) or 64 bytes
(Kernel/RootFS) are compared with the local file. Writes are read back at
0x42800000 and compared in full. No automatic erase or retry is performed
in transfer workflows. Flash must be erased before programming as needed.
The separate erase workflow detects capacity and erases the entire chip,
including firmware and saved environment. It verifies only the first 256
bytes as FF, not every byte. No workflow automatically reboots the board.
+33 -14
مشاهده پرونده
@@ -82,16 +82,37 @@ class UBoot:
return output
LAYOUTS = {
16: {"uboot": (0, 0x100000), "dtb": (0x100000, 0x10000),
"kernel": (0x110000, 0x500000), "rootfs": (0x610000, 0x900000)},
32: {"uboot": (0, 0x200000), "dtb": (0x200000, 0x110000),
"kernel": (0x310000, 0x500000), "rootfs": (0x810000, 0x17f0000)},
}
def detect_flash(cli):
output = cli.command("sf probe 0:0", r"^SF: Detected .+", timeout=20)
capacities = re.findall(r"^SF: Detected .*\btotal (\d+) MiB\s*$", output, re.MULTILINE)
if len(capacities) != 1 or int(capacities[0]) not in LAYOUTS:
raise RuntimeError("Unsupported or ambiguous flash capacity; expected 16 or 32 MiB")
capacity = int(capacities[0])
print(f"\nDetected {capacity} MiB ({capacity * 8} Mbit); selecting matching flash layout.")
return capacity
def transfer(cli, firmware, *, dtb=False, kernel=False, rootfs=False, rootfs_size=None):
capacity = detect_flash(cli)
part = "rootfs" if rootfs else "kernel" if kernel else "dtb" if dtb else "uboot"
offset, limit = LAYOUTS[capacity][part]
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"
dump_size = 64 if (kernel or rootfs) else 32
filename = {"uboot": "u-boot-sunxi-with-spl.bin", "dtb": "sun8i-v3s-licheepi-zero-dock.dtb",
"kernel": "zImage", "rootfs": "rootfs.squashfs"}[part]
if rootfs_size is not None and rootfs:
if not 64 <= rootfs_size <= limit:
raise RuntimeError("RootFS size override exceeds the selected partition or is invalid")
limit = rootfs_size
print(f"Selected {part}: flash offset {offset:#x}, maximum size {limit:#x}")
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")
@@ -122,7 +143,6 @@ def transfer(cli, firmware, *, dtb=False, kernel=False, rootfs=False, rootfs_siz
if dumped != image[:dump_size]:
raise RuntimeError(f"First {dump_size} bytes in RAM differ from the local firmware file")
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,
@@ -142,10 +162,11 @@ def transfer(cli, firmware, *, dtb=False, kernel=False, rootfs=False, rootfs_siz
def erase_flash(cli):
cli.command("sf probe 0:0", r"^SF: Detected .+total 32 MiB\s*$", timeout=20)
capacity = detect_flash(cli)
length = capacity * 1024 * 1024
cli.command(
"sf erase 0x0 0x2000000",
r"^SF: 33554432 bytes @ 0x0 Erased: OK\s*$", timeout=600,
f"sf erase 0x0 {length:#x}",
rf"^SF: {length} bytes @ 0x0 Erased: OK\s*$", timeout=600,
)
cli.command(
"sf read 0x42800000 0x0 0x100",
@@ -184,8 +205,6 @@ def main():
parser.add_argument("--rootfs-size", type=lambda value: int(value, 0), help="Actual RootFS partition size in bytes (decimal or 0x-prefixed hex)")
parser.add_argument("--confirm-squashfs-mtdblock3", action="store_true", help="Confirm actual RootFS is SquashFS on mtdblock3 and set bootargs")
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 = "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