资源地址

本文记录基于旧版 OpenWrt Barrier Breaker(Linux 3.10.14)为 MT7621 编译固件,并在根文件系统损坏后通过 U-Boot、TFTP 和 initramfs 恢复系统的完整过程。

一、编译环境与常用命令

OpenWrt 构建系统通常禁止使用 root 用户编译。如果出现以下错误:

1
2
Build dependency: Please do not compile as root.
Prerequisite check failed.

应切换到普通用户,并确保源码属于该用户:

1
2
sudo chown -R "$USER:$USER" ~/mtkopenwrt
cd ~/mtkopenwrt

首次完整编译可执行:

1
make -j$(nproc) V=s

其中:

  • nproc 返回虚拟机可用的逻辑 CPU 数量。
  • -j$(nproc) 按逻辑 CPU 数量并行编译,例如 nproc 输出 4,就等价于 -j4
  • V=s 显示较完整的构建信息。
  • V=99 显示详细命令,适合排查错误,但不会改变编译结果。

发生编译错误时,建议使用单线程,避免并行日志交错:

1
make -j1 V=99

已经完成的目标文件会被 make 复用,因此用 Ctrl+C 中断后再次执行 make,通常会继续构建,而不是全部重来。不要执行 make cleanmake dirclean,除非确实需要清理构建结果。

保存并实时观察构建日志:

1
2
make -j$(nproc) V=s 2>&1 | tee build.log
tail -f build.log

OpenWrt 没有可靠的百分比进度。构建通常依次经过 toolstoolchaintargetpackage、安装和镜像生成阶段。

二、理解生成的镜像

本次构建生成了以下主要文件:

1
2
3
4
5
openwrt-ramips-mt7621-uImage.bin
openwrt-ramips-mt7621-root.squashfs
openwrt-ramips-mt7621-mt7621-squashfs-sysupgrade.bin
openwrt-ramips-mt7621-uImage-initramfs.bin
openwrt-ramips-mt7621-vmlinux.elf

它们的用途不同:

文件 内容 主要用途
uImage.bin 普通 Linux 内核 从 Flash 启动,并挂载 Flash 中的 rootfs
root.squashfs 只读根文件系统 与内核配合使用
squashfs-sysupgrade.bin 内核 + SquashFS 永久写入 firmware 分区
uImage-initramfs.bin 内核 + RAM 根文件系统 TFTP 临时启动和救援
vmlinux.elf 未压缩或带符号内核 调试,不是直接烧录固件

使用 binwalk 检查永久固件:

1
binwalk bin/ramips/openwrt-ramips-mt7621-mt7621-squashfs-sysupgrade.bin

正确的合成固件应同时包含:

1
2
3
uImage header
LZMA compressed Linux kernel
Squashfs filesystem

本次生成的文件信息为:

1
2
3
文件大小:7864324 bytes
SquashFS 偏移:0x178281
MD5:04891b3af50af2fcf53c95172095b32c

这些数值只适用于本次构建。每次重新编译后都应重新核对文件大小和校验值。

三、为什么救援启动需要 initramfs

普通启动流程为:

1
U-Boot -> Linux 内核 -> 挂载 Flash 中的 SquashFS -> 启动 OpenWrt

TFTP 救援流程为:

1
U-Boot -> 将 recovery.bin 下载到 RAM -> 启动内核和 initramfs

initramfs 是内置在内核镜像中的临时根文件系统。它使系统不依赖 Flash 中的 rootfs,也能进入命令行进行分区检查和固件恢复。initramfs 在 RAM 中运行,重启后其中下载的文件和修改都会消失。

make menuconfig 中启用:

1
2
Target Images
[*] ramdisk

对应配置通常为:

1
CONFIG_TARGET_ROOTFS_INITRAMFS=y

然后重新构建内核:

1
2
make target/linux/clean
make -j$(nproc) V=s

四、旧版 LZMA 工具不兼容

启用 initramfs 后,旧内核可能在生成 initramfs_data.cpio.lzma 时失败:

1
2
Error: Incorrect command
recipe for target 'usr/initramfs_data.cpio.lzma' failed

这是旧版 Linux 构建脚本与主机上的 LZMA 命令参数不兼容。可将内置 initramfs 的压缩方式改为 gzip。

注意,kernel_menuconfig 中下面的选项只表示内核是否支持解压外部 ramdisk:

1
Support initial ramdisks compressed using gzip

它不一定控制内置 initramfs 的生成格式。应搜索真正的配置项:

1
INITRAMFS_COMPRESSION_GZIP

目标配置应为:

1
2
CONFIG_INITRAMFS_COMPRESSION_GZIP=y
# CONFIG_INITRAMFS_COMPRESSION_LZMA is not set

如果菜单中不可见,可定位由哪个目标配置文件启用了 LZMA:

1
grep -RnsE 'CONFIG_INITRAMFS_COMPRESSION_(LZMA|GZIP)' target/linux

修改持久配置后重新清理并编译。成功时应生成 initramfs_data.cpio.gz,而不是 .cpio.lzma

五、VirtualBox 与主机之间传输固件

可使用 VirtualBox 共享文件夹,但不要把共享目录直接挂载到源码的 bin 目录,否则原有构建产物会被挂载点暂时遮挡。

推荐让 VirtualBox 自动挂载,或使用独立目录:

1
/media/sf_openwrt_virtualbox_output

如果出现权限问题:

1
2
sudo usermod -aG vboxsf "$USER"
sudo reboot

也可以通过桥接网络和 SSH 从 Windows 拉取文件:

1
scp hlk@虚拟机IP:/home/hlk/mtkopenwrt/bin/ramips/固件文件 D:\openwrt_output\

六、识别根文件系统启动失败

错误日志示例:

1
2
3
jffs2: Magic bitmask 0x1985 not found
VFS: Cannot open root device "mtdblock5"
Kernel panic - not syncing: VFS: Unable to mount root fs

这表示内核已经启动,但没有在预期的 MTD 分区中找到有效根文件系统。常见原因包括:

  • 只写入了内核,没有写入 SquashFS。
  • 写入地址或长度错误。
  • 固件与 Flash 分区布局不匹配。
  • firmware 后部残留旧 JFFS2 数据。
  • 启动参数中的 root 分区或文件系统类型错误。

本次 initramfs 启动后的分区表为:

1
2
3
4
5
mtd0  0x02000000  ALL
mtd1 0x00030000 Bootloader
mtd2 0x00010000 Config
mtd3 0x00010000 Factory
mtd4 0x01fb0000 firmware

由此可知 Flash 容量为 32 MiB,firmware0x50000 开始。不要操作 ALLBootloaderConfigFactory,尤其不能擦除保存 MAC 和无线校准数据的 Factory 分区。

检查 Flash 内容:

1
2
hexdump -C -n 64 /dev/mtd4
hexdump -C -n 64 /dev/mtd5

常见魔数:

1
2
3
4
27 05 19 56    uImage
68 73 71 73 SquashFS(ASCII 为 hsqs)
19 85 JFFS2
ff ff ff ff 已擦除的 NOR Flash

本次检查发现 mtd4 只有一个长度为 0x21822Breed MT7621 uImage,紧随其后的 mtd5 全部为 0xFF,证明 Flash 中只有内核镜像,没有 SquashFS。

七、通过 TFTP 启动恢复系统

U-Boot 输出如下时,表示它正在等待电脑提供 recovery.bin

1
2
3
4
TFTP from server 192.168.1.2; our IP address is 192.168.1.1
Filename 'recovery.bin'.
Load address: 0x84000000
Loading: *

将 Windows 有线网卡设置为:

1
2
3
IP:192.168.1.2
掩码:255.255.255.0
网关:留空

将以下文件复制到 TFTP 根目录并重命名:

1
openwrt-ramips-mt7621-uImage-initramfs.bin -> recovery.bin

正常下载时,Loading: * 会变成连续的 #,随后 U-Boot 从 RAM 启动。进入如下提示符即表示 initramfs 启动成功:

1
root@OpenWrt:/#

注意:U-Boot 日志里的 Model 来自当前 U-Boot 使用的设备树或移植配置,不一定代表实际硬件型号。不能仅凭类似 Model: ASUS RT-AC1200GU 的文字选择固件。

八、在 initramfs 中上传永久固件

本次系统默认 LAN 地址为 192.168.16.254。为了访问位于 192.168.1.2 的 TFTP 服务器,可临时设置:

1
2
3
ifconfig br-lan 192.168.1.1 netmask 255.255.255.0 up
route add -net 192.168.1.0 netmask 255.255.255.0 dev br-lan
ping -c 4 192.168.1.2

不要给作为网桥成员的 eth0 单独配置相同地址。

将永久固件下载到 RAM:

1
2
cd /tmp
tftp -g -r openwrt-ramips-mt7621-mt7621-squashfs-sysupgrade.bin 192.168.1.2

下载后必须核对:

1
2
ls -l /tmp/openwrt-ramips-mt7621-mt7621-squashfs-sysupgrade.bin
md5sum /tmp/openwrt-ramips-mt7621-mt7621-squashfs-sysupgrade.bin

九、绕过旧无线驱动导致的 sysupgrade 死锁

本次运行 sysupgrade -n 时,厂商脚本先关闭 Wi-Fi,MT76x2 私有驱动在 StopDmaRx 中死锁:

1
2
INFO: rcu_sched detected stalls
ifconfig -> rt28xx_close -> StopDmaRx

此时尚未出现 ErasingWriting,说明 Flash 写入还没有开始,可以复位并重新进入 initramfs。

该系统的 mtd 工具支持:

1
2
-e <device>    erase <device> before executing the command
-r reboot after successful command

在已通过 binwalk、大小和 MD5 校验的前提下,可绕过会关闭 Wi-Fi 的 sysupgrade 脚本,只擦写 firmware 分区:

1
2
mtd -e firmware -r write \
/tmp/openwrt-ramips-mt7621-mt7621-squashfs-sysupgrade.bin firmware

该命令会完整擦除 firmware、写入合成固件,并在成功后自动重启。执行过程中严禁断电。不要增加 -f,除非已经明确理解镜像检查失败的原因和风险。

十、验证恢复结果

成功启动后检查:

1
2
3
4
5
mount
df -h
cat /proc/mtd
cat /proc/cmdline
dmesg | grep -Ei 'squashfs|jffs2|panic|error'

本次恢复后出现:

1
2
3
/dev/mtdblock5 on /mnt/mtdblock5 type squashfs
mtd5 "rootfs"
mtd6 "rootfs_data"

这说明内核、SquashFS 和可写数据分区已经被识别。SquashFS 显示 100% 属于正常现象,因为它是只读压缩文件系统。

验证可写数据是否持久化:

1
2
3
4
touch /root/persist-test
sync
reboot
ls -l /root/persist-test

重启后文件仍存在,才说明 overlay 或 rootfs_data 已正常提供持久化写入。

十一、访问 Web 管理后台

查看 LAN 地址:

1
ifconfig br-lan

临时改为 192.168.1.1

1
ifconfig br-lan 192.168.1.1 netmask 255.255.255.0 up

浏览器访问:

1
http://192.168.1.1

永久修改地址:

1
2
3
uci set network.lan.ipaddr='192.168.1.1'
uci commit network
/etc/init.d/network restart

如果页面无法打开,检查 Web 服务:

1
2
3
4
ps | grep uhttpd
/etc/init.d/uhttpd start
/etc/init.d/uhttpd enable
netstat -lntp | grep ':80'

若固件没有包含 uhttpd 和 LuCI,需要在 OpenWrt 配置中选入对应软件包后重新编译。

十二、恢复过程的关键原则

  1. uImageinitramfssysupgrade.bin 用途不同,不能仅靠改名互换。
  2. TFTP 临时启动应使用 initramfs;永久写入应使用包含内核和 rootfs 的合成固件。
  3. 写入前同时检查 binwalk、文件大小和 MD5。
  4. 根据 /proc/mtd 确认分区,禁止盲目擦除整片 Flash。
  5. Factory、Bootloader 和校准数据应优先备份。
  6. 只有出现明确的擦写输出后,才表示真正进入 Flash 写入阶段。
  7. initramfs 中的文件位于 RAM,重启后必须重新上传。
  8. 旧厂商 SDK 的驱动和脚本可能存在死锁,应根据调用栈定位,而不是在卡死状态下反复等待。