为了让不在OpenWrt项目支持列表中的ARM机器快速使用OpenWrt,可以用替换rootfs的简易方法进行移植。
首先,确保你的ARM盒子有能正常使用的Linux系统,并且最好有良好的社区支持,可以去armbian寻找有开源支持的开发板。
以下SoC的开源支持比较良好,多数情况下可以用上主线内核:
Rockchip
RK3328/RK3368/RK3399 系列
amlogic
s905/s912/s922 系列
sunxi
h2/h3/h5 系列
marvell
armada a3700 系列
移植OpenWrt的rootfs过程中,需要特别注意的是必须保证原有系统内与内核有关的东西(包括内核模块)不能有任何丢失。多数固件的Linux内核镜像、dtb和uboot的部分变量都是直接存放到rootfs里面的,在替换的时候一定要把这些文件完整保留。
注意:替换rootfs后,机器实际使用的内核与openwrt中由opkg管理的内核(包含内核模块)没有任何关系,因此如果要增删内核模块的话不能使用opkg进行管理。
具体流程:
准备好Linux环境,可以用虚拟机或实体机,不能用wsl
下载armvirt的通用rootfs,以OpenWrt 18.06.4为例
32位arm,适合于Cortex A7/A9/A15等:
https://downloads.openwrt.org/releases/18.06.4/targets/armvirt/32/openwrt-18.06.4-armvirt-32-default-rootfs.tar.gz64位arm,适合于Cortex A53/A72等:
https://downloads.openwrt.org/releases/18.06.4/targets/armvirt/64/openwrt-18.06.4-armvirt-64-default-rootfs.tar.gz判断固件的分区类型
对于amlogic的固件,一般有2个分区:第一分区为FAT32分区,用于存放内核镜像、dtb、uboot变量和脚本;第二分区为ext4分区,用作真正的rootfs。替换的时候必须保留FAT32分区的所有内容以及ext4分区内的
/lib/modules
和/lib/firmware
对于rockchip或sunxi的sd卡固件,一般只有1个ext4分区作为rootfs,此分区内使用
/boot
文件夹用于存放内核、dtb、uboot变量和脚本。在替换的时候,必须保留此分区内的/lib/modules
、/lib/firmware
以及/boot
。此类固件的bootloader存放在ext4分区前未分配的空间中。准备好你要修改的固件,注意修改的固件的rootfs分区必须是可写入的文件系统(如ext4),否则不能操作。
对于从SD卡启动的机器,将固件用etcher写入SD卡,然后在你的Linux环境下挂载好SD卡,继续下一步操作。
对于提供emmc刷机固件的机器,需要用loop挂载镜像,具体操作如下:
# 创建挂载目录 mkdir -p /mnt/rootfs # 查看固件的分区表 sfdisk -J /path/to/firmware # # 以amlogic的双分区(FAT32+EXT4)固件为例: # { # "partitiontable": { # "label":"dos", # "id":"0x1028b956", # "device":"/path/to/firmware", # "unit":"sectors", # "partitions": [ # {"node":"/path/to/firmware1", "start":8192, "size":262144, "type":"e"}, # {"node":"/path/to/firmware2", "start":270336, "size":30694112, "type":"83"} # ] # } # } # 可以看到rootfs为第二分区,并且偏移量为270336 blocks,所以偏移的字节数为270336*512 # 带偏移量挂载 sudo mount -o loop,offset=$((270336*512)) /path/to/firmware /mnt/rootfs
处理
/lib/modules
一般来说Linux发行版的/lib/modules
目录结构都是这样的:
/lib/modules/<内核版本号>/ ├── kernel │ ├── arch │ ├── crypto │ ├── drivers │ ├── fs │ ├── lib │ ├── mm │ ├── net │ ├── security │ ├── sound │ └── virt ├── modules.alias ├── modules.alias.bin ├── modules.builtin ├── modules.builtin.bin ├── modules.dep ├── modules.dep.bin ├── modules.devname ├── modules.order ├── modules.softdep ├── modules.symbols └── modules.symbols.bin
而OpenWrt的/lib/modules/<内核版本号>
下面直接存放kernel
目录下的所有模块,所以需要我们手工移动一下,具体操作如下:
# root挂载的目录一般需要root权限,可以用sudo或者切换成root用户操作 # 进入rootfs的挂载点 cd /path/to/rootfs # 进入内核模块目录 cd ./lib/modules/<内核版本号>/ # 删除当前目录下的所有文件,但不删除kernel目录 sudo rm -f * 2>/dev/null # 找出kernel目录下面的所有ko并移动到当前目录下 sudo mv $(find kernel -type f) . # 删除空的kernel文件夹 sudo rm -r kernel
备份文件并解压OpenWrt的rootfs
如果该镜像的内核镜像、dtb或uboot脚本等文件在rootfs里面的话,需要先备份出来。对于不同板子和不同固件,这一步的操作都不同,下面以armbian为例:
# 创建一个临时目录用于存放备份文件 mkdir -p /tmp/backup # 进入rootfs的挂载点 cd /path/to/rootfs # 对于把内核、dtb或uboot变量放在/boot目录的固件,例如sunxi和rockchip,需要将整个/boot目录备份出来 cp -ra ./boot /tmp/backup/boot # 备份/lib/modules和/lib/firmware cp -ra ./lib/modules /tmp/backup/ cp -ra ./lib/firmware /tmp/backup/ # 备份后删除当前rootfs下的所有文件 sudo rm -rf * # 将OpenWrt的rootfs解压出来 sudo tar -xvf /path/to/openwrt/rootfs.tar.gz # 删除OpenWrt rootfs里自带的/boot目录 sudo rm -rf ./boot # 恢复刚才备份的目录 sudo mv -f /tmp/backup/boot . sudo mv -f /tmp/backup/modules/<内核版本号> ./lib/modules sudo mv -f /tmp/backup/firmware ./lib/firmware
修改rootfs
启用串口的getty:对于串口设备名是
ttyS0
的内核,/etc/inittab
里已经包含,所以无需修改,而其它串口设备名就需要手动添加,具体如下:
# 进入rootfs的挂载点 cd /path/to/rootfs # 对于amlogic的内核,串口设备名为ttyAML0 echo "ttyAML0::askfirst:/usr/libexec/login.sh" |sudo tee -a ./etc/inittab # 对于rockchip的bsp内核,串口设备名为ttyFIQ0 echo "ttyFIQ0::askfirst:/usr/libexec/login.sh" |sudo tee -a ./etc/inittab # 对于marvell armada的bsp内核,串口设备名为ttyMV0 echo "ttyMV0::askfirst:/usr/libexec/login.sh" |sudo tee -a ./etc/inittab
rootfs修改完成,卸载文件系统
sync cd / && sudo umount /path/to/rootfs
启动修改后的固件,进入OpenWrt之后检查以下命令能否正常工作:
iptables -L ip6tables -L ip route
如果你的内核版本大于4.18,且iptables抛出以下错误:
root@OpenWrt:~# iptables -Liptables v1.6.2: can't initialize iptables table `filter': No child process
那么说明原内核启用了bpfilter,这可能需要重新编译整个内核,请参考这篇文章:https://www.jianshu.com/p/48e2f3e6caeb
文章作者:https://www.jianshu.com/u/70c0d31e3717