精华内容
下载资源
问答
  • 构建Linux根文件系统

    千次阅读 2016-07-11 11:46:09
    第17章 构建Linux根文件系统 本章目标 l 了解Linux的文件系统层次标准(FHS) l 了解根文件系统下各目录的作用 l 掌握构建根文件系统的方法:移植Busybox、构造各个目录、文件等 l 掌握制作yaffs、jffs2文件系统...

    本章目标

    l 了解Linux的文件系统层次标准(FHS)

    l 了解根文件系统下各目录的作用

    l 掌握构建根文件系统的方法:移植Busybox、构造各个目录、文件等

    l 掌握制作yaffs、jffs2文件系统映象文件的方法

    推广

    想了解更多嵌入式知识请移步到

    100ask.taobao.com

     

    17.1  Linux文件系统概述

    17.1.1  Linux文件系统的特点

    类似于Windows下的C、D、E等各个盘,Linux系统也可以将磁盘、Flash等存储设备划分为若干个分区,在不同分区存放不同类别的文件。与Windows的C盘类似,Linux一样要在一个分区上存放系统启动所必需的文件,比如内核映象文件(在嵌入式系统中,内核一般单独存放在一个分区中)、内核启动后运行的第一个程序(init)、给用户提供操作界面的shell程序、应用程序所依赖的库等。这些必需的、基本的文件,合称为根文件系统,它们存放在一个分区中。Linux系统启动后首先挂接这个分区──称为挂接(mount)根文件系统。其他分区上所有目录、文件的集合,也称为文件系统,比如我们常说:“挂接硬盘第二个分区”、“挂接硬盘第二个分区上的文件系统”。

    Linux中并没有C、D、E等盘符的概念,它以树状结构管理所有目录、文件,其他分区挂接在某个目录上──这个目录被称为挂接点或安装点(mount point),然后就可以通过这个目录来访问这个分区上的文件了。比如根文件系统被挂接在根目录“/”上后,在根目录下就有根文件系统的各个目录、文件:/bin、/sbin、/mnt等;再将其他分区挂接到/mnt目录上, /mnt目录下就有这个分区的各个目录、文件。

    在一个分区上存储文件时,需要遵循一定的格式,这种格式称为文件系统类型,比如fat16、fat32、ntfs、ext2、ext3、jffs2、yaffs等。除这些拥有实实在在的存储分区的文件系统类型外,Linux还有几种虚拟的文件系统类型,比如proc、sysfs等,它们的文件并不存储在实际的设备上,而是在访问它们时由内核临时生成。比如proc文件系统下的uptime文件,读取它时可以得到两个时间值(用来表示系统启动后运行的时间秒数、空闲的时间秒数),每次读取时都由内核即刻生成,每次读取结果都不一样。

    “文件系统类型”常被简称为“文件系统”,比如“硬盘第二个分区上的文件系统是EXT2”──这时指的就是文件系统类型。所以“文件系统”这个术语,有时候指的是分区上的文件集合,有时候指的是文件系统类型,需要根据语境分辨,读者在阅读各类文献时需要注意这点。

     

    17.1.2  Linux根文件系统目录结构

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

    本节根据FHS标准描述Linux根文件系统的目录结构,并不深入描述各个子目录的结构,读者可以自行阅读FHS标准了解这些内容。FHS文档可以从网站http://www.pathname.com/fhs/中下载。

    Linux根文件系统中一般有如图17.1所示的几个目录。

     

    图17.1 Linux根文件系统结构

    下面依次讲述这几个目录的作用。

    1. /bin目录

    该目录下存放所有用户(包括系统管理员和一般用户)都可以使用的、基本的命令,这些命令在挂接其他文件系统之前就可以使用,所以/bin目录必须和根文件系统在同一个分区中。

    /bin目录下常用的命令有:cat、chgrp、chmod、cp、ls、sh、kill、mount、umount、mkdir、mknod、[、test等。额外说明,[命令其实就是test命令,在脚本文件中“[ expr ]”就等价于“test expr”。

    2. /sbin目录

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

    设备文件有两种:字符设备和块设备。在PC上执行命令“ls /dev/ttySAC0 /dev/hda1 -l”可以看到如下结果。其中首行的字母“b”、“c”表示这是一个块设备文件或字符设备文件;“3,   1”、“4,  64”表示设备文件的主、次设备号;主设备号用来表示这是哪类设备,次设备号用来表示这是这类设备中的哪个。

    brwxrwxr-x    1 root     49         3,   1 Oct  9  2005 /dev/hda1

    crwxrwxr-x    1 root     root       4,  64 Sep 24  2007 /dev/ttySAC0

     

    设备文件可以使用mknod命令创建,比如:

    mknod /dev/ttySAC0 c 4 64

    mknod /dev/hda1 b 3 1

     

    /dev的创建有3种方法:

    (1)手动创建。

    在制作根文件系统的时候,就在/dev目录下创建好要使用的设备文件,比如ttySAC0等。系统挂接根文件系统后,就可以使用/dev目录下的设备文件了。

    (2)使用devfs文件系统:这种方法已经过时

    在以前的内核中,有一个配置选项CONFIG_DEVFS_FS,它用来将虚拟文件系统devfs挂接在/dev目录上,各个驱动程序注册时会在/dev目录下自动生成各种设备文件。这就免去了手动创建设备文件的麻烦,在制作根文件系统时,/dev目录可以为空。

    使用devfs比手动创建设备节点带来很多便利,但是它仍有一些无法克服的缺点,比如:

    ① 不确定的设备映射:

    比如USB接口连接两台打印机A和B,在都开机的情况下以/dev/usb/lp0访问A、以/dev/usb/lp1访问B。但是假如A没有上电,则系统启动时会根据扫描到的设备的顺序,以/dev/usb/lp0访问B。

    ② 没有足够的主/次设备号:

    主次设备号是两个8位的数字,它们并不足以与日益增加的外设一一对应。

    ③ 命名不够灵活:

    由于devfs由内核创建设备节点,当想重新修改某个设备的名字时需要修改、编译内核。

    ④ devfs消耗大量的内存

    由于这些缺点,在linux 2.3.46引入devfs之后,又在linux 2.6.13后面的版本中移除了devfs,而使用udev机制代替。

     

    (3)udev。

    udev是个用户程序(u 是指user space,dev是指device),它能够根据系统中硬件设备的状态动态地更新设备文件,包括设备文件的创建,删除等。

    使用udev机制也不需要在/dev目录下创建设备节点,它需要一些用户程序的支持,并且内核要支持sysfs文件系统。它的操作相对复杂,但是灵活性很高。

    在busybox中有一个mdev命令,它是udev命令的简化版本。

     

    4. /etc目录

    如表17.1、17.2所示,该目录下存放各种配置文件。对于PC上的Linux系统,/etc目录下目录、文件非常多,比如下面两个表格所列出来的。这些目录、文件都是可选的,它们依赖于系统中所拥有的应用程序,依赖于这些程序是否需要配置文件。在嵌入系统中,这些内容可以大为精减。

    17.1                       

    /etc目录下的子目录

    目录 描述
    opt 用来配置/opt下的程序(可选)
    X11

    用来配置X Window(可选)

    sgml


    用来配置SGML(可选)



    xml


    用来配置XML(可选)




    17.2    

     /etc目录下的文件

    文件 描述
    export 用来配置NFS文件系统(可选)
    fstab 用来指明当执行“mount -a”时,需要挂接的文件系统(可选)
    mtab 用来显示已经加载的文件系统,通常是/proc/mounts的链接文件(可选)
    ftpusers 启动FTP服务时,用来配置用户的访问权限(可选)
    group 用户的组文件(可选)
    inittab init进程的配置文件(可选)


     
    ld.so.conf
    其他共享库的路径(可选)
    passwd 密码文件(可选)


    5. /lib
    目录 

    该目录下存放共享库和可加载模块(即驱动程序),其中的共享库用于启动系统、运行根文件系统中的可执行程序,比如/bin、/sbin目录下的程序。其他不是根文件系统所必需的库文件可以放在其他目录,比如/usr/lib、/usr/X11R6/lib、/var/lib等。

    表17.3是/lib目录中的内容。

    17.3                           

    /lib目录中的内容

    目录/文件 描述
    libc.so.* 动态连接C库(可选)
    ld* 连接器、加载器(可选)
    modules 内核可加载模式存放的目录(可选)


    6. /home
    目录 

    用户目录,它是可选的。对于每个普通用户,在/home目录下都有一个以用户名命名的子目录,里面存放用户相关的配置文件。

     

    7. /root目录

    根用户(用户名为root)的目录,与此对应,普通用户的目录是/home下的某个子目录。

     

    8. /usr目录

    /usr目录的内容可以存在另一个分区中,在系统启动后再挂接到根文件系统中的/usr目录下。里面存放的是共享的、只读的程序和数据,这表明/usr目录下的内容可以在多个主机间共享──这要这些主机也是符合FHS标准的,/usr中的文件应该是只读的,其他主机相关的、可变的文件应该保存在其他目录下,比如/var。

    /usr目录通常包含如下内容,嵌入式系统中,这些内容可以进一步精减。/usr目录中的内容如表17.4所示。

    17.4                              

    /usr目录中的内容

    目录 描述
    bin 很多用户命令存放在这个目录下
    include C程序的头文件,这在PC上进行开发时才用到,在嵌入式系统中不需要
    lib 库文件
    local 本地目录
    sbin 非必需的系统命令(必需的系统命令放在/sbin目录下)
    share 架构无关的数据
    X11R6 XWindow系统
    games 游戏
    src 源代码


    9. /var
    目录 

    与/usr目录相反,/var目录中存放可变的数据,比如spool目录(mail、news、打印机等用的), log文件、临时文件。

     

    10. /proc目录

    这是一个空目录,常作为proc文件系统的挂接点。proc文件系统是个虚拟的文件系统,它没有实际的存储设备,里面的目录、文件都是由内核临时生成的,用来表示系统的运行状态,也可以操作其中的文件控制系统。

    系统启动后,使用以下命令挂接proc文件系统(常在/etc/fstab进行设置以自动挂接):

    # mount –t proc none /proc

     

    11. /mnt目录

    用于临时挂接某个文件系统的挂接点,通常是空目录;也可以在里面创建一些空的子目录,比如/mnt/cdram、/mnt/hda1等,用来临时挂接光盘、硬盘。

     

    12. /tmp目录

    用于存放临时文件,通常是空目录。一些需要生成临时文件的程序要用到/tmp目录,所以/tmp目录必须存在并可以访问。

    为减少对Flash的操作,当在/tmp目录上挂接内存文件系统,如下:

    # mount –t tmpfs none /tmp

     

     

    17.1.3  Linux文件属性介绍

    Linux系统有如表17.5所示的几种文件类型。

    17.5                             

    Linux文件类型

    文件类型 描述
    普通文件 这是最常见的文件类型
    目录文件 目录也是一种文件
    字符设备文件 用来访问字符设备
    块设备文件 用来访问块设备
    FIFO 用于进程间的通信,也称为命名管道
    套接口 用于进程间的网络通信
    连接文件 它指向另一个文件,有软连接、硬连接


    使用“ls -lih”命令可以看到各个文件的具体信息,下面选取这几种文件,列出它们的信息:
     

    228883 -rw-r--r--    2 root     root            6 Sep 27 22:10 readme.txt

    228884 lrwxrwxrwx    1 root     root           10 Sep 27 22:11 ln_soft -> readme.txt

     228883 -rw-r--r--    2 root     root            6 Sep 27 22:10 ln_hard

     228882 drwxr-xr-x    2 root     root         4.0K Sep 27 22:10 tmp_dir

     228880 crw-r--r--    1 root     root       4,  64 Sep 27 22:09 ttySAC0

     228881 brw-r--r--    1 root     root      31,   0 Sep 27 22:09 mtdblock0

     228885 prw-r--r--    1 root     root            0 Sep 27 22:16 my_fifo

    343929 srwxr-xr-x    1 root     root            0 May 20  2006 klaunchertIdhOa.slave-socket

    除设备文件ttySAC0、mtdblock0外,这些信息都分为8个字段,比如:

    228883 -rw-r--r--    2 root     root            6 Sep 27 22:10 readme.txt

    字段1     2         3  4        5              6      7          8

    它们的意义如下:

    (1)字段1:文件的索引节点inode

    索引节点里存放一个文件的上述信息,比如文件大小、属主、归属的用户组、读写权限等,并指明文件的实际数据存放的位置。

    (2)字段2:文件种类和权限

    这字段共分10位,格式如下:

    图17.2 文件类型及属性


    文件类型有7种,“-”表示普通文件,“d”表示目录,“c”表示字符设备,“b”表示块设备,“p”表示FIFO(即管道),“l”表示软连接(也称符号连接),“s”表示套接口(socket)。

    没有专门的符号来表示“硬连接”类型,硬连接也是普通文件,只不过文件的实际内容只有一个副本,连接文件、被连接文件都指向它。比如上面的ln_hard文件是使用命令“ln readme.txt ln_hard”创建出来的到readme.txt文件的硬连接,readme.txt和ln_hard的地位完全一致,它们都指向文件系统中的同一个位置,它们的“硬连接个数”都是2,表示这个文件的实际内容被引用两次──可以从上面的文件信息中看到这两个文件的inode都是228883。

    硬连接文件的引入作用有二:使得可以用别名来引用一个文件,避免文件被误删除──只有当硬连接个数为1时,对一个文件执行删除操作才会真正删除文件的副本。但是它有如下缺点:不能创建到目录的连接,被连接文件和连接文件必须在同一个文件系统中。对此,引入软连接,也称符号连接,软连接只是简单地指向一个文件(可以是目录),并不增加它的硬连接个数。比如上面的ln_soft文件就是使用命令“ln -s readme.txt ln_hard”创建出来的到readme.txt文件的软连接,它使用另一个inode。

    剩下的9位分为3组,分别用来表示文件拥有者、同一个群组的用户、其他用户对这个文件的访问权限。每组权限由rwx三位组成,表示可读、可写、可执行。如果某一位被设为“-”,则表示没有相应的权限,比如“rw-”表示只有读写权限,没有执行权限。

    (3)字段3:硬连接个数,这在上面已经提到。

    (4)字段4:文件拥有者

    (5)字段5:所属群组

    (6)字段6:文件或目录的大小

    (7)字段7:最后访问或修改时间

    (8)字段8:文件名或目录名

     

    对于设备文件,字段6表示主设备号,字段7表示次设备号。

     

    17.2  移植Busybox

    所谓制作根文件系统,就是创建上节提到的各种目录,并且在里面创建各种文件。比如在/bin、/sbin目录下存放各种可执行程序,在/etc目录下存放配置文件,在/lib目录下存放库文件。这节讲述如何使用Busybox来创建/bin、/sbin等目录下的可执行文件。

    17.2.1  Busybox概述

    Busybox是一个遵循GPL v2协议的开源项目。Busybox将众多的UNIX命令集合进一个很小的可执行程序中,可以用来替换GNU fileutils、shellutils等工具集。Busybox中各种命令与相应的GNU工具相比,所能提供的选项较少,但是能够满足一般应用。Busybox为各种小型的或者嵌入式系统提供了一个比较完全的工具集。

    Busybox在编写过程对文件大小进行的优化,并考虑了系统资源有限(比如内存等)的情况。与一般的GNU工具集动辄几M的体积相比,动态连接的Busybox只有几百K,即使静态连接也只有1M左右。Busybox按模块进行设计,可以很容易地加入、去除某些命令,或增减命令的某些选项。

    在创建一个最小的根文件系统时,使用Busybox的话,只需要在/dev目录下创建必要的设备节点、在/etc目录下创建一些配置文件就可以了──当然,如果Busybox使用动态连接,还要在/lib目录下包含库文件。

    Busybox支持uClibc库和glibc库,对Linux 2.2.x之后的内核支持良好。

    Busybox的官方网站是http://www.busybox.net/,源码可以从http://www.busybox.net/downloads/下载,本书使用busybox-1.7.0.tar.bz2。

     

    17.2.2  init进程介绍及用户程序启动过程

    本节介绍Linux系统中用户程序启动的一些基础知识,读者可以直接阅读下一节开始移植Busybox。

    init进程是由内核启动的第一个(也是唯一的一个)用户进程(进程ID为1),它根据配置文件决定启动哪些程序,比如执行某些脚本、启动shell、运行用户指定的程序等。init进程是后续所有进程的发起者,比如init进程启动/bin/sh程序后,才能够在控制台上输入各种命令。

    init进程的执行程序通常是/sbin/init,上面讲述的init进程的作用只不过是/sbin/init这个程序的功能。我们完全可以编写自己的/sbin/init程序,或者传入命令行参数“init=xxxxx”指定某个程序作为init进程运行。

    一般而言,在Linux系统有两种init程序:BSD init和System V init。BSD和System V是两种版本的UNIX系统。这两种init程序各有优缺点,现在大多Linux的发行版本使用System V init。但是在嵌入式领域,通常使用Busybox集成的init程序,下面基于它进行讲解。

    1. 内核如何启动init进程

    内核启动的最后一步就是启动init进程,代码在init/main.c文件中:

    748 static int noinline init_post(void)

    749 {

    ……

    756     if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)

    757         printk(KERN_WARNING "Warning: unable to open an initial console.\n");

    758

    759     (void) sys_dup(0);

    760     (void) sys_dup(0);

    761

    762     if (ramdisk_execute_command) {

    763         run_init_process(ramdisk_execute_command);

    764         printk(KERN_WARNING "Failed to execute %s\n",

    765                 ramdisk_execute_command);

    766     }

    ……

    774     if (execute_command) {

    775         run_init_process(execute_command);

    776         printk(KERN_WARNING "Failed to execute %s.  Attempting "

    777                     "defaults...\n", execute_command);

    778     }

    779     run_init_process("/sbin/init");

    780     run_init_process("/etc/init");

    781     run_init_process("/bin/init");

    782     run_init_process("/bin/sh");

    783

    784     panic("No init found.  Try passing init= option to kernel.");

    785 }

    786

    代码并不复杂,其中的run_init_process函数使用它的参数所指定的程序来创建一个用户进程。需要注意,一旦run_init_process函数创建进程成功,它将不会返回。

    内核启动init进程的过程如下:

    (1) 打开标准输入、标准输出、标准错误设备。

    Linux中最先打开的3个文件分别称为标准输入(stdin)、标准输出(stdout)、标准错误(stderr),它们对应的文件描述符分别为0、1、2。所谓标准输入就是在程序中使用scanf(……)、fscanf(stdin, ……)获取数据时,从哪个文件(设备)读取数据;标准输出、标准错误都是输出设备,前者对应printf(……)、fprintf(stdout, ……),后者对应fprintf(stderr, ……)。

    第756行尝试打开/dev/console设备文件,如果成功,它就是init进程标准输入设备。

    第759、760将文件描述符0复制给文件描述符1、2,所以标准输入、标准输出、标准错误都对应同一个文件(设备)。

    在移植Linux内核时,如果发现打印出“Warning: unable to open an initial console.”,其原因大多是:根文件系统虽然被正确挂接了,但是里面的内容不正确──要么没有/dev/console这个文件,要么它没有对应的设备。

     

    (2) 如果ramdisk_execute_command变量指定了要运行的程序,启动它。

    ramdisk_execute_command的取值(代码也在init/main.c中)分3种情况:

    ① 如果命令行参数中指定了“rdinit=……”,则ramdisk_execute_command等于这个参数指定的程序。

    ② 否则,如果/init程序存在,ramdisk_execute_command就等于“/init”。

    ③ 否则,ramdisk_execute_command为空。

    本书所用的命令行没有设定“rdinit=……”,根文件系统中也没有/init程序,所以ramdisk_execute_command为空,第763~765这几行的代码不执行。

     

    (3) 如果execute_command变量指定了要运行的程序,启动它。

    如果命令行参数中指定了“init=……”,则execute_command等于这个参数指定的程序,否则为空。

    本书所用的命令行没有设定“init=……”,所以第775~777这几行的代码不执行。

     

    (4) 依次尝试执行/sbin/init、/etc/init、/bin/init、/bin/sh。

    第779行执行/sbin/init程序,这个程序在我们的根文件系统中是存在的,所以init进程所用的程序就是/sbin/init。从此系统的控制权交给/sbin/init,不再返回init_post函数中。

    run_init_process函数也在init/main.c中,代码如下:

    184 static char * argv_init[MAX_INIT_ARGS+2] = { "init", NULL, };

    185 char * envp_init[MAX_INIT_ENVS+2] = { "HOME=/", "TERM=linux", NULL, };

    ……

    739 static void run_init_process(char *init_filename)

    740 {

    741     argv_init[0] = init_filename;

    742     kernel_execve(init_filename, argv_init, envp_init);

    743 }

    744

    所以执行/sbin/init程序时,它的环境参数为“"HOME=/", "TERM=linux"”。

     

    2. Busybox init进程的启动过程

    Busybox init程序对应的代码在init/init.c文件中,下面以busybox-1.7.0为例进行讲解。

    先概述其流程,再结合一个/etc/inittab文件讲述init进程的启动过程。

    (1)Busybox init程序流程。

    流程图如图17.3所示,其中与构建根文件系统关系密切的是控制台的初始化、对inittab文件的解释及执行。

    图17.3 Busybox init程序流程图

     

    内核启动init进程时已经打开“/dev/console”设备作为控制台,一般情况下Busybox init程序就使用/dev/console。但是如果内核启动init进程的同时设置了环境变量CONSOLE或console,则使用环境变量所指定的设备。在Busybox init程序中,还会检查这个设备是否可以打开,如果不能打开则使用“/dev/null”。

    Busybox init进程只是作为其他进程的发起者和控制者,并不需要控制台与用户交互,所以init进程会把它关掉──系统启动后运行命令“ls /proc/1/fd/”可以看到该目录为空。init进程创建其他子进程时,如果没有在/etc/inittab中指明它的控制台,则使用前面确定的控制台。

     

    /etc/inittab文件的相关文档和示例代码都在Busybox的examples/inittab文件中。

    如果存在/etc/inittab文件,Busybox init程序解析它,然后按照它的指示创建各种子进程;否则使用默认的配置创建子进程。

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

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

    例如:

    ttySAC0::askfirst:-/bin/sh

    对于Busybox init程序,上述各个字段作用如下:

    ① <id>:表示这个子进程要使用的控制台(即标准输入、标准输出、标准错误设备)。如果省略,则使用与init进程一样的控制台。

    ② <runlevels>:对于Busybox init程序,这个字段没有意义,可以省略。

    ③ <action>:

    表示init进程如何控制这个子进程,有如表17.6所示的8种取值:

    17.6                  /etc/inittab文件中<action>字段的意义

    action名称 执行条件 说明
    sysinit 系统启动后最先执行 只执行一次,init进程等待它结束才继续执行其他动作

    wait

     

    系统执行完sysinit进程后 只执行一次,init进程等待它结束才继续执行其他动作
    once 系统执行完wait进程后 只执行一次,init进程不等待它结束
    respawn 启动完once进程后 init进程监测发现子进程退出时,重新启动它
    askfirst 启动完respawn进程后 与respawn类似,不过init进程先输出“Please press Enter to activate this console.”,等用户输入回车键之后才启动子进程。
    shutdown 当系统关机时 即重启、关闭系统命令时
    restart Busybox中配置了CONFIG_FEATURE_USE_INITTAB,并且init进程接收到SIGHUP信号时 先重新读取、解析/etc/inittab文件,再执行restart程序
    ctrlaltdel 按下Ctrl+Alt+Delete组合键时  


    ④ <process>:要执行的程序,它可以是可执行程序,也可以是脚本。
     

    如果<procss>字段前有“-”字符,这个程序被称为“交互的”。

     

    在/etc/inittab文件文件的控制下,init进程的行为总结如下:

    ① 在系统启动前期,init进程首先启动<action>为sysinit、wait、once的3类子进程。

    ② 在系统正常运行期间,init进程首先启动<action>为respawn、askfirst的两类子进程,并监视它们,发现某个子进程退出时重新启动它。

    ③ 在系统退出时,执行<action>为shutdown、restart、ctrlaltdel的3类子进程(之一或全部)。

     

    如果根文件系统中没有/etc/inittab文件,Busybox init程序将使用如下默认的inittab条目:

    ::sysinit:/etc/init.d/rcS

    ::askfirst:/bin/sh

    tty2::askfirst:/bin/sh

    tty3::askfirst:/bin/sh

    tty4::askfirst:/bin/sh

    ::ctrlaltdel:/sbin/reboot

    ::shutdown:/sbin/swapoff -a

    ::shutdown:/bin/umount -a -r

    ::restart:/sbin/init

     

    (2)/etc/inittab实例。

    仿照Busybox的examples/inittab文件,创建一个inittab文件,内容如下:

    # /etc/inittab

    # 这是init进程启动的第一个子进程,它是一个脚本,可以在里面指定用户想执行的操作

    # 比如挂接其他文件系统、配置网络等

    ::sysinit:/etc/init.d/rcS

     

    # 启动shell,以/dev/ttySAC0作为控制台

    ttySAC0::askfirst:-/bin/sh

     

    # 按下Ctrl+Alt+Delete之后执行的程序,不过在串口控制台中无法输入Ctrl+Alt+Delete组合键

    ::ctrlaltdel:/sbin/reboot

    # 重启、关机前执行的程序

    ::shutdown:/bin/umount -a -r

     

    17.2.3  编译/安装Busybox

    http://www.busybox.net/downloads/下载busybox-1.7.0.tar.bz2。

    使用如下命令解压得到busybox-1.7.0目录,里面就是所有的源码:

    $ tar xjf busybox-1.7.0.tar.bz2

     

    Busybox集合了几百个命令,在一般系统中并不需要全部使用。可以通过配置Busybox来选择这些命令、定制某些命令的功能(选项)、指定Busybox的连接方法(动态连接还是静态连接)、指定Busybox的安装路径。

    1.  配置Busybox

    在busybox-1.7.0目录下执行“make menuconfig”命令即可进入配置界面。Busybox将所有配置项分类存放,表17.7列出了这些类别,其中的“说明”是针对嵌入式系统而言的:

    17.7                         Busybox配置选项分类

    配置项类型 说明
    Busybox Settings Busybox的一些总体设置,里面分为下面5个子类

    Busybox Settings --->

    General Configuration

    一些通用的设置,一般不需要理会

    Busybox Settings --->

    Build Options

    连接方式、编译选项等

    Busybox Settings --->

    Debugging Options

    调试选项,使用Busybox时将打印一些调试信息。一般不选。

    Busybox Settings --->

    Installation Options

    Busybox的安装路径,不需设置,可以在命令行中指定

    Busybox Settings --->

    Busybox Library Tuning

    Busybox的性能微调,比如设置在控制台上可以输入的最大字符个数,一般使用默认值即可
    Archival Utilities 各种压缩、解压缩工具,根据需要选择相关命令
    Coreutils 核心的命令,比如ls、cp等。
    Console Utilities 控制台相关的命令,比如清屏命令clear等。只是提供一些方便而已,可以不理会。
    Debian Utilities Debian命令(Debian是Linux的一种发行版本),比如which命令可以用来显示一个命令的完整路径。
    Editors 编辑命令,一般都选中vi
    Finding Utilities 查找命令,一般不用
    Init Utilities init程序的配置选项,比如是否读取inittab文件。使用默认配置即可。
    Login/Password Management Utilities 登录、用户帐号/密码等方面的命令
    Linux Ext2 FS Progs Ext2文件系统的一些工具
    Linux Module Utilities 加载/卸载模块的命令,一般都选中
    Linux System Utilities 一些系统命令,比如显示内核打印信息的dmesg命令、分区命令fdisk等。
    Miscellaneous Utilities 一些不好分类的命令
    Networking Utilities 网络方面的命令,可以选择一些可以方便调试的命令,比如telnetd、ping、tftp等。
    Process Utilities 进程相关的命令,比如查看进程状态的命令ps、查看内存使用情况的命令free、发送信号的命令kill、查看最消耗CPU资源的前几个进程的命令top等。为方便调试,可以都选中。
    Shells 有多种shell,比如msh、ash等。一般选择ash。
    System Logging Utilities 系统记录(log)方面的命令
    Runit Utilities 本书没有用到
    ipsvd utilities 监听TCP、DPB端口,发现有新的连接时启动某个程序
       

     本节使用默认配置,执行“make menuconfig”后退出、保存配置即可。

    下面只讲述一些常用的选项,以便读者参考。Busybox的配置过程大多是选择、去除各种命令,一目了然。

    (1)Busybox的性能微调。

    设置TAB键补全,比如在控制给上输入一个“ifc”后按TAB键,它会补全为“ifconfig”。如下配置:

    Busybox Settings  --->

        Busybox Library Tuning  --->

            [*]   Tab completion

     

    (2)连接/编译选项。

    以下选项指定是否使用静态连接:

    Build Options  --->

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

    使用glibc时,如果静态编译Buxybox会提示以下警告信息,表示会出现一些莫名其秒的问题:

    #warning Static linking against glibc produces buggy executables

    所以,本书使用动态连接的Busybos,在构造根文件系统时需要在/lib目录下放置glibc库文件。

     

    (3)Archival Utilities选项。

    选择tar命令:

    Archival Utilities  --->

        [*] tar

        [*]     Enable archive creation

        [*]     Enable -j option to handle .tar.bz2 files

        [*]     Enable -X (exclude from) and -T (include from) options)

        [*]     Enable -z option

        [*]     Enable -Z option

        [*]     Enable support for old tar header format

        [*]     Enable support for some GNU tar extensions

        [*]     Enable long options

     

    (4)Linux Module Utilities选项。

    要使用可加载模块,下面的配置要选上:

    Linux Module Utilities  --->    

        [*] insmod

        [*]   Module version checking

        [*]   Add module symbols to kernel symbol table

        [*]   In kernel memory optimization (uClinux only)

        [*]   Enable load map (-m) option

        [*]     Symbols in load map

        [*] rmmod

        [*] lsmod

        [*] Support version 2.6.x Linux kernels

    (5)Linux System Utilities选项。

    支持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

        [*]   umount -a option

     

    (6)Networking Utilities选项。

    除其他默认配置外,增加ifconfig命令:

    Networking Utilities  --->

        [*] ifconfig

        [*]     Enable status reporting output (+7k)

        [ ]     Enable slip-specific options "keepalive" and "outfill"

        [ ]     Enable options "mem_start", "io_addr", and "irq"

        [*]     Enable option "hw" (ether only)

        [*]     Set the broadcast automatically

     

    2.  编译和安装Busybox

    编译之前,先修改Busybox根目录的Makefile,使用交叉编译器:

    175 ARCH            ?= $(SUBARCH)

    176 CROSS_COMPILE   ?=

    改为:

    175 ARCH            ?= arm

    176 CROSS_COMPILE   ?= arm-linux-

     

    然后可执行“make”命令编译Busybox。

    最后是安装,执行“make CONFIG_PREFIX=dir_path install”就可以将Busybox安装在dir_name指定的目录下。执行以下命令在/work/nfs_root/fs_mini目录下安装Busybox:

    $ make CONFIG_PREFIX=/work/nfs_root/fs_mini install

     

    一切完成后,将在/work/nfs_root/fs_mini目录下生成如下文件、目录:

    drwxr-xr-x 2 book book 4096 2008-01-22 06:56 bin

    lrwxrwxrwx 1 book book   11 2008-01-22 06:56 linuxrc -> bin/busybox

    drwxr-xr-x 2 book book 4096 2008-01-22 06:56 sbin

    drwxr-xr-x 4 book book 4096 2008-01-22 06:56 usr

     

    其中linuxrc和上面分析的/sbin/init程序功能完全一样;其他目录下是各种命令,不过它们都是到/bin/busybox的符号连接,比如/work/nfs_root/fs_mini/sbin目录下:

    lrwxrwxrwx 1 book book 14 2008-01-22 06:56 halt -> ../bin/busybox

    lrwxrwxrwx 1 book book 14 2008-01-22 06:56 ifconfig -> ../bin/busybox

    lrwxrwxrwx 1 book book 14 2008-01-22 06:56 init -> ../bin/busybox

    lrwxrwxrwx 1 book book 14 2008-01-22 06:56 insmod -> ../bin/busybox

    lrwxrwxrwx 1 book book 14 2008-01-22 06:56 klogd -> ../bin/busybox

    ……

    除bin/busybox外,其他文件都是到bin/busybox的符号连接──busybox是所有命令的集合体,这些符号连接文件可以直接运行。比如在开发板上,运行“ls”命令和“busybox ls”命令是一样的。

     

     

    17.3  使用glibc

    在第二章制作交叉编译工具链时,已经生成了glibc库,可以直接使用它来构建根文件系统。

    17.3.1  glibc库的组成

    第二章制作的交叉编译工具链中,glibc库的位置是/work/tools/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、gcrt1.o、Mcrt1.o、Scrt1.o等。在生成应用程序时,这些文件像一般的目标文件一样被连接。

    ③ 静态库文件(.a):

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

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

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

    ⑤ libtool库文件(.la):

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

    ⑥ gconv目录:

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

    ⑦ ldscripts目录:

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

    ⑧ 其他目录及文件

     

    17.3.2  安装glibc

    在开发板上只需要加载器和动态库,假设要构建的根文件系统目录为/work/nfs_root/fs_mini,如下操作即可:

    $ mkdir -p /work/nfs_root/fs_mini/lib

    $ cd /work/tools/gcc-3.4.5-glibc-2.3.6/arm-linux/lib

    $ cp *.so* /work/nfs_root/fs_mini/lib –d

     

    上面复制的库文件不是每个都会被用到,可以根据应用程序对库的依赖关系保留需要用到的。通过ldd命令可以查看一个程序会用到哪些库,主机自带的ldd命令不能查看交叉编译出来的程序,有两种替代方法:

    ① 如果有uClibc-0.9.28的代码,可以进入utils子目录生成ldd.host工具:

    $ cd uClibc-0.9.28/utils

    $ make ldd.host

    然后将生成的ldd.host放到主机/usr/local/bin目录下即可使用。

    比如对于动态连接的Busybox,它的库依赖关系如下:

    $ ldd.host busybox

            libcrypt.so.1 => /lib/libcrypt.so.1 (0x00000000)

            libm.so.6 => /lib/libm.so.6 (0x00000000)

            libc.so.6 => /lib/libc.so.6 (0x00000000)

            /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x00000000)

    这表示Busybox要使用的库文件有libcrypt.so.1、libm.so.6、libc.so.6,加载器为/lib/ld-linux.so.2(实际上在交叉工具链目录下,加载器为ld-linux.so.2)。上面的“not found”表示主机上没有这个文件──这没关系,单板的根文件系统上有就行。

     

    ② 可以使用以下命令:

    $ arm-linux-readelf -a "your binary" | grep "Shared"

     

    比如对于动态连接的Busybox,它的库依赖关系如下:

    $ arm-linux-readelf -a ./busybox | grep "Shared"

     0x00000001 (NEEDED)                     Shared library: [libcrypt.so.1]

     0x00000001 (NEEDED)                     Shared library: [libm.so.6]

     0x00000001 (NEEDED)                     Shared library: [libc.so.6]

     

    里面没有列出加载器,构造根文件系统时,它也要复制进去。

     

    17.4  构建根文件系统

    上面两节在介绍了如何安装Busbybox、C库,建立了bin/、sbin/、usr/bin/、usr/sbin/、lib/等目录──最小根文件系统的大部分目录、文件已经建好。本节介绍剩下的部分,假设单板的根文件系统在主机上的目录为/work/nfs_root/fs_mini。

    17.4.1  构建etc目录

    init进程根据/etc/inittab文件来创建其他子进程,比如调用脚本文件配置IP地址、挂接其他文件系统,最后启动shell等。

    etc目录下的内容取决于要运行的程序,本节只需要创建3个文件:etc/inittab、etc/init.d/rcS、etc/fstab。

    1.  创建etc/inittab文件

    仿照Busybox的examples/inittab文件,在/work/nfs_root/fs_mini/etc目录下创建一个inittab文件,内容如下(其中各行的意义在第17.2.2节的最后有说明):

    # /etc/inittab

    ::sysinit:/etc/init.d/rcS

    ttySAC0::askfirst:-/bin/sh

    ::ctrlaltdel:/sbin/reboot

    ::shutdown:/bin/umount -a r

     

    2.  创建etc/init.d/rcS文件

    这是一个脚本文件,可以在里面添加想自动执行命令。以下命令完成配置IP地址、挂接/etc/fstab指定的文件系统:

    #!/bin/sh

    ifconfig eth0 192.168.1.17

    mount -a

    第一行表示这是一个脚本文件,运行时使用/bin/sh解析。

    第二行用来配置IP地址。

    第三行挂接/etc/fstab文件指定的所有文件系统。

    最后,还要改变它的属性,使它能够执行:

    chmod +x etc/init.d/rcS

     

    3.  创建etc/fstab文件

    内容如下,表示执行“mount -a”命令后将挂接proc、tmpfs文件系统:

    # device     mount-point    type   options        dump  fsck order

    proc           /proc        proc   defaults        0     0

    tmpfs          /tmp         tmpfs  defaults        0     0

     

    /etc/fstab文件被用来定义文件系统的“静态信息”,这些信息被用来控制mount命令的行为。文件中各字段意义如下:

    ① device:要挂接的设备

    比如/dev/hda2、/dev/mtdblock1等设备文件;也可以是其他格式,比如对于proc文件系统这个字段没有意义,可以是任意值;对于NFS文件系统,这个字段为<host>:<dir>。

    ② mount-point:挂接点

    ③ type:文件系统类型

    比如proc、jffs2、yaffs、ext2、nfs等;也可以是auto,表示自动检测文件系统类型。

    ④ options:挂接参数,以逗号隔开。

    /etc/fstab的作用不仅仅是用来控制“mount -a”的行为,即使是一般的mount命令也受它控制,这可以从表17.8的参数看到。除与文件系统类型相关的参数外,常用的有以下几种取值:

    17.8                         /etc/fstab参数字段常用的取值

    参数名 说明 默认值
    auto
    noauto

    决定执行“mount -a”时是否自动挂接。

    auto:挂接;noauto:不挂接

    auto
    user
    nouser

    user:允许普通用户挂接设备;

    nouser:只允许root用户挂接设备

    nouser
    exec
    noexec

    exec:允许运行所挂接设备上的程序

    noexec:不允许运行所挂接设备上的程序

    exec
    Ro 以只读方式挂接文件系统  
    rw 以读写方式挂接文件系统  
    sync
    async

    sync:修改文件时,它会同步写入设备中;

    async:不会同步写入

    sync
    defaults rw、suid、dev、exec、auto、nouser、async等的组合  


    ⑤ dump和fsck order:用来决定控制dump、fsck程序的行为。
     

    dump是一个用来备份文件的程序,fsck是一个用来检查磁盘的程序。要想了解更多信息,请阅读它们的man手册。

    dump程序根据dump字段的值来决定这个文件系统是否需要备份,如果没有这个字段,或其值为0,则dump程序忽略这个文件系统。

    fsck程序根据fsck order字段来决定磁盘的检查顺序,一般来说对于根文件系统这个字段设为1,其他文件系统设为2。如果设为0,则fsck程序忽略这个文件系统。

     

    17.4.2  构建dev目录

    本节使用两种方法构建dev目录。

    1.  静态创建设备文件

    为简单起见,本书先使用最原始的方法处理设备:在/dev目录下静态创建各种节点(即设备文件)。

    从系统启动过程可知,涉及的设备有:/dev/mtdblock*(MTD块设备)、/dev/ttySAC*(串口设备)、/dev/console、/dev/null,只要建立以下设备就可以启动系统:

    $ mkdir –p /work/nfs_root/fs_mini/dev

    $ cd /work/nfs_root/fs_mini/dev

    $ sudo mknod console c 5 1

    $ sudo mknod null c 1 3

    $ sudo mknod ttySAC0 c 204 64

    $ sudo mknod mtdblock0 b 31 0

    $ sudo mknod mtdblock1 b 31 1

    $ sudo mknod mtdblock2 b 31 2

     

    注意:在一般系统中,ttySAC0的主设备号为4,但是在S3C2410、S3C2440所用的Linux 2.6.22.6上,它们的串口主设备号为204。

     

    其他设备文件可以当系统启动后,使用“cat /proc/devices”命令查看内核中注册了哪些设备,然后一一创建相应的设备文件。

    实际上,各个Linux系统中dev目录的内容很相似,本书最终使用的dev目录就是从其他系统中复制过来的。

     

    2.  使用mdev创建设备文件

    mdev是udev的简化版本,它也是通过读取内核信息来创建设备文件。

    mdev的用法请参考busybox-1.7.0/doc/mdev.txt文件。mdev的用途主要有两个:初始化/dev目录、动态更新。“动态更新”不仅是更新/dev目录,还支持热拔插──接入、卸下设备时,执行某些动作,它需要内核支持“hotplugging”,即热热拔插。

    要使用mdev,需要内核支持sysfs文件系统,为了减少对flash的读写,还要支持tmpfs文件系统。先确保内核已经设置了CONFIG_SYSFS、CONFIG_TMPFS配置项。

    使用mdev的命令如下,请参考它们的注释以了解其作用:

    $ mount -t tmpfs mdev /dev             /* 使用内存文件系统,减少对flash的读写 */

    $ mkdir /dev/pts                       /* devpts用来支持外部网络连接(telnet)的虚拟终端 */

    $ mount -t devpts devpts /dev/pts

    $ mount -t sysfs sysfs /sys                   /* mdev通过sysfs文件系统获得设备信息 */

    $ echo /bin/mdev > /proc/sys/kernel/hotplug   /* 设置内核,当有设备拔插时调用/bin/mdev程序 */

    $ mdev s                                     /* 在/dev目录下生成内核支持的所有设备的结点 */

     

    要在内核启动时,自动运行mdev。这要修改/work/nfs_root/fs_mini中的两个文件:修改etc/fstab来自动挂载文件系统、修改etc/init.d/rcS加入要自动运行的命令。修改后的文件如下:

    ① etc/fstab:

    # device     mount-point    type   options        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

     

    ② etc/init.d/rcS:加入下面几行

    mount -a

    mkdir /dev/pts

    mount -t devpts devpts /dev/pts

    echo /sbin/mdev > /proc/sys/kernel/hotplug

    mdev -s

     

    需要注意的是,单板上通过mdev生成的/dev目录中,S3C2410、S3C2440是串口名是s3c2410_serial0、1、 2,不是ttySAC0、1、2。需要修改etc/inittab文件:

    ttySAC0::askfirst:-/bin/sh

    改为:

    s3c2410_serial0::askfirst:-/bin/sh

     

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

    $ mkdir –p /work/nfs_root/fs_mini/dev

    $ cd /work/nfs_root/fs_mini/dev

    $ sudo mknod console c 5 1

    $ sudo mknod null c 1 3

     

    17.4.3  构建其他目录

    其他目录可以是空目录,比如proc、mnt、tmp、sys、root等,如下创建:

    # cd /work/nfs_root/fs_mini

    # mkdir proc mnt tmp sys root

     

    现在,/work/nfs_root/fs_mini目录下就是一个非常小的根文件系统。单板可以将它作为网络根文件系统直接启动。如果要烧入单板,还要将它制作为一个文件──称为映象文件,这在下节介绍。

     

    17.4.4  制作/使用yaffs文件系统映象文件

    按照前面的方法,在/work/nfs_root目录下构造了两个根文件系统:fs_mini、fs_mini_mdev。前者使用dev/目录中事先建立好的设备文件,后者使用mdev机制来生成dev/目录,它们的差别只在于3点:etc/inittab文件、etc/init.d/rcS文件、dev/目录。下面两节以/work/nfs_root/fs_mini为例制作根文件系统映象。

     

    所谓制作文件系统映象文件,就是将一个目录下的所有内容按照一定的格式存放到一个文件中,这个文件可以直接烧写到存储设备上去。当系统启动后挂接这个设备,就可以看到与原来目录一样的内容。

    制作不同类型的文件系统映象文件,要使用不同的工具。

    1.  修改制作yaffs映象文件的工具

    在yaffs源码中有个utils目录(假设这个目录为/work/system/Development/yaffs2/utils),里面是工具mkyaffsimage和mkyaffs2image的源代码。前者用来制作yaffs1映象文件,后者用来制作yaffs2映象文件。

    目前mkyaffsimage工具只能生成老格式的yaffs1映象文件,需要修改才能支持新格式。对mkyaffsimage代码的修改都在补丁文件yaffs_util_mkyaffsimage.patch中,读者可以直接打补丁,也可以根据本小节进行修改。

    yaffs1新、老格式的不同在于oob区的使用发生了变化:一是ECC较验码的位置发生了变化,二是可用空间即标记(tag)的数据结构定义发生了变化。

    另外,由于配置内核时没有设置CONFIG_YAFFS_DOES_ECC,yaffs文件系统将使用MTD设备层的ECC较验方法,制作映象文件时也使用与MTD设备层相同的函数计算ECC码。

    ① oob区中较验码的位置变化:

    oob区中使用6字节来存放ECC较验码,前3字节对应上半页,后3字节对应下半页。

    参考第16章中“yaffs文件系统移植”小节,从nand_oob_16结构可知,以前的较验码在oob区中存放的位置为8、9、10、13、14和15,现在改为0、1、2、3、6和7。

     

    ② oob区中可用空间的数据结构定义变化:

    oob区中可用的空间有8字节,它用来存放文件系统的数据,代码中这些数据被称为标记(tag)。

    老格式的yaffs1中,这8字节的数据结构如下定义(在yaffs_guts.h文件中):

    typedef struct {

        unsigned chunkId:20;

        unsigned serialNumber:2;

        unsigned byteCount:10;

        unsigned objectId:18;

        unsigned ecc:12;

        unsigned unusedStuff:2;

    } yaffs_Tags;

     

    新格式的yaffs1中,它如下定义(在yaffs_packedtags1.h文件中):

    typedef struct {

        unsigned chunkId:20;

        unsigned serialNumber:2;

        unsigned byteCount:10;

        unsigned objectId:18;

        unsigned ecc:12;

        unsigned deleted:1;

        unsigned unusedStuff:1;

        unsigned shouldBeFF;      /* 新格式中,这个字节没有使用,yaffs_PackedTags1还是8字节 */

    } yaffs_PackedTags1;

     

    新、老结构有细微差别:老结构中有两位没有使用(unusedStuff);新结构中只有一位没有使用,另一位(deleted)被用来表示当前页是否已经删除。

     

    ③ oob区中ECC码的计算:

    如果配置内核时设置了CONFIG_YAFFS_DOES_ECC,则yaffs文件系统将使用yaffs2/yaffs_ecc.c文件中的yaffs_ECCCalculate函数来计算ECC码;否则使用drivers/mtd/nand/nand_ecc.c文件中的nand_calculate_ecc函数。

    mkyaffsimage工具原来的代码中使用yaffs_ECCCalculate函数。 由于上面配置内核时,没有选择CONFIG_YAFFS_DOES_ECC,为了使映象文件与内核保持一致,要修改mkyaffsimage源码,使用nand_calculate_ecc函数

     

    对mkyaffsimage的修改就是依据这3点进行:

    ① 增加头文件:

    修改文件mkyaffsimage.c,加上下面这行,里面定义了yaffs_PackedTags1结构:

    #include "yaffs_packedtags1.h"

     

    ② 修改mkyaffsimage.c文件的write_chunk函数:

    代码如下:

    231 static int write_chunk(__u8 *data, __u32 objId, __u32 chunkId, __u32 nBytes)

    232 {

    233 #ifdef CONFIG_YAFFS_9BYTE_TAGS   /* 如果要生成老格式的yaffs1映象文件,定义这个宏 */

    …… /* 原来的代码 */

    260 #else

    261     yaffs_PackedTags1 pt1;

    262     yaffs_ExtendedTags  etags;

    263     __u8 ecc_code[6];

    264     __u8 oobbuf[16];

    265     

    266     /* 写页数据,512字节 */

    267     error = write(outFile,data,512);

    268     if(error < 0) return error;

    269

    270     /* 构造tag */

    271     etags.chunkId       = chunkId;

    272     etags.serialNumber  = 0;

    273     etags.byteCount     = nBytes;

    274     etags.objectId      = objId;

    275     etags.chunkDeleted  = 0;

    276

    277     /*

    278      * 重定位oob区中的可用数据(称为tag)

    279      */

    280     yaffs_PackTags1(&pt1, &etags);

    281

    282     /* 计算tag本身的ECC码 */

    283     yaffs_CalcTagsECC((yaffs_Tags *)&pt1);

    284

    285     memset(oobbuf, 0xff, 16);

    286     memcpy(oobbuf+8, &pt1, 8);

    287

    288     /*

    289      * 使用与内核MTD层相同的方法计算一页数据(512字节)的ECC码

    290      * 并把它们填入oob

    291      */

    292     nand_calculate_ecc(data, &ecc_code[0]);

    293     nand_calculate_ecc(data+256, &ecc_code[3]);

    294

    295     oobbuf[0] = ecc_code[0];

    296     oobbuf[1] = ecc_code[1];

    297     oobbuf[2] = ecc_code[2];

    298     oobbuf[3] = ecc_code[3];

    299     oobbuf[6] = ecc_code[4];

    300     oobbuf[7] = ecc_code[5];

    301

    302     nPages++;

    303

    304     /* 写oob数据,16字节 */

    305     return write(outFile, oobbuf, 16);

    306 #endif  

    307 }

    308 

     

    值得注意的是:第275行设置新tag结构中增加的chunkDeleted成员;第292~300行将计算出来的ECC码填入新的ECC位置──它正是nand_oob_16结构的eccpos数组定义的位置。

    其中第292、293行的nand_calculate_ecc函数是从内核源文件drivers/mtd/nand/nand_ecc.c修改而来:在/work/system/Development/yaffs2/utils目录下新建一个同名文件nand_ecc.c,把内核文件nand_ecc.c的nand_calculate_ecc函数、函数中用到的nand_ecc_precalc_table数组摘出来;并去除函数中的第一个形参“struct mtd_info *mtd”──在这个函数中没用到这个参数。

     

    ③ 添加文件,修改Makefile:

    第280行的yaffs_PackTags1函数在上一层目录yaffs_packedtags1.c中定义,先将这个文件复制到当前目录:

    $ cp ../yaffs_packedtags1.c ./

     

    另外,and_calculate_ecc函数是在新加的nand_ecc.c中定义的,所以要修改Makefile,把yaffs_packedtags1.c和nand_ecc.c也编译进mkyaffsimage工具中:

    31 MKYAFFSSOURCES = mkyaffsimage.c

    改为:

    31 MKYAFFSSOURCES = mkyaffsimage.c yaffs_packedtags1.c nand_ecc.c

     

    现在,在/work/system/Development/yaffs2/utils目录下执行“make”命令生成mkyaffsimage工具,将它复制到/usr/local/bin目录:

    $ sudo cp mkyaffsimage /usr/local/bin

    $ sudo chmod +x /usr/local/bin/mkyaffsimage

     

    2.  制作/烧写yaffs映象文件

    使用如下命令将/work/nfs_root/fs_mini目录制作为fs_mini.yaffs文件:

    # cd /work/nfs_root

    # mkyaffsimage fs_mini fs_mini.yaffs

     

    将fs_mini.yaffs放入tftp目录或nfs目录后,在U-Boot控制界面就可以下载、烧入NAND Flash中,操作方法请参考《15.2.6  U-Boot的常用命令》。为方便读者,将命令列出来(以下命令将yaffs.img烧入MTD2分区,即yaffs分区):

    ① tftp 0x30000000 fs_mini.yaffs 或 nfs 0x30000000 192.168.1.57:/work/nfs_root/fs_mini.yaffs

    ② nand erase 0xA00000 0x3600000

    ③ nand write.yaffs 0x30000000 0xA00000 $(filesize)

     

    现在可以修改命令行参数以MTD2分区作为根文件系统,比如在U-Boot控制界面如下设置:

    # set bootargs noinitrd console=ttySAC0 root=/dev/mtdblock2 rootfstype=yaffs

    # saveenv

     

     

    17.4.5  制作/使用jffs2文件系统映象文件

    1.  编译制作yaffs映象文件的工具

    /work/tools/mtd-utils-05.07.23.tar.bz2是MTD设备的工具包,编译它生成mkfs.jffs2工具,用它来将一个目录制作成jffs2文件系统映象文件。

    这个工具包需要zlib压缩包,先安装zlib。在/work/GUI/xwindow/X/deps下有zlib源码zlib-1.2.3.tar.gz,执行以下命令进行安装:

    $ cd /work/GUI/xwindow/X/deps

    $ tar xzf zlib-1.2.3.tar.gz

    $ cd zlib-1.2.3

    $ ./configure --shared --prefix=/usr

    $ make

    $ sudo make install

     

    然后编译mkfs.jffs2:

    $ cd /work/tools

    $ tar xjf mtd-utils-05.07.23.tar.bz2

    $ cd mtd-utils-05.07.23/util

    $ make

    $ sudo make install

     

    2.  制作/烧写jffs2映象文件

    使用如下命令将/work/nfs_root/fs_mini目录制作为fs_mini.jffs2文件:

    $ cd /work/nfs_root

    $ mkfs.jffs2 -n -s 512 -e 16KiB -d fs_mini -o fs_mini.jffs2

    上面命令中,“-n”表示不要在每个擦除块上都加上清除标志,“-s 512”指明一页大小为512字节,“-e 16KiB”指明一个擦除块大小为16KB,“-d”表示根文件系统目录,“-o”表示输出文件。

     

    将fs_mini.jffs2放入tftp目录或nfs目录后,在U-Boot控制界面就可以将下载、烧入NAND Flash中,操作方法请参考《15.2.6  U-Boot的常用命令》。为方便读者,将命令列出来(以下命令将jffs2.img烧入MTD1分区,即jffs2分区):

    ① tftp 0x30000000 fs_mini.jffs2 或 nfs 0x30000000 192.168.1.57:/work/nfs_root/fs_mini.jffs2

    ② nand erase 0x200000 0x800000

    ③ nand write.jffs2 0x30000000 0x200000 $(filesize)

     

    系统启动后,就可以使用“mount -t jffs2 /dev/mtdblock1 /mnt”挂接jffs2文件系统。

    也可以修改命令行参数以MTD1分区作为根文件系统,比如在U-Boot控制界面如下设置:

    # set bootargs noinitrd console=ttySAC0 root=/dev/mtdblock1 rootfstype=jffs2

    # saveenv

    展开全文
  • 移植Busybox与构建Linux根文件系统

    千次阅读 2011-10-08 09:34:27
    本文旨在为以LOONGSON-1B开发板为平台,为移植busybox、构建根文件系统提供技术文档。 开发环境:  系统环境:Loongson-1B开发板(mips32指令集)、Linux3.0.0内核、Busybox1.19.2  编译环境:ubuntu10.04 ,gcc-...

    0.简介
    本文旨在为以LOONGSON-1B开发板为平台,为移植busybox、构建根文件系统提供技术文档。
    开发环境:
        系统环境:Loongson-1B开发板(mips32指令集)Linux3.0.0内核、Busybox1.19.2
        编译环境:ubuntu10.04 ,gcc-3.4.6-2f

    1. Busybox下载和配置:

    1.1 下载Busybox
    进入地址:http://www.busybox.net/downloads/,下载Busybox-1.19.2.tar.bz2工具包。

    1.2配置、编译Busybox
    busybox是一个集成了一百多个最常用linux命令和工具的软件,它甚至还集成了一个http服务器和一个telnet服务器,而所有这一切功能却只有区区1M左右的大小。Busybox的完全可定制性,提供了非常灵活,宜于扩展的结构。
    Busybox的配置方法类似于linux内核的配置。下载解压Busybox-1.19.2.tar.gz工具包后,进入busybox-1.19.2目录,运行“make menuconfig”,根据需要选择需使用的模块,保存退出后会在本地生成一个.config文件,它指定busybox在编译的过程中需要包含哪些功能。
    执行make menuconfig,弹出配置窗口如下: 
    进入Busybox Setings--->选项,General Configuration --->选项按默认配置即可。
    进入Build Options--->选项:
    这里可选择静态编译或动态编译busybox,可根据需要任选一种编译方式进行编译。
    (说明:动态编译的busybox在构建文件系统时需要加入一些必须的动态库,而静态编译的busybox不依赖动态库便可执行,构建文件系统时可省略拷贝动态库的步骤。)
    (1)静态编译:
        选择[*]Build Busybox as a static binary (no shared libs)
        进入()Cross Compiler prefix选项,修改本地交叉工具链的路径。
    (2)动态编译:
        选空[]Build Busybox as a static binary (no shared libs)
        选择[*]Build shared libbusybox
        进入()Cross Compiler prefix选项,修改本地交叉工具链的路径。
    返回上一层进入Installation Options(“make install”behavior)--->选项,配置链接类型与安装路径,这里使用默认配置:

    返回上一层进入Busybox Library Turing--->选项
        选择[*]vi-style line editing commands(NEW)
                [*]Fancy shell prompts(NEW)

    返回最顶层进入Init Utilities--->选项(这里使用默认配置,如图)
        选择[*]init
                [*]Suport reading an inittab file
                [*]Run commands with leading dash with controlling tty
           该项表示在真实的串口设备中运行命令行,不选该项启动时会出现“-sh:can’t access tty;job control turned off”的错误
                [*]Support running init from within an initrd (not initramfs)
            不选此选项将不会生成linuxrc文件

    下面是需要编译进busybox的功能选项,它们都是一些linux基本命令选项,需要哪些命令就编译进去,一般用默认配置

    配置完成后,执行make&&make install进行编译与安装。安装完成后,在Busybox1.19.2目录下生成子目录_inistall,里面的内容:

    其中可执行文件busybox在bin目录下,其他的都是指向它的符号链接。

    使用busybox建立文件系统

    3.1建立系统根目录
    #mkdir /root/rootfs
    #cd /root/rootfs
    #mkdir dev home proc tmp var etc lib mnt sys usr etc/rc.d 

    3.2建立系统配置文件
    3.2.1.etc/inittab文件
    说明:inittab 文件是init进程的配置文件,系统启动后所访问的第一个脚本文件,后续启动的文件都由它指定。
    #cd /root/ rootfs
    #vi etc/inittab
    添加如下内容
    ::sysinit:/etc/rc.d/rc.sysinit    //指定系统启动后首先执行的文件
    #Example of how to put a getty on a serial line (for a terminal)
    ttyS0::respawn:-/bin/sh    //启动后进入shell环境
    tty1::respawn:-/bin/sh
    #Stuff to do when restarting the init process
    ::restart:/sbin/init
    #Stuff to do before rebooting
    ::ctrlaltdel:/sbin/reboot    //捕捉ctrl+alt+del键,重启文件系统
    ::shutdown:/bin/umount -a –r    //当关机时卸载所有文件系统
    ::shutdown:/sbin/swapoff -a

    3.2.2.etc/rc.d/rc.sysinit文件
    说明:这是一个脚本文件,可以在里面添加想自动执行的命令。以下命令配置环境变量、主机名、dev目录环境、挂接/etc/fstab指定的文件系统、建立设备节点与设置IP
    vi etc/rc.d/rc.sysinit 
    添加如下内容
    #!/bin/sh
    #Set binary path
    export PATH=/bin:/sbin:/usr/bin:/usr/sbin
    #Set hostname
    /bin/hostname  "Loongson-gz"
    #Config dev enviornment
    mount –t tmpfs –o size=64k,mode=0755 tmpfs /dev
    mkdir –p /dev/pts
    mount –t devpts devpts /dev/pts
    # mount all filesystem defined in "/etc/fstab"
    echo "#mount all......."
    /bin/mount –a
    echo "# starting mdev...."
    echo /sbin/mdev > /proc/sys/kernel/hotplug
    /sbin/mdev –s
    #Set ip
    ifconfig eth0 192.168.3.110 up
    ifconfig lo 127.0.0.1
    (说明:eth0的ip地址可根据需要自行配置)
     
    3.2.3.etc/fstab文件
    说明:执行mount –a时挂接/etc/fstab指定的文件系统。
    vi etc/fstab
    添加如下内容
    none    /tmp    ramfs   defaults 0 0 
    none    /var    ramfs   defaults 0 0 
    sysfs   /sys    sysfs   defaults 0 0
    proc    /proc   proc    defaults 0 0 
     
    3.2.4.etc/profile文件
    说明:inittab中执行了这样一个语句“::respawn:-/bin/sh”。
    启动/bin/sh程序时会启动ash的配置信息,而它就是/etc/profile,sh会把profile的所有配置全部都运行一遍,因此用户可以把自己的启动程序放在这里。
    #vi etc/profile
    添加如下内容
    #!/bin/sh 
    #/etc/profile:system-wide .profile file for the Bourne shells 
    echo "Processing /etc/profile......" 
    # Set search library path 
    export LD_LIBRARY_PATH=/lib:/usr/lib 
    # Set user path 
    export PATH=/bin:/sbin:/usr/bin:/usr/sbin 
    #Set PS1 
    USER = "LOONGSON" 
    #LOGNAME=$USER
    HOSTNAME=’/bin/hostname’ 
    PS1='[$USER@\h:\w]\$' 
    echo "Done!"
     
    3.2.5.修改系统配置文件权限
    #chmod 755 etc/*
    #chmod 755 etc/rc.d/rc.sysinit
     
    3.2.6.拷贝Busybox文件
    将安装好的Busybox文件拷贝到/root/rootfs/目录:
    #cp ./Busybox1.19.2/_install/* /root/rootfs -rf
     
    3.2.7.拷贝库文件(配置Busybox若选择静态编译则省略此步骤)
    动态编译Busybox制作文件系统,需将下列几个必须库从工具链gcc-3.4.6-2f/mipsel-linux/lib拷贝到lib目录。
    ld.so.1, ld-2.3.6.so, libcrypt.so.1, libc.so.6, libdl.so.2, libgcc_s.so.1, libm.so.6, libpthread.so.0, libstdc++.so.6
    #cp /opt/GCC/gcc-3.4.6-2f/mipsel-linux/lib/库文件名 /root/rootfs/lib/
    为了减少根文件系统的库大小,使用交叉编译工具即gcc-3.4.6-2f的strip工具来处理库文件,把二进制文件中的包含的符号表和调试信息删除掉,可有效减少库文件大小。
    例:
    #cd /opt/GCC/gcc-3.4.6-2f/bin
    #./mipsel-linux-strip /root/rootfs/lib/*.so
    至此文件系统制作完成。

    展开全文
  • 使用busybox构建linux根文件系统

    千次阅读 2012-04-20 16:12:10
    转载地址:... 主机:Windows XP,VMware 8,Ubuntu 编译环境:arm-linux-gcc 4.4.3 ...Linux版本:linux-2.6.32.2 busybox版本:busybox-1.19.4 busybox源码下载地址:http:/

    转载地址:http://blog.chinaunix.net/uid-26310563-id-3168454.html

    主机:Windows XPVMware 8,Ubuntu

    编译环境:arm-linux-gcc 4.4.3

    Linux版本:linux-2.6.32.2

    busybox版本:busybox-1.19.4

    busybox源码下载地址:http://www.busybox.net/downloads/ 

    参考资料:《嵌入式Linux应用开发完全手册 韦东山


    所谓创建根文件系统,就是创建各种目录,并且在里面创建各种文件。比如在/bin、/sbin目录下存放各种可执行程序,在/etc目录下存放配置文件,在/lib目录下存放库文件。Busybox主要用来创建/bin、/sbin等目录下的可执行文件,如命令行下经常使用的命令ls、mv、cp等。


    编译busybox

    Busybox的编译较为简单,一般使用默认配置即可,如果熟悉配置选项的话也可以执行make menuconfig进行手动裁剪。具体配置说明可参考《嵌入式Linux应用开发完全手册》。

    修改busybox顶层目录的Makefile文件,修改如下两行:

    ARCH  ?= arm

    CROSS_COMPILE ?= arm-linux

    然后执行make,编译busybox。编译完成后执行:

    make CONFIG_PREFIX=/home/nfs/rootfs install

    将busybox安装到目录/home/nfs/rootfs下。/home/nfs/rootfs是目标板文件系统的根目录。执行命令查看安装busybox后生成的文件:

    # ls -l /home/nfs/rootfs/

    drwxr-xr-x 2 root root 4096 2012-04-05 15:24 bin

    lrwxrwxrwx 1 root root   11 2012-03-31 08:17 linuxrc -> bin/busybox

    drwxr-xr-x 2 root root 4096 2012-03-31 08:17 sbin

    drwxr-xr-x 5 root root 4096 2012-04-03 07:25 usr

    linuxrc是内核启动的init进程,那内核又如何知道要启动的init进程是哪个呢?它是由uboot传递给linux内核参数中"init=xxx"决定的。在我的目标板的uboot中传递给内核的参数为"init=/linuxrc"。内核如何启动init进程可以查看内核代码init/main.c中的init_post函数。


    构建lib库

    虽然通过编译busybox生成了我们需要的可执行文件,但现在在目标板上仍然无法运行,需要添加lib库来支持可执行文件运行。可以使用uclibc和glibc来构建lib库。由于编译lib库相对复杂,而我们又有现成的lib库可以使用,这里我们就实行拿来主义。现成的lib库就在我们的交叉编译工具arm-linux-gcc的目录下,在本人主机上的绝对路径为/opt/FriendlyARM/toolschain/4.4.3/arm-none-linux-gnueabi/lib,

    把该lib目录下的所有文件复制到目标板文件系统lib下,执行命令:

    #cp -r /opt/FriendlyARM/toolschain/4.4.3/arm-none-linux-gnueabi/lib /home/nfs/rootfs/lib

    PS:注意要加-r选项,把软链接文件原样复制过来,不加-r会复制软链接的链接文件,造成存储空间的浪费。


    构建etc目录

    创建etc/inittab参照busybox的examples/inittab文件,内容如下:


    点击(此处)折叠或打开

    1. # /etc/inittab
    2. # Boot-time system configuration/initialization script.
    3. # This is run first except when booting in single-user mode.
    4. #
    5. ::sysinit:/etc/init.d/rcS
    6. # /bin/sh invocations on selected ttys
    7. #
    8. # Note below that we prefix the shell commands with a "-" to indicate to the
    9. # shell that it is supposed to be a login shell. Normally this is handled by
    10. # login, but since we are bypassing login in this case, BusyBox lets you do
    11. # this yourself...
    12. #
    13. # Start an "askfirst" shell on the console (whatever that may be)
    14. console::askfirst:-/bin/sh
    15. #tty1::askfirst:-/bin/sh
    16. # Stuff to do before rebooting
    17. ::ctrlaltdel:/sbin/reboot
    18. ::shutdown:/bin/umount -a -r

    PS:这里的console是在构建/dev目录时创建的设备节点,对应的设备是启动Linux内核前传入的命令行参数“console=xxx”指定的控制台,我传递的参数为“console=ttySAC0,115200”,表示使用串口0,波特率为115200

    创建etc/init.d/rcS文件。rcS是系统启动后执行的第一个脚本文件,如果想把自己编写的应用程序设置为开机启动,在本文件中中加入运行该程序的命令即可。内容如下:


    点击(此处)折叠或打开

    1. #!/bin/sh
    2. ifconfig eth0 192.168.1.158
    3. mount -a

    修改添加文件可执行权限:#chmod +x etc/init.d/rcS。

    创建etc/fstab文件,内容如下:


    点击(此处)折叠或打开

    1. #device mount-poin type options dump fsck order
    2. proc /proc proc defaults 0 0
    3. tmpfs /tmp tmpfs defaults 0 0


    构建dev目录

    这里使用busybox的mdev创建设备文件,mdev是udev的简化版本,它也是通过读取内核信息来创建设备文件。

    要使用mdev,需要内核支持sysfs文件系统,为了减少对Flash的读写,还要支持tmpfs文件系统。先确保内核已经设置了CONFIG_SYSFS、CONFIG_TMPFS配置项。

    使用mdev的命令如下,请参考它们的注释以了解其作用:

    #mount -t tmpfs mdev /dev (使用内存文件系统,减少对Flash的读写)

    #mkdir /dev/pts (dev/pts用来支持外部网络连接(telnet)的虚拟终端)

    #mount -t devpts devpts /dev/pts

    #mount -t sysfs sysfs /sys (mdev通过sysfs文件系统获得设备信息)

    #echo /bin/mdev > /proc/sys/kernel/hotplug (设置内核,当有设备插拔时调用/bin/mdev程序)

    #mdev -s (在/dev目录下生成内核支持的所有设备的节点)

    要在内核启动后,自动运行mdev。需要修改etc目录下的两个文件:修改etc/fstab来自动挂载文件系统、修改etc/init.d/rcS加入要自动运行的命令。修改后的文件如下:


    etc/fstab

    点击(此处)折叠或打开

    1. #device mount-poin type options dump fsck order
    2. proc /proc proc defaults 0 0
    3. tmpfs /tmp tmpfs defaults 0 0
    4. sysfs /sys sysfs defaults 0 0
    5. tmpfs /dev tmpfs defaults 0 0

    etc/init.d/rcS

    点击(此处)折叠或打开

    1. #!/bin/sh
    2. ifconfig eth0 192.168.1.158
    3. mount -a
    4. mkdir /dev/pts
    5. mount -t devpts devpts /dev/pts
    6. echo /sbin/mdev > /proc/sys/kernel/hotplug
    7. mdev -s

    添加mdev配置文件etc/mdev.conf,mdev.conf可以用来控制设备节点的所有者和权限,格式如下:

    <device regex> <uid>:<gid> <octal permissions> 

    mdev.conf还可以设置mdev在dev目录下生成的设备节点的名字,Linux内核串口驱动原本对S3C2410、S3C2440注册的设备名是s3c2410_serial0s3c2410_serial1、s3c2410_serial2,我们可以修改mdev.conf文件,使mdev在/dev目录下对应生成ttySAC0, ttySAC1和ttySAC2以符合应用程序对于串口设备操作的习惯。配置文件mdev.conf的内容如下:


        mdev.conf

    点击(此处)折叠或打开

    1. # system all-writable devices
    2. full 0:0 0666
    3. null 0:0 0666
    4. ptmx 0:0 0666
    5. random 0:0 0666
    6. tty 0:0 0666
    7. zero 0:0 0666
    8. # console devices
    9. tty[0-9]* 0:5 0660
    10. vc/[0-9]* 0:5 0660
    11. # serial port devices
    12. s3c2410_serial0 0:5 0666 =ttySAC0
    13. s3c2410_serial1 0:5 0666 =ttySAC1
    14. s3c2410_serial2 0:5 0666 =ttySAC2
    15. s3c2410_serial3 0:5 0666 =ttySAC3
    16. # loop devices
    17. loop[0-9]* 0:0 0660 =loop/
    18. # i2c devices
    19. i2c-0 0:0 0666 =i2c/0
    20. i2c-1 0:0 0666 =i2c/1
    21. # frame buffer devices
    22. fb[0-9] 0:0 0666
    23. # input devices
    24. mice 0:0 0660 =input/
    25. mouse.* 0:0 0660 =input/
    26. event.* 0:0 0660 =input/
    27. ts.* 0:0 0660 =input/
    28. # rtc devices
    29. rtc0 0:0 0644 >rtc
    30. rtc[1-9] 0:0 0644
    31. # misc devices
    32. mmcblk0p1 0:0 0600 =sdcard */etc/rc.d/init.d/sd
    33. sda1 0:0 0600 =udisk * /etc/rc.d/init.d/udisk

    重要的一点忘写了,希望没有误导之前看这篇文章的网友。现补充如下:

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

    # mkdir -r /home/nfs/rootfs/dev

    # cd /home/nfs/rootfs/dev

    # mknod console c 5 1

    # mknod null c 1 3


    构建其他目录

    # mkdir proc mnt tmp sys root


    到此,我们的根文件系统构建完毕,/home/nfs/rootfs目录下就是我们的根文件系统。目标板可以把它通过作为网络根文件系统,通过nfs直接启动。也可以把它制作为映像文件烧写到目标板的Flash启动。


    展开全文
  • 构建linux根文件系统 (支持EABI)

    千次阅读 2012-03-19 14:39:50
    平台工具及其版本 宿主机: Windows xp;Vmware7.1.3build-324285;虚拟机Ubuntu10.10 目标平台:工装(s3c2440...交叉开发环境:arm-linux-xxx-4.3.2,支持EABI linux kernel版本:2.6.37 Busybox版本:busybox
     
    

    平台工具及其版本

    宿主机: Windows xp;Vmware7.1.3build-324285;虚拟机Ubuntu10.10

    目标平台:工装(s3c2440处理器)256M Nand Flash,64M SDRAM,2MNOR Flash
    交叉开发环境:arm-linux-xxx-4.3.2,支持EABI
    linux kernel版本:2.6.37

    Busybox版本:busybox-1.17.4

     

    一、移植Busybox

    我们使用busybox-1.17.4来创建根文件系统下载地址为:

    http://www.busybox.net/downloads/

     

    1、解压


    #tar -xvjf BusyBox-1.17.4.tar.bz2
    #cd BusyBox-1.10.1

     

    2、修改Makefile,设置CROSS_COMPILE


    ARCH  ?= arm
    CROSS_COMPILE ?= CROSS_COMPILE ?=/usr/local/arm/4.3.2/bin/arm-linux-

     

    上面指定的路径4.3.2/bin目录下arm-linux-gcc和arm-linux-g++为shell脚本

    #!/bin/bash

    execarm-none-linux-gnueabi-gcc -march=armv4t $*

    #!/bin/bash

    execarm-none-linux-gnueabi-g++ -march=armv4t $*

    可以发现编译指令仍是EABI类型的,并且指定了运行平台类型为armv4t。注意:在编译busybox时,应当使用此处的编译条件-march=armv4t。否则将编译出v5t平台下的代码。

     

    3、配置BusyBox
    运行make clean命令清除先前编译出的目标文件和可执行文件。然后运行make menuconfig进行配置,此时可能会出现下面的错误

    [root@study /work/BusyBox-1.17.4]#make menuconfig

    HOSTCC scripts/kconfig/lxdialog/checklist.o
    在包含自scripts/kconfig/lxdialog/checklist.c:24 的文件中:
    scripts/kconfig/lxdialog/dialog.h:32:20: 错误:curses.h:没有那个文件或目录

    需要安装libncurses5-dev库文件,执行apt-get install libncurses5-dev即可。

    再次执行make menuconfig,可能会提示下面问题:

    Trying libraries: crypt m

     Library crypt is not needed,excluding it

     Library m is needed, can't exclude it(yet)

    Final link with: m

      DOC    busybox.pod

      DOC    BusyBox.txt

      DOC    BusyBox.1

      DOC    BusyBox.html

    不需处理,因为下面会make把相应的库文件复制到制作的文件系统里面。

     

    确保Init Utilities的如下选项被选择,以支持/etc/inittab配置文件和在真实串口中运行命令行。


    Init Utilities—>
        [*] init
        [*] Supporting reading an inittab file
        [*] Supporting running commands with controlling-tty

     

    以下选项指定是否使用静态连接:

     

    Build Options:
        [ ] Build BusyBox as a static binary (no sharedlibs)   

     

    使用glibc时,如果使用静态编译Busybox会提示告警信息,可能会出现某些莫名其妙的问题。所以我使用动态连接,在构造根文件系统时需要在/lib目录下防止glibc库文件。其他选项使用默认即可。

    4、编译

     

    #make clean
    #make
    #make install


    这时我们可以看到在busybox-1.17.4下有_install这个目录,里面包含了应用程序的目录:bin、sbin、usr和脚本linuxrc.

    二、构建根文件系统必要的目录
    1、创建rootfs其他目录

    创建一个目录用来放置根文件系统的文件和目录.


    #mkdir root_fs 

    #cd root_fs

     

    将刚才生成的三个目录bin sbin usr和一个链接文件linuxrc考到目录root_fs下

     

    #cp -rf ../busybox-1.17.4/_install/*./  

     

    创建根文件系统必要的目录

     

    #mkdir dev etc home lib mnt opt proc rootsys tmp var

     

    创建几个必要的二级目录

     

    #mkdir usr/lib usr/share

    #mkdir etc/rc.d

    #mkdir var/lib var/lock var/run var/tmp

     

    三、创建必要文件

    1、获取库文件

    交叉编译工具链动态库放在目录

    /usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/armv4t/lib下,将其复制到lib目录下。

     

    #cp -rf  /usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/armv4t/lib/*so*   lib/  –a

     

    2、将主机 etc 目录下的passwd、group、passwd-文件拷贝到root_fs/etc目录下

     

    #cp  –f  /etc/passwd  /etc/group  /etc/passwd-  etc

     

    将目录…/busybox-1.17.2/examples/bootfloppy/etc下的所有文件拷贝到root_fs/etc下。

    在这个目录下有三个文件fstab, inittab, profile和一个目录init.d,在目录init.d中有一个文件rcS。

     

    #cp  -rf ../busybox-1.17.2/examples/bootfloppy/etc/* etc

     

    在目录etc下创建文件mdev.conf。mdev是udev的一个简化版本,我们可以通过文件mdev.conf自定义一些设备节点的名称或链接来满足特定的需要,但在此处让它为空。

     

    #touch  etc/mdev.conf

     

    3、在dev目录下创建两个设备节点


    mknod console c 5 1 -m 660
    mknod null c 1 3 -m 660

     

    在linux内核源码文件init/main.c中有打开设备文件dev/console的操作如下:

    static noinline int init_post(void)

    __releases(kernel_lock)

    {

    ………………………………

    if (sys_open((const char __user *)"/dev/console", O_RDWR, 0) < 0

    )

    printk(KERN_WARNING "Warning: unableto open an initial console.\

    n");

    ………………………………

    }

    内核启动执行到这里时mdev还没有构建dev目录,如果没有创建设备文件

    dev/console就将会打印警告Warning: unable to open an initial console。在内核启动的过程中要将产生的一些垃圾信息丢弃就需要空设备dev/null。

     

    四、修改几个必要的文件

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

    1、修改文件etc/inittab如下

     

    ::sysinit:/etc/init.d/rcS

    ::askfirst:-/bin/sh

    ::restart:/sbin/init

    ::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代表单用户运行级别脚本)

    ::askfirst:-/bin/sh

    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表明在重启关闭系统命令时执行相应进程。

    2、修改etc/init.d/rcS文件

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

     

    #! /bin/shPATH=/sbin:/bin:/usr/sbin:/usr/bin

    runlevel=S

    prevlevel=N

    umask 022

    export PATH runlevel prevlevel

    /bin/hostname cyembed

    echo "----------mountall----------"

    /bin/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 PATHrunlevel prevlevel //将设置的变量导出到环境中

    /bin/hostnamecyembed //主机名,cyembed将出现在shell提示符中

    [root@cyembed/]#

    /bin/mount -a  //将文件etc/fstab中指明的文件系统挂载到对应挂载点

    echo/sbin/mdev>/proc/sys/kernel/hotplug //用mdev来处理内核的热插拔事件。

    当有热插拔事件产生时, 内核就会调用位于/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”。

    3、修改文件etc/fstab如下:

     

     

    #device   mount-point     type      option    dump   fsck   order 

    proc          /proc        proc    defaults    0        0  

    none          /tmp        ramfs   defaults    0        0  

    sysfs         /sys          sysfs   defaults    0        0  

    mdev        /dev         ramfs   defaults    0        0

     

    在系统启动初始化文件/etc/init.d/rcS中有执行挂载命令/bin/mount -a ,这便是将文件etc/fstab中指定的文件系统挂载到对应的挂载点上。这些文件系统的挂在是执行mdev -s命令建立dev目录的前提。

    4、在启动脚本etc/init.d/rcS执行完后将启动一个shell。Shell启动过程中会根据文件/etc/profile配置登陆环境。文件/etc/profile修改如下:

     

    # Ash profile

    # vim: syntax=sh

    # No core files by default

    ulimit -S -c 0 > /dev/null 2>&1

    USER="`id -un`"

    LOGNAME=$USER

    #PS1='[\u@\h \W]\$ '

    PS1='[root@utu-Linux]\$ '

    PATH=$PATH

    HOSTNAME=`/bin/hostname`

    export USER LOGNAME PS1 PATH

     

    具体说明:

    USER="id-un"  //获取用户名id-un与whoami命令有相同的功能

    PS1='[\u@\h\W]#'  //PS1指定sh提示符的格式在本环境下将是:[root@cyembed /]#

    export USERLOGNAME PS1 PATH 将这些变量导出到环境。

    5、在用户登录时将在/etc下寻找三个文件passwd ,passwd-, group匹配相关信息。这三个文件修改如下:

     

    /etc/passwd

     

    root:$1$m31KtrUN$yLrWAmFxP33XLxLIMFBgW0:0:0:root:/:/bin/sh

    ftp::14:50:FTP User:/var/ftp:

    bin:*:1:1:bin:/bin:

    daemon:*:2:2:daemon:/sbin:

    nobody:*:99:99:Nobody:/:

    plg:PwJdita5W8Ji2:0:0:LinuxUser,,,:/root:/bin/sh

     

    /etc/group

     

    root:*:0:

    daemon:*:1:

    bin:*:2:

    sys:*:3:

    adm:*:4:

    tty:*:5:

    disk:*:6:

    lp:*:7:lp

    mail:*:8:

    news:*:9:

    uucp:*:10:

    proxy:*:13:

    kmem:*:15:

    dialout:*:20:

    fax:*:21:

    voice:*:22:

    cdrom:*:24:

    floppy:*:25:

    tape:*:26:

    sudo:*:27:

    audio:*:29:

    ppp:x:99:

    500:x:500:plg

     

    /etc/passwd-

     

    root:$1$Za8qHlhc$Tf0T1eb62/8M0fx.8WMVs/:0:0:root:/:/bin/sh

    ftp::14:50:FTP User:/var/ftp:

    bin:*:1:1:bin:/bin:

    daemon:*:2:2:daemon:/sbin:

    nobody:*:99:99:Nobody:/:

    plg:PwJdita5W8Ji2:0:0:Linux User,,,:/root:/bin/sh

     

    五、制作yaffs2根文件系统镜像

    用yaffs2文件系统镜像制作工具mkyaffs2image-128M制作根文件系统镜像。

    #./mkyaffs2image-128M  root_fs  root_fs.bin

    六、将根文件系统镜像下载到nandflash并启动。
    展开全文
  • 嵌入式Linux根文件系统构建和移植

    千次阅读 2018-06-13 22:35:07
    在嵌入式Linux构建和移植包括bootloader、内核及根文件系统和busybox、驱动、应用软件库(QT、JVM、python等)。其中最令人费解的是内核及根文件系统和busybox、驱动构建和移植。内核、根文件系统、busybox、yaffs2...
  •  Linux要在一个分区上存放系统启动所必需的文件,如内核映像文件、内核启动后运行的第一个程序、给用户提供操作界面的Shell程序、应用程序所依赖的库等,这些必需、基本的文件合称为根文件系统,它们存放在一个分区...
  • Linux-文件系统-学习笔记(15):利用busybox构建根文件系统 前言:一整套linux在只有内核的情况下是不能工作的,它需要由根文件系统的配置支持。同时根文件系统提供了根目录、shell命令集和linuxrc应用程序,使得...
  • Linux开发五_构建根文件系统

    千次阅读 2016-01-08 00:17:10
    文件系统是对一个存储设备上的数据和元数据进行组织的机制,根文件系统linux内核启动时所挂载的第一个文件系统。对于一个可启动的linux系统,根文件系统是其不可或缺...笔者此处就根文件系统构建作一个简单的介绍。
  • 构建基本的嵌入式Linux根文件系统

    千次阅读 2011-12-09 15:44:45
    1、 《Linux系统移植》:一个经典的Linux移植文档,共有95页的PDF文档,内容十分详细,里面有根文件系统的创建,还多地方都有下载(有的网站称之为《Linux系统全线移植文档》等等),很值得参考。在这里感谢文档的...
  • 搭建自己的Linux根文件系统

    千次阅读 2017-08-07 10:57:38
    整体框架:构建最小根文件系统:1) 创建设备console和null: 首先,我们需要创建一个目录,自己命名。 这里我创建czg目录:mkdir czg。然后进入自己创建的这个文件夹目录,并创建dev目录:mkdir de
  • 嵌入式Linux系统由linux内核与根文件系统两部分构成,两者缺一不可(无根文件系统的内核无法启动) 使用busybox构建嵌入式根文件系统目录结构,配置内核,并且使用Initramfs制作成根文件系统根文件系统与内核都...
  • rm ld-linux-armhf.so.3
  • 带你一起分析Linux系统设计思想,迁移并应用到自己的... 上一篇我们完善了基于busybox制作的根文件系统,并生成了yaffs2类型的根文件系统镜像,本篇来尝试制作jffs2根文件系统镜像和配置嵌入式设备使用nfs根文件系统~
  • Linux根文件系统种类

    千次阅读 2020-06-19 15:17:29
    最小系统根文件系统,只用来跑Linux C或者C++; 最小系统+Qt库,用来泡Qt界面; ubuntu桌面系统,很少人用; Android系统,常用,但是系统庞大。
  • linux 根文件系统的制作

    千次阅读 2011-09-24 23:43:54
    根文件系统构建 Linux 内核在系统启动期间的最后操作之一就是安装根文件系统根文件系统一直都是所有Unix 系统不可或缺的组件。根文件系统目前的结构有点独特,而且包含了一些多余之处,这是因为它与日俱进的...
  • 6、编译完成后,进入到/buildroot-2017.02.9/output/images目录下,将镜像文件sdcard.img拷取到本地电脑下 -rw-r--r--. 1 root root 16K 1月 31 04:02 bcm2710-rpi-3-b.dtb -rw-r--r--. 1 root root 32M 2月...
  • 构建最小根文件系统

    千次阅读 2014-07-18 13:59:38
    一、 编写目的 2 二、 构建根文件系统 2 ...本文档用于记录使用Busybox构建arm linux最小根文件系统的过程,方便日后查阅、参考。 Busybox下载地址:http://busybox.net/downloads/busybox-1.22.
  • 制作嵌入式Linux根文件系统

    千次阅读 2018-09-29 17:17:43
    解压源码并进入目录3. 配置BusyBox3-1. 选择编译静态库3-2. 选择交叉编译工具链3-3. 选择安装目录3-4. 编译安装 1. 获取BusyBox源码   Busybox的官方源码下载路径为:https://busybox.net/downloads/。   ...
  • 构建ubuntu根文件系统

    千次阅读 2017-08-20 15:48:54
    Ubuntu是一个广泛应用于个人电脑,云计算,以及智能物联网设备的开源操作系统。针对智能物联网,Ubuntu提供了一套更加安全,轻量级,专为智能物联网订制的开源操作系统Ubuntu Core。它已被广泛应用于物联网,智能...
  • 二十.Linux开发之根文件系统构建及过程详解

    万次阅读 多人点赞 2018-09-08 21:26:14
    老规矩 有道云笔记地址: 详情看这里链接,记录太多,就不一一排版了。 ...amp;sub=B945844CB6404211B5A9E9AF51C26AB8 ...一、根文件系统构建的学习路线 1.rootfs的两种表现形式:  (1) .nfs方式...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 51,064
精华内容 20,425
关键字:

构建linux根文件系统

linux 订阅