54 lines
1.7 KiB
Python
54 lines
1.7 KiB
Python
#!/usr/bin/env python3
|
|
"""Pack the bundled binaries into the boot capsule (boot/system.img) — the
|
|
single file the EFI loader reads in one sequential pass, which is the only
|
|
shape firmware file I/O is fast at (a per-file tree walk measured minutes on
|
|
real firmware). The format is the v2 initial_ramdisk (system/initial-ramdisk.zig):
|
|
entries named by full FHS path, so the running system is identical whether the
|
|
loader read the capsule or walked the tree.
|
|
|
|
Usage: pack-system-image.py <out.img> [<path> <file>]...
|
|
Layout (little-endian): Header{magic "DNR2", count}, Entry{name[64], offset, len}*N, blobs.
|
|
"""
|
|
import struct
|
|
import sys
|
|
|
|
MAGIC = 0x32524E44 # "DNR2"
|
|
HEADER = struct.Struct("<II")
|
|
ENTRY = struct.Struct("<64sQQ")
|
|
|
|
|
|
def main() -> int:
|
|
out_path = sys.argv[1]
|
|
rest = sys.argv[2:]
|
|
if len(rest) % 2 != 0:
|
|
sys.stderr.write("usage: pack-system-image.py <out.img> [<path> <file>]...\n")
|
|
return 2
|
|
items = [(rest[i], rest[i + 1]) for i in range(0, len(rest), 2)]
|
|
|
|
table_end = HEADER.size + len(items) * ENTRY.size
|
|
entries = b""
|
|
blobs = []
|
|
offset = table_end
|
|
for path, source in items:
|
|
name = path if path.startswith("/") else "/" + path
|
|
encoded = name.encode("ascii")
|
|
if len(encoded) > 63:
|
|
sys.stderr.write(f"pack-system-image: path too long (>63): {name}\n")
|
|
return 2
|
|
with open(source, "rb") as f:
|
|
data = f.read()
|
|
entries += ENTRY.pack(encoded, offset, len(data))
|
|
blobs.append(data)
|
|
offset += len(data)
|
|
|
|
with open(out_path, "wb") as f:
|
|
f.write(HEADER.pack(MAGIC, len(items)))
|
|
f.write(entries)
|
|
for blob in blobs:
|
|
f.write(blob)
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|