根文件系统
rootfs根文件系统目录从何而来?
- rootfs目录或者rootfs_ext4.img都是根文件系统,只是一个是目录一个是镜像,实际在运行中是一样的。
- 根文件系统rootfs仅仅是个代名词。
- 研究根文件系统从它包含的内容角度考虑。根文件系统包含的内容就是进入Linux系统执行:cd /然后ls看到的所有的内容,它们组成了根文件系统rootfs,还需要明确管理根文件系统内的文件和目录必须采用一种文件系统格式,例如EXT4。
细说根文件系统包含的内容:
- bin目录:存放普通用户的命令。
- sbin目录:存放超级用户的命令。
- etc目录:存放系统服务配置文件。
- lib目录:存放库。
- usr目录:存放其他命令。
- dev目录:存放设备文件,跟驱动相关。
- proc目录:存放设备信息,进程信息。
- sys目录:存放系统信息。
- 可选目录:
- home:普通用户主目录。
- mnt:挂载设备目录。
- var:存放临时文件。
制作根文件系统——busybox开源软件。
- busybox是一款著名的开源软件——www.busybox.net
- busybox不依赖硬件信息,只要是同一个CPU架构都可以运行同一个根文件系统。虽然芯片厂家提供busybox制作好的根文件系统rootfs,但是因为芯片厂家的体积非常大,所以一般从www.busybox.new下载源码自己制作即可。
- 利用busybox制作根文件系统,仅仅能提供文件系统中的必要命令,其他的库、配置文件还是需要自己去配置制作。
busybox源码操作
- 获取正确的交叉编译器
- 注意:交叉编译器版本要和busybox源码版本相匹配。
- 从www.busybox.net网站获取需要版本的busybox源码。
- ftp://PORTING/busybox-1.21.1.tar.bz2
- 修改busybox的Makefile指定将来运行的处理器架构和交叉编译器。
cp busybox-1.21.1.tar.bz2 /opt/ cd /opt tar -xvf busybox-1.21.1.tar.bz2 mv busybox-1.21.1 busybox cd /opt/busybox vim Makefile +190 ARCH ?= $(SUBARCH)改为 ARCH = ARM P164: CROSS_COMPILE ?= 改为 CROSS_COMPILE = arm-cortex_a9-linux-gnueabi- 保存退出。 make menuconfig //配置busybox //解决一个小bug Linux Module Utilities ——> //按N键取出,此选项支持的驱动安装命令insmod为精简版,需要使用完整版。 【】Simplified modutils(NEW) //按N键去除之后,立刻可以见到下面完整的命令,按Y键全部选择。 保存退出。
- 正式交叉编译busybox
cd /opt/busybox make //编译 make install //安装:将编译生成的二进制文件统一拷贝到某个目录下 //默认安装目录为根目录下的 _install
终极结论:
- 编译生成的各自命令都是软连接文件,最终链接到_install/bin/busybox这个可执行程序。
- 编译busybox最终生成了这个可执行文件,bin/busybox。
给自己制作的根文件系统添加库到根文件系统必要目录lib下。
rm /opt/rootfs -fr //删除原有的根文件系统。 cp /opt/busybox/_install /opt/rootfs -frd //此时使用busybox制作的根文件系统。 cd /opt/rootfs ls mkdir lib etc proc sys dev //创建其余目录 mkdir home mnt tmp
- 明确:下位机的根文件系统必要目录lib中保存库,并且只能是动态库(上位机编辑编译,下位机负责运行)。
- 下位机应用程序运行所需的动态库在交叉编译器中。
arm-xxxx-eabi-readelf -d [可执行文件] //获取可执行程序依赖的动态库。
- 严重依赖版本,只需执行which is arm-cortex_xxx-gcc,得到交叉编译器的位置路径。
- 得到应用程序所需动态局,然后将这些动态库复制到lib目录下。例如libm.so.6。
- 进入交叉编译器中找到所需要的动态库,复制到lib下。
- 好习惯:先看看文件属性,“-lh”,能够看出文件是否是链接文件。
- 切记:制作根文件系统,最终还需要拷贝动态链接库,简称加载器,负责将一个进程所需的动态库中的函数变量加载到当前进程的地址空间上,并且加载器都是以动态库形式存在的,并且文件名以“ld-”开头,接下来拷贝加载器:
cd /opt/toolchains/ find . -name ld-* //找到所有以ld-开头的文件,得到:
向根文件系统rootfs必要目录etc中添加Linux启动的必要配置文件:
- 明确:etc目录下只存放配置文件。
- 系统启动的必要配置文件:inittab。
vim /opt/rootfs/etc/inittab 新建inittab文件,添加: ::sysinit:/etc/init,d/rcS ::respawn:-/bin/sh 保存退出。
- 从Linux启动流程看:
- 上电——>uboot先做硬件初始化
- 通过bootcmd从某个地方加载内核到内存
- uboot通过bootargs给内核传递参数
- 最后uboot启动内核
- Linux内核启动后,首先调用七大子系统的初始化函数。
- 到最后根据uboot的bootargs参数到某个地方找到根文件系统。
- 一旦找到内核调用根文件系统/sbin/init第一号进程
- init一号进程首先打开根文件系统etc目录下的Inittab文件。
- 第一号进程首先找到inittab文件中的关键字sysinit,一旦找到关键字sysinit,然后init第一号进程创建一个子进程。子进程来调用sysinit关键字指定的脚本程序rcS,而rcS脚本文件位于根文件系统的etc/init.d目录中父进程init等待子进程的结束。
- 一旦子进程执行完rcS脚本,父进程init继续运行,然后找inittab中是否有respawn关键字,一旦找到这个关键字,init继续创建一个子进程程序来执行respawn指定的程序sh,而sh位于根文件系统的bin目录下,一旦执行sh就是执行了一个shell程序,此时用户可以输入命令了,此时此刻父进程init还在等待子进程的结束。
Linux系统启动的必要启动脚本程序rcS
- rcS本质就是一个脚本程序,就是一堆命令的集合,从头往下执行。
mkdir /opt/rootfs/etc/init.d vim /opt/rootfs/etc/init.d/rcS mount -a mkdir /dev/pts mount -t devpts devpts /dev/pts echo /sbin/mdev > /proc/sys/kernel/hotplug mdev -s 当然可以继续添加各种命令,保存退出。
- mount -a:此命令执行时,Linux系统会自动执行根文件系统etc目录下的fstab文件。
- mount -t devpts devpts /dev/pts:将devpts虚拟网络文件系统挂载到/dev/pts目录,目的将来让上位机通过telnet命令远程登录到下位机上便于将来调试,即使没有串口终端也能够玩命令。
- echo /sbin/mdev > /proc/sys/kernel/hotplug:表面看是想文件hotplug写入字符串/sbin/mdev,本质是让设备驱动将来帮设备驱动穿件设备文件。
- mdev -s:Linux启动程序,顺便执行mdev来讲当前系统中的设备驱动的设备文件创建一遍。
Linux系统启动的必要配置文件fstab
- 此文件同样位于根文件系统的etc目录下。
vim /opt/rootfs/etc/fstab proc /proc proc defaults 0 0 sysfs /sys ssfs defaults 0 0 tmpfs /dev tmpfs default 0 0 保存退出
- 将proc虚拟文件系统挂接到/proc目录下。
- 将sysfs虚拟文件系统挂接到/sys目录下。
- 将tmpfs虚拟文件系统挂接到/dev目录下。
- 注意:proc、sysfs、tmpfs、devpts,仅仅就是四种不同的文件系统格式。这四种文件系统格式管理的文件和目录都是在内存中,也就是/proc、/sys、/dev目录下的内容都是内核自己来创建,创建的内容都是给驱动程序使用,并且创建在内存中,将来掉电丢失。
优化精简根文件系统,变成最小的根文件系统。
- 利用arm-cortex_a9-linux-gnueabi-strip工具(瘦身)
需要修改的个别bug:
Ubuntu18.04的格式化命令mkfs.ext4版本太新,导致rootfs_ext4.img挂载失败。
- 解决方法:只需要修改mkfs.ext4命令的配置文件即可:
- 执行:sudo vim /etc/mke2fs.conf +13
- 将ext4的相关配置改为(即改为旧版本Ubuntu下的配置参数即可。):
ext4 = { features = has_journal, extent, hug...... }
系统启动完毕,内核无法挂载EMMC上,或者西东启动时打印“mmc error: -22”
- 解决办法:修改内核EMMC驱动的bug,修改方法如下:
- 上位机执行:cd /opt/kernel; vim drivers/mmc/core/mmc.c +295
- 将文件内整个的if语句注释掉,然后保存退出。重新编译烧写。
- make uImage
- cp uImage /tftpboot。使用新制作的uImage重新挂载到EMMC即可。