构建根文件系统学习笔记

  1. linux 中的 main.c 文件里面的 init_post 函数,首先打开 /dev/console, 然后 sys_dup(0), sys_dup(0)。这三步的作用是,打开串口作为标准输出 0,复制 0 作为标准输入1,复制 0 作为错误输出2. init_setup 这个函数执行 u-boot 参数中的 bootargs 里面的 init=linuxrc。 run_init_process() 这个函数执行正常是没有返回的,一直在系统里面运行的,所以执行了上面的 init 函数,正常就不会执行下面的 init 函数。只有上面一行不能执行,才执行下面一行。

  2. 如果删除了 根文件系统,启动内核后,报错信息就是 main.c 里面执行 init 那里的报错信息。

  3. ls, cp 之类的在 bin/ 文件夹下的命令,都是指向 busybox 的,所以执行 ls,相当于执行 busybox ls.

  4. 查看 busybox 的源码 init.c
    
    init_main
      parse_inittab
            file = open(INITTAB, "r")  //打开配置文件
            new_init_action  // 创建 init_action 的结构,并填充,然后放入 init_action_list 链表。
      run_actions(SYSINIT)
            waitfor(a, 0)  // 执行应用程序,等待执行完毕
                  run(a)   // 创建 process 子进程
                  waitpid(runpid, &status, 0)  // 等待结束
            delete_init_action(a)  // 在 init_action_list 里面删除 a
      run_actions(WAIT)
            waitfor(a, 0)  // 执行应用程序,等待执行完毕
                  run(a)   // 创建 process 子进程
                  waitpid(runpid, &status, 0)  // 等待结束
            delete_init_action(a)  // 在 init_action_list 里面删除 a
      run_actions(ONCE)  // 不需要和 sysinit, wait 一样,不需要等待执行完成。
            run(a)
            delete_init_action(a)
      while(1) {
            run_action(RESPAWN)
                  if (a->pid == 0) {
                        a->pid = run(a);
                  }
            run_action(ASKFIRST)
                  if (a->pid == 0) {
                        a->pid = run(a);
                              打印: please press enter to activate this console
                              等待回车
                              创建子进程
                  }
            WPID = WAIT(NULL)  // 等待子进程退出
            while (WPID > 0) {
                  a->pid = 0;  // 退出后, 就设置 pid = 0; 这样 上面那个 while 就又能执行 退出的子进程了。
            }
      }
inittab 格式 <id>:<runlevels>:<action>:<process>
id: /dev/id, 用于 stdout, stdin, stderr
runlevels: 可以忽略
action: 执行时机
process: 执行程序或者脚本

init 进程,首先打开 /dev/console, /dev/null,然后读取 /etc/inittab, 然后配置文件里指定的应用程序,库。init 本身即是 busybox.
正常的标准输入输出和错误写道 /dev/console 里面,那些不需要的写道 /dev/null 里面。

5. 最小根文件系统:
/dev/console, /dev/null
init 程序, busybox
/etc/inittab
配置文件指定的应用程序
C库

6. 编译 busybox 的说明在 busybox 源码目录里面 install 文件。 注意 make install 是安装到 pc 机上面,需要使用 make CONFIG_PREFIX = /path/from/root install 来安装到其他目录。

7. 编译 busybox 需要用到交叉工具链,可以先看看 make menuconfig 里面搜索 CROSS, 如果没有,那么就修改 Makefile 里面的 CROSS_PREFIX 变量了。

8. 编译 busybox ,别忘了开启 tab completion 打开补全功能。

9. 创建 console 和 null。打开 刚才编译安装 busybox 的根文件夹,然后 mkdir dev,然后在 dev 文件夹里面,仿照本机的 /dev/console, /dev/null 的属性来创建 console null。
mknod console 5 1  // 主设备号 5,次设备号 1
mknod null 1 3

10. 创建 /etc/inittab. 在根文件夹下, mkdir etc,然后在 etc 里面新建 inittab,输入:
```code
console::askfirst:-/bin/sh
  1. 安装 glibc。打开交叉编译工具链 arm-linux/lib

    cp *.so.* /xxx/lib -d      // 把 so 库复制到根文件下的 lib 文件夹里面, -d 的作用是链接文件复制过去还是链接文件。
  2. 制作 image,可以使用 yaffs2 来制作。yaffs2 可能需要通过源码编译,编译出来后的可执行文件放到 /usr/local/bin 目录即可,然后加上执行权限。 然后执行 mkyaffs2image 根文件目录 根文件目录.yaffs2 然后烧录这个 image 到开发板即可启动。

  3. 在根文件系统里面 mkdir proc, 然后挂载 proc 这个内核提供的虚拟的文件系统到 /proc 上面。mount -t proc none /proc。 这样就可以使用 ps 命令来查看进程了。 然后希望自动挂载 proc,那么需要修改 inittab 文件,加入
    ::sysinit:/etc/init.d/rcS

    然后,在实现 rcS 这个脚本就可以了。在 rcS 这个脚本里面写入,然后加上执行权限

    mount -t proc none /proc

还可以使用 mount -a 这个命令,这个命令会查看 /etc/fstab 这个文件,这个文件里面可以写上:

# device   mount-point  type      options      dump   fsck order 
proc       /proc      proc      defaults      0      0

这样 rcS 里面可以写 mount -a 即可。

使用命令 cat /proc/mounts 可以查看已经挂载的情况。

  1. udev 自动创建 /dev 目录下面的节点,busybox 中使用 mdev 来简化代替 udev, 可以查看 busybox/doc/mdev.txt 来查看详细信息。 使用 mdev,首先修改 inittab,增加:
    sysfs      /sys      sysfs      defaults      0      0
    tmpfs      /dev      tmpfs      defaults      0      0

    修改 rcS,增加 :

    mkdir /dev/pts
    mount -t devpts devpts /dev/pts
    echo /sbin/mdev > /proc/sys/kernel/hotplug   // 当系统检测到有热插拔的设备的时候,就调用 hotplug 中注明的程序,mdev 来处理。
    mdev -s   // 开机的时候把内核中现有的设备节点创建出来。

这样的文件系统就比较完善了。

  1. 文件系统除了 yaffs2 以外,也可以 jffs2,但是 jffs2 经常用于 nor flash,当然 nand flash 也可以用。jffs2 是压缩格式,需要 zlib 支持。 先解压,配置为动态库并且安装到usr目录 ./configure --shared --prefix=/usr/,编译 make,安装 zlib sudo make install。 然后解压,编译,安装 mtd-utils. 然后就可以使用命令 mkfs.jffs2 -n -s 512 -e 16KiB -d 目录 -o 目录.jffs2 。 -s 这个是页大小, -e 这个是擦除块大小 -d 标识目录。 不同的存储芯片是不一样的,可能是 -s 2048 -e 128KiB

直接通过 uboot 烧录到 nand 之后,启动时不一定能够识别 jffs2,这时候可能需要修改 uboot 的启动参数

set bootargs noinitrd root=/dev/mtdblock3 rootfstype=jffs2 init=linuxrc console=ttySAC0
save
boot
  1. 为了省略重复烧录文件系统的麻烦,可以使用 nfs 网络根文件系统。 首先 ifconfig 看看有没有网卡,没有就 ifconfig eth0 up 来启动网卡。然后 ifconfig eth0 192.xxx 来设置 ip 地址。 想用网络根文件系统,首先需要 pc 机允许目录能够被单板挂载,这个设置在 /etc/exports 里面,然后在单板上设置挂载。 修改 /etc/exports:
    根文件系统目录 *(rw,sync,no_root_squash)

    然后重启服务 sudo /etc/init.d/ntf-kernel-server restart 然后尝试挂载这个文件系统 sudo mount -t nfs 192.xxx:根文件系统目录 /mnt

在单板上挂载根文件系统 mount -t nfs -o nolock 192.xxx:根文件系统目录 /mnt

这种方法是从 nand 启动后,挂载 nfs 文件系统。

  1. 直接从 nfs 根文件系统启动,具体文件查看 内核/Doc/nfsroot.txt
    set bootargs noinitrd root=/dev/nfs nfsroot=192.xxx:根文件目录 ip=单板ip:服务器ip:网管:子网掩码:hostname:eth0:off rootfstype=jffs2 init=linuxrc console=ttySAC0
    save
    boot

    这样就可以通过 nfs 上的根文件系统来启动了。 我们可以通过 ssh 连接服务器,在服务器中交叉编译,然后单板上可以通过 nfs 直接运行查看效果,确认无误,再烧录为镜像。

tq2440 默认的 bootargs 是: bootargs=noinitrd root=/dev/mtdblock2 init=/linuxrc console=ttySAC0 更改后的 bootargs 是: bootargs=noinitrd root=/dev/nfs nfsroot=192.168.123.113:/home/book/embed_sky/root_nfs ip=192.168.123.121:192.168.123.113:192.168.123.124:255.255.255.0:tq2440.embedsky.net:eth0:off rootfstype=yaffs init=linuxrc console=ttySAC0

标签: rootfs

添加新评论