Skip to content

Instantly share code, notes, and snippets.

@ahxxm
Last active February 18, 2023 13:30
Show Gist options
  • Save ahxxm/ec4aae6191f638a7f36c4d98a1c8a476 to your computer and use it in GitHub Desktop.
Save ahxxm/ec4aae6191f638a7f36c4d98a1c8a476 to your computer and use it in GitHub Desktop.
python3 compatible crclist.txt file update script, use after patching boot.img. backup sparsecrc.txt in case failed to flash `super`
#!/usr/bin/env python
# fixes: 2to3 syntax, assertions for int(d1/d2) value
from __future__ import print_function
import getopt, posixpath, signal, struct, sys
import os, copy
import binascii
sparse_file_list = {
"super":"super.img",
"cust":"cust.img",
"rescue":"rescue.img",
"userdata":"userdata.img",
}
unsparse_file_list = {
"preloader1":"preloader_xaga.bin",
"preloader2":"preloader_xaga.bin",
"vbmeta_a":"vbmeta.img",
"vbmeta_system_a":"vbmeta_system.img",
"vbmeta_vendor_a":"vbmeta_vendor.img",
"md1img_a":"md1img.img",
"spmfw_a":"spmfw.img",
"mcf_ota_a":"mcf_ota.img",
"audio_dsp_a":"audio_dsp.img",
"pi_img_a":"pi_img.img",
"dpm_a":"dpm.img",
"scp_a":"scp.img",
"ccu_a":"ccu.img",
"vcp_a":"vcp.img",
"sspm_a":"sspm.img",
"mcupm_a":"mcupm.img",
"gpueb_a":"gpueb.img",
"apusys_a":"apusys.img",
"mvpu_algo_a":"mvpu_algo.img",
"gz_a":"gz.img",
"lk_a":"lk.img",
"boot_a":"boot.img",
"vendor_boot_a":"vendor_boot.img",
"dtbo_a":"dtbo.img",
"tee_a":"tee.img",
"logo_a":"logo.bin",
}
MAX_DOWNLOAD_SIZE = 256*1024*1024;
MAX_SPARSE_PARTS = 68;
SPARSE_IMAGE_HEAD_SZ = 28;
SPARSE_CHUNK_HEAD_SZ = 12;
SPARSE_OVER_HEAD_SZ = SPARSE_IMAGE_HEAD_SZ + 2*SPARSE_CHUNK_HEAD_SZ + 4
file_list=dict(unsparse_file_list,**sparse_file_list)
class SparseChunk:
def __init__(self):
self.type = 0
self.size = 0
self.total_sz = 0
self.data_sz = 0
self.bksz = 0
self.data = []
def split_sparse_chunk(backed_sz,bck,sck):
split_max_len = MAX_DOWNLOAD_SIZE - SPARSE_OVER_HEAD_SZ
backed_real_sz = backed_sz[0] - SPARSE_CHUNK_HEAD_SZ - 4
if backed_real_sz + bck.data_sz<= split_max_len:
backed_sz[0] += bck.total_sz
return 0,0
elif backed_real_sz >= (split_max_len*7)/8 :
if bck.total_sz <= split_max_len :
backed_sz[0] = bck.total_sz + SPARSE_IMAGE_HEAD_SZ + SPARSE_CHUNK_HEAD_SZ
return 0,1
else:
over_flag = 1
backed_real_sz = 0
else:
over_flag = 0
split_sz = bck.bksz * ((split_max_len - backed_real_sz) / bck.bksz)
sck.type = bck.type
sck.size = bck.size
sck.bksz = bck.bksz
sck.data_sz = bck.data_sz - split_sz
sck.total_sz = sck.data_sz + SPARSE_CHUNK_HEAD_SZ
print(f"split_sz is {split_sz}")
assert split_sz == int(split_sz)
split_sz = int(split_sz)
sck.data = bck.data[split_sz:]
sck.size = sck.total_sz / sck.bksz
bck.data_sz = split_sz
bck.total_sz = bck.data_sz + SPARSE_CHUNK_HEAD_SZ
bck.data = bck.data[:bck.data_sz]
bck.size = bck.total_sz / bck.bksz
if over_flag == 1:
backed_sz[0] = bck.total_sz
return 1,1
else:
backed_sz[0] = SPARSE_CHUNK_HEAD_SZ + SPARSE_IMAGE_HEAD_SZ
return 1,2
def read_chunk_from_file(FH,blk_sz):
chunk = SparseChunk()
header_bin = FH.read(12)
header = struct.unpack("<2H2I", header_bin)
chunk.type = header[0]
reserved1 = header[1]
chunk.size = header[2]
chunk.total_sz = header[3]
chunk.bksz = blk_sz
chunk.data_sz = chunk.total_sz - SPARSE_CHUNK_HEAD_SZ
#print ("chunk.type=0x%x reserved1=0x%x chunk.size=%d chunk.total_sz=%d chunk.bksz=%d chunk.data_sz=%d " % (chunk.type, reserved1, chunk.size, chunk.total_sz, chunk.bksz,chunk.data_sz))
if chunk.type == 0xCAC1:
if chunk.data_sz != (chunk.size * blk_sz):
raise Exception(" Raw chunk input size (%u) does not match output size (%u)!!!"
% (chunk.data_sz, chunk.size * blk_sz))
else:
chunk.data = FH.read(chunk.data_sz)
elif chunk.type == 0xCAC2:
if chunk.data_sz != 4:
raise Exception("Fill chunk should have 4 bytes of fill, but this has %u!!!"
% (chunk.data_sz), end="")
else:
chunk.data = FH.read(4)
elif chunk.type == 0xCAC3:
if chunk.data_sz != 0:
print("Don't care chunk input size is non-zero (%u)" % (chunk.data_sz))
elif chunk.type == 0xCAC4:
if chunk.data_sz != 4:
raise Exception("CRC32 chunk should have 4 bytes of CRC, but this has %u!!!"
% (chunk.data_sz), end="")
else:
chunk.data = FH.read(4)
crc = struct.unpack("<I",chunk.data)
print("Unverified CRC32 0x%08X" % (crc))
else:
raise Exception("Unknown chunk type 0x%04X!!!" % (chunk.type), end="")
return chunk
def calulate_sparse_chunk_crc(chunk,crc):
if chunk.type == 0xCAC1:
crc = binascii.crc32(chunk.data,crc)
elif chunk.type == 0xCAC2:
tmp = chunk.bksz/chunk.data_sz
assert tmp == int(tmp)
print(f"tmp value is {tmp}, int {int(tmp)}")
fill_buf = chunk.data*(int(chunk.bksz/chunk.data_sz))
for j in range(1,chunk.size+1):
crc = binascii.crc32(fill_buf,crc)
return crc
def gen_sparse_crc(path):
sparse_parts = 0
crc_result_list = [0 for i in range(MAX_SPARSE_PARTS)]
backedsize = [SPARSE_IMAGE_HEAD_SZ]
FH = open(path, 'rb')
header_bin = FH.read(SPARSE_IMAGE_HEAD_SZ)
header = struct.unpack("<I4H4I", header_bin)
magic = header[0]
major_version = header[1]
minor_version = header[2]
file_hdr_sz = header[3]
chunk_hdr_sz = header[4]
blk_sz = header[5]
total_blks = header[6]
total_chunks = header[7]
image_checksum = header[8]
image_sz = 0
if magic != 0xED26FF3A:
raise Exception("%s: Magic should be 0xED26FF3A but is 0x%08X"
% (path, magic))
if major_version != 1 or minor_version != 0:
raise Exception("%s: I only know about version 1.0, but this is version %u.%u"
% (path, major_version, minor_version))
if file_hdr_sz != 28:
raise Exception("%s: The file header size was expected to be 28, but is %u."
% (path, file_hdr_sz))
if chunk_hdr_sz != 12:
raise Exception("%s: The chunk header size was expected to be 12, but is %u."
% (path, chunk_hdr_sz))
print("%s: Total of %u %u-byte output blocks in %u input chunks."
% (path, total_blks, blk_sz, total_chunks))
if image_checksum != 0:
print("checksum=0x%08X" % (image_checksum))
offset = 0
for i in range(1,total_chunks+1):
rchunk = read_chunk_from_file(FH,blk_sz)
split_flag = 1
sck = SparseChunk()
while(split_flag == 1):
split_flag,sparse_part = split_sparse_chunk(backedsize,rchunk,sck)
if (sparse_part==1): sparse_parts += 1
crc_result_list[sparse_parts] = calulate_sparse_chunk_crc(rchunk,crc_result_list[sparse_parts])
if (sparse_part==2): sparse_parts += 1
#print("%d : crc_result_list[%d] = 0x%x" % (i , sparse_parts , crc_result_list[sparse_parts] & (2**32-1)))
rchunk = copy.deepcopy(sck)
return sparse_parts + 1, crc_result_list
def gen_crc(file_path):
f = open(file_path, "rb")
crc = binascii.crc32(f.read())
return crc
def get_sparse_count(cmd):
line = os.popen(cmd, 'r').readline()
if line[0]=='I' or line[0]=='i':
return -1;
return int(line)
#------------------------------------------------------------------------------
if __name__ == "__main__":
thispath = os.path.dirname(__file__)
path = os.path.join(thispath, 'images')
crclist = os.path.join(path, 'crclist.txt')
sparsecrclist = os.path.join(path, 'sparsecrclist.txt')
crc = 0
try:
fs = open(sparsecrclist, 'w')
f = open(crclist, 'w')
fs.write("SPARSECRC-LIST\n")
f.write("CRC-LIST\n")
for ptn in file_list:
filepath = os.path.join(path, file_list[ptn])
print(filepath)
if not os.path.isfile(filepath):
print(filepath + ' doesn\'t exist, skip it')
continue
if ptn in unsparse_file_list:
crc = gen_crc(filepath)
if crc:
f.write(ptn + ' ' + hex(crc & (2**32-1)) + '\n')
else:
size = os.path.getsize(filepath)
parts,crclist = gen_sparse_crc(filepath)
if parts == 0:
raise Exception("sparse file error!!!!!!!")
else:
fs.write(ptn + ' ' + str(parts))
for i in range(1,parts+1):
fs.write(' ' + hex(crclist[i-1] & (2**32-1)))
fs.write('\n')
except Exception as e:
os.remove(crclist)
os.remove(sparsecrclist)
raise
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment