ramlife

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理
  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: /dev/id, 用于 stdout, stdin, stderr
runlevels: 可以忽略
action: 执行时机
process: 执行程序或者脚本

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

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

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

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

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

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

  6. 创建 /etc/inittab. 在根文件夹下, mkdir etc,然后在 etc 里面新建 inittab,输入:

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

  2. 在根文件系统里面 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

posted on 2020-05-05 22:48  ramlife  阅读(84)  评论(0编辑  收藏  举报