ورک فلو نصب u-boot

This commit is contained in:
2026-11-09 20:43:58 +03:30
والد d35c3cfd6b
کامیت 3cfe096d81
3فایلهای تغییر یافته به همراه74 افزوده شده و 5 حذف شده
@@ -0,0 +1,16 @@
name: Transfer U-Boot to RAM
on:
workflow_dispatch:
jobs:
uboot-transfer:
runs-on: serial-runner
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Transfer firmware and verify RAM contents
run: |
/usr/bin/python3 scripts/serial_command.py transfer
+10
مشاهده پرونده
@@ -0,0 +1,10 @@
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.
+48 -5
مشاهده پرونده
@@ -4,6 +4,7 @@ import fcntl
import re
import sys
import time
from pathlib import Path
import serial
@@ -55,7 +56,7 @@ class UBoot:
self.prompt = candidate
print("\nU-Boot-style CLI prompt detected: " + candidate, flush=True)
def command(self, command, expected=None, timeout=10):
def command(self, command, expected=None, timeout=10, allow_missing=()):
print("\n>>> " + command, flush=True)
self.port.write((command + "\r").encode())
self.port.flush()
@@ -65,21 +66,57 @@ class UBoot:
self.port.flush()
status, _ = self.read_prompt(5)
codes = re.findall(r"(?m)^__UBOOT_STATUS_ (\d+) *$", status)
if codes != ["0"]:
# Only the initial environment inspection may report unset variables.
missing_pattern = r'^## Error: "(' + "|".join(map(re.escape, allow_missing)) + r')" not defined$'
missing = re.findall(missing_pattern, output, re.MULTILINE) if allow_missing else []
checked_output = re.sub(missing_pattern, "", output, flags=re.MULTILINE) if missing else output
if codes != ["0"] and not (codes == ["1"] and missing):
raise RuntimeError("Command failed or its exit status could not be verified: " + command)
if ERROR.search(output):
if ERROR.search(checked_output):
raise RuntimeError("Error in command response: " + command)
if expected and not re.search(expected, output, re.MULTILINE):
raise RuntimeError("Expected response missing: " + command)
if missing:
print("\nInitially unset: " + ", ".join(missing), flush=True)
print("\nVerified: " + command, flush=True)
return output
def transfer(cli, firmware):
image = firmware.read_bytes()
if not 32 <= len(image) <= 0x02000000:
raise RuntimeError("Firmware must contain at least 32 bytes and fit RAM at 0x42000000")
output = cli.command(
"tftp 0x42000000 u-boot-sunxi-with-spl.bin",
r"^Bytes transferred = \d+", timeout=120,
)
transferred = re.findall(r"^Bytes transferred = (\d+)", output, re.MULTILINE)
if transferred != [str(len(image))]:
raise RuntimeError("TFTP byte count differs from the local firmware file")
output = cli.command("echo ${filesize}", r"^[0-9a-fA-F]+$")
sizes = re.findall(r"^([0-9a-fA-F]+)$", output, re.MULTILINE)
if len(sizes) != 1 or int(sizes[0], 16) != len(image):
raise RuntimeError("U-Boot filesize differs from the local firmware file")
output = cli.command("md.b 0x42000000 0x20", r"^42000000:")
dumped = bytearray()
for address in ("42000000", "42000010"):
rows = re.findall(r"^" + address + r":((?: [0-9a-fA-F]{2}){16})(?:\s|$)", output, re.MULTILINE)
if len(rows) != 1:
raise RuntimeError("Missing or invalid memory dump at " + address)
dumped.extend(bytes.fromhex(rows[0]))
if dumped != image[:32]:
raise RuntimeError("First 32 bytes in RAM differ from the local firmware file")
print("\nTransfer verified: size and first 32 bytes match; no flash write performed.")
def main():
parser = argparse.ArgumentParser()
parser.add_argument("mode", choices=("check", "configure"), default="check", nargs="?")
parser.add_argument("mode", choices=("check", "configure", "transfer"), default="check", nargs="?")
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")
args = parser.parse_args()
if args.mode == "transfer" 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:
fcntl.flock(lock, fcntl.LOCK_EX | fcntl.LOCK_NB)
@@ -88,8 +125,14 @@ def main():
cli.detect()
if args.mode == "check":
return
if args.mode == "transfer":
transfer(cli, args.firmware)
return
cli.command("version", r"^U-Boot \d")
cli.command("printenv ipaddr serverip ethaddr bootcmd bootargs")
cli.command(
"printenv ipaddr serverip ethaddr bootcmd bootargs",
allow_missing=("ipaddr", "serverip", "ethaddr", "bootcmd", "bootargs"),
)
cli.command("setenv ipaddr 192.168.75.100")
cli.command("printenv ipaddr", r"^ipaddr=192\.168\.75\.100$")
cli.command("setenv serverip 192.168.75.247")