mini2440 root_qtopia 文件系统启动过程分析(arm9 版主)

mini2440 root_qtopia 文件系统启动过程分析(arm9 版主)
来源: ChinaUnix博客  日期: 2010.01.19 17:47 (共有条评论) 我要评论
 
对于mini2440最新的root_qtopia文件系统启动过程,我在这里做了一些简单的分析,和大家分享一下经验,不足之处也请大家及时指出。 
其实,虽然root_qtopia这个文件系统的GUI是基于Qtopia的,但其初始化启动过程却是由大部分由busybox完成,Qtopia(qpe)只是在启动的最后阶段被开启。 
由于默认的内核命令行上有init=/linuxrc, 因此,在文件系统被挂载后,运行的第一个程序是根目录下的linuxrc。 这是一个指向/bin/busybox的链接,也就是说,系统起来后运行的第一个程序也就是busybox本身。 

种情况下,busybox首先将试图解析/etc/inittab来获取进一步的初始化配置信息(参考busybox源代码init/init.c中的
parse_inittab()函数)。而事实上,root_qtopia中并没有/etc/inittab这个配置文件,根据busybox的逻辑,它
将生成默认的配置 
[url=javascript:]复制代码[/url]
  • static void parse_inittab(void)
  • {
  • #if ENABLE_FEATURE_USE_INITTAB
  • char *token[4];
  • parser_t *parser = config_open2("/etc/inittab", fopen_for_read);

  • if (parser == NULL)
  • #endif
  • {
  • /* No inittab file -- set up some default behavior */
  • /* Reboot on Ctrl-Alt-Del */
  • new_init_action(CTRLALTDEL, "reboot", "");
  • /* Umount all filesystems on halt/reboot */
  • new_init_action(SHUTDOWN, "umount -a -r", "");
  • /* Swapoff on halt/reboot */
  • if (ENABLE_SWAPONOFF)
  • new_init_action(SHUTDOWN, "swapoff -a", "");
  • /* Prepare to restart init when a QUIT is received */
  • new_init_action(RESTART, "init", "");
  • /* Askfirst shell on tty1-4 */
  • new_init_action(ASKFIRST, bb_default_login_shell, "");
  • //TODO: VC_1 instead of ""? "" is console -> ctty problems -> angry users
  • new_init_action(ASKFIRST, bb_default_login_shell, VC_2);
  • new_init_action(ASKFIRST, bb_default_login_shell, VC_3);
  • new_init_action(ASKFIRST, bb_default_login_shell, VC_4);
  • /* sysinit */
  • new_init_action(SYSINIT, INIT_SCRIPT, "");
  • return;

  • 其中, 最重要的一个,就是new_init_action(SYSINIT, INIT_SCRIPT, ""), 也就决定了接下去初始化的脚本是INIT_SCRIPT所定义的值。这个宏的默认值是"/etc/init.d/rcS". 
    下面是文件系统中/etc/init.d/rcS的内容, 也是我们要分析的重点 
    [url=javascript:]复制代码[/url]
  • #! /bin/sh

  • PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin:
  • runlevel=S
  • prevlevel=N
  • umask 022
  • export PATH runlevel prevlevel

  • #
  • # Trap CTRL-C &c only in this shell so we can interrupt subprocesses.
  • #
  • trap ":" INT QUIT TSTP
  • /bin/hostname FriendlyARM

  • /bin/mount -n -t proc none /proc
  • /bin/mount -n -t sysfs none /sys
  • /bin/mount -n -t usbfs none /proc/bus/usb
  • /bin/mount -t ramfs none /dev

  • echo /sbin/mdev > /proc/sys/kernel/hotplug
  • /sbin/mdev -s
  • /bin/hotplug
  • # mounting file system specified in /etc/fstab
  • mkdir -p /dev/pts
  • mkdir -p /dev/shm
  • /bin/mount -n -t devpts none /dev/pts -o mode=0622
  • /bin/mount -n -t tmpfs tmpfs /dev/shm
  • /bin/mount -n -t ramfs none /tmp
  • /bin/mount -n -t ramfs none /var
  • mkdir -p /var/empty
  • mkdir -p /var/log
  • mkdir -p /var/lock
  • mkdir -p /var/run
  • mkdir -p /var/tmp

  • /sbin/hwclock -s

  • syslogd
  • /etc/rc.d/init.d/netd start
  • echo " " > /dev/tty1
  • echo "Starting networking..." > /dev/tty1
  • sleep 1
  • /etc/rc.d/init.d/httpd start
  • echo " " > /dev/tty1
  • echo "Starting web server..." > /dev/tty1
  • sleep 1
  • /etc/rc.d/init.d/leds start
  • echo " " > /dev/tty1
  • echo "Starting leds service..." > /dev/tty1
  • echo " "
  • sleep 1

  • /sbin/ifconfig lo 127.0.0.1
  • /etc/init.d/ifconfig-eth0

  • /bin/qtopia &
  • echo " " > /dev/tty1
  • echo "Starting Qtopia, please waiting..." > /dev/tty1

  • 下面就逐个来分析:
    [url=javascript:]复制代码[/url]
  • PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin:
  • runlevel=S
  • prevlevel=N
  • umask 022
  • export PATH runlevel prevlevel 
    为启动环境设置必要的环境变量;
    [url=javascript:]复制代码[/url]
  • /bin/hostname FriendlyARM 
    设置机器名字;
    [url=javascript:]复制代码[/url]
  • /bin/mount -n -t proc none /proc
  • /bin/mount -n -t sysfs none /sys
  • /bin/mount -n -t usbfs none /proc/bus/usb
  • /bin/mount -t ramfs none /dev 
    挂载“虚拟”文件系统,/proc, /sys,并且在/dev目录上挂载一个ramfs,相当于把原本NAND Flash上的只读的/dev目录“覆盖”上一块可写的空的SDRAM。
    这里要注意的是,/sys和挂载了ramfs的/dev是正确创建设备节点的关键。对于2.6.29内核来说,已经没有了devfs的支持,创建设备节点只有通过两种办法由文件系统完成:
    1) 制作文件系统镜像前用mknod手动创建好系统中所有的(包括可能有的)设备节点,并把这些节点文件一起做进文件系统镜像中;
    2)在文件系统初始化过程中,通过/sys目录所输出的信息,在/dev目录下动态的创建系统中当前实际有的设备节点。

    然,方法1)有很大的局限性,仅限于没有设备动态增加或减少的情况,不适用于很多设备热插拔的情况,比如U盘,SD卡等等。方法2)是目前大多数PC上
    Linux的做法(基于udev实现)。这种方法有两个前提: /sys目录挂载和一个可写的/dev目录。
    这也就是为什么我们在这里需要挂载/sys和ramfs在/dev目录上。事实上,这种方法最早就是为热插拔设计的,
    你可以理解为当系统启动是,所有设备一下子全部“插入”了进来。


    这里有一点要说明的是,在文件系统初始化跑到这里之前,原本的/dev目录下必须有一个的设备节点:/dev/console。
    [url=javascript:]复制代码[/url]
  • echo /sbin/mdev > /proc/sys/kernel/hotplug
  • /sbin/mdev -s
  • /bin/hotplug
    这几个就是用来完成我上面所说的两个东西: 1)通过mdev -s 在/dev目录下建立必要的设备节点; 2)设置内核的hotplug handler为mdev, 即当设备热插拔时,由mdev接收来自内核的消息并作出相应的回应, 比如挂载U盘。
    对于mdev,需要注意的是,文件系统里存在/etc/mdev.conf文件,它包含了mdev的配置信息。通过这个文件,我们可以自定义一些设备节点的名称或链接来满足特定的需要。这是root qtopia中mdev.conf的内容:
    [url=javascript:]复制代码[/url]
  • # system all-writable devices
  • full        0:0    0666
  • null        0:0    0666
  • ptmx        0:0    0666
  • random        0:0    0666
  • tty        0:0    0666
  • zero        0:0    0666

  • # console devices
  • tty[0-9]*    0:5    0660
  • vc/[0-9]*    0:5    0660

  • # serial port devices
  • s3c2410_serial0    0:5    0666    =ttySAC0
  • s3c2410_serial1    0:5    0666    =ttySAC1
  • s3c2410_serial2    0:5    0666    =ttySAC2
  • s3c2410_serial3    0:5    0666    =ttySAC3

  • # loop devices
  • loop[0-9]*    0:0    0660    =loop/

  • # i2c devices
  • i2c-0        0:0    0666    =i2c/0
  • i2c-1        0:0    0666    =i2c/1

  • # frame buffer devices
  • fb[0-9]        0:0    0666

  • # input devices
  • mice        0:0    0660    =input/
  • mouse.*        0:0    0660    =input/
  • event.*        0:0    0660    =input/
  • ts.*        0:0    0660    =input/

  • # rtc devices
  • rtc0        0:0    0644    >rtc
  • rtc[1-9]    0:0    0644

  • # misc devices
  • mmcblk0p1    0:0    0600    =sdcard */bin/hotplug
  • sda1        0:0    0600    =udisk * /bin/hotplug

    以看到,原本串口驱动注册的设备名是s3c2410_serial0,
    s3c2410_serial1和s3c2410_serial2,而mdev则会在/dev目录下对应生成ttySAC0,
    ttySAC1和ttySAC2以符合应用程序对于串口设备名称的习惯。同样的,/dev/sdcard和/dev/udisk永远分别指向SD卡和U盘
    的第一个分区。(所以,用那些没有分区表的SD卡或U盘的兄弟知道原因了吧...)
    [url=javascript:]复制代码[/url]
  • # mounting file system specified in /etc/fstab
  • mkdir -p /dev/pts
  • mkdir -p /dev/shm
  • /bin/mount -n -t devpts none /dev/pts -o mode=0622
  • /bin/mount -n -t tmpfs tmpfs /dev/shm
  • /bin/mount -n -t ramfs none /tmp
  • /bin/mount -n -t ramfs none /var
  • mkdir -p /var/empty
  • mkdir -p /var/log
  • mkdir -p /var/lock
  • mkdir -p /var/run
  • mkdir -p /var/tmp
    就像注释中所说的,这是用来挂载其他一些常用的文件系统,并在/var目录下(同样是ramfs,可写的)新建必要的目录。
    [url=javascript:]复制代码[/url]
  • /sbin/hwclock -s
    用来设定系统时间的,从硬件RTC中获取,不过似乎有问题
    接下来就是启动系统服务了,包括log记录,网络, http server和自定义的"跑马灯服务"...
    关于mdev.conf中的
    [url=javascript:]复制代码[/url]
  • # misc devices
  • mmcblk0p1    0:0    0600    =sdcard */bin/hotplug
  • sda1        0:0    0600    =udisk * /bin/hotplug一点补充说明:

    两句配置的意思是当SD卡或者U盘插入/拔出时,将这个消息传递给自定义的热插拔handler, /bin/hotplug.
    这个程序是友善之臂开发的用于自动挂载可移动设备的,目前是SD卡和U盘。它的逻辑很简单,将SD卡或者U盘的第一个分区作为FAT/FAT32挂载到
    /sdcard或者/udisk.
    但这也同时带来一个问题,当SD卡或者U盘上没有分区表或者第一个分区不是FAT/FAT32格式的时候,它就玩不转了,兄弟们要小心了:)
    这是/bin/hotplug里的二进制数据片段,可以看到我上面说的逻辑:
    000010d0h: 52 00 00 00 4D 00 00 00 00 00 00 00 41 00 00 00 ; R...M.......A...
    000010e0h: 43 00 00 00 54 00 00 00 49 00 00 00 4F 00 00 00 ; C...T...I...O...
    000010f0h: 4E 00 00 00 00 00 00 00 44 00 00 00 45 00 00 00 ; N.......D...E...
    00001100h: 56 00 00 00 4E 00 00 00 41 00 00 00 4D 00 00 00 ; V...N...A...M...
    00001110h: 45 00 00 00 00 00 00 00 61 00 00 00 64 00 00 00 ; E.......a...d...
    00001120h: 64 00 00 00 00 00 00 00 72 00 00 00 65 00 00 00 ; d.......r...e...
    00001130h: 6D 00 00 00 6F 00 00 00 76 00 00 00 65 00 00 00 ; m...o...v...e...
    00001140h: 00 00 00 00 2F 00 00 00 64 00 00 00 65 00 00 00 ; ..../...d...e...
    00001150h: 76 00 00 00 2F 00 00 00 75 00 00 00 64 00 00 00 ; v.../...u...d...
    00001160h: 69 00 00 00 73 00 00 00 6B 00 00 00 00 00 00 00 ; i...s...k.......
    00001170h: 2F 00 00 00 64 00 00 00 65 00 00 00 76 00 00 00 ; /...d...e...v...
    00001180h: 2F 00 00 00 73 00 00 00 64 00 00 00 63 00 00 00 ; /...s...d...c...
    00001190h: 61 00 00 00 72 00 00 00 64 00 00 00 00 00 00 00 ; a...r...d.......
    000011a0h: 4D 00 00 00 44 00 00 00 45 00 00 00 56 00 00 00 ; M...D...E...V...
    000011b0h: 00 00 00 00 6D 00 00 00 6D 00 00 00 63 00 00 00 ; ....m...m...c...
    000011c0h: 62 00 00 00 6C 00 00 00 6B 00 00 00 30 00 00 00 ; b...l...k...0...
    000011d0h: 70 00 00 00 31 00 00 00 00 00 00 00 73 00 00 00 ; p...1.......s...
    000011e0h: 64 00 00 00 61 00 00 00 31 00 00 00 00 00 00 00 ; d...a...1.......
    000011f0h: 76 00 00 00 66 00 00 00 61 00 00 00 74 00 00 00 ; v...f...a...t...
    00001200h: 00 00 00 00 2F 00 00 00 64 00 00 00 65 00 00 00 ; ..../...d...e...
    00001210h: 76 00 00 00 2F 00 00 00 77 00 00 00 61 00 00 00 ; v.../...w...a...
    00001220h: 74 00 00 00 63 00 00 00 68 00 00 00 64 00 00 00 ; t...c...h...d...
    00001230h: 6F 00 00 00 67 00 00 00 00 00 00 00 9A B2 01 81 ; o...g.......毑.?
    00001240h: B0                                              ; ?
    [url=javascript:]复制代码[/url]
  • syslogd
  • /etc/rc.d/init.d/netd start
  • echo "                        " > /dev/tty1
  • echo "Starting networking..." > /dev/tty1
  • sleep 1
  • /etc/rc.d/init.d/httpd start
  • echo "                        " > /dev/tty1
  • echo "Starting web server..." > /dev/tty1
  • sleep 1
  • /etc/rc.d/init.d/leds start
  • echo "                        " > /dev/tty1
  • echo "Starting leds service..." > /dev/tty1
  • echo "                        "
  • sleep 1
    启动一系列服务:
    syslog - 用于记录内核和应用程序debug信息
    netd -     inetd, 一个挂载启动各种网络相关服务的看守进程
    httpd -    http server看守进程
    leds  -   跑马灯看守进程
    其中,inetd的配置文件为/etc/inetd.conf,这是文件内容
    [url=javascript:]复制代码[/url]
  • # /etc/inetd.conf:  see inetd(8) for further informations.
  • echo     stream  tcp    nowait    root    internal
  • echo     dgram   udp    wait    root    internal
  • daytime  stream  tcp    nowait    root    internal
  • daytime  dgram   udp    wait    root    internal
  • time     stream  tcp    nowait    root    internal
  • time     dgram   udp    wait    root    internal

  • # These are standard services.
  • #
  • ftp    stream    tcp    nowait    root    /usr/sbin/ftpd        /usr/sbin/ftpd
  • telnet    stream    tcp    nowait    root    /usr/sbin/telnetd    /usr/sbin/telnetd -i
    可以看到,这里启动的网络服务有两个: 1)ftp server 和 2)telnet server。有关网络服务的端口和协议等具体信息,可以参考/etc/services, /etc/protocols
    再接下来
    [url=javascript:]复制代码[/url]
  • /sbin/ifconfig lo 127.0.0.1
  • /etc/init.d/ifconfig-eth0
    配置网络设备(网卡):
    1)设定本机回环地址为127.0.0.1
    2)运行网卡设置脚本/etc/init.d/ifconfig-eth0
    这是/etc/init.d/ifconfig-eth0的内容, 加入了我的一些注释
    [url=javascript:]复制代码[/url]
  • #!/bin/sh

  • echo -n Try to bring eth0 interface up......>/dev/ttySAC0

  • #判断/etc/eth0-setting文件是否存在
  • if [ -f /etc/eth0-setting ] ; then
  •                      #读取配置文件信息
  •     source /etc/eth0-setting

  •                       #如果根文件系统为nfs,则说明网卡已经配置OK,这里什么都不需要配置了
  •     if grep -q "^/dev/root / nfs " /etc/mtab ; then
  •         echo -n NFS root ... > /dev/ttySAC0
  •                      #否则,根据配置文件中的MAC, IP, Mask和Gateway通过ifconfig命令相应地配置网卡
  •     else
  •         ifconfig eth0 down
  •         ifconfig eth0 hw ether $MAC
  •         ifconfig eth0 $IP netmask $Mask up
  •         route add default gw $Gateway
  •     fi

  •                      #将配置文件中的DNS设置写入/etc/resolv.conf使之生效
  •     echo nameserver $DNS > /etc/resolv.conf
  • #配置文件不存在,使用默认配置
  • else
  •                        
  •                       #如果根文件系统为nfs,则说明网卡已经配置OK,这里什么都不需要配置了
  •     if grep -q "^/dev/root / nfs " /etc/mtab ; then
  •         echo -n NFS root ... > /dev/ttySAC0
  •     else
  •                      #将网卡的IP地址设定为192.168.1.230
  •     /sbin/ifconfig eth0 192.168.1.230 netmask 255.255.255.0 up
  •     fi
  • fi

  • echo Done > /dev/ttySAC0
    可以看到,NFS自动识别就是靠判断/etc/mtab中是否有nfs的挂载记录实现的。
    这是root qtopia文件系统中/etc/eth0-settings文件
    [url=javascript:]复制代码[/url]
  • IP=192.168.1.230
  • Mask=255.255.255.0
  • Gateway=192.168.1.1
  • DNS=192.168.1.1
  • MAC=08:90:90:90:90:90
    终于到最后了,启动Qtopia GUI环境
    [url=javascript:]复制代码[/url]
  • /bin/qtopia &
  • echo "                                  " > /dev/tty1
  • echo "Starting Qtopia, please waiting..." > /dev/tty1
    可以看到,这里Qtopia是通过运行/bin/qtopia来启动的。事实上,/bin/qtopia也是一个脚本,它的任务是设定Qtopia运行必要的环境, 最后通过调用qpe可执行文件真正启动Qtopia。这是它的全部内容,我加入了一些注释:
    [url=javascript:]复制代码[/url]
  • #!/bin/sh

  • #tslib环境变量设置,包括了touchscreen设备文件,tslib配置文件,tslib plug-in位置和touchscreen校准数据文件
  • export TSLIB_TSDEVICE=/dev/input/event0
  • export TSLIB_CONFFILE=/usr/local/etc/ts.conf
  • export TSLIB_PLUGINDIR=/usr/local/lib/ts
  • export TSLIB_CALIBFILE=/etc/pointercal
  • #Qtopia环境变量设置,设定了Qtopia主要文件位置
  • export QTDIR=/opt/Qtopia
  • export QPEDIR=/opt/Qtopia
  • #设定PATH和LD_LIBRARY_PATH以包含Qtopia的可执行文件和共享库文件,方便Qtopia正确运行
  • export PATH=$QTDIR/bin:$PATH
  • export LD_LIBRARY_PATH=$QTDIR/lib:/usr/local/lib:$LD_LIBRARY_PATH

  • #通过判断/sys/devices/virtual/input/input0/uevent中是否包含touchscreen信息使Qtopia自动识别touchscreen和USB鼠标
  • TS_INFO_FILE=/sys/devices/virtual/input/input0/uevent
  • if [ -e $TS_INFO_FILE -a "/bin/grep -q TouchScreen
  •     export QWS_MOUSE_PROTO="TPanel:/dev/input/event0 USB:/dev/input/mice"
  •     if [ -e /etc/pointercal -a ! -s /etc/pointercal ] ; then
  •         rm /etc/pointercal
  •     fi
  • else
  •     export QWS_MOUSE_PROTO="USB:/dev/input/mice"
  •     >/etc/pointercal
  • fi
  • unset TS_INFO_FILE

  • export QWS_KEYBOARD=TTY:/dev/tty1
  • export KDEDIR=/opt/kde

  • export HOME=/root

  • #通过调用/opt/Qtopia/bin/qpe真正启动Qtopia
  • exec $QPEDIR/bin/qpe 1>/dev/null 2>/dev/null
    到此为止,文件系统从初始化到最终启动Qtopia GUI环境的全部过程就结束了,大家可以看到,友善之臂的“小秘密”其实都在这里,说穿了很简单:)只要大家能够静下心来认真看看脚本,看看源代码,加上一些背景知识的了解,搞清楚一个嵌入式系统就这么简单

    /////////////////////////////////////////
    通常/linuxrc这个文件只有在
    1. 使用了Initial Ramdisk (initrd)
    2. 内核命令行上指定了init=/linuxrc

    两种情况下才有用,mini2440的root_qtopia属于情况2),
    在root_qtopia中,/linuxrc是指向/bin/busybox的符号链接,也就是说,整个文件系统的入口就变成了busybox的
    main()函数,busybox支持这种方式来启动busybox本身和整个文件系统的初始化。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值