浅谈ARM嵌入式中的根文件系统rootfs

根文件系统和 Linux 内核是分开的,单独的 Linux 内核是没法正常工作的,必须要搭配根文件系统。根文件系统的这个“根”字就说明了这个文件系统的重要性,它是其他文件系统的根,没有这个“根”,其他的文件系统或者软件就别想工作。嵌入式会把rootfs保存在NAND flash或EMMC中。内核可以直接挂载Emmc中的rootfs;也可以使用uboot把rootfs加载到ramdisk中,挂载内存中的rootfs。

1.根文件系统和 Linux 内核是分开的,单独的 Linux 内核是没法正常工作的

根文件系统是 Linux 内核启动以后挂载(mount)的第一个文件系统,然后从根文件系统中读取初始化脚本,比如 rcS,inittab 等。根文件系统和 Linux 内核是分开的,单独的 Linux 内核是没法正常工作的,必须要搭配根文件系统。如果不提供根文件系统,Linux 内核在启动的时候就会提示内核崩溃(Kernel panic)的提示。
在这里插入图片描述
图1: 根文件系统缺失错误
最后一行:

Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0) 

也就是提示内核崩溃,因为 VFS(虚拟文件系统)不能挂载根文件系统,因为根文件系统目录不存在,所以内核会提示在UBOOT中设置一个正确的环境变量“root=” ( Please append a correct “root=” boot option)。即使根文件系统目录存在,如果根文件系统目录里面是空的依旧会提示内核崩溃。
这个就是根文件系统缺失导致的内核崩溃,但是内核是启动了的,只是根文件系统不存在而已。

2.如何构建根文件系统rootfs

根文件系统的这个“根”字就说明了这个文件系统的重要性,它是其他文件系统的根,没有这个“根”,其他的文件系统或者软件就别想工作。比如我们常用的 ls、mv、ifconfig 等命令其实就是一个个小软件,只是这些软件没有图形界面,而且需要输入命令来运行。这些小软件就保存在根文件系统中。

可以使用BusyBox,Buildroot ,Yocto,构建根文件系统rootfs
在这里插入图片描述
图2:创建好的 rootfs

Linux 内核 init 进程最后会查找用户空间的 init 程序,找到以后就会运行这个用户空间的 init 程序,从而切换到用户态。如果 bootargs 设置 init=/linuxrc,那么 linuxrc 就是可以作为用户空间的 init 程序,所以用户态空间的 init 程序是 busybox 来生成的。

在ARM嵌入式中,UBOOT会把上面创建好的rootfs会被保存到nand flash中。

在UBOOT代码中默认的 NAND 分区为:

 #define CONFIG_MFG_NAND_PARTITION "mtdparts=gpmi-nand:64m(boot),16m(kernel),16m(dtb),1m(misc),-(rootfs) "

分区结果如表
在这里插入图片描述
表1:NAND 分区设置
从表中可以看到,rootfs被放到了96M的位置。当然NAND 的分区是可以调整的,比如 boot 分区我们用不了 64M 这么大,因此可以将其改小,其他的分区一样的。

3.内核启动时是如何知道rootfs在哪里呢?

当然是通过Uboot传递来的环境变量 bootargs 。如下:

mmcargs=setenv bootargs console= ttymxc0, 115200 root= /dev/mmcblk1p2 rootwait rw 

可以看出环境变量 mmcargs 就是设置 bootargs 的值为“console= ttymxc0, 115200 root=/dev/mmcblk1p2 rootwait rw”,bootargs 就是设置了很多的参数的值,这些参数 Linux 内核会使用到,常用的参数有:
1、console
console 用来设置 linux 终端(或者叫控制台),也就是通过什么设备来和 Linux 进行交互,是
串口还是 LCD 屏幕?如果是串口的话应该是串口几等等。一般设置串口作为 Linux 终端,这样我们就可以在电脑上通过 SecureCRT 来和 linux 交互了。这里设置 console 为 ttymxc0,因为 linux启动以后 I.MX6ULL 的串口 1 在 linux 下的设备文件就是/dev/ttymxc0,在 Linux 下,一切皆文件。
ttymxc0 后面有个“,115200”,这是设置串口的波特率,console=ttymxc0,115200 综合起来就是设
2、root
root 用来设置根文件系统的位置,root=/dev/mmcblk1p2 用于指明根文件系统存放在
mmcblk1 设备的分区 2 中。EMMC 版本的核心板启动 linux 以后会存在/dev/mmcblk0、
/dev/mmcblk1、/dev/mmcblk0p1、/dev/mmcblk0p2、/dev/mmcblk1p1 和/dev/mmcblk1p2 这样的文件,其中/dev/mmcblkx(x=0~n)表示 mmc 设备,而/dev/mmcblkxpy(x=0n,y=1n)表示 mmc 设备x 的分区 y。在 I.MX6U-ALPHA 开发板中/dev/mmcblk1 表示 EMMC,而/dev/mmcblk1p2 表示EMMC 的分区 2。
root 后面有“rootwait rw”,rootwait 表示等待 mmc 设备初始化完成以后再挂载,否则的话
mmc 设备还没初始化完成就挂载根文件系统会出错的。rw 表示根文件系统是可以读写的,不加rw 的话可能无法在根文件系统中进行写操作,只能进行读操作。
3、rootfstype
此选项一般配置 root 一起使用,rootfstype 用于指定根文件系统类型,如果根文件系统为ext 格式的话此选项无所谓。如果根文件系统是 yaffs、jffs 或 ubifs 的话就需要设置此选项,指定根文件系统的类型。
bootargs 常设置的选项就这三个,后面遇到其他选项的话再讲解。


上面的例子中我们把根文件系统放在了EMMC中,加载rootfs时直接从EMMC中加载rootfs,并没有使用ramdisk。想使用ramdisk可以参考下面的文章:https://blog.csdn.net/weixin_30608131/article/details/98945515

NAND FLASH加载ramdisk文件系统

虚拟机下制作ramdisk的命令

dd if=/dev/zero of=ramdisk bs=2M count=14

/sbin/losetup /dev/loop2 ramdisk

mkfs.ext2 /dev/loop2

mount -t ext2 /dev/loop2 /mnt

cp -r /tmp/myroot/* /mnt/

umount /dev/loop2

/sbin/losetup -d /dev/loop2

cp /tmp/ramdisk /tftpboot

其中bs,和count的大小可以改变。据观察,发现生成的ramdisk大小,大约为bs*count用命令查看ramdisk的大小

du -h ramdisk

在超级终端uboot下做相应配制

tftp 0x80700000 uImage-ti-davinci_evm-2.6.10_mvl401-1.1.1.0600990
nand erase 0x2250000 0x200000
nand write 0x80700000 0x2250000 0x200000

tftp 0x82000000 ramdisk
nand erase 0x60000 0x2000000
nand write 0x82000000 0x60000 0x2000000

setenv bootcmd 'nand read 0x82000000 0x60000 0x2000000; nboot 0x80700000 0 0x2250000; bootm'
setenv bootargs mem=120M console=ttyS0,115200n8 root=/dev/ram0 rw initrd=0x82000000,29M ip=192.168.1.14:192.168.1.13:192.168.1.1:255.255.255.0

其中,内核uImage-ti-davinci_evm-2.6.10_mvl401-1.1.1.0600990通过tftp传到ddr中(0x80700000),然后烧写进nand flash(相对于0x02000000的偏移地址0x2250000,大小0x200000)。制作好的ramdisk文件系统ramdisk,通过tftp下载到ddr中(0x82000000),然后烧写进nand flash(相对于0x02000000的偏移地址0x60000,大小0x2000000)。
注意(0x82000000+0x2000000)不要和(0x80700000+0x2250000)重叠了。

bootcmd参数,‘nand read 0x82000000 0x60000 0x2000000’ ,是把0x60000处的文件系统数据拷贝到0x82000000处,共32M字节(要比文件系统大)。nboot 0x80700000 0 0x2250000,是打开device 0,把0x2000000字节搬移到0x80700000中。

root=/dev/ram0指明根文件系统存放在内存ram0中。

bootargs参数 initrd=0x82000000是文件系统的位置,29M是文件系统的大小。

NOTE:当NAND FLASH报错Skipping bad block ……时,不会有影响的。