Files
retroSoC/scripts/package_hp_boot.py
T
maksyuki 0e36b6a82f feat: introduce RV64 support and related tooling for HP workloads
- Added build_hp_rtthread.py for building the RT-Thread kernel with RV64 support.
- Updated build_hp_smoke.py to target RV64 architecture and modified output filenames.
- Modified generate_vexiiriscv.py to reflect RV64 configuration and memory management.
- Created hp_tools.py for shared utilities related to RV64 builds.
- Enhanced package_hp_boot.py to package RV64 workloads and updated versioning.
- Implemented run_hp_sim.py for executing and validating HP workloads with specific markers.
- Developed setup_hp_rtthread.py for installing RT-Thread source and environment setup.
- Updated GenerateRetroSocHp.scala to generate RV64 application cores.
- Enhanced tests for HP boot bundles, platform specifications, and tool utilities to accommodate RV64 changes.
- Adjusted test cases to validate new workload types and ensure compatibility with RV64 architecture.
2026-09-26 15:47:26 +08:00

143 lines
4.6 KiB
Python
Executable File

#!/usr/bin/env python3
"""Package LP firmware and a typed RV64 HP workload into a V2 flash image."""
from __future__ import annotations
import argparse
import hashlib
import json
import struct
import zlib
from pathlib import Path
FLASH_SIZE = 16 * 1024 * 1024
BUNDLE_OFFSET = 1 * 1024 * 1024
PAYLOAD_ALIGNMENT = 4096
MAGIC = 0x50485352
VERSION = 2
REQUIRED = 1
HEADER = struct.Struct("<8I")
ENTRY = struct.Struct("<6I")
ARTIFACTS = (
(1, "fw_jump.bin", 0x38000000, 512 * 1024),
(2, "retrosoc_hp.dtb", 0x38080000, 64 * 1024),
(3, "Image", 0x38400000, 12 * 1024 * 1024),
(4, "rootfs.cpio", 0x39000000, 8 * 1024 * 1024),
)
HEADER_SIZE = HEADER.size + (ENTRY.size * len(ARTIFACTS))
WORKLOADS = {"linux": 1, "smoke": 2, "rtthread": 3}
def artifacts_for(workload: str) -> tuple[tuple[int, str, int, int], ...]:
if workload == "linux":
return ARTIFACTS
if workload not in WORKLOADS:
raise ValueError(f"unsupported HP workload: {workload}")
name = "hp_smoke.bin" if workload == "smoke" else "rtthread.bin"
return ((5, name, 0x38000000, 512 * 1024),)
def align_up(value: int, alignment: int) -> int:
return (value + alignment - 1) & ~(alignment - 1)
def sha256(data: bytes) -> str:
return hashlib.sha256(data).hexdigest()
def package(args: argparse.Namespace) -> None:
workload = getattr(args, "workload", "linux")
artifacts = artifacts_for(workload)
firmware = args.firmware.read_bytes()
if len(firmware) > BUNDLE_OFFSET:
raise ValueError(
f"LP firmware is {len(firmware)} bytes; bundle starts at {BUNDLE_OFFSET}"
)
payload_offset = align_up(BUNDLE_OFFSET + HEADER_SIZE, PAYLOAD_ALIGNMENT)
entries: list[bytes] = []
payloads: list[tuple[int, bytes]] = []
artifact_manifest: dict[str, object] = {}
cursor = payload_offset
for kind, name, load_address, maximum in artifacts:
data = (args.images / name).read_bytes()
if not data or len(data) > maximum:
raise ValueError(f"{name} size {len(data)} is outside 1..{maximum} bytes")
crc32 = zlib.crc32(data) & 0xFFFFFFFF
entries.append(ENTRY.pack(kind, cursor, load_address, len(data), crc32, REQUIRED))
payloads.append((cursor, data))
artifact_manifest[name] = {
"crc32": f"0x{crc32:08X}",
"flash_offset": f"0x{cursor:08X}",
"load_address": f"0x{load_address:08X}",
"sha256": sha256(data),
"size_bytes": len(data),
}
cursor = align_up(cursor + len(data), PAYLOAD_ALIGNMENT)
if cursor > FLASH_SIZE:
raise ValueError(f"HP boot image needs {cursor} bytes; flash capacity is {FLASH_SIZE}")
total_size = cursor - BUNDLE_OFFSET
header = HEADER.pack(
MAGIC,
VERSION,
HEADER_SIZE,
len(entries),
total_size,
0,
REQUIRED,
WORKLOADS[workload],
) + b"".join(entries).ljust(HEADER_SIZE - HEADER.size, b"\0")
header_crc32 = zlib.crc32(header) & 0xFFFFFFFF
header = HEADER.pack(
MAGIC,
VERSION,
HEADER_SIZE,
len(entries),
total_size,
header_crc32,
REQUIRED,
WORKLOADS[workload],
) + b"".join(entries).ljust(HEADER_SIZE - HEADER.size, b"\0")
image = bytearray(b"\xFF" * cursor)
image[: len(firmware)] = firmware
image[BUNDLE_OFFSET : BUNDLE_OFFSET + len(header)] = header
for offset, data in payloads:
image[offset : offset + len(data)] = data
args.output.parent.mkdir(parents=True, exist_ok=True)
args.output.write_bytes(image)
manifest = {
"schema_version": 1,
"format": "retrosoc-hp-boot-bundle-v2",
"workload": workload,
"xlen": 64,
"bundle_offset": f"0x{BUNDLE_OFFSET:08X}",
"flash_capacity_bytes": FLASH_SIZE,
"header_crc32": f"0x{header_crc32:08X}",
"image_sha256": sha256(image),
"image_size_bytes": len(image),
"lp_firmware_size_bytes": len(firmware),
"artifacts": artifact_manifest,
}
args.manifest.parent.mkdir(parents=True, exist_ok=True)
args.manifest.write_text(
json.dumps(manifest, indent=2, sort_keys=True) + "\n", encoding="utf-8"
)
def main() -> None:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--firmware", type=Path, required=True)
parser.add_argument("--images", type=Path, required=True)
parser.add_argument("--output", type=Path, required=True)
parser.add_argument("--manifest", type=Path, required=True)
parser.add_argument("--workload", choices=WORKLOADS, default="linux")
package(parser.parse_args())
if __name__ == "__main__":
main()