记录一次失败的小米路由器 MiWiFi R2D 救砖之旅

2022-05-05

上了大学了,搞了一些嵌入式的东西,我感觉我行了! R2D: 我觉得你不行...

接上文 小米路由器 2 硬盘版(MiWifi R2D)刷第三方固件(OpenWrt)(实为救砖而且还没成功),更多信息请参见该文章。

最近焊工有所提高,并且最近有对 Linux 嵌入式板子的需求,所以打算着手修复一下很久以前因为刷错固件导致挂掉的小米路由器 R2D。

上面的硬盘已经拆下来作为 NAS 盘在家中服役很久,本体为 ARM 核心的 Broadcom BCM4709C0 ,Flash 为 512MB 的 Spansion S34ML04G2。

更多参数参见:https://deviwiki.com/wiki/Xiaomi_MiWiFi_(R2D)

Broadcom BCM4709C0

这个核心跟 PHICOMM K3 A1 是同款芯片,但是与其不同的是,存储大小和布局以及内存大小都不大一样,所以固件不建议通刷。

PHICOMM K3 A1 受 OpenWrt 官方支持,可能也是因为它的发布比较晚而且比较热门,但是 R2D 就没有这么幸运的待遇了。

值得注意的是,OpenWrt 中的 bcm47xx 指的是运行 MIPS 核心的 Broadcom 芯片,运行 ARM 核心的 BCM4709 固件和软件包是放在 bcm53xx 中:

PHICOMM K3 A1 相关内容对将来研究 R2D 提供很好的参考:

关于小米的 OpenWrt

小米原厂的 OpenWrt 跟原版 OpenWrt 不同,使用的 musl libc 库,同时数据放在 /data 文件夹中(印象中),像是安卓的风格。

小米的 OpenWrt 好像没有开源,雷声大雨点小...

不过找到了一个 R1D 的参考信息:

关于小米路由器的救砖系统

在初期发布的时候,小米路由器主打可玩,支持开启 SSH 权限。但是第一次上电就封掉 U-Boot (其他型号),以及后期获取 SSH 权限的网站不能正常运行,很难感受到小米的诚意。

SSH 权限的获取,需要从网站上下载解锁文件 miwifi_ssh.bin 放在 u 盘中插在路由器上启动(后期好像路由器都没有 USB 了)

小米路由器提供了救砖功能,但是根据启动日志,这个救砖功能好像是放在系统中,而非 bootloader 中,但是如果系统被破坏了,这个功能也就无法正常运行了,比较鸡肋。

类似于解锁路由器,救砖需要将下载的固件改名为 miwifi.bin 放在 u 盘中启动。

Ref:

管中窥豹 Broadcom CFE

Broadcom CFE 是 Broadcom 设备的 bootloader,代码不开源。用于 CFE 启动的系统需要满足一定的格式。这个格式一般叫做 trx ,一般以 HDR0 作为其最开始的几个字符(magic byte)。miwifi.bin 和 miwifi_ssh.bin 最开始几个字符为 HDR1 ,可能为其变体。

(猜测)CFE 本体是存储在 NAND 中,由芯片中 Bootrom 加载启动,CFE 与 linux 类似,先加载一个解压缩头,然后由其解压后面的代码到内存中运行。

不知道是我之前连接芯片过程中所用的电平不对亦或小米固件本身的问题,我的 CFE 不对 Ctrl-C Esc 作出响应。

关于 trx 格式,参见:

关于使用 CFE 刷机,参见:[OpenWrt Wiki] CFE

有趣的是,对 CFE 做逆向的时候,看到一篇维基解密的文档 Firmware Reverse Engineering

Spansion S34ML04G2

这是一个 NAND 芯片,虽然容量大,但是同时也意味着许多便宜的编程器对他并不适用,我购买的是 XGecu TL866II 。

内存布局随设备而变,OpenWrt 下分区情况,可以通过在启动日志中搜索 mtd 来寻找。

虽然我的设备坏了,但是仍然从网上找到了启动日志,显示的分区情况为:

[    5.320000] Creating 8 MTD partitions on "nflash":
[    5.330000] 0x000000000000-0x000000080000 : "boot"
[    5.330000] 0x000000080000-0x000000100000 : "nvram"
[    5.340000] 0x000000100000-0x000000140000 : "board_data"
[    5.340000] 0x000000140000-0x000000180000 : "crash"
[    5.350000] 0x000000180000-0x000000200000 : "rsvd0"
[    5.350000] 0x000000200000-0x000000600000 : "os0"
[    5.360000] 0x000000600000-0x000000a00000 : "os1"
[    5.360000] 0x000000a00000-0x000001000000 : "rsvd1"
[    7.960000] Creating 3 MTD partitions on "brcmnand":
[    7.960000] 0x000001000000-0x000009000000 : "rootfs0"
[    7.970000] 0x000009000000-0x000011000000 : "rootfs1"
[    7.970000] 0x000011000000-0x000020000000 : "overlay"

Source: 《R2D》无限重启,求大神指点,万谢!-恩山无线论坛

更多信息:

使用 XGpro 烧录软件

NAND 由块(Block)、页(Page)组成,一个 NAND 有多个块,每个块有多个页。一般每个页都会有恢复纠错区域(OOB/Spare Space)。擦除的最小单位为块。

这款 NAND 在烧录程序中识别的参数为:

Page Size: 2048
Spare Size: 128
Pages Per Blog: 64
Total Blocks: 4096 

在默认情况下,通过 读取 命令读到的数据会保存 OOB 区域,对于这款芯片,在每 0x800 字节数据后,会保存 0x80 OOB 数据。

我写了一个小脚本,用于将原始数据转换为不含有 OOB 的数据:

const fs = require('fs');

const pageSize = 0x800;
const oobSize = 0x80;
const tolSize = pageSize + oobSize;

const bin = fs.readFileSync('in.bin');
const output = [];
for (let i = 0; i < bin.length / tolSize; ++i) 
  output.push(bin.slice(i * tolSize, i * tolSize + pageSize));
fs.writeFileSync('out.bin', Buffer.concat(output));

编程器在使用的过程中,可以通过指定分区表,对指定区域进行操作,避免全盘写入,在 配置与选项 > 4.存取文件路径与分区设置 ,选择 单个文件分区模式 ,只点开第一个 Part ,对应 ST_BLK END_BLK CNT_BLK 输入参数 0 128 128

这样也可以尽量避免烧录失败的错误。

同时推荐选择 删除时不清除芯片坏块标记 ,以及 坏块处理方式 > 跳过坏块

Ref:

Binwalk 使用

Binwalk 是一个固件逆向工具,虽然说对于我来讲,并没有用上,但是也推荐了解一下。这个工具最好在 Linux 环境下使用(我用的是 Ubuntu)

Ref:

焊接相关

对于这种因为固件失效,且 Bootloader 不好使的情况,需要把 NAND 芯片拆下来,并且对裸 NAND 编程。

我清除掉了 os0 和 os1 分区(0x000000200000-0x000000a00000)内的全部数据(置 0xff)。

拆下芯片的过程推荐使用热风枪,且第一次拆下的时候,使用低温锡换一下原厂锡,热风温度我设定为 390 度。吹的过程中,先对整个芯片周围加热升温,到差不多时候时,单吹一边,用镊子慢慢翘起,使其不与主板连接即可(不要用力过度,导致另外一侧引脚弯掉!)。

焊接过程中推荐用电烙铁进行,我设定的温度为 380~400 度。先清理焊盘,使得芯片与电路板直接接触;再将对角线两个点加热,焊接到板子上;再用锡将一侧引脚上一遍锡。如果有连锡的情况,一般是助焊剂干了,或者温度不够,相应的加上更多助焊剂,并且适当提高温度(加个10度,不够再加)。

现在的情况

在一次拆 NAND 中,由于好奇心作祟,我在 NAND 没有连在板子上的时候,将主板上电。

现在主板 12V 保护管后大短路。在没有热成像仪的情况下和更加广泛的电路知识之前,这个板子只能再次搁置在一边了。

上一张尸体照:

dead.jpg

20220510 更新

这台小米路由成功复活了,参见 R2D 它复活了!