太长不看版

最终实现了强制引导U盘系统,即使 emmc 损坏或者物理上不存在,依然可以从U盘启动。具体可以看 GitHub仓库

只要 emmc 芯片硬件没有损坏,可以完成等价于“拆掉 emmc 直接写数据”的操作。

需要以下准备:

  • 一台 Linux 主机
  • N1可以引导的U盘启动盘(需要包含 BOOTROOTFS 分区)
  • Linux 主机需要安装 libusb 库,ubuntu 的包名为 libusb-0.1-4,其它系统可参考
  • 双公头 USB 数据线

具体使用方法见正文最后一节。如果你是因为分区表被破坏导致变砖且无法刷入官方固件的,可以参考本文。

废话部分

最近需要为某网络环境实现透明代理,好哥们贡献了自己的一台斐讯N1来做旁路由。到手的时候上面的系统是不知道谁编译的 OpenWrt,但好哥们想换成 Kwrt,于是在 Kwrt 官网下载到了斐讯N1的预编译固件。

这个固件文件是一个普通的磁盘镜像,有 BOOTROOTFS 分区,文件系统分别是 FAT32EXT4,符合预期。并且在 BOOT 分区下至少有 u-boot 和 内核、设备树等关键内容,看起来和设备 emmc 上的 boot 分区内容大差不差。

于是按我的经验,这玩意直接用 dd 命令写到磁盘上就好了!废话不多说,制作U盘启动盘,设备默认引导U盘,然后再从另一个U盘中离线写入 emmc。dd 命令正确返回了,但重启后设备并没有如预期启动新系统,而是彻底没反应了。用行话说就是:变砖了。

上网搜索,大部分资料来自恩山论坛,多数帖子总结的救砖步骤如下:

  1. 拆机,短接进入烧写模式
  2. 使用 Amlogic USB Burning Tool,先刷 T1 的包,卡在 21%
  3. 再刷 N1 的包,这次可以刷完

第一难:拆机

那么先拆机。N1的螺丝孔和螺丝都特别小,在试了一堆小螺丝刀后,终于拆开了。

主板整体做工感觉相当不错(要是再提前焊一排 uart 针脚就好了)。

第二难:数据线玄学

废话不多说,短接开机,连接电脑,开始刷机。

进度死活卡在 2%。因为之前玩过全志芯片的电视盒子,直觉告诉我这可能和数据线有关系。于是在美团上买了一条双公口 USB2.0 数据线。

第三难:CPU玄学

换了数据线之后,进度终于是超过 2% 了,然而这次并没有走多远。

这次卡在了 4%。在把恩山论坛翻了个遍之后得出结论:软件对 AMD 处理器的适配有问题,只能换英特尔处理器解决。

懒得细究原因,于是连夜跑到实验室换电脑操作。

第四难:不知道啥玄学

换了台 Intel 处理器的机器后,进度条跨过了 4%,然而遗憾的是这次也没有走多远

进度无论如何都会卡在 7%。

于是又把恩山论坛翻了个遍,暂时得出结论:emmc 炸了

N1救砖卡在7%怎么解决,有没有大佬知道-斐讯无线路由器以及其它斐迅网络设备-恩山无线论坛 - Powered by Discuz!

这种情况大部分帖子给出的解决方案是换闪存芯片。

然而事实果真如此吗?

知己知彼

Amlogic 官方的烧录工具是如何读写 emmc 闪存的?

Amlogic 的烧录模式和高通 EDL 极其相似,如果你熟悉高通平台的 EDL 模式的话,拉一个清单来对比你就理解了

阶段 / 功能高通 (Qualcomm)晶晨 (Amlogic)
底层硬件代码PBL (Primary Bootloader)BootROM / MaskROM
PC 端识别端口9008 端口 (QDLoader)WorldCup Device (VID 1B8E)
内存初始化协议Sahara 协议Amlogic USB 控制传输 (发 BL2)
内存中的烧录器Firehose Programmer特制的临时版 U-Boot
实际写入执行者Firehose 接收数据并写入闪存内存中的 U-Boot 接收数据并写入 eMMC

当我们手动短接 emmc 时,emmc 对于 CPU 来说等同于不存在,此时 SoC 内部的 ROM 会回退到烧录模式,主板会以 USB 设备的身份被识别。

烧录工具首先会通过 USB 发送命令初始化设备上的内存,然后上传一个临时的 U-Boot,当内存中的 U-Boot 开始运行后,即可接收来自烧录工具上传的数据并将其写入 emmc。

邪招

如果你比较细心,就会注意到一个很关键的信息:直到 U-Boot 实际对 emmc 写数据之前,emmc 本身完全不参与任何步骤。

也就是说,在整个烧录过程的初始阶段,emmc 芯片就算是坏了或者是压根不存在,都不会有任何影响。

同时,既然我们能通过 USB 控制 U-Boot 的行为、读写设备内存,那么我们完全可以把 Linux 内核和设备树、initrd上传到内存中,然后直接启动 Linux 内核。

只要修改 initrd 中的 init 脚本,我们就能得到一个临时的 shell,这已经足够我们了解情况了。如果我们手速够快,迅速拔掉数据线、插上启动盘,甚至能直接挂载U盘内的根文件系统,启动完整的系统。

然而烧录工具上传的 U-Boot 有相当多的限制,实际尝试后发现它并不能直接引导 Linux 内核,所以我们得稍微修改一下流程,在上传 Linux 内核之前先上传一个完整的 U-Boot,然后通过 go 命令跳转到新的 U-Boot,再通过这个完整的 U-Boot 启动内核。

init 脚本默认是通过 UUID 来识别根文件系统分区的,然而之前通过 dd 写过 emmc,这导致 emmc 上的第二个分区的 UUID 与启动盘的根文件系统分区完全一致,而 init 脚本又没有对挂载命令的返回进行检查,所以实际上静默失败了。

不过至少内核成功启动了,这证明了之前的理论是正确的,而且也证实了 emmc 并没有损坏。

重新修改 init 脚本,指定 ROOTFS 分区为 /dev/sda2 后,这次成功启动了U盘里的 Kwrt。

shell 出现时,我们已经重新掌握了局势😎。

接下来可以选的路就多了,我甚至可以在网上下载一份N1的 emmc 全盘备份,然后直接写进去。

但这里我先选择一个比较便宜的路,把 /dev/mmcblk2 的头部抹掉,然后重试刷官方固件。

果不其然,重启后再刷官方固件,一路畅通无阻!

我的猜测是官方的烧录工具对分区结构有严格要求,但报错信息又过于模糊🤬

通用方案

经过完善,上述流程已经打包成一个一键脚本 n1-usb-boot,只需要短接设备并连接到主机,同时把制作好的启动盘插在主机上,一路回车,直到提示换线时,在15秒内把数据线拔掉、把启动盘插到盒子上距 HDMI 接口更近的那个 USB 接口,即可直接引导启动盘内的系统~