From 866f3aed1c6da05520126d28acfd97112a1ba9e4 Mon Sep 17 00:00:00 2001 From: remittor Date: Thu, 15 Sep 2022 14:38:06 +0300 Subject: [PATCH] Add support install OpenWrt FIT images --- install_fw.py | 127 ++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 102 insertions(+), 25 deletions(-) diff --git a/install_fw.py b/install_fw.py index 0cf5107..2522ca5 100644 --- a/install_fw.py +++ b/install_fw.py @@ -33,6 +33,7 @@ fn_local = None dn_tmp = 'tmp/fw/' fn_kernel = dn_tmp + 'kernel.bin' fn_rootfs = dn_tmp + 'rootfs.bin' +fn_fitubi = dn_tmp + 'fitubi.bin' os.makedirs(dn_dir, exist_ok = True) os.makedirs(dn_tmp, exist_ok = True) @@ -104,6 +105,7 @@ class Image(): fn_remote = None data = None data2 = None # unpacked image + fit = False dtb = None # device-tree cmd = None @@ -136,6 +138,53 @@ if c_sysupgrade: # TODO: insert hsqs to UBI FS !!! ''' +def parse_fit(data, offset = 0): + if data[offset:offset+4] != FIT_MAGIC: + die('FIT: Incorrect image (0)') + hdrsize = ctypes.sizeof(fdt_header) + fit_hdr = fdt_header.from_buffer_copy(data[offset:offset+hdrsize]) + fit_size = fit_hdr.totalsize + if fit_size < 1*1024*1024: + die('FIT: Incorrect image (1)') + if kernel.data: + die('FIT: Found second "kernel" section') + kernel.data = data[offset:offset + fit_size] + print('FIT size = 0x%X (%d KiB)' % (fit_size, fit_size // 1024)) + fit_dt = fdt.parse_dtb(kernel.data) + #if fit_dt.root.nodes[0]._name != 'images': + # die('FIT: Incorrect image (4)') + fit_name = fit_dt.get_property('description').value + print('FIT name = "{}"'.format(fit_name)) + kernel.fit = True + if 'OpenWrt FIT' in fit_name: + kernel.ostype = 'openwrt' + if not kernel.ostype: + die('FIT: Currently supported only OpenWrt FIT images!') + ''' + fdt1 = dt.get_node('/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)) + print('FDT compression = "{}"'.format(fdt1.get_property('compression').value)) + if fdt1.get_property('type').value != 'flat_dt': + die('FIT: Incorrect image (6)') + kernel.hdr.arch = fdt1.get_property('arch').value + ''' + if kernel.ostype == 'openwrt': + if len(data) - offset - fit_size < 1024: + return 1 + rootfs_offset = data.find(UBIv1_MAGIC, offset + fit_size) + if rootfs_offset < 0: + return 1 + rootfs_offset -= offset + print('FIT UBI offset = 0x%X' % rootfs_offset) + if rootfs.data: + die('FIT: Found two RootFS images') + rootfs.data = data[offset+rootfs_offset:] + rootfs.addr = rootfs_offset + return 2 + return 1 + def parse_factory(data, offset = 0): if offset + 512 > len(data): return -1 @@ -150,7 +199,7 @@ def parse_factory(data, offset = 0): if kernel_size > len(kernel.data): die("Kernel header is incorrect!") if data[offset:offset+4] == FIT_MAGIC: # factory squashfs image - die('ARM images not supported!') + return parse_fit(data, offset) if kernel_size == 0: die("Kernel header is incorrect!") if kernel_size < 1*1024*1024: @@ -311,7 +360,22 @@ with open(rootfs.fn_local, "wb") as file: if kernel.data[:4] == FIT_MAGIC: - die('FIT images not supported!') + part_fw = dev.get_part('firmware') + part_fw1 = dev.get_part('firmware1') + if part_fw and part_fw1: + kernel.addr = part_fw['addr'] + if not rootfs.addr: + die("FIT: Can't found addr for UBI image") + kernel_size = len(kernel.data) + kernel.data += (b"\x00" * (rootfs.addr - kernel_size)) + rootfs.data + rootfs.addr = None + kernel.fn_remote = '/tmp/fitubi.bin' + kernel.fn_local = fn_fitubi + with open(kernel.fn_local, "wb") as file: + file.write(kernel.data) + kernel.partname = "firmware" # kernel0 + if not kernel.addr: + die("FIT: Can't found partition for flashing FIT image") if kernel.data[:4] == UIMAGE_MAGIC: data2 = kernel.data[0x40:] @@ -406,13 +470,9 @@ if kernel.data[:4] == UIMAGE_MAGIC: rootfs.data = b'\x00' * part2_size -kernel.fn_remote = '/tmp/kernel.bin' -kernel.fn_local = fn_kernel with open(kernel.fn_local, "wb") as file: file.write(kernel.data) -rootfs.fn_remote = '/tmp/rootfs.bin' -rootfs.fn_local = fn_rootfs with open(rootfs.fn_local, "wb") as file: file.write(rootfs.data) @@ -446,7 +506,15 @@ if c_stock: rootfs.addr = dev.partlist[rp]['addr'] rootfs.cmd = 'mtd -e "{part}" write "{bin}" "{part}"'.format(part=rootfs.partname, bin=rootfs.fn_remote) -if kernel.ostype == 'openwrt' or kernel.ostype == 'padavan': +if kernel.fit is True: + if not kernel.addr or not kernel.partname: + die('FIT: Unknown addr for flashing!') + fw_num = 0 + kernel.cmd = 'mtd -e "{part}" write "{bin}" "{part}"'.format(part=kernel.partname, bin=kernel.fn_remote) + rootfs.cmd = None + +elif kernel.ostype == 'openwrt' or kernel.ostype == 'padavan': + fw_addr = 0 if not kernel.addr or not rootfs.addr: die('Unknown addr for flashing!') part = dev.get_part_by_addr(kernel.addr) @@ -490,35 +558,44 @@ if dev.bl.type == 'breed': fw_addr = activate_boot.breed_boot_change(gw, dev, None, kernel.addr, None) pass -if fw_num is not None: - print("Run scripts for change NVRAM params...") - activate_boot.uboot_boot_change(gw, fw_num) - print('Boot from partition "kernel{}" activated.'.format(fw_num)) - -if not kernel.cmd or not rootfs.cmd: +if not kernel.cmd or (not kernel.fit and not rootfs.cmd): die("Flashing recipe unknown!") gw.set_timeout(12) gw.upload(kernel.fn_local, kernel.fn_remote) -gw.upload(rootfs.fn_local, rootfs.fn_remote) - -cmd = "nvram set bootdelay=3; nvram set boot_wait=on; nvram set ssh_en=1; nvram commit;" +if rootfs.cmd: + gw.upload(rootfs.fn_local, rootfs.fn_remote) + +cmd = [] +cmd.append("nvram set bootdelay=3") +cmd.append("nvram set boot_wait=on") +cmd.append("nvram set bootmenu_delay=30") +cmd.append("nvram set ssh_en=1") +cmd.append("nvram set uart_en=1") +cmd.append("nvram commit") gw.run_cmd(cmd, timeout = 8) +if fw_num is not None: + print("Run scripts for change NVRAM params...") + activate_boot.uboot_boot_change(gw, fw_num) + print('Boot from partition "{}" activated.'.format(kernel.partname)) + print('Writing kernel image to addr {} ...'.format("0x%08X" % kernel.addr)) print(" " + kernel.cmd) -gw.run_cmd(kernel.cmd, timeout = 22) +gw.run_cmd(kernel.cmd, timeout = 34) -print('Writing rootfs image to addr {} ...'.format("0x%08X" % rootfs.addr)) -print(" " + rootfs.cmd) -gw.run_cmd(rootfs.cmd, timeout = 60) +if rootfs.cmd: + print('Writing rootfs image to addr {} ...'.format("0x%08X" % rootfs.addr)) + print(" " + rootfs.cmd) + gw.run_cmd(rootfs.cmd, timeout = 60) print("The firmware has been successfully flashed!") -gw.run_cmd("sync ; umount -a", timeout = 12) - - - - +if kernel.fit: + print('Send command "reboot" via SSH ...') + gw.run_cmd("reboot -f") + print("Force REBOOT activated!") +else: + gw.run_cmd("sync ; umount -a", timeout = 12)