nt9856x/build/nvt-tools/verify_fdt.py
2023-03-28 15:07:53 +08:00

499 lines
20 KiB
Python
Executable File

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys
import os
import pyfdt
import json
import argparse
# some oaalnx has no colorama
#import colorama
from pyfdt import FdtBlobParse
def dbg_err(msg):
#print(colorama.Fore.RED+colorama.Style.BRIGHT+msg+colorama.Style.RESET_ALL, file=sys.stderr)
print(msg, file=sys.stderr)
def dbg_wrn(msg):
#print(colorama.Fore.YELLOW+colorama.Style.BRIGHT+msg+colorama.Style.RESET_ALL, file=sys.stderr)
print(msg, file=sys.stderr)
def parse_nvt_info(fdt):
nvt_info = dict()
fdt_nvt_info = fdt.to_fdt().resolve_path(r'/nvt_info')
iter = fdt_nvt_info.walk()
for item in iter:
if isinstance(item[1], pyfdt.FdtPropertyStrings):
nvt_info[item[1].name] = item[1].strings[0]
else:
nvt_info[item[1].name] = ""
return nvt_info
def parse_flash_partition(fdt, flash_path):
partitions = []
fdt_partitions = fdt.to_fdt().resolve_path(flash_path)
if fdt_partitions is None:
return partitions
iter = fdt_partitions.walk()
for item in iter:
if not isinstance(item[1], pyfdt.FdtNode):
continue
if "partition_" not in item[1].name:
continue
partition = dict()
partition["name"] = item[1].name
iter2 = item[1].walk()
for item2 in iter2:
if item2[1].name == "label":
partition["label"] = item2[1].strings[0]
elif item2[1].name == "reg":
partition["ofs"] = (item2[1].words[0] <<
64) | (item2[1].words[1])
partition["size"] = (item2[1].words[2] <<
64) | (item2[1].words[3])
partitions.append(partition)
return partitions
def parse_nvt_memory_cfg(fdt):
nvt_memory_cfgs = []
fdt_nvt_memory_cfg = fdt.to_fdt().resolve_path(r"/nvt_memory_cfg")
iter = fdt_nvt_memory_cfg.walk()
for item in iter:
if not isinstance(item[1], pyfdt.FdtNode):
continue
nvt_memory_cfg = dict()
nvt_memory_cfg["name"] = item[1].name
iter2 = item[1].walk()
for item2 in iter2:
if item2[1].name == "reg":
nvt_memory_cfg["ofs"] = item2[1].words[0]
nvt_memory_cfg["size"] = item2[1].words[1]
nvt_memory_cfgs.append(nvt_memory_cfg)
return nvt_memory_cfgs
def parse_linux_memory(fdt):
linux_memories = []
fdt_linux_memory = fdt.to_fdt().resolve_path(r"/memory/reg")
for idx in range(int(len(fdt_linux_memory.words)/2)):
linux_memory = dict()
linux_memory["ofs"] = fdt_linux_memory.words[idx*2]
linux_memory["size"] = fdt_linux_memory.words[idx*2+1]
linux_memories.append(linux_memory)
return linux_memories
def parse_reserved_memory(fdt):
reserved_memories = []
fdt_reserved_memory = fdt.to_fdt().resolve_path(r"/reserved-memory")
if fdt_reserved_memory is None:
return reserved_memories
iter = fdt_reserved_memory.walk()
for item in iter:
if not isinstance(item[1], pyfdt.FdtNode):
continue
reserved_memory = dict()
reserved_memory["name"] = item[1].name
reserved_memory["ofs"] = item[1][item[1].index("reg")].words[0]
reserved_memory["size"] = item[1][item[1].index("reg")].words[1]
reserved_memories.append(reserved_memory)
return reserved_memories
def parse_hdal_memory(fdt):
hdal_memory = dict()
fdt_hdal_memory = fdt.to_fdt().resolve_path(r"/hdal-memory/media/reg")
hdal_memory["ofs"] = fdt_hdal_memory.words[0]
hdal_memory["size"] = fdt_hdal_memory.words[1]
return hdal_memory
def parse_nvtpack(fdt, flash_path):
nvtpack_items = []
fdt_nvtpack = fdt.to_fdt().resolve_path(flash_path + r"/nvtpack/index")
if fdt_nvtpack is None:
return nvtpack_items
iter = fdt_nvtpack.walk()
for item in iter:
if not isinstance(item[1], pyfdt.FdtNode):
continue
if "id" not in item[1].name:
continue
nvtpack_item = dict()
nvtpack_item["id"] = item[1].name
iter2 = item[1].walk()
for item2 in iter2:
if item2[1].name == "partition_name":
nvtpack_item["partition_name"] = item2[1].strings[0]
nvtpack_items.append(nvtpack_item)
return nvtpack_items
def parse_top(fdt):
top = dict()
fdt_top = fdt.to_fdt().resolve_path(r"/top@f0010000")
if fdt_top is None:
return top
iter = fdt_top.walk()
for item in iter:
if not isinstance(item[1], pyfdt.FdtNode):
continue
top[item[1].name] = item[1][0].words[0]
return top
def check_nvt_info_embmem(nvt_info):
if nvt_info["EMBMEM"] == "EMBMEM_NONE":
return 0 # no embmem
if nvt_info["EMBMEM"] == "EMBMEM_NAND":
dbg_err("EMBMEM_NAND has deprecated.".format(
nvt_info["EMBMEM"], nvt_info["EMBMEM_BLK_SIZE"]))
return -1
if nvt_info["EMBMEM"] == "EMBMEM_SPI_NOR" and nvt_info["EMBMEM_BLK_SIZE"] != "0x10000":
dbg_err("EMBMEM({}) and EMBMEM_BLK_SIZE({}) are not matched".format(
nvt_info["EMBMEM"], nvt_info["EMBMEM_BLK_SIZE"]))
return -1
if nvt_info["EMBMEM"] == "EMBMEM_SPI_NAND" and nvt_info["EMBMEM_BLK_SIZE"] != "0x20000" and nvt_info["EMBMEM_BLK_SIZE"] != "0x40000":
dbg_err("EMBMEM({}) and EMBMEM_BLK_SIZE({}) are not matched".format(
nvt_info["EMBMEM"], nvt_info["EMBMEM_BLK_SIZE"]))
return -1
if nvt_info["EMBMEM"] == "EMBMEM_EMMC" and nvt_info["EMBMEM_BLK_SIZE"] != "0x200":
dbg_err("EMBMEM({}) and EMBMEM_BLK_SIZE({}) are not matched".format(
nvt_info["EMBMEM"], nvt_info["EMBMEM_BLK_SIZE"]))
return -1
# check NVT_ROOTFS_TYPE
if nvt_info["NVT_ROOTFS_TYPE"] == "NVT_ROOTFS_TYPE_RAMDISK":
pass
elif nvt_info["NVT_ROOTFS_TYPE"] == "NVT_ROOTFS_TYPE_SQUASH":
pass
elif nvt_info["EMBMEM"] == "EMBMEM_SPI_NOR" and "NVT_ROOTFS_TYPE_NOR" not in nvt_info["NVT_ROOTFS_TYPE"]:
dbg_err("NVT_ROOTFS_TYPE must be NVT_ROOTFS_TYPE_RAMDISK or NVT_ROOTFS_TYPE_NOR* or NVT_ROOTFS_TYPE_SQUASH")
return -1
elif nvt_info["EMBMEM"] == "EMBMEM_SPI_NAND" and "NVT_ROOTFS_TYPE_NAND" not in nvt_info["NVT_ROOTFS_TYPE"]:
dbg_err("NVT_ROOTFS_TYPE must be NVT_ROOTFS_TYPE_RAMDISK or NVT_ROOTFS_TYPE_NAND* or NVT_ROOTFS_TYPE_SQUASH")
return -1
elif nvt_info["EMBMEM"] == "EMBMEM_EMMC" and "NVT_ROOTFS_TYPE_EXT4" not in nvt_info["NVT_ROOTFS_TYPE"]:
dbg_err("NVT_ROOTFS_TYPE must be NVT_ROOTFS_TYPE_RAMDISK or NVT_ROOTFS_TYPE_EXT4* or NVT_ROOTFS_TYPE_SQUASH")
return -1
return 0
def check_flash_partition(nvt_info, partitions):
if nvt_info["EMBMEM"] == "EMBMEM_NONE":
return 0 # no flash
# check partition flash type matched with EMBMEM
if len(partitions[nvt_info["EMBMEM"]]) == 0:
dbg_err(
"storage-partition type is not matched to {} ".format(nvt_info["EMBMEM"]))
return -1
# check partition size block
blk_size = int(nvt_info["EMBMEM_BLK_SIZE"], 0)
partition = partitions[nvt_info["EMBMEM"]]
if len(partition) < 3:
dbg_err("flash partition counts are less than 3. it doesn't make scene")
return -1
# check first must be loader or mbr and their size follow our spec
if nvt_info["EMBMEM"] == "EMBMEM_EMMC":
if partition[0]["name"] != "partition_mbr":
dbg_err("first flash partition must be partition_mbr")
return -1
if partition[1]["name"] != "partition_fdt":
dbg_err("2nd flash partition must be partition_fdt")
return -1
if partition[1]["ofs"] != 0x40000:
dbg_err("2nd flash partition offset must be 0x40000 for EMMC")
return -1
else:
if partition[0]["name"] != "partition_loader":
dbg_err("first flash partition must be partition_loader")
return -1
if partition[1]["name"] != "partition_fdt":
dbg_err("2nd flash partition must be partition_fdt")
return -1
if nvt_info["EMBMEM"] == "EMBMEM_SPI_NAND":
if partition[1]["ofs"] != blk_size*2:
dbg_err("2nd flash partition offset must be 0x{:X} for EMBMEM_SPI_NAND".format(
blk_size*2))
return -1
else:
if partition[1]["ofs"] != blk_size:
dbg_err(
"2nd flash partition offset must be 0x{:X} for EMBMEM_SPI_NOR".format(blk_size))
return -1
# check if partition_fdt.restore existing
if partition[2]["name"] != "partition_fdt.restore":
dbg_err("3nd flash partition suggest partition_fdt.restore")
for item in partition:
if item["size"] % blk_size != 0:
dbg_err("flash partition {} is not {} bytes aligned.".format(
item["label"], blk_size))
return -1
# check partition if in order and overlapped
for idx in range(len(partition)):
if idx == 0:
continue
if partition[idx]["ofs"] < partition[idx-1]["ofs"]+partition[idx-1]["size"] and partition[idx]["label"] != "all":
dbg_err("partition {}@0x{:X}, 0x{:X} overlapped with {}@0x{:X}, 0x{:X}".format(
partition[idx]["label"],
partition[idx]["ofs"],
partition[idx]["size"],
partition[idx-1]["label"],
partition[idx-1]["ofs"],
partition[idx-1]["size"]))
return -1
return 0
def check_nvtpack(nvt_info, partitions, nvtpack_items):
if nvt_info["EMBMEM"] == "EMBMEM_NONE":
return 0 # no flash
# check partition flash type matched with EMBMEM
if len(nvtpack_items[nvt_info["EMBMEM"]]) == 0:
dbg_err(
"nvtpack-partition type is not matched to {} ".format(nvt_info["EMBMEM"]))
return -1
# check if id's partition_name is matched to storage partition
partition = partitions[nvt_info["EMBMEM"]]
nvtpack_item = nvtpack_items[nvt_info["EMBMEM"]]
n_item = len(partition) if len(partition) < len(
nvtpack_item) else len(nvtpack_item)
for idx in range(n_item):
nvtpack_partition_name = "partition_" + \
nvtpack_item[idx]["partition_name"]
if nvtpack_partition_name != partition[idx]["name"]:
dbg_err("nvtpack index.{} partition name '{}' but '{}' is excepted.".format(
idx,
nvtpack_item[idx]["partition_name"],
partition[idx]["name"].replace("partition_", "")))
return -1
return 0
def check_memory(nvt_memory_cfgs, linux_memories, reserved_memories, hdal_memory):
fdt = None
rtos = None
bridge = None
linuxtmp = None
uboot = None
# nvt_memory_cfgs first must be dram size
if nvt_memory_cfgs[0]["name"] != "dram":
dbg_err("nvt_memory_cfg first item must be 'dram' but rather '{}'".format(
nvt_memory_cfgs[0]["name"]))
return -1
dram_size = nvt_memory_cfgs[0]["size"]
# check each element if is over range
for nvt_memory_cfg in nvt_memory_cfgs:
if nvt_memory_cfg["ofs"]+nvt_memory_cfg["size"] > dram_size:
dbg_err("nvt_memory_cfg's '{}' is out of dram size".format(
nvt_memory_cfg["name"]))
return -1
# keep fdt, rtos, bridge info for checking fastboot sanity later
if nvt_memory_cfg["name"] == "fdt":
fdt = nvt_memory_cfg
elif nvt_memory_cfg["name"] == "rtos":
rtos = nvt_memory_cfg
elif nvt_memory_cfg["name"] == "bridge":
bridge = nvt_memory_cfg
elif nvt_memory_cfg["name"] == "linuxtmp":
linuxtmp = nvt_memory_cfg
elif nvt_memory_cfg["name"] == "uboot":
uboot = nvt_memory_cfg
# check each element if in order and overlapped (disable it, becase rtos DEMO_EVB, rtos can overlap loader)
"""
for idx in range(len(nvt_memory_cfgs)):
if idx == 0:
continue
if nvt_memory_cfgs[idx]["ofs"] < nvt_memory_cfgs[idx-1]["ofs"]+nvt_memory_cfgs[idx-1]["size"] and nvt_memory_cfgs[idx-1]["name"] != "dram":
dbg_err("nvt_memory_cfg {}@0x{:X}, 0x{:X} overlapped with {}@0x{:X}, 0x{:X}".format(
nvt_memory_cfgs[idx]["name"],
nvt_memory_cfgs[idx]["ofs"],
nvt_memory_cfgs[idx]["size"],
nvt_memory_cfgs[idx-1]["name"],
nvt_memory_cfgs[idx-1]["ofs"],
nvt_memory_cfgs[idx-1]["size"]))
return -1
"""
# check if linux memory is over range
for linux_memory in linux_memories:
# linux_memory["ofs"] < dram_size for skipping dram2
if linux_memory["ofs"]+linux_memory["size"] > dram_size and linux_memory["ofs"] < dram_size:
dbg_err("linux memory is out of dram size")
return -1
# check if hdal memory is over range
# hdal_memory["ofs"] < dram_size for skipping dram2
if hdal_memory["ofs"]+hdal_memory["size"] > dram_size and hdal_memory["ofs"] < dram_size:
dbg_err("hdal memory is out of dram size")
return -1
# uboot memory cannot be overlapped with linux system memory region
for linux_memory in linux_memories:
if uboot["ofs"] > linux_memory["ofs"] and uboot["ofs"] < linux_memory["ofs"]+linux_memory["size"]:
dbg_err(
"uboot memory cannot be overlapped with linux system memory region")
return -1
if uboot["ofs"] < linux_memory["ofs"] and uboot["ofs"]+uboot["size"] > linux_memory["ofs"]:
dbg_err(
"uboot memory cannot be overlapped with linux system memory region")
return -1
# check reserved_memories must be in range of linux-memory and 4MB alignment
for reserved_memory in reserved_memories:
if (reserved_memory["size"] % 0x400000) != 0:
dbg_err("{} size must be 4MB alignment".format(
reserved_memory["name"]))
return -1
valid = 1
for linux_memory in linux_memories:
valid = 1
if reserved_memory["ofs"] < linux_memory["ofs"]:
valid = 0
continue
if reserved_memory["ofs"]+reserved_memory["size"] > linux_memory["ofs"]+linux_memory["size"]:
valid = 0
continue
if valid:
break
if not valid:
dbg_err(
"{} is out of linux-memory".format(reserved_memory["name"]))
return -1
# check if hdal memory overlap with linux-memory
for linux_memory in linux_memories:
if hdal_memory["ofs"] > linux_memory["ofs"] and hdal_memory["ofs"] < linux_memory["ofs"]+linux_memory["size"]:
dbg_err(
"hdal_memory memory cannot be overlapped with linux system memory region")
return -1
if hdal_memory["ofs"] < linux_memory["ofs"] and hdal_memory["ofs"]+hdal_memory["size"] > linux_memory["ofs"]:
dbg_err(
"uboot memory cannot be overlapped with linux system memory region")
return -1
# if bridge exist, check fastboot requirement
if bridge is not None:
# check1: fdt, rtos and bridge memory region must be contiguous.
if fdt["ofs"] + fdt["size"] != rtos["ofs"]:
dbg_err("fdt, rtos and bridge memory region must be contiguous.")
return -1
if rtos["ofs"] + rtos["size"] != bridge["ofs"]:
dbg_err("fdt, rtos and bridge memory region must be contiguous.")
return -1
hotplug_mem = dict()
hotplug_mem["ofs"] = fdt["ofs"]
hotplug_mem["size"] = fdt["size"] + rtos["size"] + bridge["size"]
# check2: fdt, rtos and bridge memory region cannot overlap with hdal and linux memory
for linux_memory in linux_memories:
if hotplug_mem["ofs"] > linux_memory["ofs"] and hotplug_mem["ofs"] < linux_memory["ofs"]+linux_memory["size"]:
dbg_err(
"fdt, rtos and bridge memory region cannot overlap with hdal and linux memory")
return -1
if hotplug_mem["ofs"] < linux_memory["ofs"] and hotplug_mem["ofs"]+hotplug_mem["size"] > linux_memory["ofs"]:
dbg_err(
"fdt, rtos and bridge memory region cannot overlap with hdal and linux memory")
return -1
# check3: fdt, rtos and bridge memory region cannot overlap with linuxtmp
if hotplug_mem["ofs"] > linuxtmp["ofs"] and hotplug_mem["ofs"] < linuxtmp["ofs"]+linuxtmp["size"]:
dbg_err("fdt, rtos and bridge memory region cannot overlap with linuxtmp")
return -1
if hotplug_mem["ofs"] < linuxtmp["ofs"] and hotplug_mem["ofs"]+hotplug_mem["size"] > linuxtmp["ofs"]:
dbg_err("fdt, rtos and bridge memory region cannot overlap with linuxtmp")
return -1
# check4: fdt, rtos and bridge memory have to start at 8MB alignment, and the size also needs 8MB alignment
if (hotplug_mem["ofs"] % 0x800000) != 0:
dbg_err(
"fdt, rtos and bridge memory have to start at 8MB alignment, and the size also needs 8MB alignment")
return -1
if (hotplug_mem["size"] % 0x800000) != 0:
dbg_err(
"fdt, rtos and bridge memory have to start at 8MB alignment, and the size also needs 8MB alignment")
return -1
return 0
def check_top(top, nvt_info):
if nvt_info["EMBMEM"] == "EMBMEM_SPI_NAND" and (top["nand"] & 0xC) == 0xC:
dbg_err(
"top/nand is incorrect: 0x{:X} for EMBMEM=EMBMEM_SPI_NAND".format(top["nand"]))
return -1
if nvt_info["EMBMEM"] == "EMBMEM_SPI_NOR" and (top["nand"] & 0xC) == 0xC:
dbg_err(
"top/nand is incorrect: 0x{:X} for EMBMEM=EMBMEM_SPI_NOR".format(top["nand"]))
return -1
if nvt_info["EMBMEM"] == "EMBMEM_EMMC" and (top["sdio3"] & 0x3) == 0x0:
dbg_err(
"top/sdio3 is incorrect: 0x{:X} for EMBMEM=EMBMEM_EMMC".format(top["sdio3"]))
return -1
return 0
def parse_args(argv):
parser = argparse.ArgumentParser(description='fdt checker')
parser.add_argument('-f', '--file', metavar='.dtb/.bin', required=True,
dest='file', action='store',
help='fdt binary file')
args = parser.parse_args()
return args
def main(argv):
if 0:
argv.append(r"-f")
# argv.append(r"d:\tmp\nvt-na51055-evb.bin")
argv.append(
r"Z:\firmware\na51055_dual_sdk\na51055_linux_sdk\output\nvt-na51055-evb.bin")
args = parse_args(argv)
if not os.path.isfile(args.file):
print("cannot find {}".format(args.file), file=sys.stderr)
return -1
print("verify {}".format(args.file))
with open(args.file, 'rb') as infile:
fdt = FdtBlobParse(infile)
nvt_info = parse_nvt_info(fdt)
partitions = dict()
partitions["EMBMEM_SPI_NAND"] = parse_flash_partition(
fdt, r"/nand@f0400000")
partitions["EMBMEM_SPI_NOR"] = parse_flash_partition(fdt, r"/nor@f0400000")
partitions["EMBMEM_EMMC"] = parse_flash_partition(fdt, r"/mmc@f0510000")
nvt_memory_cfgs = parse_nvt_memory_cfg(fdt)
linux_memories = parse_linux_memory(fdt)
reserved_memories = parse_reserved_memory(fdt)
hdal_memory = parse_hdal_memory(fdt)
nvtpack_items = dict()
nvtpack_items["EMBMEM_SPI_NAND"] = parse_nvtpack(fdt, r"/nand@f0400000")
nvtpack_items["EMBMEM_SPI_NOR"] = parse_nvtpack(fdt, r"/nor@f0400000")
nvtpack_items["EMBMEM_EMMC"] = parse_nvtpack(fdt, r"/mmc@f0510000")
top = parse_top(fdt)
if check_nvt_info_embmem(nvt_info) != 0:
return -1
if check_flash_partition(nvt_info, partitions) != 0:
return -1
if check_nvtpack(nvt_info, partitions, nvtpack_items) != 0:
return -1
if check_memory(nvt_memory_cfgs, linux_memories, reserved_memories, hdal_memory) != 0:
return -1
if check_top(top, nvt_info) != 0:
return -1
return 0
if __name__ == '__main__':
try:
# colorama.init()
er = main(sys.argv)
except Exception as exp:
er = -1
print(exp, file=sys.stderr)
raise exp
sys.exit(er)