tl-wr802n v1: 使用bootloader的自动更新固件功能

tplink官方提供的GPL代码编译出来的bootloader(tuboot.bin),是有自动更新固件功能的。只要按着reset通电开机,就可以自动执行这个命令:从tftp server(ip: 192.168.0.66)中下载wr841nv10_tp_recovery.bin。

先看一下bootloader中与升级相关的代码:

TL_WR802NV1_GPL/soho5_qca_trunk_prep/ap143/boot/u-boot/common/main.c

    ...
            if (is_auto_upload_firmware)
            {
                char image_name[32] = {0};
                char upload_cmd[64] = {0};

                strcpy(upload_cmd, FW_IMAGE_UPLOAD_CMD);
                strcpy(image_name, FW_RECOVERY_DEV);
                strcat(image_name, FW_IMAGE_NAME);
                strcat(upload_cmd, image_name);

                ath_fw_led_on();

                /* wait for ethernet config done. by HouXB, 28Apr11 */

                udelay(2000*1000);

                fw_recovery = 1;

                run_command("setenv serverip 192.168.0.66", 0);
                run_command("setenv ipaddr 192.168.0.86", 0);

                run_command(upload_cmd, 0);

                memcpy(&original_product_id, ORG_PRODUCT_ID_POS, PRODUCT_ID_VER_LEN);
                memcpy(&original_product_ver, ORG_PRODUCT_VER_POS, PRODUCT_ID_VER_LEN);

                memcpy(&recovery_product_id, UP_PRODUCT_ID_POS, PRODUCT_ID_VER_LEN);
                memcpy(&recovery_product_ver, UP_PRODUCT_VER_POS, PRODUCT_ID_VER_LEN);

                if ((original_product_id == recovery_product_id)
                     && (original_product_ver== recovery_product_ver))
                {
                    s = getenv("filesize");

                    if (s)
                    {
                        file_size = simple_strtoul(s, NULL, 16);
                    }
                    printf("Firmware recovery: product id verify sucess!\n");
                    printf("Firmware recovery: filesize = 0x%x.\n", file_size);
                    if (FLASH_SIZE == 4)
                    {
                        if (file_size == 0x3c0000)
                        {
                            run_command("erase 0x9f020000 +3c0000; cp.b 0x80800000 0x9f020000 3c0000", 0);
                        }
                        else if (file_size == 0x3e0200)
                        {
                            run_command("erase 0x9f020000 +3c0000; cp.b 0x80820200 0x9f020000 3c0000", 0);
                        }
                    }
                                                                                                                    else if (FLASH_SIZE == 8)
                    {
                        if (file_size == 0x7c0000)
                        {
                            run_command("erase 0x9f020000 +7c0000; cp.b 0x80800000 0x9f020000 7c0000", 0);
                        }
                        else if (file_size == 0x7e0200)
                        {
                            run_command("erase 0x9f020000 +7c0000; cp.b 0x80820200 0x9f020000 7c0000", 0);
                        }
                    }
                    else if (FLASH_SIZE == 16)
                    {
                        if (file_size == 0xfc0000)
                        {
                            run_command("erase 0x9f020000 +fc0000; cp.b 0x80800000 0x9f020000 fc0000", 0);
                        }
                        else if (file_size == 0xfe0200)
                        {
                            run_command("erase 0x9f020000 +fc0000; cp.b 0x80820200 0x9f020000 fc0000", 0);
                        }
                    }
                    do_reset (NULL, 0, 0, NULL);
                }
                else
                {
                    printf("auto update firmware: product id verify fail!\n");
                    ath_fw_led_off();
                }
            }
    ...

从这里可以看出固件升级时:

  1. LED灯会常亮, 当LED灯亮时就可以松开reset按键,以防止再次进行固件升级模式。升级时LED处于off的状态,不会看到明显的变化,所以如果想知道路由器是否进入升级模式,可能就得通过tcpdump或者tftp server端的log来确定了。(why?)
  2. 固件下载完成后会去比较两个固件的product id和product version, 如果不一致就取消更新。
  3. 固件的大小是固定的, 对于16MB的flash, 大小只能0xfc0000或者是0xfe0200。

bootloader中记录的product id位于:0x9f01fd00(内存位置)/0x0001fd00(flash中的位置),长度为4个字节

product version位于:0x9f01fd04(内存中的位置)/0x0001fd00(flash中的位置),长度为4个字节

而固件的product id位于文件0x40处,长度为4个字节,可通过如下命令查看:

$ hexdump -s $((0x40)) -n 4 -v -e '4/1 "%02X ""\n"' openwrt-15.05-ar71xx-generic-tl-wr841n-v9-squashfs-factory.bin

product version位于文件0x44处,长度为4个字节:

hexdump -s $((0x44)) -n 4 -v -e '4/1 "%02X ""\n"' openwrt-15.05-ar71xx-generic-tl-wr841n-v9-squashfs-factory.bin

当然也可以通过如下命令修改product id和product version的值:

$ echo -e "\x08\x02\x00\x01" | dd of=openwrt-15.05-ar71xx-generic-tl-wr841n-v9-squashfs-factory.bin bs=1 count=4 seek=$((0x40)) conv=notrunc
$ echo -e "\x00\x00\x00\x01" | dd of=openwrt-15.05-ar71xx-generic-tl-wr841n-v9-squashfs-factory.bin bs=1 count=4 seek=$((0x44)) conv=notrunc

使用openwrt的Image generator生成的16MB固件的大小为0xf80000需要再padding 0x40000字节:

$ tr '\000' '\377' < /dev/zero | \
    dd of=openwrt-15.05-ar71xx-generic-tl-wr841n-v9-squashfs-factory.bin \
    bs=1 seek=$((0xf80000)) count=$((0x40000))

升级过程中的串口log如下:

...
Setting 0x181162c0 to 0x58b1a100
is_auto_upload_firmware=1
eth1 link down
enet0 port4 up
dup 1 speed 100
Using eth0 device
TFTP from server 192.168.0.66; our IP address is 192.168.0.86
Filename 'wr841nv10_tp_recovery.bin'.
Load address: 0x80800000
Loading: *^H#################################################################
...
         #########################################
done
Bytes transferred = 16515072 (fc0000 hex)
Firmware recovery: product id verify sucess!
Firmware recovery: filesize = 0xfc0000.
Erasing flash...
First 0x2 last 0xfd sector size 0x10000
Erased 252 sectors
Copy to Flash... write addr: 9f020000
done

U-Boot 1.1.4-ge4671519-dirty (Jan 24 2016 - 01:00:08)

ap143-2.0 - Honey Bee 2.0
...

升级成功之后会自动重启。

《tl-wr802n v1: 使用bootloader的自动更新固件功能》有2个想法

  1. 你好,我购买的国内的WR802n,我通过电脑和虚拟机进行TFTP传输是可以的,而且是由日志生成的,按照你的方法在上电前按住Reset按钮,然后上电,并松开,但是没有进入Bootloader的自动更新固件,固件命名是wr841nv10_tp_recovery.bin,不是应该wr802nv1_tp_recovery.bin.

    1. 看来是硬件版本不一样,对于同一型号的路由器,会出现有多个硬件版本的情况,你的硬件版本是v10

发表评论

电子邮件地址不会被公开。 必填项已用*标注