嵌入式linux系统的开发——基于JFSS2文件系统的分区及镜像制作
前言
对于嵌入式Linux系统来说,绝大多数硬件设备采用Flash作为存储介质,LEDE/OPENWRT发行版会使用squash文件系统和jffs2文件系统相结合的方式作为整个系统的文件系统,其中squash文件系统是一种压缩只读文件系统,而jffs2文件系统支持可读可写操作。
当uboot启动kernel后,kernel加载由squashFS文件系统格式化的ROM分区,将其挂载到/rom目录,由JFFS2文件系统格式化的Flash剩余空间则挂载到了/overlay目录,/rom最终挂载到/根目录下, /overlay覆盖在/rom之上,即所谓的Overlay透明挂载技术,从用户的使用角度看,/根目录下可以任意修改、删除、添加文件,但实际上对/rom目录下只读文件修改后会将修改的文件放到/overlay目录下,当对/overlay和/rom目录下同名的文件修改时只会对/overlay目录下文件影响,/rom目录下文件保持不变,这种方式的好处是恢复出厂设置时只需清空/overlay分区下文件,/rom目录下的文件会成为出厂状态,但这样/rom目录下始终占用一定的空间来存放系统所必要文件来恢复系统。
本文将介绍如何在LEDE发行版17.01.4上只使用JSFF2文件系统的方法以及镜像的制作,相比与squash文件系统无需占用空间备份相同的文件。
JFSS2格式配置
在source-17.01.4/config/路径下包含Config-images.in文件对应LEDE Configuration界面中Target Images选项内容,由于默认并未开放对JSFF2文件系统的选择,此处需要更改以下代码增加对JFSS2文件系统支持。
menu "Target Images" ... config TARGET_ROOTFS_JFFS2 bool "jffs2" default y if USES_JFFS2 #depends on USES_JFFS2 help Build a JFFS2 root filesystem. ...
系统分区
dts文件为实现更加灵活的硬件支持和配置,对设备的硬件信息进行描述,涉及到系统flash类型、系统分区、网口寄存器、led gpio声明等。在source-17.01.4/target/linux/ramips/dts/路径下更改对应硬件平台(LEDE Configuration——>Target Profile选项中配置)dts文件的系统分区部分。
&spi0 { status = "okay"; m25p80@0 { #address-cells = <1>; #size-cells = <1>; compatible = "jedec,spi-nor"; reg = <0>; spi-max-frequency = <10000000>; m25p,chunked-io = <32>; partition@0 { label = "u-boot"; reg = <0x0 0x30000>; read-only; }; partition@30000 { label = "u-boot-env"; reg = <0x30000 0x10000>; #read-only; }; factory: partition@40000 { label = "factory"; reg = <0x40000 0x10000>; read-only; }; kernel: partition@50000 { label = "kernel"; reg = <0x50000 0x180000>;/*1.5M*/ }; rootfs: partition@1D0000 { label = "rootfs"; reg = <0x1D0000 0x0D00000>;/*13M 0x0D00000*/ }; upgrade: partition@ED0000 { label = "upgrade"; reg = <0xED0000 0x0E80000>;/*14.5M 0x0D00000*/ }; partition { label = "firmware"; reg = <0x50000 0x1fb0000>; }; }; spidev@1 { #address-cells = <1>; #size-cells = <1>; compatible = "linux,spidev"; reg = <1>; spi-max-frequency = <10000000>; }; };
固件合成
将/source-17.01.4/build_dir/target-mipsel_24kc_musl-1.1.16/linux-ramips_mt7628/路径下的kernel和 rootfs的bin文件进行固件合成。由于在dts文件中kernel分区大小为1.5M、rootfs分区大小为13.5M,需要通过dd命令将bin文件扩充后,再使用cat命令将两份bin文件连接合成为一份固件。
Linux的dd命令可用指定大小块拷贝一个文件,并在拷贝的同时进行指定的转换。如wrtnode2p-kernel.bin文件的扩充,以768k为1个block,2个blocks即为1.5M, 不足部分用空(NUL)字符补齐。具体参数如下所示:
1)if=文件名:输入文件名,缺省为标准输入。即指定源文件。
2)of=文件名:输出文件名,缺省为标准输出。即指定目的文件。
3)ibs=bytes:一次读入bytes个字节,即指定一个块大小为bytes个字节。
4)obs=bytes:一次输出bytes个字节,即指定一个块大小为bytes个字节。
5)bs=bytes:同时设置读入/输出的块大小为bytes个字节。
6)cbs=bytes:一次转换bytes个字节,即指定转换缓冲区大小。
7)skip=blocks:从输入文件开头跳过blocks个块后再开始复制。
8)seek=blocks:从输出文件开头跳过blocks个块后再开始复制。
9) count=blocks:仅拷贝blocks个块,块大小等于ibs指定的字节数。
10) conv=conversion:用指定的参数转换文件。
- ascii:转换ebcdic为ascii
- ebcdic:转换ascii为ebcdic
- ibm:转换ascii为alternate ebcdic
- block:把每一行转换为长度为cbs,不足部分用空格填充
- unblock:使每一行的长度都为cbs,不足部分用空格填充
- lcase:把大写字符转换为小写字符
- ucase:把小写字符转换为大写字符
- swab:交换输入的每对字节
- noerror:出错时不停止
- notrunc:不截短输出文件
- sync:将每个输入块填充到ibs个字节,不足部分用空(NUL)字符补齐。
Linux的cat命令可用于创建文件、显示文件内容以及连接文件,此处使用cat命令可将填充后的kernel和rootfs文件连接。
dd if=wrtnode2p-kernel.bin of=dwrtnode2p-kernel.bin bs=768k count=2 conv=sync dd if=root.jffs2-64k of=droot.jffs2-64k bs=6656K count=2 conv=sync cat dwrtnode2p-kernel.bin droot.jffs2-64k > ledeupdate.bin
注:将命令以shell脚本方式调用(./xx.sh)更为便捷
将合成后的固件以TFTP协议下载至设备Flash中,具体方法可参考《嵌入式linux系统的开发——发行版的编译和烧写》中固件烧写章节。
镜像制作
所谓镜像文件制作即像照镜子一样将烧写在原设备上的固件复制成一份文件,继而再烧写至其他同类设备上。
通过cat /proc/mtd命令查看当前系统分区信息,结合dts文件中分区信息,可通过dd命令或cat命令从MTD(Memory Technology Devices)接口访问Flash分区中的固件,并制作成镜像文件,对kernel和rootfs单独分区的好处即是可单独制作分区的镜像文件。
dd if=/dev/mtd3 of=/tmp/kernel.bin dd if=/dev/mtd4 of=/tmp/rootfs.bin cat /dev/mtd3 > /tmp/kernel.bin cat /dev/mtd4 > /tmp/rootfs.bin
总结
使用jffs2文件系统不仅可以多出M级以上的可支配空间,而且可以方便地单独更新kernel或rootfs固件。