一步一步制作yaffs/yaffs2根文件系统--生成yaffs/yaffs2镜像文件及下载到开发板

来源:互联网 发布:估算网络机房电源容量 编辑:程序博客网 时间:2024/05/17 12:06

  开发环境:Ubuntu 12.04

                            开发板:mini2440  256M NandFlash   64M SDRAM

                             交叉编译器:arm-linux-gcc 4.4.3 点此可下载

                             BusyBox版本:busybox-1.13.3  点此可下载

                            yaffs制作工具:mkyaffsimage

                            yaffs2制作工具:mkyaffs2image(适合64M)、mkyaffs2image-128(适合128M以上)

写之前的罗嗦

     这几天制作根文件系统整得我够呛,毕竟是初学制作,各种不会,各种谷歌百度,害的我过情人节都在想着根文件系统!之所以写下来,主要是想把自己的制作过程记下来,防止以后工作了忘记了,二也是和大家分享,希望能对你有所帮助!本节先讲理论知识,我倒是建议本节内容你可以大致浏览,做到“知道是这么回事”的程度就可以了,在后续的制作过程中再结合实际来理解本节内容。要感谢一位DpLife的大哥啊,耐心的在QQ上给我启示,排除问题原因,好人呐。

     不管是想要制作yaffs文件,还是yaffs2,本文章都适合,只是最后使用不同的工具生成罢了。现在,开始吧!

主要参考书籍

   《嵌入式Linux应用程序开发完全手册》

   《国嵌内核驱动进阶教材》

文件系统简介

    理论上说一个嵌入式设备如果内核能运行起来,且不需要用户进程的话(估计这种情况很少),是不需要文件系统的。文件系统简单的说就是一种目录结构,由于linux操作系统的设备在系统中是以文件的形式存在(这个很关键奥!和win7的不同之处就在于linux的Everything is a File!),将这些文件分类管理以及提供和内核交互的接口,就形成了一定的目录结构也就是文件系统。文件系统是为用户反映系统的一种形式,为用户提供一个检测控制系统的接口。

    而根文件系统,就是一种特殊的文件系统。那么根文件系统和普通的文件系统有什么区别呢?借用书上的话说就是,根文件系统就是内核启动时挂载的第一个(第一个的意思就是不止一个吧,你看,区别出来了啊)文件系统。由于根文件系统是启动时挂载的第一个文件系统,那么根文件系统就要包括Linux启动时所必须的目录和关键性的文件,例如Linux 启动时都需要有用户进程 init 对应的文件,在Linux挂载分区时一定要会找 /etc/fstab这个挂载文件等,根文件系统中还包括了许多的应用程序,如 /bin目录下的命令等。任何Linux启动时所必须的文件的文件系统都可以称为根文件系统。

    Linux支持多种文件系统,如包括 ext2、ext3、vfat、jffs、ramfs、yaffs 和nfs等,为了对各类文件系统进行统一管理,Linux引入了虚拟文件系统 VFS(可别小看这个VFS,它可是解决了linux启动时的“鸡生蛋,蛋生鸡”的问题呢),为各类文件系统提供一个统一的操作界面和应用程序接口。下图为Linux文件系统层次关系图

   

Yaffs 文件系统

   YAFFS(Yet Another Flash File System)文件系统是专门为Nand Flash设计的文件系统,与JFFS/JFFS2文件系统有些类似,不同之处是 JFFS/JFFS2 文件系统是专门为Nor Flash的应用场合设计的,而Nor Flash和Nand Flash本质上有较大的区别(坏块、备用区、容量),所以尽管 JFFS/JFFS2文件系统也能用与Nand Flash,但对于Nand Flash来说,通常不是最优方案(性能较低,启动速度稍慢)。而YAFFS利用 NandFlash提供的每个页面16字节或64字节的Spare区(OOB备用区)空间来存放ECC和文件系统的组织信息,能够实现错误检测和坏块处理。这样的设计充分考虑了NandFlash以页面为存取单元的特点,将文件组织成固定大小的数据段,能够提高文件系统的加载速度。

   YAFFS目前有yaffs、yaffs2两个版本,一般来说,yaffs对小页面(512B+16B/页)的NandFlash(68M)有很好的支持,yaffs2对更大的页面(2K+64B/页)的NandFlash(128M、256M或者更大)支持更好。不得不说说这个yaffs和yaffs2,前几天学习yaffs制作的时候,我一直以为它们两个的区别蛮大的(确实有区别),但是后来才发现基本的制作过程是一样的,不一样的只是最后生成这两个版本的工具不一样!!!!yafffs由mkyaffsimage生成,而yaffs2由mkyaffs2image生成!

BusyBox简介

   BusyBox是一个遵循 GPLv2协议(这是依照书上打的,我可不知道这什么协议)的开源项目。有人将BusyBox比喻成Linux工具的瑞士军刀,简单的说就是Linux的一个大的工具集,包括了Linux中的大部分命令和工具。BusyBox中各种命令与相应的 GNU工具相比,所能提供的选项较少,但是能够满足一般应用。因此,BusyBox主要是为各种小型设备或者嵌入式系统提供。你看,下图就是利用BusyBox安装在根文件系统内的bin目录下的命令。


   嵌入式根目录下的bin,sbin和usr目录中的命令以及启动程序linuxrc通常就是通过BusyBox产生的。BusyBox产生的。BusyBox会根据配置的不同自动生成一些文件,但是有些根文件系统下的文件还是需要用户自己建立。

Linux 根文件系统目录结构

   为了在安装软件时能够预知文件、目录的位置,为了让用户方便地找到不同类型的文件,在构造文件系统时,建议遵循FHS标准(File Hierarchy Standard,文件系统层次标准)。它定义了文件系统中目录、文件分类存放的原则,定义了系统运行时所需的最小文件、目录的集合,并列举了不遵循这些原则的例外情况及其原因。FHS并不是一个强制的标准,但是大多的Linux、Unix发行版本都遵循FHS。

   Linux根文件系统中一般有如图2所示的几个目录,如下图

  

  下面依次讲述这几个目录的作用(很可能你会看烦,但是我保证,它真的需要你静下心去理解,可以在制作的过程中再返回来看)

1、/bin 目录

   该目录下存放所有用户(包括系统管理员和一般用户)都可以使用的、基本的命令。

   /bin 目录下常用的命令有:cat、chgrp、chmod、cp、ls、sh、kill、mount、umount、mkdir等。

2、/sbin目录

    该目录下存放系统命令,即只有管理员能够使用的命令、系统命令还可以存放在/usr/sbin、/usr/local/sbin目录下。/sbin 目录中存放的是基本的系统命令,它们用于启动系统、修复系统等,与/bin目录相似,在挂接其他文件系统之前就可以使用 /sbin。

   /sbin目录下常用的命令有:shutdown、reboot、fdisk、fsck等。

  不是急迫需要使用的命令存放在/usr/sbin目录下。本地安装的(Locally-installed)的系统命令存放在/usr/local/sbin目录下。

3、/dev 目录

   该目录下存放的是设备文件。设备文件是Linux中特有的文件类型,在Linux系统下,以文件的方式访问各种外设,即通过读写某个设备文件操作某个具体硬件。比如通过“/dev/ttySAC0”文件可以操作串口0,通过“/dev/mtdblock1”可以访问MTD设备(NAND Flash、Nor Flash等)的第2个分区。在接下来利用uboot启动的时候要设置入口参数   setenv bootargs "noinitrd root=/dev/mtdblock3 rootfsyle=yaffs2 rw console=ttySAC0,115200 init=/linuxrc mem=64M",其中的就是mtdblock3,有的人可能会问为什么是mtdblock3,而不是mtdblock2呢?这和你的nand flash分区有关,咱们在内核移植的时候将nandflash分成了4个区,如下


其中的root分区就是用来存放yaffs文件系统的,对应的为/dev/mtdblock3!

   设备文件有两种:字符设备和块设备。设备文件可以使用mknod命令创建,详细的就不讲述了。

  /dev 的创建有3中方法:

  ① 手动创建

   在制作根文件系统的时候,就在/dev 目录下使用mknod命令创建好要使用的设备文件,比如ttySAC0等。系统挂接根文件系统后,就可以使用/dev目录下的设备文件了。但是这种方法只能使用已经创建好的设备文件,万一我以后再插上优盘的时候,优盘这样的设备文件岂不是不能用了?佛说:不好....不好....

  ② 使用devfs文件系统。韦老师的书上说已经过时,我直接略过了。

  ③ udev

  udev 是个用户程序(u是指user space,dev是指device),它能够根据系统中硬件设备的状态更新设备文件,包括设备文件的创建、删除等。使用udev机制也不需要在/dev 目录下创建设备节点,它需要一些用户程序的支持,并且内核要支持sysfs文件系统。它的操作相对复杂,但是灵活性很高。

  在 BusyBox中有一个mdev命令(注意,是命令奥),它是udev命令的简化版本。适合于嵌入式的应用埸合。其具有使用简单的特点。它的作用,就是在系统启动和热插拔或动态加载驱动程序时,自动产生驱动程序所需的节点文件。在以busybox为基础构建嵌入式linux的根文件系统时,使用它是最优的选择。我接下来的创建根文件系统会用这种方法。

开发环境:Ubuntu 12.04

                            开发板:mini2440  256M NandFlash   64M SDRAM

                             交叉编译器:arm-linux-gcc 4.4.3 点此可下载

                             BusyBox版本:busybox-1.13.3  点此可下载

                            yaffs制作工具:mkyaffsimage

                            yaffs2制作工具:mkyaffs2image(适合64M)、mkyaffs2image-128(适合128M以上,我的256M的用这个)

接上一节:http://blog.csdn.net/mybelief321/article/details/9995199

1、首先,将咱们制作根文件系统的BusyBox和mkyaffs2image-128M存放在一个文件夹内,如下

 

2、执行命令:mkdir rootfs  建立一个文件夹rootfs,咱们的根文件目录将建立在这里,要记得这个目录的绝对路径奥,我的路径为/home/song/rootfs_make/rootfs,咱们在安装BusyBox的时候要使用这个路径。


配置BusyBox

3、执行命令:tar -zxf busybox-1.13.3.tar.gz   解压咱们的busybox (注意,该命令前边千万不要加sudo啊!)


4、BusyBox集合了几百个命令,在一般系统中并不需要全部使用。可以通过配置 BusyBox来选择这些命令、定制某些命令的功能(选项)、指定BusyBox的连接方法(动态连接还是静态连接)、指定BusyBox的安装路径。执行命令:cd busybox-1.7.0/  进入该文件夹


5、执行命令:make menuconfig 进入图形配置界面。



6、下面仅介绍一些常用的选项,以后可以自己添加补全。

Busybox Settings  ---> 

   Busybox Library Tuning  ---> 

      [*]   Fancy shell prompts 

选择Facncy Shell prompts一项,这可以使我们在profile这个文件中设置的命令提示符PS1中的转义字符生效


7、指定是否使用静态连接

Busybox Settings  ---> 

    Build Options  ---> 

             [ *] Build BusyBox as a static binary (no shared libs) 

这里选择静态链接,以静态链接的方式生成需要的命令!我按照韦老师上使用动态链接没有成功(注意,我在这里首先要真挚的道歉!!!括号里的话是我后加上去的,这里选择了静态链接,所以后面有一步像lib内加入库是没必要的,我在这一节做了纠正http://blog.csdn.net/mybelief321/article/details/10068293)


8、选择交叉编译工具

Busybox Settings  ---> 

    Build Options  ---> 

        ()  Cross Compiler prefix 

进入Cross Compiler prefix中编辑交叉编译工具前缀为arm-linux-,如下图


  

9、支持mdev。这可以很方便地构造 /dev目录,并且可以支持热插拔设备。另外,为方便调试,选中mount、umount命令,并让mount命令支持NFS(网络根文件系统)

Linux System Utilities  ---> 

     [*] mdev

     [*]   Support /etc/mdev.conf    

     [*]     Support command execution at device addition/removal 

     [*] mount 
     [*]   Support mounting NFS file systems 

     [*] umount                                                           
     [*]   Support option -a

以上这些选项默认都是选择的。    

10、支持Initttab。

Init Utilities  ---> 

    [*]   Support reading an inittab file

选择这一项,可以使我们放在/etc下的inittab这个文件被busybox 的init进程解析,如下图


以上这些选项,默认的好像都选上了!

11、配置完这些后,退出,选择YES保存

 

编译和安装BusyBox

12、执行命令:make 编译Busybox


出现下图,编译完成


友情提示:在这里不要随便使用sudo,我前边用的sudo makemenuconfig  、sudo vim Makefile 、sudo make结果出现了下边的提示错误,很可恶的!!!

13、执行命令:make CONFIG_PREFIX=/home/song/rootfs_make/rootfs install   将BusyBox安装到你创建的rootfs文件夹内


出现下图表示已经安装完成


14、执行命令:cd ../rootfs/  进入咱们的rootfs文件夹内,可以看到BusyBox已经安装到了此目录,自动生成了/bin /sbin /usr linuxrc这4个目录和文件



在我们制作交叉编译工具链arm-linux-gcc时,已经生成了glibc库,可以直接使用它来构建根文件系统,本文使用的时光盘里自带的压缩库,由下图可以看出,这是arm-linux-gcc3.4.5版本的glibc库,而我的arm-linux-gcc是4.4.3的,可不可以使用呢?答案是可以的!(补充,其实不可以的,所用的动态链接库必须和你PC机的交叉编译工具的动态链接库,所以我这里必须要用arm-linux-gcc的动态库。但是,我并没有修改这个错误,而是将错就错,所以建议你什么都不要变,还是按照这篇文章的步骤做下去,我本系列最后一个文章是针对出现的这个错误纠错的,相信你一结合,会明白不少的!

15、将下载的arm-linux-gcc-3.4.5-glibc-2.3.6.tar.bz2 放在和rootfs同一个文件夹,如下


16、执行命令:tar -jxf arm-linux-gcc-3.4.5-glibc-2.3.6.tar.bz2 解压此库


我们需要的glibc库的位置存放在gcc-3.4.5-glibc-2.3.6/arm-linux/lib 文件夹下。

执行命令:ls gcc-3.4.5-glibc-2.3.6/arm-linux/lib 可以看到该目录下的文件。其实这个目录下的文件并非都属于glibc库,比如crt1.o、libstdc++.a等文件是gcc工具本身生成的。里面的目录、文件可以分为8类。

    ①  加载器ld-2.3.6.so、ld-linux.so.2。

    动态程序启动前,它们都被用来加载动态库。

    ②  目标文件(.o)。

    比如crt1.o、crti.o、crtn.o、Mctr1.o、Scrt1.o等,在生成应用程序时,这些文件像一般的目标文件一样被链接。

    ③  静态库文件(.a)。

    比如静态数学库libm.a、静态c++库libstdc++.a等,编译静态程序时会连接它们

    ④  动态库文件(.so、,so.[0-9]*)。

    比如动态数学库libm.so、动态c++库libstdc++.so等,它们可能是一个链接文件。编译动态库时会用到这些文件,但是不会连接它们,运行时才连接。

    ⑤  libtool库文件(.la)。

    在连接库文件时,这些文件会被用到,比如它们列出了当前库文件所依赖的其他库文件。程序运行时无需这些文件。

    ⑥  gconv目录。

    里面是有头字符的集的动态库,比如ISO8859-1.so、GB18010.so等。

    ⑦  ldscripts目录。

   里面是各种连接脚本,在编译应用程序时,它们被用于制定程序的运行地址、各段的位置等。

    ⑧  其他目录及文件。

17、现在安装glibc库,在上一节我们编译安装busybox时使用的是动态连接,这里在开发板上只需要加载器和动态库。

执行命令:mkdir -p rootfs/lib  在rootfs中创建lib文件夹,用来存放咱们的加载器和动态库

执行命令:cp gcc-3.4.5-glibc-2.3.6/arm-linux/lib/*.so* rootfs/lib/  安装glibc库到咱们的文件夹下


18、执行命令:cd rootfs  进入到rootfs文件夹,此时可以看到在lib文件夹已经有咱们需要的库了。


至此,glibc库已经安装完成,也已经在根文件目录下创建了/lib目录。其实,上面复制的库文件不是每个文件都会被用到,可以根据应用程序对库的依赖关系保留需要用到的。通过ldd命令可以查看一个应用程序会用到哪些库。

前面两节介绍了如何安装Busybox、C库,建立了 bin/、sbin/、usr/sbin、usr/bin、lib/等目录,最小根文件系统的大部分目录、文件已经建好,本节介绍剩下的部分。

构建 /etc目录

19、执行命令:mkdir etc  创建一个etc目录

       执行命令:cd etc 进入该目录


20、执行命令:vim mdev.conf 创建mdev.conf。前边已经介绍mdev是一个udev的简化版本,主要用来支持一些热插拔设备。我们可以通过文件mdev.conf自定义一些设备节点的名称或链接来满足特定的需要,但在此处让它为空。


21、在启动过程中bootloader会传递参数init=/linuxrc给内核的main( )函数,所以在文件系统被挂载后,运行的第一个程序是linuxrc,而linuxrc是一个指向/bin/busybox的链接文件,也就是说文件系统被挂在后运行的第一个程序是busybox。Busybox首先会解析文件/etc/inittab,这个文件中存放的是系统的配置信息,这些配置信息指明了接下来将要启动那些程序。

   执行命令:vim inittab 创建 inittab文件


   内容如下:

   #/etc/inittab
   ::sysinit:/etc/init.d/rcS
   s3c2410_serial0::askfirst:-/bin/sh
   ::ctrlaltdel:/sbin/reboot
   ::shutdown:/bin/umount -a -r


 /etc/inittab 文件中每个条目用来定义一个子进程,并确定它的启动方法,格式如下 

     <id>:<runlevels>:<action>:<process>

<id>:表示这个进程要使用的控制台(即标准输入、标准输出、标准错误设备)。如果省 略,则使用与init进程一样的控制台。
<runlevels>:对于Busybox init程序,这个字段滑意义,可以省略。
<action>:表示init程序如何控制这个子进程,
<process>: 要执行的程序,它可以是可执行程序,也可以是脚本


  文件etc/inittab配置条目说明如下:

  ::sysinit:/etc/init.d/rcS    启动系统初始化文件/etc/init.d/rcS。字段sysinit表明文件/etc/init.d/rcS在系统启动后最先执行,并且只执行一次,init进程等待它结束才继续执行其它动作。(脚本文件名一般为rc,后缀S代表单用户运行级别脚本)

  s3c2410_serial0::askfirst:-/bin/sh   在串口s3c2410_serial0上启动askfirst动作的shell。S3C2410的串口名在/dev下是s3c2410_serialx。在mini2440移植内核时定义的串口名为s3c2410_serial0。需要注意的是,开发板上通过mdev生成的/dev目录中,S3C2410、S3C2440的串口名是s3c2410_serial0、s3c2410_serial1、s3c2410_serial2,不是 ttySAC0、ttySAC1、ttySAC2。当静态创建设备文件时,这里要将s3c2410_serial0 修改为 ttySAC0 。askfirst表明init进程先输出“Please press Enter to actvie this console”,等用户输入回车键之后才启动-/bin/sh。

  ::ctrlaltdel:/sbin/reboot  当按下Ctrl+Alt+Delete组合键时,init重启执行程序。字段ctrlaltdel表明当按下Ctrl+Alt+Delete组合键时,执行相应的进程。

  ::shutdown:/bin/umount -a -r   告诉init在关机时运行umount命令卸载所有的文件系统,如果卸载失败,试图以只读方式重新挂载。字段shutdown表明在重启关闭系统命令时执行相应进程。

22、当解析完文件etc/inittab后就将启动这些进程,首先要执行的是启动脚本etc/init.d/rcS。

      执行命令:mkdir init.d  创建一个init.d文件夹

      执行命令:cd init.d  进入该文件夹


23、执行命令:vim rcS  编写rcS可执行文件,这是一个脚本文件,可以在里面添加想自动执行的命令。


内容如下

#!/bin/sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin
runlevel=S
prevlevel=N
umask 022 
export PATH runlevel prevlevel
mount -a
echo /sbin/mdev>/proc/sys/kernel/hotplug
mdev -s

详解:

#!/bin/sh    #用busybox的shell

PATH=/sbin:/bin:/usr/sbin:/usr/bin  #shell命令的搜索路径

runlevel=S   #运行在单用户模式

prevlevel=N  #前一个级别,为N则表示没有前一个级别

umask 022   #权限位掩码

export PATH runlevel prevlevel   #将环境的变量导出到环境中

mount -a   #将文件 /etc/fstab 中指明的文件挂载到对应的挂载点上

echo /sbin/mdev>/proc/sys/kernel/hotplug  #当有热插拔事件产生时, 内核就会调用位于/sbin目录的 mdev。 这时 mdev通过环境变量中的 ACTION 和 DEVPATH,(这两个变量是系统自带的)来确定此次热插拔事件的动作以及影响了/sys 中的那个目录。接着会看看这个目录中是否有“dev”的属性文件,如果有就利用这些信息为 这个设备在/dev 下创建设备节点文件。
mdev -s   #建立dev目录。以‘-s’为参数调用位于/sbin 目录写的 mdev(其实是个链接,作用是传递参数给/bin目录下的busybox 程序并调用它) ,mdev扫描 /sys/class和/sys/block中所有的类设备目录,如果在目录中含有名为“dev”的文件,且文件中包含的是设备号,则 mdev 就利用这些信息为这个设备在/dev下创建设备节点文件。一般只在启动时才执行一次  “mdev -s” 。

24、执行命令:chmod +x rcS 改变rcS的属性,使它可执行。


25、执行命令:cd .. 返回上一级目录

        执行命令:vim fstab  ,创建fstab文件。


   内容如下

  #device   mount-point     type      option     dump   fsck   order 
  proc        /proc     proc     defaults    0        0  
  tmpfs        /tmp     tmpfs    defaults    0        0  
  sysfs       /sys      sysfs    defaults    0        0  
  tmpfs        /dev      tmpfs    defaults    0        0  


编写好之后,保存退出。

26、执行命令:cd ..  返回根文件系统目录

27、执行命令: mkdir  dev 创建dev目录 


28、执行命令:cd dev 进入该目录,准备创建设备节点

29、先后执行命令:sudo mknod console c 5 1

                                     sudo mknod null c 1 3


因为mdev是通过init进程来启动的,在使用mdev构造 /dev 目录之前,init 进程至少要用到设备文件 /dev/console、/dev/null,所以要建立这两个设备文件。

30、执行命令:cd ../  返回上一级目录

31、执行命令:mkdir proc mnt tmp sys root home  创建剩余的目录


到这里,在rootfs下就是一个非常小的根文件系统。我将这个根文件系统打包传上去了,如有需要,请自行下载

  我的板子是256M的,所以在这里我需要利用mkyaffs2iamge-128M工具制作成yaffs2镜像文件。

32、执行命令:./mkyaffs2image-128M rootfs/ rootfs.yaffs2   生成yaffs2镜像文件

    如果要生成yaffs镜像文件,则执行命令:./mkyaffsimage rootfs/ rootfs.yaffs


33、现在就将制作好的镜像文件下载到开发板中去。利用supervivi的a命令将uboot下载到开发板去,然后nand flash启动。

34、烧写内核文件uImage

   先后执行命令:

   tftp 0x30008000 uImage

   nand erase 0x80000 0x500000

   nand write 0x30008000 0x80000 0x500000 


35、烧写yaffs2映像文件

先后执行命令:

  tftp 0x30008000 rootfs.yaffs2

  nand erase 0x580000 7a80000

  nand write.yaffs 0x30008000 0x580000 dbb040




36、设置内核参数

先后执行命令:

   setenv bootargs "noinitrd root=/dev/mtdblock3 rootfstyle=yaffs2 console=ttySAC0,115200 init=/linuxrc mem=64M"

   setenv bootcmd "nand read 0x30008000 0x80000 0x500000;bootm 0x30008000" 

   saveenv


37、重启开发板,可以看到咱们的根文件系统启动了,尽管不完善,后面我将接着完善。


  其实,说实话,我是真心的建议你先用nfs测试你的文件系统,先不要着急直接下载到nand flash里边,毕竟来回擦除也伤害板子呢!先吃饭去了,太热了!


0 0