Files
gps/soc/software/tools/make_flash_image.py
T
2026-07-12 11:01:51 +03:00

114 lines
3.6 KiB
Python
Executable File

#!/usr/bin/env python3
import argparse
import json
import re
import struct
import subprocess
import zlib
from pathlib import Path
BOOT_IMAGE_MAGIC = 0x54425652
BOOT_IMAGE_VERSION = 1
BOOT_HEADER_SIZE = 64
def parse_int(value):
return int(value, 0)
def run(cmd):
return subprocess.check_output(cmd, text=True)
def elf_entry(readelf, elf):
text = run([readelf, "-h", str(elf)])
match = re.search(r"Entry point address:\s+(0x[0-9a-fA-F]+)", text)
if not match:
raise SystemExit(f"could not parse ELF entry from {elf}")
return int(match.group(1), 16)
def elf_load_addr(readelf, elf):
text = run([readelf, "-l", str(elf)])
pattern = re.compile(
r"LOAD\s+0x[0-9a-fA-F]+\s+0x[0-9a-fA-F]+\s+"
r"(0x[0-9a-fA-F]+)\s*\n\s+"
r"(0x[0-9a-fA-F]+)\s+(0x[0-9a-fA-F]+)",
re.MULTILINE,
)
matches = list(pattern.finditer(text))
if not matches:
raise SystemExit(f"could not parse LOAD segment from {elf}")
return min(int(match.group(1), 16) for match in matches)
def main():
parser = argparse.ArgumentParser(description="Create VCU118 Rocket flash boot image")
parser.add_argument("--elf", required=True)
parser.add_argument("--out", required=True)
parser.add_argument("--payload-out")
parser.add_argument("--manifest-out")
parser.add_argument("--flash-offset", type=parse_int, required=True)
parser.add_argument("--load-addr", type=parse_int)
parser.add_argument("--entry", type=parse_int)
parser.add_argument("--objcopy", default="/tools/toolchains/rvtc/bin/riscv64-unknown-elf-objcopy")
parser.add_argument("--readelf", default="/tools/toolchains/rvtc/bin/riscv64-unknown-elf-readelf")
args = parser.parse_args()
elf = Path(args.elf)
out = Path(args.out)
payload_out = Path(args.payload_out) if args.payload_out else out.with_suffix(".payload.bin")
manifest_out = Path(args.manifest_out) if args.manifest_out else out.with_suffix(".json")
out.parent.mkdir(parents=True, exist_ok=True)
payload_out.parent.mkdir(parents=True, exist_ok=True)
manifest_out.parent.mkdir(parents=True, exist_ok=True)
subprocess.check_call([args.objcopy, "-O", "binary", str(elf), str(payload_out)])
payload = payload_out.read_bytes()
entry = args.entry if args.entry is not None else elf_entry(args.readelf, elf)
load_addr = args.load_addr if args.load_addr is not None else elf_load_addr(args.readelf, elf)
payload_flash_offset = args.flash_offset + BOOT_HEADER_SIZE
crc = zlib.crc32(payload) & 0xFFFFFFFF
header_words = [
BOOT_IMAGE_MAGIC,
BOOT_IMAGE_VERSION,
BOOT_HEADER_SIZE,
0,
payload_flash_offset,
load_addr,
entry,
len(payload),
crc,
0, 0, 0, 0, 0, 0, 0,
]
out.write_bytes(struct.pack("<16I", *header_words) + payload)
manifest = {
"elf": str(elf),
"image": str(out),
"payload": str(payload_out),
"flash_offset": f"0x{args.flash_offset:08x}",
"payload_flash_offset": f"0x{payload_flash_offset:08x}",
"load_addr": f"0x{load_addr:08x}",
"entry": f"0x{entry:08x}",
"size": len(payload),
"crc32": f"0x{crc:08x}",
}
manifest_out.write_text(json.dumps(manifest, indent=2) + "\n")
print(f"image: {out}")
print(f"flash_offset: 0x{args.flash_offset:08x}")
print(f"payload_flash_offset: 0x{payload_flash_offset:08x}")
print(f"load_addr: 0x{load_addr:08x}")
print(f"entry: 0x{entry:08x}")
print(f"size: {len(payload)}")
print(f"crc32: 0x{crc:08x}")
if __name__ == "__main__":
main()