Files
kunlun_ramtool/bin/bin_to_hex.py

609 lines
20 KiB
Python

import re
import os
import sys
import struct
import json
from bin.log import myprint
from bin.base import bin_path
from bin.crc import CRC32
# kunlun1,kunlun2,kunlun3的img类型
# FRW是指未压缩的fw CFRW是指压缩之后的fw
_ImgType={
0x0000:"imgROM", # Maybe,ROM doesn't need a imgType */
0xFC00:"imgSP", # sp */
0xFC01:"imgSBL", # sbl */
0xFC02:"imgFRW", # kl1: 1MB fw, uncompressed for sta, run in flash; compressed for cco, run in psram */
0xFC03:"imgCFG", # The first pib file. */
0xFC04:"imgEFUSE", # efuse */
0xFC05:"imgOEM", # oem */
0xFC06:"imgFRW2", # The second fw, maybe the backup one. not used. */
0xFC07:"imgCFG2", # The second pib file. */
0xFC08:"imgCFRW1", # kl1: 2MB fw, compressed for sta or cco, run in flash; kl2: 4M flash fw */
0xFC09:"imgCFRW2", # The second fw, maybe the backup one. not used. */
0xFC0A:"imgCFRW", # kl1: 2MB fw, compressed for sta or cco, run in psram; kl2: 4M psram fw */
0xFC0B:"imgREF", # ref */
0xFC0C:"imgCUS", # cus */
0xFC0D:"imgCFRW4F", # kl1: 4MB fw, compressed for sta or cco, run in flash */
0xFC0E:"imgCFRW4P", # kl1: 4MB fw, compressed for sta or cco, run in psram */
0xFFFF:"imgMAX", # invalid */
0x00:"imgV1ROM", # Maybe,ROM doesn't need a imgType */
0x01:"imgV1SBL", # sbl */
0x02:"imgV1FRWPLC", # FW-PLC */
0x03:"imgV1CFG", # The first pib file. */
0x05:"imgV1OEM", # oem */
0x06:"imgV1FRWCUS", # FW-CUS */
0xFF:"imgV1MAX" # invalid */
}
_DevType={
0xDC01:"devkunlun1",
0xDC02:"devkunlun2",
0xDC03:"devkunlun3",
0xFFFF:"devMax",
0x01:"devV1kunlun1",
0x02:"devV1kunlun2",
0x03:"devV1kunlun3",
0x04:"devV1Pangu",
0xFF:"devV1Max"
}
_PatternType={
0x00:"HTZD",
0x55:"HTZD",
0xaa:"JSMT",
0x99:"FLX",
0x66:"QJ",
0xcc:"SPE",
0x33:"GX",
0xdd:"DT",
0xa9:"YP",
0xc6:"WTZ",
0x93:"TCE"
}
_layout_cfg='''
g_layout_f1_v0
part_name offset size size(kB) note
SP 0x00000000 0x00008000 32
SBL 0x00008000 0x00008000 32
PARAM 0x00010000 0x00001000 4
OEM 0x00011000 0x00001000 4
PIB1 0x00012000 0x00006000 24
LOG1 0x00018000 0x00001000 4
PIB2 0x00019000 0x00006000 24
LOG2 0x0001F000 0x00001000 4
FW1 0x00020000 0x0006F000 444
CUS 0x0008F000 0x00001000 4
FW2 0x00090000 0x0006F000 444
DUMP 0x00000000 0x00000000 0 not use
CAL 0x000FF000 0x00001000 4
-
g_layout_f2_v0
part_name offset size size(kB) note
SP 0x00000000 0x00008000 32
SBL 0x00008000 0x00008000 32
PARAM 0x00010000 0x00001000 4
OEM 0x00011000 0x00001000 4
PIB1 0x00012000 0x00007000 28
PIB2 0x00019000 0x00007000 28
RUN 0x00020000 0x000E0000 896 log part use the remaining space
FW1 0x00100000 0x00070000 448
FW2 0x00170000 0x00070000 448
CUS 0x001E0000 0x0001E000 120
DUMP 0x001FE000 0x00001000 4
CAL 0x001FF000 0x00001000 4
-
g_layout_f2_v1
part_name offset size size(kB) note
SBL 0x00000000 0x0000C000 48
PIB1_EXT 0X0000C000 0X00002000 8
PIB2_EXT 0X0000E000 0X00002000 8
PARAM 0x00010000 0x00001000 4
OEM 0x00011000 0x00001000 4
PIB1 0x00012000 0x00007000 28
PIB2 0x00019000 0x00007000 28
RUN 0x00020000 0x000E0000 896
FW1 0x00100000 0x00070000 448
FW2 0x00170000 0x00070000 448
DUMP 0x001E0000 0x00001000 4
CUS 0x001E1000 0x0001E000 120
CALI 0x001FF000 0x00001000 4
-
g_layout_f2_v2
part_name offset size size(kb) note
SBL 0x00000000 0x0000C000 48
PIB1_EXT 0X0000C000 0X00002000 8
PIB2_EXT 0X0000E000 0X00002000 8
PARAM 0x00010000 0x00001000 4
OEM 0x00011000 0x00001000 4
PIB1 0x00012000 0x00007000 28
PIB2 0x00019000 0x00007000 28
RUN_CUS 0x00020000 0x00028000 160
RUN_FW 0x00048000 0x000B8000 736
CUS1 0x00100000 0x00018000 96
FW1 0x00118000 0x00058000 352
CUS2 0x00170000 0x00018000 96
FW2 0x00188000 0x00058000 352
RESERVED 0x001E0000 0x00001000 4
CUST 0x001E1000 0x0001E000 120
CALI 0x001FF000 0x00001000 4
-
g_layout_f2_p_v0
part_name offset size size(kB) note
SP 0x00000000 0x00008000 32
SBL 0x00008000 0x00008000 32
PARAM 0x00010000 0x00001000 4
OEM 0x00011000 0x00001000 4
PIB1 0x00012000 0x00007000 28
PIB2 0x00019000 0x00007000 28
FW1 0x00020000 0x000A0000 640
LOG1 0x000C0000 0x00020000 128
LOG2 0x000E0000 0x00020000 128
FW2 0x00100000 0x000A0000 640
CUS 0x001A0000 0x0005E000 376
SP_FW1 0x001F0000 0x00000000 0 not use
PARAM2 0x001F7000 0x00000000 0 not use
DUMP 0x001FE000 0x00001000 4
CAL 0x001FF000 0x00001000 4
-
g_layout_f2_p_v1
part_name offset size size(kB) note
SBL 0x00000000 0x00010000 64
PARAM 0x00010000 0x00001000 4
OEM 0x00011000 0x00001000 4
PIB1 0x00012000 0x00007000 28
PIB2 0x00019000 0x00007000 28
FW1 0x00020000 0x000A0000 640
LOG1 0x000C0000 0x00020000 128
FW2 0x000E0000 0x000A0000 640
LOG2 0x00180000 0x00020000 128
DUMP 0x001A0000 0x00001000 4
CUS 0x001A1000 0x0005E000 376
CALI 0x001FF000 0x00001000 4
-
g_layout_f4_v0
part_name offset size size(kb) note
SP 0x00000000 0x00008000 32
SBL 0x00008000 0x00008000 32
PARAM 0x00010000 0x00001000 4
OEM 0x00011000 0x00001000 4
PIB1 0x00012000 0x00007000 28
LOG1 0x00000000 0x00000000 0 not use
PIB2 0x00019000 0x00007000 28
LOG2 0x00000000 0x00000000 0 not use
RUN 0x00020000 0x00160000 1408 log part use the remaining space
FW1 0x00180000 0x000C0000 768
FW2 0x00240000 0x000C0000 768
SP_FW1 0x00000000 0x00000000 0 not use
PARAM2 0x00000000 0x00000000 0 not use
SP_FW2 0x00000000 0x00000000 0 not use
DUMP 0x00000000 0x00000000 0 not use
CUS 0x00300000 0x000FF000 1020
CAL 0x003FF000 0x00001000 4
-
g_layout_f4_v1
part_name offset size size(kb) note
SBL 0x00000000 0x00010000 64
PARAM 0x00010000 0x00001000 4
OEM 0x00011000 0x00001000 4
PIB1 0x00012000 0x00007000 28
PIB2 0x00019000 0x00007000 28
RUN 0x00020000 0x00160000 1408
FW1 0x00180000 0x000B0000 704
FW2 0x00230000 0x000B0000 704
PIB1_EXT 0x002E0000 0x0000F000 60
PIB2_EXT 0x002EF000 0x0000F000 60
DUMP 0x002FE000 0x00001000 4
RESERVED 0x002FF000 0x00001000 4
CUS 0x00300000 0x000FF000 1020
CALI 0x003FF000 0x00001000 4
-
g_layout_f4_p_v0
part_name offset size size(kb) note
SP 0x00000000 0x00008000 32
SBL 0x00008000 0x00008000 32
PARAM 0x00010000 0x00001000 4
OEM 0x00011000 0x00001000 4
PIB1 0x00012000 0x00007000 28
PIB2 0x00019000 0x00007000 28
RUN 0x00020000 0x000FA000 1000
LOG1 0x0011A000 0x00066000 408
FW1 0x00180000 0x000FA000 1000
LOG2 0x0027A000 0x00066000 408
DUMP 0x002E0000 0x00001000 4
RESERVED 0x002E1000 0x00001000 4
SP_FW1 0x002E2000 0x0000F000 60
SP_FW2 0x002F1000 0x0000F000 60
CUS 0x00300000 0x000FF000 1020
CAL 0x003FF000 0x00001000 4
FW2 0x002E0000 0x00000000 0 not use
PARAM2 0x00000000 0x00000000 0 not use
-
g_layout_f4_p_v1
part_name offset size size(kb) note
SBL 0x00000000 0x00010000 64
PARAM 0x00010000 0x00001000 4
OEM 0x00011000 0x00001000 4
PIB1 0x00012000 0x00007000 28
PIB2 0x00019000 0x00007000 28
FW1 0x00020000 0x000FA000 1000
LOG1 0x0011A000 0x00030000 192
LOG2 0x0014A000 0x00030000 192
RESERVED1 0x0017A000 0x00006000 24
FW2 0x00180000 0x000FA000 1000
PIB1_EXT 0x0027A000 0x0000F000 60
PIB2_EXT 0x00289000 0x0000F000 60
DUMP 0x00298000 0x00001000 4
RESERVED2 0x00299000 0x00067000 412
CUS 0x00300000 0x000FF000 1020
CALI 0x003FF000 0x00001000 4
-
g_layout_f4_p_v2
part_name offset size size(kb) note
SBL 0x00000000 0x00010000 64
PARAM 0x00010000 0x00001000 4
OEM 0x00011000 0x00001000 4
PIB1 0x00012000 0x00007000 28
PIB2 0x00019000 0x00007000 28
FW1-CUS 0x00020000 0x00080000 512
FW1-PLC 0x000A0000 0x000E0000 896
LOG1 0x00180000 0x00030000 192
LOG2 0x001B0000 0x00030000 192
FW2-CUS 0x001E0000 0x00080000 512
FW2-PLC 0x00260000 0x000E0000 896
PIB1_EXT 0x00340000 0x0000F000 60
PIB2_EXT 0x0034F000 0x0000F000 60
DUMP 0x0035E000 0x00001000 4
CUST 0x0035F000 0x000A0000 640
CALC 0x003FF000 0x00001000 4
-
'''
_layout_list=[
'g_layout_f1_v0',
'g_layout_f2_v0',
'g_layout_f2_p_v0',
'g_layout_f4_v0',
'g_layout_f4_p_v0',
'g_layout_f2_v1',
'g_layout_f2_p_v1',
'g_layout_f4_v1',
'g_layout_f4_p_v1',
'g_layout_f4_p_v2',
'g_layout_f2_v2',
]
# 根据layout index 找到 layout
def get_layout(index:int):
layout_len=len(_layout_list)
if(index>=layout_len):
return None
name=_layout_list[index]
layout=_layout_cfg.split('-')
for item in layout:
if(item.find(name)>=0):
part=item.split('\n')
break
part_dict_list:list[dict]=[]
for item in part:
sp=item.split()
if(len(sp)>=4) and sp[3].isdigit():
# myprint(f"layout {item}")
d={
'name':sp[0],
'offset':int(sp[1],base=16),
'size':int(sp[2],base=16),
}
part_dict_list.append(d)
return part_dict_list
# 校验 当前地址是不是分区地址
def check_part_addr(addr:int,part_list:list[dict]):
for item in part_list:
if(item.get('offset',None)==addr):
return item
return None
_PKT_HEADER_MAGIC_NO = 0x00005566
_IMG_HEADER_MAGIC_NO = 0xa4e49a17
# 从info文件读取flash信息
def load_flash_info(file_name:str):
flash_info_list:list[dict]=[]
with open(file_name,mode='r',encoding='utf-8') as f:
lines=f.readlines()
for line in lines:
# 如果开头两个字符是数字
info = re.match(r"^\d{2}",line)
if(info):
# print(info.group(0))
sp=line.split()
flash_info={}
flash_info["DevType"]=_DevType[int(sp[1],base=16)]
flash_info["ImgType"]=_ImgType[int(sp[2],base=16)]
flash_info["Offset"]=int(sp[3],base=16)
flash_info["Size"]=int(sp[4])
flash_info_list.append(flash_info)
return flash_info_list
# 查看是不是数据头,不是返回 "",是返回解析值
def tran_pkg_header(data:bytearray):
size=len(data)
ret={}
if(size>=96):
# 大写为无符号 B 单字节 H 双字节 I 4字节 L 4字节 Q 8字节
# f 单精度浮点 d 双精度浮点 s 字符串
a=struct.unpack('>BBHIIIIIIIIIIIIIIIIIIIIIIHBB',data)
if(a[5]==_PKT_HEADER_MAGIC_NO):
ret["enctype"]=str(a[0])
ret["pattern"]=hex(a[1])
ret["dev_type"]=hex(a[2])
ret["file_crc"]=hex(a[3])
ret["file_len"]=str(a[4])
ret["magic_no"]=hex(a[5])
ret["version"]=hex(a[6])
ret["sp_start"]=hex(a[7])
ret["sp_len"]=str(a[8])
ret["sbl_start"]=hex(a[9]) # 32bytes
ret["sbl_len"]=str(a[10])
ret["oem_start"]=hex(a[11])
ret["oem_len"]=str(a[12])
ret["pib_start"]=hex(a[13])
ret["pib_len"]=str(a[14])
ret["fw_start"]=hex(a[15])
ret["fw_len"]=str(a[16])
ret["efuse_start"]=hex(a[17]) # 64bytes
ret["efuse_len"]=str(a[18])
ret["fw2_start"]=hex(a[19])
ret["fw2_len"]=str(a[20])
ret["ref_start"]=hex(a[21])
ret["ref_len"]=str(a[22])
ret["cus_start"]=hex(a[23])
ret["cus_len"]=str(a[24])
ret["vendor_id"]=hex(a[25])
ret["img_type"]=hex(a[26])
ret["img_flag"]=hex(a[27])
t=str(ret)
t=t.replace(',','\n')
# t=json.dumps(ret, sort_keys=True, indent=2, separators=(',', ': '))
return t
return ""
def tran_img_headerv0(data:bytearray):
size=len(data)
ret={}
if(size>=64):
# 大写为无符号 B 单字节 H 双字节 I 4字节 L 4字节 Q 8字节
# f 单精度浮点 d 双精度浮点 s 字符串
a=struct.unpack('>HHIHBBIIIBBBBI',data[0:32])
if(a[8]==_IMG_HEADER_MAGIC_NO):
ret["devType"]=hex(a[0])+f"({_DevType.get(a[0],'unknown')})"
ret["imgType"]=hex(a[1])+f"({_ImgType.get(a[1],'unknown')})"
ret["imgSize"]=str(a[2])
ret["imgVer"]=hex(a[3])
ret["psramSize"]=str(a[4])
ret["hdrVer"]=hex(a[5])
ret["fwSize"]=str(a[6])
ret["imgCRC"]=hex(a[7])
ret["guard"]=hex(a[8])
ret["layoutIdx"]=hex(a[9])
# reserved 3bytes
ret["fwCRC"]=hex(a[13])
ret["sha256"]=data[32:].hex()
t=str(ret)
t=t.replace(',','\n')
return t,ret
return "",{}
def tran_img_headerv1(data:bytearray):
size=len(data)
ret={}
if(size>=64):
# 大写为无符号 B 单字节 H 双字节 I 4字节 L 4字节 Q 8字节
# f 单精度浮点 d 双精度浮点 s 字符串
a=struct.unpack('>BBBBIBBBBIIIBBBBI',data[0:32])
if(a[11]==_IMG_HEADER_MAGIC_NO):
ret["devType"]=hex(a[0])+f"({_DevType.get(a[0],'unknown')})"
ret["imgType"]=hex(a[1])+f"({_ImgType.get(a[1],'unknown')})"
ret["encType"]=hex(a[2])
ret["cfg"]=hex(a[3])
ret["imgSize"]=str(a[4])
ret["zipType"]=hex(a[5])
ret["flashSize"]=str(a[6])
ret["psramSize"]=hex(a[7])
ret["hdrVer"]=hex(a[8])
ret["imgVer"]=hex(a[9])
ret["imgCRC"]=hex(a[10])
ret["guard"]=hex(a[11])
ret["layoutIdx"]=hex(a[12])
# reserved 3bytes
ret["runAddr"]=hex(a[16])
ret["sha256"]=data[32:].hex()
t=str(ret)
t=t.replace(',','\n')
return t,ret
return "",{}
# 判断是不是pkt_header
def pkt_header_check(data:bytearray):
magic=(data[12]<<24)|(data[13]<<16)|(data[14]<<8)|(data[15])
if (magic==_PKT_HEADER_MAGIC_NO):
return True
myprint(f"magic={hex(magic)}")
return False
# 判断是不是img_header
def img_header_check(data:bytearray):
if(len(data)<32):
return ''
magic=(data[20]<<24)|(data[21]<<16)|(data[22]<<8)|(data[23])
if (magic==_IMG_HEADER_MAGIC_NO):
imghdr_v=data[11]
myprint(f"magic={hex(magic)}, imghdr_v={imghdr_v}")
# 返回使用的结构体类型
if(imghdr_v==0x10):
return 'V1'
else:
return "V0"
return ""
# 判断是不是加密了
def pkt_encrypt_check(data:bytearray):
magic_data=data[12:16]
pat=magic_data[0]
for i in range(len(magic_data)):
magic_data[i]=magic_data[i]^pat
magic=(magic_data[0]<<24)|(magic_data[1]<<16)|(magic_data[2]<<8)|(magic_data[3])
if (magic==_PKT_HEADER_MAGIC_NO):
if(pat!=0):
return True
return False
# 转化为hex文本
def bin_to_hex(bin:bytearray,f,oem_file=None,layout_index=None):
all_size=len(bin)
pack_size=32
turned=0
turned_old=0
out_text=''
kunlun=''
if(layout_index is not None):
layout_list=get_layout(layout_index)
if(pkt_header_check(bin)):
out_text=tran_pkg_header(bin[0:96])+'\n'
f.write(out_text)
while turned < all_size:
if(turned+pack_size<=all_size):
data=bin[turned:turned+pack_size]
turned_old=turned
turned+=pack_size
else:
data=bin[turned:]
turned_old=turned
turned=all_size
if(all_size-turned_old>=64):
hdr_data=bin[turned_old:turned_old+64]
else:
hdr_data=bytearray()
hdr_v=img_header_check(hdr_data)
if(hdr_v=='V0'):
kunlun='kl1'
out_text,ret=tran_img_headerv0(hdr_data)
out_text+='\n'
f.write(out_text)
elif(hdr_v=='V1'):
kunlun='kl3'
out_text,ret=tran_img_headerv1(hdr_data)
out_text+='\n'
f.write(out_text)
# 截取oem部分
if(oem_file is not None):
if(_ImgType[hdr_data[1]]=="imgV1OEM"):
size=int(ret["imgSize"])
oem_bin=bin[turned_old+64:turned_old+64+size]
oem_file.write(oem_bin)
if(layout_index is not None):
layout=check_part_addr(turned_old,layout_list)
if(layout is not None):
layout['crc32']=hex(CRC32(bin[turned_old:turned_old+layout['size']]))
f.write(str(layout).replace(',',' ')+'\n')
out_text=f"[{hex(turned_old)}] {data.hex(' ')}\n"
f.write(out_text)
return kunlun
def bin_to_hex_file(bin_file_name:str,hex_file_name:str,layout_index:int):
with open(bin_file_name,mode='rb') as f:
bin=bytearray(f.read())
if(pkt_encrypt_check(bin)):
myprint("start decrypt:")
pat=(bin[12]^0x00)&0xff
myprint(f"decrypt image:{hex(pat)}({_PatternType.get(pat,'unknown')})")
for index in range(len(bin)):
bin[index]=bin[index]^pat
with open(hex_file_name,mode='w+',encoding="utf-8") as f:
# oem_bin 去除原始后缀 .bin.txt 添加新后缀 -oem.bin
oem_name=hex_file_name[0:-8]+'-oem.bin'
oem_name=os.path.normpath(oem_name)
with open(oem_name,mode='wb+') as oem_f:
kl=bin_to_hex(bin,f,oem_f,layout_index)
# 调用oem_tool 打印oem信息
oem_tool=os.path.join(bin_path(),f"{kl}_oem.exe")
if(os.path.exists(oem_tool)):
cmd_str=f"{oem_tool} --parse={oem_name}"
with os.popen(cmd_str) as f:
for line in f.readlines():
myprint(line.strip())
# os.system(cmd_str)
else:
myprint(f"oem_tool not found: {oem_tool}")
# 固件解密
def bin_file_decrypt(bin_file:str):
with open(bin_file,mode='rb') as f:
bin=bytearray(f.read())
# 自动判断是否需要解密
if (pkt_encrypt_check(bin)):
pat=(bin[12]^0x00)&0xff
myprint(f"decrypt image:{hex(pat)}({_PatternType.get(pat,'unknown')})")
for index in range(len(bin)):
bin[index]=bin[index]^pat
else:
pat=bin[1]
myprint(f"copy image:{hex(pat)}({_PatternType.get(pat,'unknown')})")
with open('tmp.bin',mode='wb+') as f:
f.write(bin)
return "tmp.bin"
# 判断一个固件是kl1还是kl3的,需要解密后的固件
def check_bin_type(file:str):
with open(file,mode='rb') as f:
bin=bytearray(f.read())
while len(bin)>32:
tmp=img_header_check(bin[:32])
if(tmp=="V1"):
return '3'
elif(tmp=="V0"):
return '1'
bin=bin[32:]
return None
def clear_tmp():
tmp_list=['tmp.bin']
for item in tmp_list:
if os.path.exists(item):
os.remove(item)
# bin_to_hex.py input_file
if __name__ == "__main__":
bin_to_hex_file(sys.argv[1],"work/"+sys.argv[1]+".txt",int(sys.argv[2]))
# get_layout(0)