اضافه شدن قابلیت تشخیص حافظه
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
name: Erase Entire 32 MiB SPI Flash
|
name: Detect and Erase Entire SPI Flash
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|||||||
@@ -2,11 +2,6 @@ name: Transfer, Write and Verify RootFS
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
|
||||||
rootfs_size:
|
|
||||||
description: 'Actual RootFS partition size in bytes (decimal or 0x-prefixed hex)'
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
rootfs-transfer:
|
rootfs-transfer:
|
||||||
@@ -16,8 +11,6 @@ jobs:
|
|||||||
- name: Checkout Repository
|
- name: Checkout Repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Transfer RootFS, write SPI flash and verify read-back
|
- name: Detect flash, transfer RootFS and verify read-back
|
||||||
env:
|
|
||||||
ROOTFS_PARTITION_SIZE: ${{ inputs.rootfs_size }}
|
|
||||||
run: |
|
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
|
Every transfer starts with sf probe 0:0. The reported total capacity must
|
||||||
0x0 through 0x1ffffff, including all firmware and any saved environment.
|
be exactly 16 or 32 MiB; an unknown or ambiguous result stops execution.
|
||||||
It requires a successful 32 MiB flash probe, checks the erase/read command
|
The selected offsets and maximum sizes (hex bytes) are:
|
||||||
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.
|
| 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.
|
||||||
|
|||||||
@@ -82,16 +82,37 @@ class UBoot:
|
|||||||
return output
|
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):
|
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
|
address = 0x41000000 if (dtb or rootfs) else 0x42000000
|
||||||
offset = 0x310000 if kernel else (0x200000 if dtb else 0)
|
dump_size = 64 if (kernel or rootfs) else 32
|
||||||
limit = 0x500000 if kernel else (0x110000 if dtb else 0x200000)
|
filename = {"uboot": "u-boot-sunxi-with-spl.bin", "dtb": "sun8i-v3s-licheepi-zero-dock.dtb",
|
||||||
dump_size = 64 if kernel else 32
|
"kernel": "zImage", "rootfs": "rootfs.squashfs"}[part]
|
||||||
filename = "zImage" if kernel else ("sun8i-v3s-licheepi-zero-dock.dtb" if dtb else "u-boot-sunxi-with-spl.bin")
|
if rootfs_size is not None and rootfs:
|
||||||
if rootfs:
|
if not 64 <= rootfs_size <= limit:
|
||||||
if rootfs_size is None or rootfs_size < 64:
|
raise RuntimeError("RootFS size override exceeds the selected partition or is invalid")
|
||||||
raise RuntimeError("Actual RootFS partition size is required (at least 64 bytes)")
|
limit = rootfs_size
|
||||||
offset, limit, dump_size, filename = 0x810000, rootfs_size, 64, "rootfs.squashfs"
|
print(f"Selected {part}: flash offset {offset:#x}, maximum size {limit:#x}")
|
||||||
image = firmware.read_bytes()
|
image = firmware.read_bytes()
|
||||||
if not dump_size <= len(image) <= limit:
|
if not dump_size <= len(image) <= limit:
|
||||||
raise RuntimeError(f"Firmware size must be between {dump_size} and {limit:#x} bytes")
|
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]:
|
if dumped != image[:dump_size]:
|
||||||
raise RuntimeError(f"First {dump_size} 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(f"\nTransfer verified: size and first {dump_size} 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(
|
cli.command(
|
||||||
f"sf write {address:#x} {offset:#x} ${{filesize}}",
|
f"sf write {address:#x} {offset:#x} ${{filesize}}",
|
||||||
rf"^SF: {len(image)} bytes @ {offset:#x} Written: OK\s*$", timeout=120,
|
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):
|
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(
|
cli.command(
|
||||||
"sf erase 0x0 0x2000000",
|
f"sf erase 0x0 {length:#x}",
|
||||||
r"^SF: 33554432 bytes @ 0x0 Erased: OK\s*$", timeout=600,
|
rf"^SF: {length} bytes @ 0x0 Erased: OK\s*$", timeout=600,
|
||||||
)
|
)
|
||||||
cli.command(
|
cli.command(
|
||||||
"sf read 0x42800000 0x0 0x100",
|
"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("--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")
|
parser.add_argument("--confirm-squashfs-mtdblock3", action="store_true", help="Confirm actual RootFS is SquashFS on mtdblock3 and set bootargs")
|
||||||
args = parser.parse_args()
|
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:
|
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")
|
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
|
args.firmware = Path(__file__).resolve().parent.parent / "firmware" / filename
|
||||||
|
|||||||
مرجع در شماره جدید
مسدود کردن کاربر