fix: rebalance HX GNSS OTA partitions
This commit is contained in:
@@ -18,6 +18,10 @@ FLASH_TYPE = ROOT / "ql-config/config/QuecFLashType.ini"
|
||||
CHIP_PLATFORM = ROOT / "ql-config/config/CHIP_PLAT.ini"
|
||||
LINKER = ROOT / "ql-application/threadx/config/common/app_linkscript.ld"
|
||||
FS_IMAGE = ROOT / "ql-config/config/EG800AKCN_11LG/customer_fs.bin"
|
||||
DSP_IMAGE = ROOT / "ql-config/soc_platform/CRANELRH/images/DSP_Reduce_SuLog_Buffer/dsp.bin"
|
||||
RF_IMAGE = ROOT / "ql-config/config/EG800AKCN_11LG/rf.bin"
|
||||
GNSS_BOOT_IMAGE = ROOT / "ql-config/config/EG800AKCN_11LG/gnss_boot.pkg"
|
||||
GNSS_FIRM_IMAGE = ROOT / "ql-config/config/EG800AKCN_11LG/gnss_firm.pkg"
|
||||
KERNEL_FLAGS = ROOT / "ql-kernel/threadx/config/common/default_dflags_1602.mk"
|
||||
FOTA_HEADER = ROOT / "ql-application/threadx/common/include/ql_fota.h"
|
||||
BASELINE_HEADER = ROOT / "ql-application/threadx/interface/custom_app/inc/ota_baseline.h"
|
||||
@@ -30,15 +34,15 @@ LEGACY_HTTP_SOURCE = ROOT / "ql-application/threadx/interface/custom_app/http_ao
|
||||
|
||||
FLASH_SIZE = 0x400000
|
||||
EXPECTED = {
|
||||
"app_start": 0x002C2000,
|
||||
"app_size": 0x00073000,
|
||||
"fs_start": 0x00335000,
|
||||
"fs_size": 0x000A0000,
|
||||
"reserved_size": 0x0003B000,
|
||||
"xip_start": 0x802C2000,
|
||||
"app_start": 0x002E5000,
|
||||
"app_size": 0x00060000,
|
||||
"fs_start": 0x00345000,
|
||||
"fs_size": 0x00090000,
|
||||
"xip_start": 0x802E5000,
|
||||
}
|
||||
FBF_HEADER_ALLOWANCE = 8192
|
||||
EXPECTED_FS_SHA256 = "19bd849dbcc6816f6dfffd1e585645a3474a2265f96a926b5dd073f0affb69f9"
|
||||
MINIMUM_SYSTEM_MARGIN = 64 * 1024
|
||||
EXPECTED_FS_SHA256 = "45350804d65fc6ded24caf9b215b71e89f9160d10d4998c5d57d4f4496d6000d"
|
||||
|
||||
|
||||
def fail(message: str) -> None:
|
||||
@@ -76,9 +80,9 @@ def verify_layout() -> None:
|
||||
tail = flattened_tail()
|
||||
sizes = dict(tail)
|
||||
if sizes.get("customer_app") != EXPECTED["app_size"]:
|
||||
fail("customer_app must be 460 KiB")
|
||||
fail("customer_app must be 384 KiB")
|
||||
if sizes.get("customer_fs") != EXPECTED["fs_size"]:
|
||||
fail("customer_fs must be 640 KiB")
|
||||
fail("customer_fs must be 576 KiB")
|
||||
|
||||
suffix = 0
|
||||
starts: dict[str, int] = {}
|
||||
@@ -93,20 +97,15 @@ def verify_layout() -> None:
|
||||
if starts.get("customer_fs") != EXPECTED["fs_start"]:
|
||||
fail(f"customer_fs starts at 0x{starts.get('customer_fs', 0):08X}, expected 0x{EXPECTED['fs_start']:08X}")
|
||||
|
||||
# The system image ends at 0x287000 for this accepted 4 MiB CRANELRH baseline.
|
||||
reserved = EXPECTED["app_start"] - 0x00287000
|
||||
if reserved != EXPECTED["reserved_size"]:
|
||||
fail("reserved partition calculation changed")
|
||||
|
||||
|
||||
def verify_linker() -> None:
|
||||
text = LINKER.read_text(encoding="utf-8")
|
||||
rom = re.search(r"__ROM_START_ADDR\s*=\s*(0x[0-9A-Fa-f]+)", text)
|
||||
maximum = re.search(r"__MAX_ROM_SIZE\s*=\s*(0x[0-9A-Fa-f]+)", text)
|
||||
if not rom or int(rom.group(1), 16) != EXPECTED["xip_start"]:
|
||||
fail("linker ROM address is not 0x802C2000")
|
||||
fail("linker ROM address is not 0x802E5000")
|
||||
if not maximum or int(maximum.group(1), 16) != EXPECTED["app_size"]:
|
||||
fail("linker ROM limit is not the 460 KiB customer_app partition")
|
||||
fail("linker ROM limit is not the 384 KiB customer_app partition")
|
||||
|
||||
|
||||
def verify_fs_image() -> None:
|
||||
@@ -123,8 +122,33 @@ def verify_fs_image() -> None:
|
||||
disk_version, block_size, block_count = struct.unpack_from("<III", image, magic_at + 12)
|
||||
if disk_version >> 16 != 2:
|
||||
fail(f"unsupported LittleFS disk version 0x{disk_version:08X}")
|
||||
if block_size != 4096 or block_count != 160:
|
||||
fail(f"LittleFS geometry is block_size={block_size}, block_count={block_count}; expected 4096/160")
|
||||
if block_size != 4096 or block_count != 144:
|
||||
fail(f"LittleFS geometry is block_size={block_size}, block_count={block_count}; expected 4096/144")
|
||||
|
||||
|
||||
def align_up(value: int, alignment: int) -> int:
|
||||
return (value + alignment - 1) // alignment * alignment
|
||||
|
||||
|
||||
def verify_system_fit(kernel_path: Path) -> None:
|
||||
images = (kernel_path, DSP_IMAGE, RF_IMAGE, GNSS_BOOT_IMAGE, GNSS_FIRM_IMAGE)
|
||||
for path in images:
|
||||
if not path.is_file():
|
||||
fail(f"system image does not exist: {path}")
|
||||
|
||||
# bootloader=88 KiB; system begins with ptable=4 KiB and rd=16 KiB.
|
||||
system_end = (88 + 4 + 16) * 1024
|
||||
for path in images:
|
||||
system_end = align_up(system_end, 4096)
|
||||
system_end += path.stat().st_size
|
||||
system_end = align_up(system_end, 4096)
|
||||
|
||||
margin = EXPECTED["app_start"] - system_end
|
||||
if margin < MINIMUM_SYSTEM_MARGIN:
|
||||
fail(
|
||||
f"system ends at 0x{system_end:08X}; margin before customer_app is "
|
||||
f"{margin} bytes, expected at least {MINIMUM_SYSTEM_MARGIN}"
|
||||
)
|
||||
|
||||
|
||||
def verify_fota_contract() -> None:
|
||||
@@ -143,12 +167,12 @@ def verify_fota_contract() -> None:
|
||||
if symbol not in api:
|
||||
fail(f"SDK FULLOTA2 API {symbol} is missing")
|
||||
identity = BASELINE_HEADER.read_text(encoding="utf-8")
|
||||
if "eg800akcn_11lg-fs640-app2c2000" not in identity:
|
||||
if "eg800akcn_11lg-hxgnss-fs576-app2e5000" not in identity:
|
||||
fail("application layout identity is missing")
|
||||
generated = BUILD_MACRO.read_text(encoding="utf-8", errors="replace")
|
||||
if '#define CUSTOM_APP_OTA_LAYOUT_ID "eg800akcn_11lg-fs640-app2c2000"' not in generated:
|
||||
if '#define CUSTOM_APP_OTA_LAYOUT_ID "eg800akcn_11lg-hxgnss-fs576-app2e5000"' not in generated:
|
||||
fail("generated build macro has the wrong OTA layout identity")
|
||||
if '#define CUSTOM_APP_OTA_BUILD_PROFILE "ota_ready_fs640"' not in generated:
|
||||
if '#define CUSTOM_APP_OTA_BUILD_PROFILE "ota_ready_hxgnss_fs576"' not in generated:
|
||||
fail("generated build macro has the wrong OTA build profile")
|
||||
|
||||
makefile = APP_MAKEFILE.read_text(encoding="utf-8", errors="replace")
|
||||
@@ -200,6 +224,7 @@ def verify_app(path: Path) -> None:
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--app-bin", type=Path, help="also enforce the application/FBF capacity gate")
|
||||
parser.add_argument("--kernel-bin", type=Path, help="also enforce the GNSS system/customer_app margin")
|
||||
args = parser.parse_args()
|
||||
verify_layout()
|
||||
verify_linker()
|
||||
@@ -207,7 +232,9 @@ def main() -> int:
|
||||
verify_fota_contract()
|
||||
if args.app_bin:
|
||||
verify_app(args.app_bin if args.app_bin.is_absolute() else ROOT / args.app_bin)
|
||||
print("OTA-ready baseline verified: fs640, app@0x002C2000, FULLOTA2 available")
|
||||
if args.kernel_bin:
|
||||
verify_system_fit(args.kernel_bin if args.kernel_bin.is_absolute() else ROOT / args.kernel_bin)
|
||||
print("OTA-ready baseline verified: hxgnss fs576, app384@0x002E5000, FULLOTA2 available")
|
||||
return 0
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user