一、先来分析下busybox
在根文件系统中有很多命令,如ls、cp等等,每个命令都相当于应用程序,若它有很多命令的话,我们一个个去把应用程序找出来然后编译是很麻烦的事情。
在嵌入式系统中有一个busybox,它就是如ls、cp等等这些命令的组合,当我们去编译busybox的时候会得到一个 叫busybox的应用程序(这时如ls、cp等等这些命令都是它的符号链接),当我们再去执行命令时,其实就是在执行busybox程序。例如当在根文件系统下输入ls -l /bin/ls 便会发现 /bin/ls -> busybox。
同样的道理内核启动的第一个应用程序init也是busybox程序的符号链接,可以通过 ls -l /sbin/init查看(所以想确定init做了那些事情,就要去分析busybox源码)打开init/init.c文件可以发现busybox调用了init_main ,调用关系如下
注:打开examples/inittab文件发现其格式为::::,其中id项最终会加上一个/dev, 即/dev/id,用作终端(stdin,stdout,stderr:printf,scanf,err),若不设置id的话就对应/dev/null;runlevels可以完全忽略;action用来指示何时执行;process表示应用程序或脚本。
由以上不难看出,一个最小根文件系统应该满足如下要求:
1)/dev/console /dev/null
2)init应用程序(一般来源于busybox);init程序运行时需要读的配置文件 /etc/inittab ;配置文件中指定的应用程序。
3)为程序运行提供函数的库(若当在make menuconfig的时候若将Build Options设置为静态的,那就可以不需要这里的库了,除非客户的应用程序需要)
二、下面便一步步来构建最小根文件系统
1、编译busybox
将busybox解压后通过阅读INSTALL文件便可知道编译方法,这里就像编译内核一样,编译前交叉编译工具链要选择好。若使用交叉编译的话,在编译完安装的时候就千万不要直接make install,因为这样做的话就会直接安装到PC机上了,这样有可能把PC机破换。要把它安装在一个指定目录里,譬如/work/nfs_root/fs_mini。
安装完成后进入/work/nfs_root/fs_mini,用ls命令就会发现里面有一个文件linuxrc(它是busybox的符号链接,即linuxrc -> busybox)与三个文件夹(bin(里面的命令也是指向busybox的),sbin和usr)
2、在/work/rootfs下创建设备文件
创建设备文件前,首先我们先看下服务器上 /dev/console 和 /dev/null的信息如下(其中c表示为字符设备,5表示主设备号,1表示次设备号)
下面我们来创建:
mkdir dev
cd /dev
sudo mknod console c 5 1
sudo mknod null c 1 3
3、在/work/nfs_root/fs_mini下构造inttab
若不构造的话,它就会有一个默认的配置项(我们并不需要默认的配置项)。
mkdir etc
vi etc/inittab 然后可以里面输入一句内容(如 console::askfirst:~/bin/sh)
4、在/work/nfs_root/fs_mini下构造库
其中-d表示如果原来有链接文件,当拷贝过来后仍然保持为链接文件,如果不加-d的话就会拷贝真是所指向的文件,这样拷贝过来的库就会很大。.so表示动态链接库(我们用动态链接库)
以上完成后 用ls命令查看,包含了 bin sbin usr linuxrc dev etc lib
这便构建了最小根文件系统(配置文件中还没指定应用程序),当用工具把它做成一个映像文件后便可以烧到开发板中去。烧写到最后可以看到如下的打印信息,回车后就会启动那个应用程序,这就和我们在第3步的时候的对应上了(这里inittab中 只有一项)
用ls命令便可看到文件信息
三、完善最小根文件系统
1、例如当输入一个命令,如ps命令后就提示没有 /proc这个目录 :那我们就mkdir proc,但是即使有了proc这个目录还是不够的(当执行ps时还是没有任何东西,如下图所示)。这是由于内核提供一个虚拟的文件系统proc来收集有哪些应用程序在跑,手工挂载后,用ps命令就会进到如下的/proc目录下就能看到有哪些程序,有那些内容。如下用cd进入到内核提供的虚拟文件系统/proc就可看到如下信息
若不想手工挂载的话,可以加个配置文件,譬如说,在inttab中把原来加的那句删除,只加如下的一句
创建脚本文件/etc/init.d/rcs 后,在rcs中加入mount -t proc none /proc这句话,加完后赋予权限
这样当文件再重新烧到开发板启动后,就会去执行/etc/init.d/rcs,进而执行mount -t proc none /proc,如果想增加其他命令的时候也可以在里面加上去
2、除了以上mount -t 的方法外,还有一种方法:在上面的基础上将mount -a这句话加入etc/init.d/rcs,然后再创建一个文件/etc/fstab,将以下内容写入fstab(mount -a 它会读出/etc/fstab,根据这个配置文件中的内容指示来挂载文件系统)
再次做成映像文件,烧录启动后,在最后就可 看到如下,当用ps命令就会发现有效果了;用cat /proc/mounts可以查看,当前挂载了那些文件系统
四、继续完善这个根文件系统
此时,/dev下只有console和null。我们知道 /dev目录下的东西是对应于那些设备,那些驱动的,试想一下若有成千上完个设备驱动的话,一个一个去创建这些 /dev目录的话就太麻烦了。而udev机制可以自动创建 /dev目录下的设备节点,在busybox里面有一个udev的简化版本叫mdev。其中docs/medv.txt便是使用方法。
操作如下:
mkdir sys
在etc/fstab中增加:
在/etc/init.d/rcs 中增加:这里medv -s中的-s表示一开始的时候就先把原先内核现有的那些驱动的设备节点都创建出来。
再次制作烧录根文件系统镜像启动后查看 /dev目录下就会有很多的设备文件了,这都是medv为我们创建的,并且也挂载了很多文件系统,如下:
到这里的话这个最小的根文件系统就比较完善了
五:挂载NFS
从上面的操作可以看出每做一次就烧写一次,那么有没有办法不让每次都烧写呢?这就要用到网络文件系统NFS。挂载NFS
情况一:从flash上启动根文件系统后去挂载
需要满足二个条件:
1、服务器”允许“那个目录可被别人挂接,即nfs服务
服务器的nfs配置文件在/etc/exports,将要被挂载的共享文件目录譬如/work/nfs_root/fs_mini放入该配置文件后重启服务即可(可以在服务器上试一下自己挂接自己,譬如 sudo mount -t nfs 172.16.104.33:/work/nfs_root/fs_mini /mnt)。
2、开饭板去挂接
在开发板上根文件系统下创建一个目录,如 mkdir mnt
然后 mount -t nfs -o nolock 172.16.104.33:/work/nfs_root/fs_mini /mnt
此时在开发板上执行 ls /mnt所看到的东西就和在服务器上/work/nfs_root/fs_mini目录下的东西是一样的,例如在服务器上echo hello >test.txt,则在开发板的/mnt 目录下也能看到test.txt
情况二:直接从nfs启动
需要修改uboot 命令行bootargs参数:服务器IP,目录;设置开发板自己的IP等,其在内核的Documentation/nfsroot.txt可以查看,有固定的格式。
可以做个小测试,比如
当在网络文件系统启动后,可以写一个应用程序hello.c
然后编译 arm-linux-gcc -o hello hello.c
就可以直接 ./hello