UBI Image Generation for OEM-Compatible Firmware

Hi
I have this device I am trying to add support to
which i have failed to produce an image that boots

The device accepts firmware upgrade through OEM upgrade server only
U-Boot is Locked

So long story short i have managed to replicate OEM upgrade server

Also the Device firmware hosted encrypted, so i have managed to decrypt the OEM firmware.
and also encrypt my custom built Openwrt image

The OEM decrypted firmware contain Header + UBI + Footer

the header and footer looks very similar to what qsdk-ipq-factory-nand generate.
but the OEM has in includes installation script. and also has file name + SHA-1 hash for the name

Long story short, i had to use the Header and the footer structure for the firmware to pass OEM checks

By only replacing OEM UBI with mine and change UBI checksum at the footer

But Openwrt UBI is very different than the OEM

Here are OEM information starting with ubireader info for OEM decrypted firmware

ubireader_display_info OEM_decrypted.img
UBI_File Warning: end_offset - start_offset length is not block aligned, could mean missing data.
UBI File
---------------------
        Min I/O: 2048
        LEB Size: 126976
        PEB Size: 131072
        Total Block Count: 175
        Data Block Count: 173
        Layout Block Count: 2
        Internal Volume Block Count: 0
        Unknown Block Count: 0
        First UBI PEB Number: 1

        Image: 402958865
        ---------------------
                Image Sequence Num: 402958865
                Volume Name:kernel
                Volume Name:ubi_rootfs
                Volume Name:rootfs_data
                PEB Range: 2 - 174

                Volume: kernel
                ---------------------
                        Vol ID: 0
                        Name: kernel
                        Block Count: 38

                        Volume Record
                        ---------------------
                                alignment: 1
                                crc: '0xa55489c5'
                                data_pad: 0
                                errors: ''
                                flags: 0
                                name: 'kernel'
                                name_len: 6
                                padding: '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
                                rec_index: 0
                                reserved_pebs: 38
                                upd_marker: 0
                                vol_type: 'dynamic'


                Volume: ubi_rootfs
                ---------------------
                        Vol ID: 1
                        Name: ubi_rootfs
                        Block Count: 135

                        Volume Record
                        ---------------------
                                alignment: 1
                                crc: '0xc8d0565'
                                data_pad: 0
                                errors: ''
                                flags: 0
                                name: 'ubi_rootfs'
                                name_len: 10
                                padding: '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
                                rec_index: 1
                                reserved_pebs: 135
                                upd_marker: 0
                                vol_type: 'dynamic'


                Volume: rootfs_data
                ---------------------
                        Vol ID: 2
                        Name: rootfs_data
                        Block Count: 0

                        Volume Record
                        ---------------------
                                alignment: 1
                                crc: '0xa1d725dc'
                                data_pad: 0
                                errors: ''
                                flags: 'autoresize'
                                name: 'rootfs_data'
                                name_len: 11
                                padding: '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
                                rec_index: 2
                                reserved_pebs: 1
                                upd_marker: 0
                                vol_type: 'dynamic'

from within a working device

/ # cat /proc/mtd
dev:    size   erasesize  name
mtd0: 00040000 00010000 "0:SBL1"
mtd1: 00020000 00010000 "0:MIBIB"
mtd2: 00060000 00010000 "0:QSEE"
mtd3: 00010000 00010000 "0:CDT"
mtd4: 00010000 00010000 "0:DDRPARAMS"
mtd5: 00010000 00010000 "0:APPSBLENV"
mtd6: 00080000 00010000 "0:APPSBL"
mtd7: 00010000 00010000 "0:ART"
mtd8: 00020000 00010000 "0:BOOTCONFIG"
mtd9: 00020000 00010000 "0:BOOTCONFIG1"
mtd10: 00030000 00010000 "RESV"
mtd11: 00010000 00010000 "RESV0"
mtd12: 02900000 00020000 "rootfs"
mtd13: 02900000 00020000 "rootfs_1"
mtd14: 01200000 00020000 "RESV1"
mtd15: 00c00000 00020000 "qcacfg"
mtd16: 01000000 00020000 "qcalog"
mtd17: 0049a000 0001f000 "kernel"
mtd18: 00e88000 0001f000 "ubi_rootfs"
mtd19: 013bd000 0001f000 "rootfs_data"
mtd20: 008b8000 0001f000 "qcacfg"
mtd21: 00c98000 0001f000 "qcalog"
/ # ubinfo -a
UBI version:                    1
Count of UBI devices:           3
UBI control device major/minor: 10:59
Present UBI devices:            ubi0, ubi1, ubi2

ubi0
Volumes count:                           3
Logical eraseblock size:                 126976 bytes, 124.0 KiB
Total amount of logical eraseblocks:     328 (41648128 bytes, 39.7 MiB)
Amount of available logical eraseblocks: 0 (0 bytes)
Maximum count of volumes                 128
Count of bad physical eraseblocks:       0
Count of reserved physical eraseblocks:  3
Current maximum erase counter value:     4
Minimum input/output unit size:          2048 bytes
Character device major/minor:            248:0
Present volumes:                         0, 1, 2

Volume ID:   0 (on ubi0)
Type:        dynamic
Alignment:   1
Size:        38 LEBs (4825088 bytes, 4.6 MiB)
State:       OK
Name:        kernel
Character device major/minor: 248:1
-----------------------------------
Volume ID:   1 (on ubi0)
Type:        dynamic
Alignment:   1
Size:        120 LEBs (15237120 bytes, 14.5 MiB)
State:       OK
Name:        ubi_rootfs
Character device major/minor: 248:2
-----------------------------------
Volume ID:   2 (on ubi0)
Type:        dynamic
Alignment:   1
Size:        163 LEBs (20697088 bytes, 19.7 MiB)
State:       OK
Name:        rootfs_data
Character device major/minor: 248:3

===================================

ubi1
Volumes count:                           1
Logical eraseblock size:                 126976 bytes, 124.0 KiB
Total amount of logical eraseblocks:     96 (12189696 bytes, 11.6 MiB)
Amount of available logical eraseblocks: 0 (0 bytes)
Maximum count of volumes                 128
Count of bad physical eraseblocks:       0
Count of reserved physical eraseblocks:  20
Current maximum erase counter value:     17
Minimum input/output unit size:          2048 bytes
Character device major/minor:            247:0
Present volumes:                         0

Volume ID:   0 (on ubi1)
Type:        dynamic
Alignment:   1
Size:        72 LEBs (9142272 bytes, 8.7 MiB)
State:       OK
Name:        qcacfg
Character device major/minor: 247:1

===================================

ubi2
Volumes count:                           1
Logical eraseblock size:                 126976 bytes, 124.0 KiB
Total amount of logical eraseblocks:     128 (16252928 bytes, 15.5 MiB)
Amount of available logical eraseblocks: 0 (0 bytes)
Maximum count of volumes                 128
Count of bad physical eraseblocks:       0
Count of reserved physical eraseblocks:  20
Current maximum erase counter value:     5
Minimum input/output unit size:          2048 bytes
Character device major/minor:            240:0
Present volumes:                         0

Volume ID:   0 (on ubi2)
Type:        dynamic
Alignment:   1
Size:        104 LEBs (13205504 bytes, 12.6 MiB)
State:       OK
Name:        qcalog
Character device major/minor: 240:1

Now Again I am trying to explain every thing so stay with me

the firmware image i generated with replacing OEM UBI and only changing crc32 checksum at the footer
Accepted by device and flashed to inactive part and device reboots but fails to read UBI and verify checksum

DRAM:  256 MiB
machid : 0x8010100
NAND:  spi_nand: spi_nand_flash_probe SF NAND ID 0:ef:aa:21
SF: Detected W25N01GV with page size 2 KiB, total 128 MiB
SF: Detected W25Q32 with page size 4 KiB, total 4 MiB
ipq_spi: page_size: 0x100, sector_size: 0x1000, size: 0x400000
132 MiB
Boot act=0
0x000000000000-0x000002900000 : "mtd=0"
UBI error: check_sv: bad scanning information, error 1
UBI error: ubi_init: cannot attach mtd2
UBI error: ubi_init: UBI error: cannot initialize UBI, error -22
UBI init error 22


Image checksum error!!!

and then reset and change active side to 1 and boot OEM firmware.

Now the thing is OEM UBI is 22400KiB 0x015E0000 and has 6 blocks 0x1000 each has 0xDEADC0DE mark at the end of the UBI at these offsets

0x0158A000
0x0158B000
0x0158D000
0x01595000
0x015A6000
0x015C7000

now I have failed to generate a UBI that is identical to OEM I have tried many things
Using pad-to 22400k pads the UBI to the size but with 0x00
trying to set volume names and sizes from image recipe failed
using qsdk-ipq-factory-nand also failed i had to use OEM's pre generated

So how can I generate UBI that has specific volume names and sizes?
And is this is the problem ?

Help is much appreciated

have you tried to dump the decrypted firmware with dumpimage ?

ie ..

ipq50xx$ dumpimage -l openwrt-qualcommax-ipq50xx-glinet_gl-b3000-squashfs-factory.img
Image contains unit addresses @, this will break signing
FIT description: OpenWrt factory image
Created:         Mon Apr 21 11:12:42 2025
 Image 0 (script)
  Description:  glinet_gl-b3000 uboot bootscript
  Created:      Mon Apr 21 11:12:42 2025
  Type:         Script
  Compression:  uncompressed
  Data Size:    1518 Bytes = 1.48 KiB = 0.00 MiB
  Hash algo:    crc32
  Hash value:   5c8e2d31
 Image 1 (ubi)
  Description:  ubi
  Created:      Mon Apr 21 11:12:42 2025
  Type:         Firmware
  Compression:  uncompressed
  Data Size:    16908288 Bytes = 16512.00 KiB = 16.12 MiB
  Architecture: ARM
  OS:           Unknown OS
  Load Address: unavailable
  Hash algo:    crc32
  Hash value:   966ef639
ipq50xx$ dumpimage -l openwrt-qualcommax-ipq50xx-glinet_gl-b3000-initramfs-uImage.itb
Image contains unit addresses @, this will break signing
FIT description: ARM64 OpenWrt FIT (Flattened Image Tree)
Created:         Mon Apr 21 11:12:42 2025
 Image 0 (kernel-1)
  Description:  ARM64 OpenWrt Linux-6.6.87
  Created:      Mon Apr 21 11:12:42 2025
  Type:         Kernel Image
  Compression:  gzip compressed
  Data Size:    15805986 Bytes = 15435.53 KiB = 15.07 MiB
  Architecture: AArch64
  OS:           Linux
  Load Address: 0x41080000
  Entry Point:  0x41080000
  Hash algo:    crc32
  Hash value:   b04c4005
  Hash algo:    sha1
  Hash value:   3e82055eb66d1dd896ea02ecd1a69d6fe025b95e
 Image 1 (fdt-1)
  Description:  ARM64 OpenWrt glinet_gl-b3000 device tree blob
  Created:      Mon Apr 21 11:12:42 2025
  Type:         Flat Device Tree
  Compression:  uncompressed
  Data Size:    24436 Bytes = 23.86 KiB = 0.02 MiB
  Architecture: AArch64
  Hash algo:    crc32
  Hash value:   c89c61c8
  Hash algo:    sha1
  Hash value:   9915ddd8fb57f7b4eeb5e314e04b5f8249b69183
 Default Configuration: 'config@mp03.5-c1'
 Configuration 0 (config@mp03.5-c1)
  Description:  OpenWrt glinet_gl-b3000
  Kernel:       kernel-1
  FDT:          fdt-1

if you can take it apart with dumpimage, you can put it back together with mkimage afterwards

ipq50xx$ mkimage -h
mkimage: invalid option -- 'h'
Error: Invalid option
Usage: mkimage [-T type] -l image
          -l ==> list image header information
          -T ==> parse image file as 'type'
          -q ==> quiet
       mkimage [-x] -A arch -O os -T type -C comp -a addr -e ep -n name -d data_file[:data_file...] image
          -A ==> set architecture to 'arch'
          -O ==> set operating system to 'os'
          -T ==> set image type to 'type'
          -C ==> set compression type 'comp'
          -a ==> set load address to 'addr' (hex)
          -e ==> set entry point to 'ep' (hex)
          -n ==> set image name to 'name'
          -R ==> set second image name to 'name'
          -d ==> use image data from 'datafile'
          -x ==> set XIP (execute in place)
          -s ==> create an image with no data
          -v ==> verbose
       mkimage [-D dtc_options] [-f fit-image.its|-f auto|-f auto-conf|-F] [-b <dtb> [-b <dtb>]] [-E] [-B size] [-i <ramdisk.cpio.gz>] fit-image
           <dtb> file is used with -f auto, it may occur multiple times.
          -D => set all options for device tree compiler
          -f => input filename for FIT source
          -i => input filename for ramdisk file
          -E => place data outside of the FIT structure
          -B => align size in hex for FIT structure and header
          -b => append the device tree binary to the FIT
          -t => update the timestamp in the FIT
Signing / verified boot options: [-k keydir] [-K dtb] [ -c <comment>] [-p addr] [-r] [-N engine]
          -k => set directory containing private keys
          -K => write public keys to this .dtb file
          -g => set key name hint
          -G => use this signing key (in lieu of -k)
          -c => add comment in signature node
          -F => re-sign existing FIT image
          -p => place external data at a static position
          -r => mark keys used as 'required' in dtb
          -N => openssl engine to use for signing
          -o => algorithm to use for signing
       mkimage -V ==> print version information and exit
Use '-T list' to see a list of available image types
Long options are available; read the man page for details

Hi Hostle

well using dumpimage from within the device

/tmp/usb/kt # dumpimage -l OEM_decrypted.img
FIT description: Flashing norplusnand 100 10000
Created:         Fri Sep  8 05:48:24 2023
 Image 0 (script)
  Description:  flash.scr
  Type:         Script
  Compression:  uncompressed
  Data Size:    12026 Bytes = 11.74 kB = 0.01 MB
  Hash algo:    crc32
  Hash value:   d1f44996
 Image 1 (ubi-2113e3f3cc2a94e31f40d2c220669cca1b7e2845)
  Description:  openwrt-ipq806x-ipq40xx-ubi-root.img
  Type:         Firmware
  Compression:  uncompressed
  Data Size:    22937600 Bytes = 22400.00 kB = 21.88 MB
  Architecture: ARM
  Load Address: unavailable
  Hash algo:    crc32
  Hash value:   69e7267b

that's the script i am talking about.
that's exactly what i am using in my custom built image. otherwise the device would not accepted and flashed my image.

the issue that i cannot produce UBI that works !

then just use dump image to extraxt the ubi ...

dump the flash.src

dumpimage -T flat_dt -p 0 -o flash.scr  OEM_decrypted.img

and then the ubi

dumpimage -T flat_dt -p 1 -o ubi.bin  OEM_decrypted.img

-T : type flat_dt
-p partition #
-o output name

you can see how i build similar images for the gl-b3000

note there is a few error in the gl-qsdk-factory make function, you mat or may not have spotted this, it was corrected via patch after the fact. but it should be enough to get you going ... bonus points if you spot the errors in the make recipe .. :slight_smile:

1 Like

well the version within the device has limited options

 dumpimage -h
dumpimage: invalid option -- h
Usage: dumpimage -l image
          -l ==> list image header information
       dumpimage -i image [-p position] [-o outfile] data_file
          -i ==> extract from the 'image' a specific 'data_file', indexed by 'position' (starting at 0)
       dumpimage -V ==> print version information and exit
       dumpimage -c image
          -c ==> do board upgrade check

I see your device now and it is interesting i have to build my own flash.scr
I have the script content extracted already using hexworkshop + AI :slight_smile:
I did not knew i could use dumpimage to extract the script.

if test "x$verbose" = "x"; then
failedmsg='[failed]'
else
failedmsg='######################################## Failed'
fi
if test "$machid" = "8010000"; then

sf probe || setenv stdout serial && echo "$failedmsg" && exit 1
if test "x$verbose" = "x"; then
echo \\c'Flashing ubi:                           '
setenv stdout nulldev
else
echo '######################################## Flashing ubi: Started'
fi
imxtract $imgaddr ubi-2113e3f3cc2a94e31f40d2c220669cca1b7e2845 || setenv stdout serial && echo "$failedmsg" && exit 1
nand device 1 && nand erase 0x00000000 0x02900000 || setenv stdout serial && echo "$failedmsg" && exit 1
nand write $fileaddr 0x00000000 0x015e0000 || setenv stdout serial && echo "$failedmsg" && exit 1
if test "x$verbose" = "x"; then
setenv stdout serial
echo '[ done ]'
setenv stdout nulldev
setenv stdout serial
else
echo '######################################## Flashing ubi: Done'
fi
exit 0

fi

if test "x$verbose" = "x"; then
failedmsg='[failed]'
else
failedmsg='######################################## Failed'
fi
if test "$machid" = "8010100"; then

sf probe || setenv stdout serial && echo "$failedmsg" && exit 1
if test "x$verbose" = "x"; then
echo \\c'Flashing ubi:                           '
setenv stdout nulldev
else
echo '######################################## Flashing ubi: Started'
fi
imxtract $imgaddr ubi-2113e3f3cc2a94e31f40d2c220669cca1b7e2845 || setenv stdout serial && echo "$failedmsg" && exit 1
nand device 1 && nand erase 0x00000000 0x02900000 || setenv stdout serial && echo "$failedmsg" && exit 1
nand write $fileaddr 0x00000000 0x015e0000 || setenv stdout serial && echo "$failedmsg" && exit 1
if test "x$verbose" = "x"; then
setenv stdout serial
echo '[ done ]'
setenv stdout nulldev
setenv stdout serial
else
echo '######################################## Flashing ubi: Done'
fi
exit 0

fi

if test "x$verbose" = "x"; then
failedmsg='[failed]'
else
failedmsg='######################################## Failed'
fi
if test "$machid" = "8010001"; then

sf probe || setenv stdout serial && echo "$failedmsg" && exit 1
if test "x$verbose" = "x"; then
echo \\c'Flashing ubi:                           '
setenv stdout nulldev
else
echo '######################################## Flashing ubi: Started'
fi
imxtract $imgaddr ubi-2113e3f3cc2a94e31f40d2c220669cca1b7e2845 || setenv stdout serial && echo "$failedmsg" && exit 1
nand device 0 && nand erase 0x00000000 0x02900000 || setenv stdout serial && echo "$failedmsg" && exit 1
nand write $fileaddr 0x00000000 0x015e0000 || setenv stdout serial && echo "$failedmsg" && exit 1
if test "x$verbose" = "x"; then
setenv stdout serial
echo '[ done ]'
setenv stdout nulldev
setenv stdout serial
else
echo '######################################## Flashing ubi: Done'
fi
exit 0

fi

if test "x$verbose" = "x"; then
failedmsg='[failed]'
else
failedmsg='######################################## Failed'
fi
if test "$machid" = "8010301"; then

sf probe || setenv stdout serial && echo "$failedmsg" && exit 1
if test "x$verbose" = "x"; then
echo \\c'Flashing ubi:                           '
setenv stdout nulldev
else
echo '######################################## Flashing ubi: Started'
fi
imxtract $imgaddr ubi-2113e3f3cc2a94e31f40d2c220669cca1b7e2845 || setenv stdout serial && echo "$failedmsg" && exit 1
nand device 0 && nand erase 0x00000000 0x02900000 || setenv stdout serial && echo "$failedmsg" && exit 1
nand write $fileaddr 0x00000000 0x015e0000 || setenv stdout serial && echo "$failedmsg" && exit 1
if test "x$verbose" = "x"; then
setenv stdout serial
echo '[ done ]'
setenv stdout nulldev
setenv stdout serial
else
echo '######################################## Flashing ubi: Done'
fi
exit 0

fi

if test "x$verbose" = "x"; then
failedmsg='[failed]'
else
failedmsg='######################################## Failed'
fi
if test "$machid" = "8010401"; then

sf probe || setenv stdout serial && echo "$failedmsg" && exit 1
if test "x$verbose" = "x"; then
echo \\c'Flashing ubi:                           '
setenv stdout nulldev
else
echo '######################################## Flashing ubi: Started'
fi
imxtract $imgaddr ubi-2113e3f3cc2a94e31f40d2c220669cca1b7e2845 || setenv stdout serial && echo "$failedmsg" && exit 1
nand device 1 && nand erase 0x00000000 0x02900000 || setenv stdout serial && echo "$failedmsg" && exit 1
nand write $fileaddr 0x00000000 0x015e0000 || setenv stdout serial && echo "$failedmsg" && exit 1
if test "x$verbose" = "x"; then
setenv stdout serial
echo '[ done ]'
setenv stdout nulldev
setenv stdout serial
else
echo '######################################## Flashing ubi: Done'
fi
exit 0

fi

if test "x$verbose" = "x"; then
failedmsg='[failed]'
else
failedmsg='######################################## Failed'
fi
if test "$machid" = "8010501"; then

sf probe || setenv stdout serial && echo "$failedmsg" && exit 1
if test "x$verbose" = "x"; then
echo \\c'Flashing ubi:                           '
setenv stdout nulldev
else
echo '######################################## Flashing ubi: Started'
fi
imxtract $imgaddr ubi-2113e3f3cc2a94e31f40d2c220669cca1b7e2845 || setenv stdout serial && echo "$failedmsg" && exit 1
nand device 0 && nand erase 0x00000000 0x02900000 || setenv stdout serial && echo "$failedmsg" && exit 1
nand write $fileaddr 0x00000000 0x015e0000 || setenv stdout serial && echo "$failedmsg" && exit 1
if test "x$verbose" = "x"; then
setenv stdout serial
echo '[ done ]'
setenv stdout nulldev
setenv stdout serial
else
echo '######################################## Flashing ubi: Done'
fi
exit 0

fi

if test "x$verbose" = "x"; then
failedmsg='[failed]'
else
failedmsg='######################################## Failed'
fi
if test "$machid" = "8010007"; then

sf probe || setenv stdout serial && echo "$failedmsg" && exit 1
if test "x$verbose" = "x"; then
echo \\c'Flashing ubi:                           '
setenv stdout nulldev
else
echo '######################################## Flashing ubi: Started'
fi
imxtract $imgaddr ubi-2113e3f3cc2a94e31f40d2c220669cca1b7e2845 || setenv stdout serial && echo "$failedmsg" && exit 1
nand device 1 && nand erase 0x00000000 0x02900000 || setenv stdout serial && echo "$failedmsg" && exit 1
nand write $fileaddr 0x00000000 0x015e0000 || setenv stdout serial && echo "$failedmsg" && exit 1
if test "x$verbose" = "x"; then
setenv stdout serial
echo '[ done ]'
setenv stdout nulldev
setenv stdout serial
else
echo '######################################## Flashing ubi: Done'
fi
exit 0

fi

if test "x$verbose" = "x"; then
failedmsg='[failed]'
else
failedmsg='######################################## Failed'
fi
if test "$machid" = "8010005"; then

sf probe || setenv stdout serial && echo "$failedmsg" && exit 1
if test "x$verbose" = "x"; then
echo \\c'Flashing ubi:                           '
setenv stdout nulldev
else
echo '######################################## Flashing ubi: Started'
fi
imxtract $imgaddr ubi-2113e3f3cc2a94e31f40d2c220669cca1b7e2845 || setenv stdout serial && echo "$failedmsg" && exit 1
nand device 0 && nand erase 0x00000000 0x02900000 || setenv stdout serial && echo "$failedmsg" && exit 1
nand write $fileaddr 0x00000000 0x015e0000 || setenv stdout serial && echo "$failedmsg" && exit 1
if test "x$verbose" = "x"; then
setenv stdout serial
echo '[ done ]'
setenv stdout nulldev
setenv stdout serial
else
echo '######################################## Flashing ubi: Done'
fi
exit 0

fi

if test "x$verbose" = "x"; then
failedmsg='[failed]'
else
failedmsg='######################################## Failed'
fi
if test "$machid" = "8010006"; then

sf probe || setenv stdout serial && echo "$failedmsg" && exit 1
if test "x$verbose" = "x"; then
echo \\c'Flashing ubi:                           '
setenv stdout nulldev
else
echo '######################################## Flashing ubi: Started'
fi
imxtract $imgaddr ubi-2113e3f3cc2a94e31f40d2c220669cca1b7e2845 || setenv stdout serial && echo "$failedmsg" && exit 1
nand device 0 && nand erase 0x00000000 0x02900000 || setenv stdout serial && echo "$failedmsg" && exit 1
nand write $fileaddr 0x00000000 0x015e0000 || setenv stdout serial && echo "$failedmsg" && exit 1
if test "x$verbose" = "x"; then
setenv stdout serial
echo '[ done ]'
setenv stdout nulldev
setenv stdout serial
else
echo '######################################## Flashing ubi: Done'
fi
exit 0

fi

if test "x$verbose" = "x"; then
failedmsg='[failed]'
else
failedmsg='######################################## Failed'
fi
if test "$machid" = "80100306"; then

sf probe || setenv stdout serial && echo "$failedmsg" && exit 1
if test "x$verbose" = "x"; then
echo \\c'Flashing ubi:                           '
setenv stdout nulldev
else
echo '######################################## Flashing ubi: Started'
fi
imxtract $imgaddr ubi-2113e3f3cc2a94e31f40d2c220669cca1b7e2845 || setenv stdout serial && echo "$failedmsg" && exit 1
nand device 0 && nand erase 0x00000000 0x02900000 || setenv stdout serial && echo "$failedmsg" && exit 1
nand write $fileaddr 0x00000000 0x015e0000 || setenv stdout serial && echo "$failedmsg" && exit 1
if test "x$verbose" = "x"; then
setenv stdout serial
echo '[ done ]'
setenv stdout nulldev
setenv stdout serial
else
echo '######################################## Flashing ubi: Done'
fi
exit 0

fi

if test "x$verbose" = "x"; then
failedmsg='[failed]'
else
failedmsg='######################################## Failed'
fi
if test "$machid" = "1010002"; then

sf probe || setenv stdout serial && echo "$failedmsg" && exit 1
if test "x$verbose" = "x"; then
echo \\c'Flashing ubi:                           '
setenv stdout nulldev
else
echo '######################################## Flashing ubi: Started'
fi
imxtract $imgaddr ubi-2113e3f3cc2a94e31f40d2c220669cca1b7e2845 || setenv stdout serial && echo "$failedmsg" && exit 1
nand device 1 && nand erase 0x00000000 0x02900000 || setenv stdout serial && echo "$failedmsg" && exit 1
nand write $fileaddr 0x00000000 0x015e0000 || setenv stdout serial && echo "$failedmsg" && exit 1
if test "x$verbose" = "x"; then
setenv stdout serial
echo '[ done ]'
setenv stdout nulldev
setenv stdout serial
else
echo '######################################## Flashing ubi: Done'
fi
exit 0

fi

if test "x$verbose" = "x"; then
failedmsg='[failed]'
else
failedmsg='######################################## Failed'
fi
if test "$machid" = "1010003"; then

sf probe || setenv stdout serial && echo "$failedmsg" && exit 1
if test "x$verbose" = "x"; then
echo \\c'Flashing ubi:                           '
setenv stdout nulldev
else
echo '######################################## Flashing ubi: Started'
fi
imxtract $imgaddr ubi-2113e3f3cc2a94e31f40d2c220669cca1b7e2845 || setenv stdout serial && echo "$failedmsg" && exit 1
nand device 1 && nand erase 0x00000000 0x02900000 || setenv stdout serial && echo "$failedmsg" && exit 1
nand write $fileaddr 0x00000000 0x015e0000 || setenv stdout serial && echo "$failedmsg" && exit 1
if test "x$verbose" = "x"; then
setenv stdout serial
echo '[ done ]'
setenv stdout nulldev
setenv stdout serial
else
echo '######################################## Flashing ubi: Done'
fi
exit 0

fi

if test "x$verbose" = "x"; then
failedmsg='[failed]'
else
failedmsg='######################################## Failed'
fi
if test "$machid" = "1010004"; then

sf probe || setenv stdout serial && echo "$failedmsg" && exit 1
if test "x$verbose" = "x"; then
echo \\c'Flashing ubi:                           '
setenv stdout nulldev
else
echo '######################################## Flashing ubi: Started'
fi
imxtract $imgaddr ubi-2113e3f3cc2a94e31f40d2c220669cca1b7e2845 || setenv stdout serial && echo "$failedmsg" && exit 1
nand device 1 && nand erase 0x00000000 0x02900000 || setenv stdout serial && echo "$failedmsg" && exit 1
nand write $fileaddr 0x00000000 0x015e0000 || setenv stdout serial && echo "$failedmsg" && exit 1
if test "x$verbose" = "x"; then
setenv stdout serial
echo '[ done ]'
setenv stdout nulldev
setenv stdout serial
else
echo '######################################## Flashing ubi: Done'
fi
exit 0

fi

so i will have to use my own qsdk image , ok thanks allot Hostle i will dive in your pull request and hopefully get back with good result .

its same procedure just different parameters. That just an older version of dumpimage. If you want i can dig up the proper cmd inputs ..

dumpimage -i ${img} -o /tmp/${fullname}.bin -T "flat_dt" -p "${position}" ${fullname}

so

ubi

dumpimage -i  OEM_decrypted.img -o ubi.bin -T flat_dt -p 1 ubi

bootscript

dumpimage -i  OEM_decrypted.img -o flash.scr -T flat_dt -p 0 script
1 Like

you likely flashing the image with the script still attached, see the /lib/upgrade/glinet-upgrade.sh in my pr for how to use dumpimage to extract the ubi and pass it to nand_do_upgrade :wink:

alternatively, build an image without the script and try it. The script is only for uboot, its not needed after the upgrade .. so we do like uboot and extract the image (ubi) only ..discarding the script afterwards

Well I decompiled the tool the OEM uses to decrypt the firmware using Ghidra
the tool is called from sysupgrade and sysupgrade is called from another OEM tool that fetch new firmware from OEM server.
So upon called from sysupgrade to decrypt the image it make sure the script is there with correct crc32 for the script and UBI

So I cannot loose this, that's why I was trying just to replace UBI with correct checksum.
I am looking carefully now in your pull request which is new Hot :smiley:

I am lucky then
i will write my own based on yours, test and get back.

by the way thanks for the commands it worked
only needed to put ubi full name

1 Like

pay special attention to how the rootfs_size is set in the bootscript .. pre mkimage. this size needs to match your ubi size. this may be the culprit causing the no-boot condition you are experiencing

Well that was a great help i am now able to build my own QSDK rather than using OEM's
dumpimage of my build is identical now

FIT description: Flashing norplusnand 100 10000
Created:         Mon Feb  3 23:09:37 2025
 Image 0 (script)
  Description:  flash.scr
  Type:         Script
  Compression:  uncompressed
  Data Size:    12026 Bytes = 11.74 kB = 0.01 MB
  Hash algo:    crc32
  Hash value:   d1f44996
 Image 1 (ubi-2113e3f3cc2a94e31f40d2c220669cca1b7e2845)
  Description:  openwrt-ipq806x-ipq40xx-ubi-root.img
  Type:         Firmware
  Compression:  uncompressed
  Data Size:    22937600 Bytes = 22400.00 kB = 21.88 MB
  Architecture: ARM
  Load Address: unavailable
  Hash algo:    crc32
  Hash value:   63486a5a

and the device accepted the firmware and flashed it but with the same result

UBI error: check_sv: bad scanning information, error 1
UBI error: ubi_init: cannot attach mtd2
UBI error: ubi_init: UBI error: cannot initialize UBI, error -22
UBI init error 22


Image checksum error!!!

My UBI is padded to 22400K
padding with 0x00

while OEM UBI >

I even manually calculated the offsets and added the deadc0de manually.
now looking into my UBI info

UBI_File Warning: end_offset - start_offset length is not block aligned, could mean missing data.
UBI File
---------------------
        Min I/O: 2048
        LEB Size: 126976
        PEB Size: 131072
        Total Block Count: 119
        Data Block Count: 112
        Layout Block Count: 2
        Internal Volume Block Count: 0
        Unknown Block Count: 5
        First UBI PEB Number: 57

        Image: 1738624177
        ---------------------
                Image Sequence Num: 1738624177
                Volume Name:kernel
                Volume Name:ubi_rootfs
                Volume Name:rootfs_data
                PEB Range: 2 - 118

                Volume: kernel
                ---------------------
                        Vol ID: 0
                        Name: kernel
                        Block Count: 38

                        Volume Record
                        ---------------------
                                alignment: 1
                                crc: '0xa55489c5'
                                data_pad: 0
                                errors: ''
                                flags: 0
                                name: 'kernel'
                                name_len: 6
                                padding: '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
                                rec_index: 0
                                reserved_pebs: 38
                                upd_marker: 0
                                vol_type: 'dynamic'


                Volume: ubi_rootfs
                ---------------------
                        Vol ID: 1
                        Name: ubi_rootfs
                        Block Count: 74

                        Volume Record
                        ---------------------
                                alignment: 1
                                crc: '0xad40bb82'
                                data_pad: 0
                                errors: ''
                                flags: 0
                                name: 'ubi_rootfs'
                                name_len: 10
                                padding: '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
                                rec_index: 1
                                reserved_pebs: 74
                                upd_marker: 0
                                vol_type: 'dynamic'


                Volume: rootfs_data
                ---------------------
                        Vol ID: 2
                        Name: rootfs_data
                        Block Count: 0

                        Volume Record
                        ---------------------
                                alignment: 1
                                crc: '0x2913d43c'
                                data_pad: 0
                                errors: ''
                                flags: 'autoresize'
                                name: 'rootfs_data'
                                name_len: 11
                                padding: '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
                                rec_index: 2
                                reserved_pebs: 9
                                upd_marker: 0
                                vol_type: 'dynamic'



While OEM's

every time with the same error.
i think UBI needs a tweak maybe ubinize-image.sh

how are you flashing it to the device .. uboot ? or sysupgrade?

What is the end goal here, a full openwrt port for the device ? or just trying to ticker with things in oem image ?

1st thank you for your help, it is much appreciated

Device is u-boot locked, OEM web interface dose not allow users to do sysupgrade.

offcource full openwrt support, that is why i used your method and adjusted it to match OEM's

do you have something prepared i can have a look at. I am having a hard time comprehending your strategy.

I assume you have the oem dts and the derived openwrt dts ... can i see it somewhere ?

Yeah I nearly finished every thing. But i am not sure about networking and leds. I need to install openwrt to finish up the device.

Sure
Decompiled DTBs

OEM bootlog

[    0.826860] m25p80 spi0.0: found w25q32, expected n25q128a11
[    0.831502] m25p80 spi0.0: w25q32 (4096 Kbytes)
[    0.836082] 12 ofpart partitions found on MTD device spi0.0
[    0.841559] Creating 12 MTD partitions on "spi0.0":
[    0.846444] 0x000000000000-0x000000040000 : "0:SBL1"
[    0.852573] 0x000000040000-0x000000060000 : "0:MIBIB"
[    0.857746] 0x000000060000-0x0000000c0000 : "0:QSEE"
[    0.862790] 0x0000000c0000-0x0000000d0000 : "0:CDT"
[    0.867798] 0x0000000d0000-0x0000000e0000 : "0:DDRPARAMS"
[    0.873189] 0x0000000e0000-0x0000000f0000 : "0:APPSBLENV"
[    0.878542] 0x0000000f0000-0x000000170000 : "0:APPSBL"
[    0.883572] 0x000000170000-0x000000180000 : "0:ART"
[    0.888498] 0x000000180000-0x0000001a0000 : "0:BOOTCONFIG"
[    0.893950] 0x0000001a0000-0x0000001c0000 : "0:BOOTCONFIG1"
[    0.899586] 0x0000001c0000-0x0000001f0000 : "RESV"
[    0.904316] 0x0000001f0000-0x000000200000 : "RESV0"

[    1.202202] nand: device found, Manufacturer ID: 0xef, Chip ID: 0xaa
[    1.207554] nand: Winbond W25N01GV 128MiB 3.3V
[    1.211952] nand: 128MiB, SLC, page size: 2048, OOB size: 64
[    1.217623] Scanning device for bad blocks
[    1.459408] random: nonblocking pool is initialized
[    1.900507] Bad eraseblock 914 at 0x000007240000
[    1.905986] Bad eraseblock 917 at 0x0000072a0000
[    1.938676] Bad eraseblock 957 at 0x0000077a0000
[    1.990880] 5 ofpart partitions found on MTD device spi0.1
[    1.995350] Creating 5 MTD partitions on "spi0.1":
[    2.000111] 0x000000000000-0x000002900000 : "rootfs"
[    2.006213] mtd: device 12 (rootfs) set to be root filesystem
[    2.012930] mtdsplit: no squashfs found in "rootfs"
[    2.016809] mtdsplit: no squashfs found in "spi0.1"
[    2.021641] 0x000002900000-0x000005200000 : "rootfs_1"
[    2.027858] 0x000005200000-0x000006400000 : "RESV1"
[    2.032756] 0x000006400000-0x000007000000 : "qcacfg"
[    2.037777] 0x000007000000-0x000008000000 : "qcalog"

my dts node


&blsp1_spi1 {
	pinctrl-0 = <&spi_0_pins>;
	pinctrl-names = "default";
	status = "okay";
	cs-gpios = <&tlmm 54 GPIO_ACTIVE_HIGH>, <&tlmm 59 GPIO_ACTIVE_HIGH>;

	flash@0 {
		compatible = "jedec,spi-nor", "n25q128a11";
		#address-cells = <1>;
		#size-cells = <1>;
		reg = <0>;
		spi-max-frequency = <24000000>;

		partitions {
			compatible = "fixed-partitions";
			#address-cells = <1>;
			#size-cells = <1>;

			partition@0 {
				label = "0:SBL1";
				reg = <0x0 0x40000>;
				read-only;
			};

			partition@40000 {
				label = "0:MIBIB";
				reg = <0x40000 0x20000>;
				read-only;
			};

			partition@60000 {
				label = "0:QSEE";
				reg = <0x60000 0x60000>;
				read-only;
			};

			partition@c0000 {
				label = "0:CDT";
				reg = <0xc0000 0x10000>;
				read-only;
			};

			partition@d0000 {
				label = "0:DDRPARAMS";
				reg = <0xd0000 0x10000>;
				read-only;
			};

			partition@E0000 {
				label = "0:APPSBLENV";
				reg = <0xe0000 0x10000>;
				read-only;
			};

			partition@F0000 {
				label = "0:APPSBL";
				reg = <0xf0000 0x80000>;
				read-only;
			};

			partition@170000 {
				label = "0:ART";
				reg = <0x170000 0x10000>;
				read-only;

				compatible = "nvmem-cells";
				#address-cells = <1>;
				#size-cells = <1>;

				macaddr_art_1006: macaddr@1006 {
					reg = <0x1006 0x6>;
				};

				precal_art_1000: precal@1000 {
					reg = <0x1000 0x2f20>;
				};

				precal_art_5000: precal@5000 {
					reg = <0x5000 0x2f20>;
				};
			};

			partition@180000 {
				label = "0:BOOTCONFIG";
				reg = <0x180000 0x20000>;
				read-only;
				};

			partition@1a0000 {
				label = "0:BOOTCONFIG1";
				reg = <0x1a0000 0x20000>;
				read-only;
				};

			partition@1c0000 {
				label = "RESV";
				reg = <0x1c0000 0x30000>;
				};

			partition@1f0000 {
				label = "RESV";
				reg = <0x1f0000 0x10000>;
			};
		};
	};

	spi-nand@1 {
		compatible = "spi-nand", "spinand,mt29f";
		#address-cells = <1>;
		#size-cells = <1>;
		reg = <1>;
		spi-max-frequency = <24000000>;

		partitions {
			compatible = "fixed-partitions";
			#address-cells = <1>;
			#size-cells = <1>;

			partition@0 {
				reg = <0x0 0x2900000>;
				label = "rootfs";
				compatible = "linux,ubi";
			};

			partition@2900000 {
				reg = <0x2900000 0x5200000>;
				label = "rootfs_1";
				compatible = "linux,ubi";
			};

			partition@5200000 {
				reg = <0x5200000 0x1200000>;
				label = "RESV1";
			};

			partition@6400000 {
				reg = <0x6400000 0xc00000>;
				label = "qcacfg";
				compatible = "linux,ubi";
			};

			partition@7000000 {
				reg = <0x7000000 0x1000000>;
				label = "qcalog";
				compatible = "linux,ubi";
			};
		};
	};
};

my image recipe

define Device/xx_xx-xx
	$(call Device/FitImage)
	DEVICE_VENDOR := XX
	DEVICE_MODEL := XX-XX
	SOC := qcom-ipq4018
	BLOCKSIZE := 128k
	PAGESIZE := 2048
	IMAGE_SIZE := 22400k
	KERNEL_SIZE := 5120k
	DEVICE_DTS_CONFIG := config@ddr-ap-dk01.1-c2
	BOOT_SCRIPT:= xx_xx-xx.bootscript
	UBINIZE_OPTS := -E 5
	KERNEL_IN_UBI := 1
	FILESYSTEMS := squashfs
	KERNEL_LOADADDR := 0x84000000
	IMAGES += factory.img
	IMAGE/factory.img := append-ubi | pad-to 22400k | kt-davolink-factory
	DEVICE_PACKAGES := uboot-envtools kmod-usb-acm kmod-usb-net-qmi-wwan kmod-usb-serial-option uqmi
endef
TARGET_DEVICES += xx_xx-xx

I do not know Openwrt Policy about this situation
But I am going to add support for all this company's device as I have managed to replicate their upgrade server.

and by spoofing DNS record the devices download openwrt firmware from my server.

Also I don't know even if Openwrt would accept a PR for a u-boot locked devices.
And I Don't know if that Company could sue me for replicating their system.
I had to decompile and reverse engineer their system and build my replica.
Would Openwrt accept PR's if the device needs external service to initially install openwrt image and later on use Openwrt sysupgrades ? or every thing must be public and open source?
I have exposed encryption Hash's and methods. what would be my legal position if I made every thing public?
things like fW****mw****+Hash-****i$Money$9*HOw?MucH

99.9999% sure thats a hard no

what does your choosen node look like ? do you have the ubiblock set correctly. I seen the -22 error while I was testing to find the correct block. For my device, it turned out to be /dev/ubiblock0_1 as shown below, but i have seen many different entries .. /dev/ubiblock0_0 ../dev/ubiblock0_2 ..etc.

The will cause -22 so its worth investigating.

I think there is work arounds for this ... have you found anything on the subject ?

chosen {
		bootargs-append = " root=/dev/ubiblock0_1 swiotlb=1 coherent_pool=2M";
		stdout-path = "serial0:115200n8";
	};

as you saw from the installation script it is dealing with many boards

this is the passed bootargs from u-boot to openwrt

/ # cat /proc/cmdline
ubi.mtd=rootfs root=mtd:ubi_rootfs rootfstype=squashfs rootwait loglevel=0 clk_ignore_unused
/ #

Linux version 3.14.77 OpenWrt/Linaro GCC 4.8-2014.04

Yeah this is part of OEM's platform.sh

flash_section() {
	local sec=$1

	local board=$(ipq806x_board_name)
	case "${sec}" in
		hlos*) switch_layout linux; do_flash_failsafe_partition ${sec} "0:HLOS";;
		rootfs*) switch_layout linux; do_flash_failsafe_partition ${sec} "rootfs";;
		fs*) switch_layout linux; do_flash_failsafe_partition ${sec} "rootfs";;
		ubi*) switch_layout linux; do_flash_ubi ${sec} "rootfs";;
		sbl1*) switch_layout boot; do_flash_partition ${sec} "0:SBL1";;
		sbl2*) switch_layout boot; do_flash_failsafe_partition ${sec} "0:SBL2";;
		sbl3*) switch_layout boot; do_flash_failsafe_partition ${sec} "0:SBL3";;
		mibib*) switch_layout boot; do_flash_partition ${sec} "0:MIBIB";;
		dtb-$(to_upper $board)*) switch_layout boot; do_flash_partition ${sec} "0:DTB";;
		u-boot*) switch_layout boot; do_flash_failsafe_partition ${sec} "0:APPSBL";;
		ddr-$(to_upper $board)*) switch_layout boot; do_flash_ddr ${sec};;
		ddr-${board}-*) switch_layout boot; do_flash_failsafe_partition ${sec} "0:DDRCONFIG";;
		ssd*) switch_layout boot; do_flash_partition ${sec} "0:SSD";;
		tz*) switch_layout boot; do_flash_tz ${sec};;
		rpm*) switch_layout boot; do_flash_failsafe_partition ${sec} "0:RPM";;
		*) echo "Section ${sec} ignored"; return 1;;
	esac

	echo "Flashed ${sec}"
}

and while testing my encrypted firmware from within hacked root shell device. shows it is actually could upgrade all these in one encrypted firmware package.

/ # sysupgrade -T /tmp/usb/openwrt.img
uci: Entry not found
umount: can't unmount /tmp/usbdisk: Invalid argument
Warning: optional section "sb11" missing from "/tmp/usb/openwrt.img". Continue...
Warning: optional section "sbl2" missing from "/tmp/usb/openwrt.img". Continue...
Warning: optional section "u-boot" missing from "/tmp/usb/openwrt.img". Continue...
Warning: optional section "ddr-ap-dk01.1-c2" missing from "/tmp/usb/openwrt.img". Continue...
Warning: optional section "ssd" missing from "/tmp/usb/openwrt.img". Continue...
Warning: optional section "tz" missing from "/tmp/usb/openwrt.img". Continue...
Warning: optional section "rpm" missing from "/tmp/usb/openwrt.img". Continue...

but I have zero experience in building u-boot

so my strategy is to add support for the device away from Openwrt. Untill devices would have unofficial build.
As time goes by there will be a lot of devices switched to Openwrt already
as for instance there is another mt7621 device for the same company already installed my firmware on 50k+ devices. and i was able to get unlocked u-boot version (older version for same device)
that I can add support to? while there are versions that are locked and others are not. and some other already has unofficial Openwrt firmware installed?

this is out of my wheelhouse i'm afraid, I am not familiar with any of the uboot mods, and encrypted firmwares .. my device was not locked and a pretty straight forward port. You seem to have a much more involved port on your hands. I will chime in when i have anything to offer. I would suggest you try and get to an unlocked uboot .. things will be much less complex from that point.

1 Like

Thank you very much you already have been a great help.

1 Like