Linux根文件系统的组成及构建方案

嵌入式技术

1372人已加入

描述

Linux“三巨头”已经完成了 2 个了,就剩最后一个 rootfs(根文件系统)了,本章就来学习一下根文件系统的组成以及如何构建根文件系统。这是 Linux 移植的最后一步,根文件系统构建好以后就意味着已经拥有了一个完整的、可以运行的最小系统。

  根文件系统首先是内核启动时所 mount(挂载)的第一个文件系统,内核代码映像文件保存在根文件系统中,而系统引导启动程序会在根文件系统挂载之后从中把一些基本的初始化脚本和服务等加载到内存中去运行。

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

  嵌入式 Linux 并没有将内核代码镜像保存在根文件系统中,而是保存到了其他地方。比如 NAND Flash 的指定存储地址、EMMC 专用分区中。根文件系统是 Linux 内核启动以后挂载(mount)的第一个文件系统,然后从根文件系统中读取初始化脚本,比如 rcS,inittab 等。根文件系统和 Linux 内核是分开的,单独的 Linux 内核是没法正常工作的,必须要搭配根文件系统。如果不提供根文件系统,Linux 内核在启动的时候就会提示内核崩溃(Kernel panic)的提示。

  根目录,需要大体了解

根文件系统
 

  (来源于网络)
  | BusyBox 构建根文件系统

  BusyBox 是一个集成了大量的 Linux 命令(如 ls、mv、ifconfig 等命令)和工具的软件,一般下载 BusyBox 的源码,然后配置 BusyBox,选择自己想要的功能,最后编译即可。BusyBox 可以在其官网下载到,官网地址为:https://busybox.net/,官网比较简陋:
 

根文件系统
 

  读者可以直接去官网下载,也可以使用原子提供的:
 

路径为:1、例程源码->6、BusyBox 源码->busybox-1.29.0.tar.bz2
    | 搭建NFS服务
  一般在 Linux 驱动开发的时候都是通过 nfs 挂载根文件系统的,当产品最终上市开卖的时候才会将根文件系统烧写到 EMMC 或者 NAND 中。
  安装并开启 Ubuntu 中的 NFS 服务,使用如下命令安装 NFS 服务:
 
sudo apt-get install nfs-kernel-server rpcbind
  等待安装完成,安装完成以后在用户根目录下创建一个名为“linux”的文件夹,以后所有的东西都放到这个“linux”文件夹里面,在“linux”文件夹里面新建一个名为“nfs”的文件夹;

 



根文件系统


 

创建的 nfs 文件夹供 nfs 服务器使用,以后我们可以在开发板上通过网络文件系统来访问 nfs 文件夹,要先配置 nfs,使用如下命令打开 nfs 配置文件/etc/exports:  

sudo gedit /etc/exports
  打开/etc/exports 以后在后面添加如下所示内容:
   
/home/noah/linux/nfs *(rw,sync,no_root_squash)
 

 

根文件系统

  重启 NFS 服务,使用命令如下:  

sudo /etc/init.d/nfs-kernel-server restart
 

 

根文件系统

    | 编译 BusyBox 构建根文件系统

  在nfs服务器目录中创建一个名为rootfs的子目录,然后把根文件系统放进去并解压:

// 解压命令
tar -vxjf busybox-1.29.0.tar.bz2
 

 

根文件系统


 

  修改 Makefile,添加编译器
    打开 busybox 的顶层 Makefile,添加 ARCH 和 CROSS_COMPILE的值,如下所示:

CROSS_COMPILE ?= /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-
......
ARCH ?= arm
 

 

根文件系统


 

  busybox 中文字符支持

  如果默认直接编译 busybox 的话,在使用串口工具的时候中文字符是显示不正常的,中文字符会显示为“?”,所以我们需要修改 busybox 源码,取消 busybox 对中文显示的限制;   打开文件busybox-1.29.0/libbb/printable_string.c,找到函数 printable_string,然后修改一下,主要就是禁止字符大于0X7F以后 break 和输出‘?’:
 

根文件系统

  接着打开文件 busybox-1.29.0/libbb/unicode.c,找到如下内容:  

根文件系统

  配置 busybox
  busybox有以下几种配置选项:
  ①、defconfig,缺省配置,也就是默认配置选项。
  ②、allyesconfig,全选配置,也就是选中 busybox 的所有功能。

 

③、allnoconfig,最小配置。

  一般使用默认配置即可,因此使用如下命令先使用默认配置来配置一下 busybox:
 

make defconfig
  busybox 也支持图形化配置,通过图形化配置我们可以进一步选择自己想要的功能,输入如下命令打开图形化配置界面:
 
make menuconfig
 

 

根文件系统

  设置Settings -> Build static binary (no shared libs)

  选项“Build static binary (no shared libs)”用来决定是静态编译 busybox 还是动态编译,静态编译的话就不需要库文件,但是编译出来的库会很大。动态编译的话要求根文件系统中有库文件,但是编译出来的 busybox 会小很多。这里我们不能采用静态编译!因为采用静态编译的话 DNS 会出问题!无法进行域名解析:

 

根文件系统

  提示:选中Exit再按回车,就能返回上一级;

  设置Settings -> vi-style line editing commands 按空格键进行选中和取消,这里要选中(出现*biao'sh);
 

根文件系统

  配置Linux Module Utilities -> Simplified modutils 默认会选中“Simplified modutils”,这里我们要取消勾选!
   

根文件系统

  配置Linux System Utilities -> mdev (16 kb) 确保下面的全部选中,默认都是选中的:

根文件系统

  设置Settings -> Support Unicode 使能 busybox 的 unicode 编码以支持中文:

根文件系统

  最后按两下ESC退出设置,并选择YES保持存。 busybox 的配置就到此结束了,大家也可以根据自己的实际需求选择配置其他的选项,不过对于初学者笔者不建议再做其他的修改,可能会出现编译出错的情况发生。


| 编译 busybox      

输入如下指令进行编译:

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- install CONFIG_PREFIX=/home/noah/linux/nfs/rootfs
 

 

编译完成以后会在 busybox 的所有工具和文件就会被安装到 rootfs 目录中,rootfs 目录内容:

根文件系统

  rootfs目录下新增bin、sbin和usr三个目录,以及linuxrc文件。Linux内核linit进程最后会查找用户空间的init程序,找到以后就会运行这个用户空间的init程序,从而切换到用户态。如果bootargs设置init=/linuxrc,那么linuxrc就是可以作为用户空间的init程序,所以用户态空间的 init 程序是 busybox 来生成的。

根文件系统

  busybox 的工作就完成了,但是此时的根文件系统还不能使用,还需要一些其他的文件,继续来完善 rootfs。


  | 向根文件系统添加 lib 库  

Linux 中的应用程序一般都是需要动态库的,当然你也可以编译成静态的,但是静态的可执行文件会很大。如果编译为动态的话就需要动态库,所以我们需要向根文件系统中添加动态库。

  向 rootfs 的“/lib”目录添加库文件  

在 rootfs 中创建一个名为“lib”的文件夹,lib 库文件从交叉编译器中获取,前面搭建交叉编译环境的时候将交叉编译器存放到了“/usr/local/arm/”目录中,具体路径在:

/usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linuxgnueabihf/libc/lib
   

 

根文件系统

  此目录下有很多的*so*(*是通配符)和.a 文件,这些就是库文件,将此目录下所有的*so*和.a文件都拷贝到 rootfs/lib 目录中,拷贝命令如下:
 

cp *so* *.a /home/noah/linux/nfs/rootfs/lib/ -d
  后面的“-d”表示拷贝符号链接,这里有个比较特殊的库文件:ld-linux-armhf.so.3,此库文件也是个符号链接,相当于 Windows 下的快捷方式。会链接到库 ld-2.19-2014.08-1-git.so 上,输入命令如下指令查看此文件详细信息:
 
ls ld-linux-armhf.so.3 -l
   

 

根文件系统

  ld-linux-armhf.so.3 后面有个“->”,表示其是个软连接文件,链接到文件 ld-2.19-2014.08-1-git.so,因为其是一个“快捷方式”,因此大小只有 24B。但是,ld-linux-armhf.so.3 不能作为符号链接,否则的话在根文件系统中执行程序无法执行!所以我们需要重新复制ld-linux- armhf.so.3,替换掉这个软链接。 先将 rootfs/lib 中的 ld-linux-armhf.so.3 文件删除掉,命令如下:

rm ld-linux-armhf.so.3
  然后重新进入到 /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/libc/lib 目录中,重新拷贝 ld-linux-armhf.so.3,命令如下:
cp ld-linux-armhf.so.3 /home/noah/linux/nfs/rootfs/lib/
  拷贝完成以后再到 rootfs/lib目录下查看ld-linux-armhf.so.3文件详细信息:
ls ld-linux-armhf.so.3 -l
   

 

根文件系统

此时ld-linux-armhf.so.3已经不是软连接了,而是实实在在的一个库文件,而且文件大小为 724392B。 继续进入如下目录中:  

/usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/lib
  此目录下也有很多的的*so*和.a 库文件,将其也拷贝到 rootfs/lib 目录中,命令如下:
cp *so* *.a /home/noah/linux/nfs/rootfs/lib/ -d
  复制完后,rootfs/lib 目录的库文件如图:

 

根文件系统

  向 rootfs 的“usr/lib”目录添加库文件  

在 rootfs 的 usr 目录下创建一个名为 lib 的目录,将如下目录中的库文件拷贝到 rootfs/usr/lib目录下:

/usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/libc/usr/lib
  将此目录下的 so 和.a 库文件都拷贝到 rootfs/usr/lib 目录中,命令如下:  
cp *so* *.a /home/noah/linux/nfs/rootfs/usr/lib/ -d
  完成以后的 rootfs/usr/lib 目录如图所示:  

 

根文件系统

至此,根文件系统的库文件就全部添加好了,可以使用“du”命令来查看一下 rootfs/lib 和rootfs/usr/lib 这两个目录的大小,命令如下:

cd rootfs //进入根文件系统目录
du ./lib ./usr/lib/ -sh //查看 lib 和 usr/lib 这两个目录的大小
结果如图所示:  

 

根文件系统

  创建其他文件夹  

在根文件系统中创建其他文件夹,如 dev、proc、mnt、sys、tmp 和 root 等,命令如下:

mkdir dev proc mnt sys tmp root
   

 

根文件系统

注意:根文件系统源码和解压后的源码剪切到别的文件夹;

| 根文件系统初步测试

接下来使用测试一下前面创建好的根文件系统 rootfs,测试方法就是使用 NFS 挂载;

uboot里面的bootargs环境变量会设置root的值,需要将root的值改为NFS挂载,设置格式如下:

 

root=/dev/nfs nfsroot=[:][,] ip=::::::::

 

:服务器IP,存放根文件系统的Ubuntu的IP地址,比如我的就是192.168.2.55。

 :根文件系统的存放路径,比如我的就是/home/noah/linux/nfs/rootfs。

:NFS 的其他可选选项,一般不设置。

 :客户端IP ,开发板的IP地址,Linux内核启动以后就会使用此IP地址来配置开发板。我的为192.168.2.50。

 :网关地址,我的就是 192.168.2.1。

:子网掩码,我的就是 255.255.255.0。

:客户机的名字,一般不设置,此值可以空着。

 :设备名,也就是网卡名,一般是 eth0,eth1….,正点原子与野火的开发板均为ENET2为eth0,ENET1为eth1。这里我们使用ENET2,所以网卡名就是 eth0。

 :自动配置,一般不使用,所以设置为 off。

 :DNS0 服务器 IP 地址,不使用。

 :DNS1 服务器 IP 地址,不使用。

根据上面的格式bootargs环境变量的root值如下:

 

root=/dev/nfs nfsroot=192.168.2.55:/home/noah/linux/nfs/rootfs,proto=tcp rw ip=192.168.2.50:192.168.2.55:192.168.2.1:255.255.255.0::eth0:off

 

启动开发板,串口连接开发板,进入uboot命令行模式,然后设置bootargs环境变量,命令如下:

 

setenv bootargs 'console=ttymxc0,115200 root=/dev/nfs nfsroot=192.168.2.55:/home/noah/linux/nfs/rootfs,proto=tcp rw ip=192.168.2.50192.168.2.1off'
saveenv

 

设置好以后使用“boot”命令启动Linux内核;

 

tftp 80800000 zImage
tftp 83000000 imx6ull-14x14-evk.dtb
bootz 80800000 - 83000000

 

根文件系统

在进入根文件系统的时候会有下面这一行错误提示:

can't run '/etc/init.d/rcS': No such file or directory
提示很简单,说是无法运行“/etc/init.d/rcS”这个文件,因为这个文件不存在。制作的 rootfs 还是缺文件,后续一步一步的完善。 --END--

 

 审核编辑:汤梓红
 
打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分