赞
踩
根文件系统也叫做rootfs,通俗点来说,根文件系统就像是windows下的一个磁盘,里面存放很多的目录或者文件夹。在这个目录里面存放很多文件,这些文件都是Linux运行所必须要有的。比如库、常用的软件和命令、配置文件等等。在网上根文件系统的解释为:
根文件系统首先是内核启动时所 mount(挂载)的第一个文件系统,内核代码映像文件保存在根文件系统中,而系统引导启动程序会在根文件系统挂载之后从中把一些基本的初始化脚本和服务等加载到内存中去运行。
百度百科上说:内核代码映像文件保存在根文件系统中,但是在嵌入式Linux并没有将内核代码镜像保存在根文件系统中,而是保存在其他地方,比如NAND Flash指定存储地址、EMMC专用分区中。
根文件系统是 Linux 内核启动以后挂载(mount)的第一个文件系统,然后从根文件系统中读取初始化脚本,比如 rcS, inittab 等。根文件系统和 Linux 内核是分开的,单独的 Linux 内核是没法正常工作的,必须要搭配根文件系统。如果不提供根文件系统, Linux 内核在启动的时候就会提示内核崩溃(Kernel panic)的提示。
根文件系统非常重要,它是文件系统的根,在Linux下,一切皆文件,没有这个根,其他的软件、我门常用的ls、cp命令等等就无法正常工作。
在ubuntu下的根文件系统(ubuntu下的更稳健系统的目录名字为‘/’)
在根文件目录下有很多的目录和文件,这些都是ubuntu系统所必须的,但是其中有很多的目录和文件在嵌入式Linux中是用不到的,所以下面介绍一些常用的子目录:
1、/bin目录
看到“bin”大家应该能想到 bin 文件, bin 文件就是可执行文件。所以此目录下存放着系统需要的可执行文件,一般都是一些命令,比如 ls、 mv 等命令。此目录下的命令所有的客户都可以使用。
2、/dev目录
dev 是 device 的缩写,所以此目录下的文件都是和设备有关的,此目录下的文件都是设备
文件。在 Linux 下一切皆文件,即使是硬件设备,也是以文件的形式存在的,比如
/dev/ttymxc0 (I.MX6ULL 根目录会有此文件)就表示 I.MX6ULL 的串口 0,我们要想通过串口 0
发送或者接收数据就要操作文件/dev/ttymxc0,通过对文件/dev/ttymxc0 的读写操作来实现串口
0 的数据收发。
3、/etc目录
此目录下存放着各种配置文件,大家可以进入 Ubuntu 的 etc 目录看一下,里面的配置文件
非常多!但是在嵌入式 Linux 下此目录会很简洁。
4、 /lib 目录
lib 是 library 的简称,也就是库的意思,因此此目录下存放着 Linux 所必须的库文件。这些
库文件是共享库,命令和用户编写的应用程序要使用这些库文件。
5、 /mnt 目录
临时挂载目录,一般是空目录,可以在此目录下创建空的子目录,比如/mnt/sd、 /mnt/usb,
这样就可以将 SD 卡或者 U 盘挂载到/mnt/sd 或者/mnt/usb 目录中。
6、 /proc 目录
此目录一般是空的,当 Linux 系统启动以后会将此目录作为 proc 文件系统的挂载点, proc
是个虚拟文件系统,没有实际的存储设备。 proc 里面的文件都是临时存在的,一般用来存储系
统运行信息文件。
7、 /usr 目录
要注意, usr 不是 user 的缩写,而是 Unix Software Resource 的缩写,也就是 Unix 操作系统软件资源目录。这里有个小知识点,那就是 Linux 一般被称为类 Unix 操作系统,苹果的 MacOS
也是类 Unix 操作系统。关于 Linux 和 Unix 操作系统的渊源大家可以直接在网上找 Linux 的发展历史来看。既然是软件资源目录,因此/usr 目录下也存放着很多软件,一般系统安装完成以后此目录占用的空间最多。
8、 /var 目录
此目录存放一些可以改变的数据。
9、 /sbin 目录
此目录页用户存放一些可执行文件,但是此目录下的文件或者说命令只有管理员才能使用,
主要用户系统管理。
10、 /sys 目录
系统启动以后此目录作为 sysfs 文件系统的挂载点, sysfs 是一个类似于 proc 文件系统的特殊文件系统, sysfs 也是基于 ram 的文件系统,也就是说它也没有实际的存储设备。此目录是系
统设备管理的重要目录,此目录通过一定的组织结构向用户提供详细的内核数据结构信息。
11、 /opt
可选的文件、软件存放区,由用户选择将哪些文件或软件放到此目录中。关于 Linux 的根目录就介绍到这里,接下来的构建根文件系统就是研究如何创建上面这些子目录以及子目录中的文件。
"忙碌的盒子",上面说过,根文件系统就是一堆的文件和文件夹,很多命令的文件,软件的文件,我们使用时不希望一个一个从网上下载,所以BusyBox就是一个相当于一个软件,把这些我们常用的命令,软件等文件都收集起来,在进行打包,它集成了Linux的许多工具和命令。
BusyBox 可以在其官网下载,官网地址为: https://busybox.net/
一般在Linux驱动开发的时候都通过nfs挂载根文件系统,一维这样比较方便调试,不需要一维修改一点小BUG而重新烧写一边系统,我们只需要将根文件系统挂载到nfs,然后修改后在通过网络总结修改刚才修改过的文件就可以。
注:前提条件是nfs网络搭建已经搭建完成
在ubuntu的nfs目录下新建一个目录,存放根文件系统。开发板启动后,通过nfs服务使用ubuntu下nfs下新建的这个根文件系统。
再将下载好的BusyBox压缩包从windows传到ubuntu中,再将BusyBox解压。
同 Uboot 和 Linux 移植一样,打开 busybox 的顶层 Makefile,添加 ARCH 和 CROSS_COMPILE的值,如下所示:
这里使用的绝对路径对指定编译器,我的交叉编译器下载到这个目录下,版本号也要对得上,不然编译要报错。
BusyBox默认是不支持中文显示的,所以还得修改中文显示的问题。在BusyBox下的目录libbbb下有printable_string.c文件。
红色方框内 当字符大于 0X7F 以后就跳出去,如果支持UNICODE码的话,就会输出“?”。不支持中文显示。所以我们将代码进行修改:
也是在libbb目录下的unicode.c文件中 ,修改UNICODE码的源代码支持中文:
和前面的Uboot、Linux内核一样,BusyBox也需要配置,有下面几种配置选项:
1、defconfig:缺省配置,也就是默认配置。
2、allyesconfig:全选配置,所有功能都使用。
3、allnoconfig:最小配置,使用最少的配置。
一般使用默认配置即可。使用命令默认配置
make defconfig
BusyBox也支持图形化界面配置
make menuconfig
注:打开图形化配置界面时,你的终端窗口不能过小,过小的话会报错,打不开。
配置路径:
- Location:
- -> Settings
- -> Build static binary (no shared libs)
选项“Build static binary (no shared libs)”用来决定是静态编译 busybox 还是动态编译,静
态编译的话就不需要库文件,但是编译出来的库会很大。动态编译的话要求根文件系统中有库
文件,但是编译出来的 busybox 会小很多。这里我们不能采用静态编译!因为采用静态编译的
话 DNS 会出问题!无法进行域名解析。
- Location:
- -> Settings
- -> vi-style line editing commands
支持vi风格的命令行模式。
- Location:
- -> Linux Module Utilities
- -> Simplified modutils
启动小程序,我门不需要启动小程序。
- Location:
- -> Linux System Utilities
- -> mdev (16 kb) //确保下面的全部选中,默认都是选中的
用于动态创建设备
- Location:
- -> Settings
- -> Support Unicode //选中
- -> Check $LC_ALL, $LC_CTYPE and $LANG environment variables //选中
配置号BusyBox后就可以编译了,我们指定编译完成后的文件存放在前面创建的nfs目录下的rootfs目录中。
make install CONFIG_PREFIX=/home/zxg/linux/nfs/rootfs
CONFIG_PREFIX:指定编译结果的存放路径。
编译完成后在指定的目录下会有这几个目录和文件。
Linux 内核 init 进程最后会查找用户空间的 init 程序,找到以后就会运行这个用户空间的 init 程序,从而切换到用户态。如果 bootargs 设置 init=/linuxrc,那么 linuxrc 就是可以作为用户空间的 init 程序,所以用户态空间的 init 程序是 busybox 来生成的。
Linux 中的应用程序一般都是需要动态库的,我们编译时也使用动态库,当然你也可以编译成静态的,但是静态的可
执行文件会很大。如果编译为动态的话就需要动态库,所以我们需要向根文件系统中添加动态
库。在 rootfs 中创建一个名为“lib”的文件夹。
库文件一般从交叉编译器中获取,在前面搭建交叉编译器时,存放在/usr/local/arm/目录当中。
将/arm-linux-gnueabihf/libc里面的的lib文件夹下有很多的 .so.文件和.a文件都是库文件。我们将这些库文件都拷贝到我们创建的nfs目录下的根文件系统的lib文件夹下。
cp *so* *.a /home/zxg/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-linuxarmhf.so.3 不能作为符号链接,否则的话在根文件系统中执行程序无法执行!所以我们需要 ldlinux-armhf.so.3 完成逆袭,由“快捷方式”变为“本尊”,方法很简单,那就是重新复制 ld-linuxarmhf.so.3,只是不复制软链接即可
可以看出这个“快捷方式”就转化成真正源文件了。
将/arm-linux-gnueabihf/lib目录下的 .so.文件和.a文件拷贝到我们创建的nfs目录下的根文件系统的lib文件夹下。
在 rootfs 的 usr 目录下创建一个名为 lib 的目录,和前面添加lib一样,也是将/arm-linux-gnueabihf/libc/usr/lib中的库文件考本到创建的usr/lib目录下。
到此,我们的根文件系统的库文件全部添加完成。我们可以时用du命令来查看一下目录的大小。
我们的根文件系统也模拟ubuntu的根文件系统,所以还需要添加一些常用的文件夹。这些文件夹的含义前面我们已经介绍过了。
我们时用nfs挂载的方式,测试刚刚我们所构建的根文件系统(rootfs)。
在uboot里面的bootargs环境变量会设置root的值,所以我们将root的值改为nfs挂载即可。在Linux内核源码有相应的文档(Documentation/filesystems/nfs/nfsroot.txt)讲届如何配置
- root=/dev/nfs
-
- nfsroot=[<server-ip>:]<root-dir>[,<nfs-options>]
-
- ip=<client-ip>:<server-ip>:<gw-ip>:<netmask>:<hostname>:<device>:<autoconf>:
- <dns0-ip>:<dns1-ip>
server-ip :服务器IP地址,就是ubuntu的IP地址,用ifconfig查看。
root-dir :根文件系统的存放路径,就是我们刚刚创建的nfs目录下的根文件系统。
nfs-options:NFS的其他可选项,一般不设置。
client-ip :客户端IP,也就是开发板IP。在前面的uboot移植和Linux内核移植时我们已经设置过了。注意客户端IP和服务器IP要处于同一网段内。
gw-ip :网关地址。一般也是自己设置的。
netmask :子网掩码,一般都设置为255.255.255.0
hostname :客户机的名字,一般也不设置,直接空着。
device :设备名,也就是网卡名称,一般是eth0,eth1....,正点原子的ENET2为eth0,ENET1为eth1。我们是用的是eth0。
autoconf :自动配置,一般不使用。设置off为不使用。
dns0-ip :DNS0服务器IP地址,不使用。
dns1-ip :DNS1服务器IP地址,不使用。
设置bootargs环境变量root的值:
- root=/dev/nfs
-
- nfsroot=192.168.10.100:/home/zxg/linux/nfs/rootfs,proto=tcp rw
-
- ip=192.168.10.50:192.168.10.100:192.168.10.1:255.255.255.0::eth0:off
设置好以后使用boot启动Linux内核。
出先此错误,说明没有nfs有问题没有识别出来,可以是我们的ubuntu版本高了不支持kernel的uboot启动。解决办法:
我在网上查找很多的方法,主要还是uboot启动Linux通过nfs时候,只能支持V2版本的。查看自己ubuntu支持版本命令为:
sudo cat /proc/fs/nfsd/versions
如果你的版本不支持+2的话就会出先我前面的情况,这就是ubuntu版本过高而导致的。可以区参考其他人的解决,我是通过直接降低ubuntuLinux版本来实现的。大家可以参考这个。
重新进行启动,完美识别出来,但是出现一个错误:
无法运行“/etc/init.d/rcS”这个文件,,因为这个文件本身不存在,所以还得完善根文件系统。
rcS其实是个shell脚本,它的作用就是Linux内核启动后西药启动一些服务,rcS就是用来启动哪些服务文件的shell脚本。
PATH是个环境变量,保存可执行文件可能存在的目录。
LD_LIBRARY_PATH也是环境变量,保存库文件所在的目录。
export用来导出上面的环境变量。
mount命令用来挂载所有的文件系统,这些文件系统有文件/etc/fstab来指定,所以我们还得创建一个/etc/fstab文件。
创建/dtv/pts,将devpts挂载导这里面来。
最后是管理支持热插拔设备。
fstab文件,在Linux开机以后自动配置哪些需要自动挂载的分区。
<file system> <mount point> <type> <options> <dump> <pass>
file system : 要挂载的特殊设备,也可以是块设备,比如/dev/sda等等。
mount point :挂载点。
type :文件系统类型,比如EXT3,EXT2,PROC等等。
options :挂载选项,一般用defaults默认选项。
dump :备份。(1表示备份)
pass :磁盘检查设置(1表示检查)
启动成功,没有任何错误,但是还需创建一个/etc/inittab文件。
可以参考BustBox下的examples/inittabw文件。 inittab文件其实就是由若干跳指令组成,init程序会读取这个文件。每条指令的结构都是一样的,由“:”分隔的4个组,格式:
<id>:<runlevels>:<action>:<process>
id :每个指令的标识符,不饿能重复。
runlevels :BustBox没用,所以我们也不用。
action :动作,用来指定后面process可以能导的动作。
process :具体的动作,BusyBox支持如下动作:
第 2 行,系统启动以后运行/etc/init.d/rcS 这个脚本文件。
第 3 行,将 console 作为控制台终端,也就是 ttymxc0。
第 4 行,重启的话运行/sbin/init。
第 5 行,按下 ctrl+alt+del 组合键的话就运行/sbin/reboot,看来 ctrl+alt+del 组合键用于重
启系统。
第 6 行,关机的时候执行/bin/umount,也就是卸载各个文件系统。
第 7 行,关机的时候执行/sbin/swapoff,也就是关闭交换分区。
到这里我门的根文件系统就完成了。
使用Linux的目的就是运行我们自己写的软件,我们在ubuntu下的根文件系统创建一个drivers的文件夹。在文件加下写一个hello wrod的c文件:
使用交叉编译器将c文件编译成和执行文件:
arm-linux-gnueabihf-gcc hello.c -o hello
然后使用file命令查看文件类型,可以看到是ARM架构,并且是动态连接。
在开发板执行hello文件
hello 这个软件运行正常,说明我们的根文件系统中的共享库是没问题的,要想终止 hello 的运行,按下“ctrl+c”组合键即可。
我们可以让hello在后台运行这样就不抢占终端控制权,我们可以使用终端:在运行软件上加上 & 比如./hello &这样就进入后台运行了。
在他输出hello world的时候我一眼可以使用终端,如果想要结束这个软件的话我们可以使用“kill -9 pid(进程 ID)”命令来关闭掉,不过要线使用ps命令查看pid。
可以看出软件运行没有问题。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。