Files
lumia-emulator/tools/mkimage.py
T
2026-09-11 08:16:25 +00:00

134 lines
6.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""mkimage.py — сборка emmc.img с РЕАЛЬНОЙ GPT RM-1127 (33 раздела).
Layout: Boot1 4M + Boot2 4M + RPMB 4M + User 15154944 секторов.
Пока разделы пустые (нули) — контент из FFU payload будет следующим шагом.
Использование: ./tools/mkimage.py images/emmc.img
"""
import struct
import sys
import uuid
import zlib
SECTOR = 512
BOOT_MB = 4
RPMB_MB = 4
USER_SECTORS = 15154944 # MinSectorCount из FFU
# QEMU 6.2 sd-card требует power-of-2 размер: добиваем файл до 8GiB.
# GPT (primary+backup) остается на РЕАЛЬНЫХ смещениях User-области,
# хвост после User — нули (Windows увидит только primary GPT, WIP-допущение).
FILE_SIZE = 8 * 1024 * 1024 * 1024
BASIC = "ebd0a0a2-b9e5-4433-87c0-68b6b72699c7"
# (name, lba0, lba1, type_guid) — из tools/ffu_parse.py по orig FFU
PARTS = [
("DPP", 4096, 20479, BASIC),
("MODEM_FSG", 20480, 23551, "638ff8e2-22c9-e33b-8f5d-0e81686a68cb"),
("MODEM_FS1", 24576, 27647, "ebbeadaf-22c9-e33b-8f5d-0e81686a68cb"),
("MODEM_FS2", 28672, 31743, "0a288b1f-22c9-e33b-8f5d-0e81686a68cb"),
("MODEM_FSC", 32768, 32799, "57b90a16-22c9-e33b-8f5d-0e81686a68cb"),
("DDR", 36864, 36927, "20a0c19c-286a-42fa-9ce7-f64c3226a794"),
("LogFS", 40960, 73727, "bc0330eb-3410-4951-a617-03898dbe3372"),
("SSD", 73728, 73759, "2c86e742-745e-4fdd-bfd8-b6a7ac638772"),
("UEFI_BS_NV", 77824, 78335, "f0b4f48b-aeba-4ecf-9142-5dc30cdc3e77"),
("UEFI_RT_NV", 81920, 82431, "6bb94537-7d1c-44d0-9dfe-6d77c011dbfc"),
("BOOTMODE", 86016, 86047, "0e91ab96-8339-4ae4-a310-ed94357fd7d0"),
("SBL1", 90112, 91135, "dea0ba2c-cbdd-4805-b4f9-f428251c3e98"),
("DBI", 94208, 94271, "d4e0d938-b7fa-48c1-9d21-bc5ed5c4b203"),
("UEFI", 98304, 102399, "400ffdcd-22e0-47e7-9a23-f16ed9382388"),
("RPM", 102400, 103423, "098df793-d712-413d-9d4e-89d711772228"),
("QSEE", 106496, 108543, "a053aa7f-40b8-4b1c-ba08-2f68ac71a4f4"),
("QHEE", 110592, 111615, "e1a6a689-0c8d-4cc6-b4e8-55a4320fbd8a"),
("WINSECAPP", 114688, 115711, "69b4201f-a5ad-45eb-9f49-45b38ccdaef5"),
("TZAPPS", 118784, 151551, "14d11c40-2a3d-4f97-882d-103a1ec09333"),
("BACKUP_SBL1", 151552, 152575, "a3381699-350c-465e-bd5d-fa3ab901a39a"),
("BACKUP_DBI", 155648, 155711, "a3381699-350c-465e-bd5d-fa3ab901a39a"),
("BACKUP_UEFI", 159744, 163839, "a3381699-350c-465e-bd5d-fa3ab901a39a"),
("BACKUP_RPM", 163840, 164863, "a3381699-350c-465e-bd5d-fa3ab901a39a"),
("BACKUP_QSEE", 167936, 169983, "a3381699-350c-465e-bd5d-fa3ab901a39a"),
("BACKUP_QHEE", 172032, 173055, "a3381699-350c-465e-bd5d-fa3ab901a39a"),
("BACKUP_WINSECAPP", 176128, 177151, "a3381699-350c-465e-bd5d-fa3ab901a39a"),
("BACKUP_TZAPPS", 180224, 212991, "a3381699-350c-465e-bd5d-fa3ab901a39a"),
("PLAT", 212992, 229375, "543c031a-4cb6-4897-bffe-4b485768a8ad"),
("EFIESP", 229376, 360447, BASIC),
("MMOS", 360448, 372735, BASIC),
("SEC", 372736, 372767, "303e6ac3-af15-4c54-9e9b-d9a8fbecf401"),
("MainOS", 376832, 4089855, BASIC),
("Data", 4096000, 15150847, BASIC),
]
def gpt_header(nent, lba_backup, disk_guid, crc_entries, cur=1):
h = struct.pack("<8sIIIIQQQQ16sQIII",
b"EFI PART", 0x10000, 92, 0, 0, cur, lba_backup,
34, USER_SECTORS - 34,
disk_guid.bytes_le, 2, nent, 128, crc_entries)
crc = zlib.crc32(h) & 0xFFFFFFFF
return struct.pack("<8sIIIIQQQQ16sQIII",
b"EFI PART", 0x10000, 92, crc, 0, cur, lba_backup,
34, USER_SECTORS - 34,
disk_guid.bytes_le, 2, nent, 128, crc_entries)
def main():
out = sys.argv[-1] if not sys.argv[-1].startswith("-") else "images/emmc.img"
user_src = None
if "--user" in sys.argv:
user_src = sys.argv[sys.argv.index("--user") + 1]
pre = (BOOT_MB * 2 + RPMB_MB) * 1024 * 1024
total = FILE_SIZE
assert pre + USER_SECTORS * SECTOR <= total
print(f"[mkimage] {out}: boot {BOOT_MB}M x2 + rpmb {RPMB_MB}M + "
f"user {USER_SECTORS} sectors" +
(f" + content {user_src}" if user_src else " (zero)"))
with open(out, "wb") as f:
f.truncate(total) # sparse
uoff = pre
with open(out, "wb") as f:
f.truncate(total) # sparse
uoff = pre
# protective MBR
mbr = bytearray(512)
mbr[446:462] = struct.pack("<B3sB3sII", 0, b"\x00\x02\x00", 0xEE,
b"\xFF\xFF\xFF",
1, USER_SECTORS - 1)
mbr[510:512] = b"\x55\xAA"
f.seek(uoff)
f.write(mbr)
# entries
ent = bytearray(128 * 128)
for i, (name, a, b, t) in enumerate(PARTS):
e = struct.pack("<16s16sQQQ", uuid.UUID(t).bytes_le,
uuid.uuid4().bytes_le, a, b, 0)
e += name.encode("utf-16-le")[:72].ljust(72, b"\x00")
ent[i * 128:(i + 1) * 128] = e
crc_e = zlib.crc32(ent) & 0xFFFFFFFF
disk = uuid.uuid4()
f.seek(uoff + 512)
f.write(gpt_header(128, USER_SECTORS - 1, disk, crc_e))
f.seek(uoff + 1024)
f.write(ent)
# backup GPT at end of User
f.seek(uoff + (USER_SECTORS - 33) * SECTOR)
f.write(ent)
f.seek(uoff + (USER_SECTORS - 1) * SECTOR)
f.write(gpt_header(128, 1, disk, crc_e,
cur=USER_SECTORS - 1))
if user_src:
print(f"[mkimage] copying User content (keeps GPT in place)...")
with open(user_src, "rb") as u:
# copy in 128M chunks, skipping GPT areas (LBA 0..33, backup)
u.seek(34 * SECTOR)
f.seek(uoff + 34 * SECTOR)
left = (USER_SECTORS - 33) * SECTOR - 34 * SECTOR
while left > 0:
d = u.read(min(left, 134217728))
if not d:
break
f.write(d)
left -= len(d)
print(f"[mkimage] OK: {len(PARTS)} partitions, primary+backup GPT, CRC ok")
if __name__ == "__main__":
main()