[install_fw] Fix FDT parsing (part list and other)

pull/24/head
remittor 1 year ago
parent b782ca1426
commit 1b04256d39

@ -148,7 +148,17 @@ class XqFlash():
self.cpuarch = self.dev.info.cpu_arch
if self.cpuarch not in 'mips armv7 arm64':
die("Currently support only MIPS, ARMv7, ARM64 arch!")
'''
if True:
for part in self.dev.partlist:
if part['name'] == 'firmware':
part['name'] = 'ubi'
if part['name'] == 'firmware1':
part['name'] = 'ubi1'
if part['name'] == 'kernel':
part['name'] = '_kernel'
print('=== device partlist patched ===')
'''
self.img_stock_names = { }
print('Parse all images...')
for img in self.imglist:
@ -212,7 +222,7 @@ class XqFlash():
self.init_image(self.fw_img, image, 'Incorrect image! (403)')
if img_name:
self.img_stock_names[img_name] = len(image)
self.save_all_images(req_cmd = False, prefix = "_ubi_")
#self.save_all_images(req_cmd = False, prefix = "_ubi_")
return hr
def parse_stock_image(self, image):
@ -360,6 +370,55 @@ class XqFlash():
return 2
return 1
def get_fdt_node(self, dt, path):
plist = [ path ]
if '*' in path:
plist = [ ]
plist.append(path.replace('*', '-'))
plist.append(path.replace('*', '@'))
for npath in plist:
try:
node = dt.get_node(npath)
return node
except ValueError:
pass
return None
def get_fdt_node_by_name(self, dt, name, compatible = None):
res = [ ]
for path, nodes, props in dt.walk():
nodename = os.path.basename(path)
if nodename == name:
if compatible:
try:
compat = dt.get_property('compatible', path)
except ValueError:
continue # go to next node
if compat.value != compatible:
continue # go to next node
res.append(path)
return res
def get_fdt_part_list(self, dt, partlist):
res = [ ]
if isinstance(partlist, str):
partlist = dt.get_node(partlist)
for node in partlist.nodes:
name = node.get_property('label').value
addr = node.get_property('reg')[0]
size = node.get_property('reg')[1]
readonly = False
if node.get_property('read-only'):
readonly = True
res.append( { 'addr': addr, 'size': size, 'name': name, 'ro': readonly } )
return res
def get_dtb_part_info(self, partlist, name):
for i, part in enumerate(partlist):
if part['name'] == name:
return part
return None
def parse_fit(self, image, offset = 0, footer = True):
kernel = self.kernel
rootfs = self.rootfs
@ -382,30 +441,69 @@ class XqFlash():
kernel.ostype = None
print('FIT size = 0x%X (%d KiB)' % (fit_size, fit_size // 1024))
fit_dt = fdt.parse_dtb(kernel.data)
#print(fit_dt.info(props = True))
#if fit_dt.root.nodes[0]._name != 'images':
# die('FIT: Incorrect image (4)')
fit_name = fit_dt.get_property('description').value
print(f'FIT: name = "{fit_name}"')
self.fit_dt = fit_dt
fdt1 = self.get_fdt_node(fit_dt, '/images/fdt*1')
print('FDT: desc = "{}"'.format(fdt1.get_property('description').value))
print('FDT: type = "{}"'.format(fdt1.get_property('type').value))
print('FDT: arch = "{}"'.format(fdt1.get_property('arch').value))
if fdt1.get_property('type').value != 'flat_dt':
die('FIT: Incorrect image (6)')
if fdt1.get_property('compression').value != 'none':
die('FIT: Incorrect image (7)')
kernel.hdr.arch = fdt1.get_property('arch').value
krn1 = self.get_fdt_node(fit_dt, '/images/kernel*1')
print('KRN: desc = "{}"'.format(krn1.get_property('description').value))
print('KRN: type = "{}"'.format(krn1.get_property('type').value))
print('KRN: arch = "{}"'.format(krn1.get_property('arch').value))
print('KRN: compression = "{}"'.format(krn1.get_property('compression').value))
print(f'KRN: len(data) = {len(krn1.get_property("data"))} bytes')
krn_dt_data = fdt1.get_property('data').data
dt = fdt.parse_dtb(krn_dt_data)
self.krn_dt = dt
dt_tree = dt.info(props = True)
#with open('dt_tree.txt', "w") as file:
# file.write(dt_tree)
dt_compat = dt.get_property('compatible').value
print(f'FDT: compatible = "{dt_compat}"')
dt_model = dt.get_property('model').value
print(f'FDT: model = "{dt_model}"')
dt_part = self.get_fdt_node_by_name(dt, 'partitions', 'fixed-partitions')
print(f'FDT: dt_part: {dt_part}')
kernel.fit = True
if self.img_stock:
kernel.ostype = 'stock' # aka OpenWRT
kernel.ostype = 'stock'
else:
if 'OpenWrt FIT' in fit_name:
kernel.ostype = 'openwrt'
if not kernel.ostype:
die('FIT: Currently supported only OpenWrt FIT images!')
if kernel.into_ubi:
x1 = kernel.data.find(b'ARM64 OpenWrt xiaomi', 1*1024*1024)
if x1 > 0:
iname = extract_str(kernel.data, x1, maxlen = 256)
print(f'FIT: Found rootfs image: "{iname}"')
self.init_image(rootfs, kernel.data[x1:], 'FIT: Found second "rootfs" section!')
if ' initrd' in iname:
kernel.initrd = True
rootfs.initrd = True
if kernel.into_ubi:
rootfs.into_ubi = True
return 2
rootfs1 = self.get_fdt_node(fit_dt, '/images/rootfs*1')
if rootfs1:
die('FIT: Founded "rootfs-1" node. Not supported!')
initrd1 = self.get_fdt_node(fit_dt, '/images/initrd*1')
if initrd1:
print('FIT: Founded "initrd-1" node')
iname = initrd1.get_property('description').value
print(f'FIT: initrd image name: "{iname}"')
if self.img_stock:
die('FIT: Error (4566)')
initrd1_data = initrd1.get_property('data')
self.init_image(rootfs, initrd1.get_property('data').data, 'FIT: Found second "rootfs" section!')
kernel.initrd = True
rootfs.initrd = True
if kernel.into_ubi:
rootfs.into_ubi = True
return 2
if footer:
hr = self.parse_footer(image, offset + fit_size)
if hr >= 1:
@ -569,7 +667,23 @@ class XqFlash():
dtb = get_dtb(kernel.data2, 0)
if not dtb:
die("Can't found FDT (flattened device tree)")
kernel_part = get_dtb_part_info(dtb, "kernel")
dt = fdt.parse_dtb(dtb)
#print(dt.info(props = True))
dt_compat = dt.get_property('compatible').value
print(f'FDT: compatible = "{dt_compat}"')
dt_model = dt.get_property('model').value
print(f'FDT: model = "{dt_model}"')
self.dt = dt
dt_part = self.get_fdt_node_by_name(dt, 'partitions', 'fixed-partitions')
print(f'FDT: dt_part: {dt_part}')
if len(dt_part) == 0:
die("Cannot found fixed-partitions node into FDT")
if len(dt_part) > 1:
die("Several nodes were found with fixed-partition info")
dt_part = dt_part[0]
partlist = self.get_fdt_part_list(dt, dt_part)
#print(partlist)
kernel_part = self.get_dtb_part_info(partlist, "kernel")
if not kernel_part:
die('Cannot found "kernel" partition in DTB!')
print('part kernel = 0x%X (size: 0x%X)' % (kernel_part['addr'], kernel_part['size']))
@ -577,9 +691,9 @@ class XqFlash():
part = dev.get_part_by_addr(kernel.addr)
if not part:
die("Can't support flashing kernel to addr 0x%X" % kernel.addr)
kernel2_part = get_dtb_part_info(dtb, "kernel_dup")
kernel2_part = self.get_dtb_part_info(partlist, "kernel_dup")
if not kernel2_part:
kernel2_part = get_dtb_part_info(dtb, "kernel_stock")
kernel2_part = self.get_dtb_part_info(partlist, "kernel_stock")
if not kernel2_part:
die('Cannot found "kernel_dup"/"kernel_stock" partition in DTB!')
print('part kernel2 = 0x%X (size: 0x%X)' % (kernel2_part['addr'], kernel2_part['size']))
@ -587,7 +701,7 @@ class XqFlash():
part = dev.get_part_by_addr(kernel.addr2)
if not part:
die("Can't support flashing kernel to addr 0x%X" % kernel.addr2)
ubi_part = get_dtb_part_info(dtb, "ubi")
ubi_part = self.get_dtb_part_info(partlist, "ubi")
if not ubi_part:
die('Cannot found "ubi" partition in DTB!')
print('part ubi = 0x%X (size: 0x%X)' % (ubi_part['addr'], ubi_part['size']))

Loading…
Cancel
Save