本来想把文件系统制作的过程系统的整理一下,发现离最终目的还有一段距离。所以,还是采取边实验边修改,尝试可能情况,最终完成常用的所有功能的移植。这样,在具体应用中只需要做相应的裁减就可以了。为了搞清楚每一个功能部件的依赖关系,要从最小的功能出发,逐步添加功能。
Linux的启动阶段分为两大阶段。第一个阶段从bootloader引导内核,至内核挂载root fs成功为止,这个阶段的一个标志就是如下打印信息:
VFS: Mounted root (jffs2 filesystem). Freeing init memory: 100K
|
第二个阶段分为如下顺序:init --> getty --> login --> shell四个阶段。而成功的打印信息:
当然,根据你设定的shell的PS1,显示也会有所不同。但最终成功都会打印出shell prompt。
init现在力求统一标准,最为常用的还是system V init和busybox init。system V init是host上常用的,也是redhat的默认init。system V init是比较复杂的,支持多级别启动。相对于嵌入式系统来说,有些复杂。busybox只支持一个级别,相对来说,更适合嵌入式系统应用。
login在选择上也有busybox login和tinylogin。而tinylogin要支持的好一点。
shell的选择上有busybox ash,也可以交叉编译出一个bash,这样的话bash的功能要强一点。
(1)创建根文件系统的基本目录结构
这个肯定要参考FHS。最初制作的时候,我认为直接用root用户创建就可以了,这个与host还是比较一致的。
[armlinux@lqm basicfs1]$ tree -L 1 . |-- bin |-- dev |-- etc |-- home |-- lib |-- mnt |-- proc |-- root |-- rootfs |-- sbin |-- sys |-- tmp |-- usr `-- var
|
也写了小的脚本:
[armlinux@lqm fs]$ cat mkrootfs.sh #!/bin/bash # make the basic root file system
# set the target documentation ROOTFS=rootfs TRUE=1 FALSE=0
# check whether the user is the root is_root() { if [ `id -u` == 0 ]; then return $TRUE else return $FALSE fi }
# must be the root if is_root; then echo "Must be root to run this script." exit 1 fi
# create the rootfs mkdir $ROOTFS; cd $ROOTFS
mkdir -p bin dev etc lib/modules proc sbin sys usr/bin usr/lib usr/sbin tmp
# create the basic dev mknod -m 600 dev/console c 5 1 mknod -m 666 dev/null c 1 3
# copy lib cp -av ../simple_fs/lib
cp -av ../simple_fs/etc/* etc/
|
这个制作过程并不复杂。只是在最小的组织上还是有待考虑的。
(2)编译busybox
主要就是修改ARCH和CROSS,然后menuconfig,最后指定路径安装。这里有一个版本对应问题,我是选择了cross-3.4.1,编译没有问题。
|
文件: |
busybox.rar |
大小: |
0KB |
下载: |
下载 | |
(3)编译tinylogin
这里需要注意的是,不采用tinylogin自带的加密算法。需要改动的地方是:
diff -urN tinylogin-1.4.orig/Makefile tinylogin-1.4/Makefile --- tinylogin-1.4.orig/Makefile 2003-01-03 18:56:33.000000000 +0800 +++ tinylogin-1.4/Makefile 2008-03-19 11:00:01.000000000 +0800 @@ -49,12 +49,12 @@ # this adds just 1.4k to the binary size (which is a _lot_ less then glibc NSS # costs). Note that if you want hostname resolution to work with glibc, you # still need the libnss_* libraries. -USE_SYSTEM_PWD_GRP = true +USE_SYSTEM_PWD_GRP = false
# Setting this to `true' will cause tinylogin to directly use the system's # shadow password functions. If you leave this off, tinylogin will use its # own (probably smaller) shadow password functions. -USE_SYSTEM_SHADOW = true +USE_SYSTEM_SHADOW = false
# This enables compiling with dmalloc ( http://dmalloc.com/ )
# which is an excellent public domain mem leak and malloc problem @@ -73,7 +73,7 @@
# If you are running a cross compiler, you may want to set this # to something more interesting, like "powerpc-linux-". -CROSS = +CROSS = /usr/local/arm/3.4.1/bin/arm-linux- CC = $(CROSS)gcc AR = $(CROSS)ar STRIPTOOL = $(CROSS)strip
|
这样就可以使用host的/etc/group /etc/passwd /etc/shadow了。
(3)/etc/下基本配置文件的探讨
如果你在bootloader的命令行参数中没有指定"init=filename",那么首先init默认执行的是/sbin/init,而该程序现在采用的busybox的init,具体的流程为:
·为init设置信号处理流程
·初始化控制台
·剖析inittab文件,/etc/inittab
·根据/etc/inittab文件的设置来进行初始化,缺省情况首先执行/etc/init.d/rcS。
·执行所有会导致init暂停的inittab命令(动作类型:wait)
·执行所有仅执行一次的inittab命令(动作类型:once)
一旦完成,init进程就会循环执行如下工作:
·执行所有终止时必须重新启动的inittab命令(动作类型:respawn)
·执行所有终止时必须重新启动但启动前必须先询问用户的inittab命令(动作类型:askfirst)
其实简单的说,就是找到init,然后读取inittab脚本来执行。如果没有inittab脚本,busybox会按照默认的值进行操作。
这里多说几句的是,no init的错误是很普遍的。主要的原因有:一是没有找到init;二是找了了执行的init,但是没有执行权限,所以还是无法执行;三是找到了init,并且可执行,但是如果是动态编译,对应的共享库有问题的话,也是无法执行程序的。基本的原因就这三个,你当然可以按照最小的文件系统的功能进行测试,只需要一个bin文件(内含sh),一个dev文件夹(内含console),还有一个init脚本,指定exac /bin/sh。测试成功的话,说明你的基本流程可以走通,然后就应该逐步增加功能了。
当然因为后续功能添加的时候,dev中还必须包含null。其他的设备文件则可以通过udev的简化版本mdev来实现了。这个地方需要注意的是mdev对应脚本加载时的初始化顺序是非常重要的,并非随便写。在后面telnet server移植设定的时候就遇到了这个问题。建议读一下mdev.txt,按照上面的流程来写,就没有问题。
·/etc/inittab 这是init读取的第一个文件,语法是比较晦涩的,功能的易读性上也不好。所以它只是提供了一个动作的入口,具体的功能实现都在执行的操作里。
[armlinux@lqm etc]$ cat inittab ::sysinit:/etc/init.d/rcS ::respawn:-/bin/login ::restart:/sbin/init ::ctrlaltdel:/sbin/reboot ::shutdown:/bin/umount -a -r ::shutdown:/sbin/swapoff -a
|
·/etc/init.d/rcS
就是shell脚本了,所有的初始化信息都可以逐步加在这里。初步的rcS参考Tekkaman Ninja的就可以了。这个是我后来完成的一个,仍然是初级脚本。
[armlinux@lqm etc]$ cat init.d/rcS #!/bin/sh # Initial Environment
# mount /etc/fstab spcified device /bin/mount -a
# mount devpts in order to use telnetd /bin/mkdir /dev/pts /bin/mount -t devpts devpts /dev/pts
# read the busybox docs: mdev.txt /bin/mount -t sysfs sysfs /sys /bin/echo /sbin/mdev > /proc/sys/kernel/hotplug /sbin/mdev -s
# when mdev is mounted, /sys can be umounted /bin/umount /sys
# Hostname Setting /bin/hostname listentec
# Network Setting /sbin/ifconfig lo 127.0.0.1 /sbin/ifconfig eth0 192.168.1.100 netmask 255.255.255.0 /sbin/route add default gw 192.168.1.1
# Adjust Time /usr/sbin/ntpdate 210.72.145.44
# NFS client /bin/mount -o nolock,wsize=1024,rsize=1024 192.168.1.106:/home/armlinux/nfs /mnt/nfs /bin/echo "NFS client is on now and the mounted point is /mnt/nfs"
# Print the author information /bin/echo /bin/echo "********************************" /bin/echo " made by lqm " /bin/echo "********************************" /bin/echo
|
·/etc/mdev.conf
这个可以为空,也可以根据mdev的配置语法来编写。但是必须要有,否则就会报错。
·/etc/fstab
这是mount -a要读取的文本。根据需要编写。
[armlinux@lqm etc]$ cat fstab proc /proc proc defaults 0 0 mdev /dev tmpfs defaults 0 0
|
关于login的还有/etc/passwd, /etc/group, /etc/shadow,直接从host拷贝就可以了。
U-Boot 1.3.0 (Mar 18 2008 - 15:25:30)
U-Boot code: 21F00000 -> 21F16EA4 BSS: -> 21F34004 RAM Configuration: Bank #0: 20000000 32 MB Flash: 8 MB In: serial Out: serial Err: serial Hit any key to stop autoboot: 0 ## Booting image at 21000000 ... Image Name: RAM disk Image Type: ARM Linux Kernel Image (gzip compressed) Data Size: 1149858 Bytes = 1.1 MB Load Address: 20008000 Entry Point: 20008000 Verifying Checksum ... OK Uncompressing Kernel Image ... OK
Starting kernel ...
Linux version 2.6.20 (armlinux@lqm) (gcc version 3.4.1) #1 Tue Mar 18 16:53:40 CST 2008 CPU: ARM920T [41129200] revision 0 (ARMv4T), cr=c0003177 Machine: Jinan ListenTec Co. LTD AT91RM9200DK Memory policy: ECC disabled, Data cache writeback Clocks: CPU 179 MHz, master 59 MHz, main 18.432 MHz CPU0: D VIVT write-back cache CPU0: I cache: 16384 bytes, associativity 64, 32 byte lines, 8 sets CPU0: D cache: 16384 bytes, associativity 64, 32 byte lines, 8 sets Built 1 zonelists. Total pages: 8128 Kernel command line: noinitrd root=/dev/mtdblock3 rw rootfstype=jffs2 console=ttySAC0,115200 mem=32M AT91: 128 gpio irqs in 4 banks PID hash table entries: 128 (order: 7, 512 bytes) Console: colour dummy device 80x30 Dentry cache hash table entries: 4096 (order: 2, 16384 bytes) Inode-cache hash table entries: 2048 (order: 1, 8192 bytes) Memory: 32MB = 32MB total Memory: 30012KB available (2108K code, 223K data, 100K init) Mount-cache hash table entries: 512 CPU: Testing write buffer coherency: ok NET: Registered protocol family 16 NET: Registered protocol family 2 IP route cache hash table entries: 1024 (order: 0, 4096 bytes) TCP established hash table entries: 1024 (order: 0, 4096 bytes) TCP bind hash table entries: 512 (order: -1, 2048 bytes) TCP: Hash tables configured (established 1024 bind 512) TCP reno registered NetWinder Floating Point Emulator V0.97 (double precision) JFFS2 version 2.2. (NAND) (SUMMARY) (C) 2001-2006 Red Hat, Inc. io scheduler noop registered io scheduler anticipatory registered (default) AT91 Watchdog Timer enabled (5 seconds, nowayout) atmel_usart.0: ttyS0 at MMIO 0xfefff200 (irq = 1) is a ATMEL_SERIAL atmel_usart.1: ttyS1 at MMIO 0xfffc0000 (irq = 6) is a ATMEL_SERIAL atmel_usart.2: ttyS2 at MMIO 0xfffc4000 (irq = 7) is a ATMEL_SERIAL RAMDISK driver initialized: 16 RAM disks of 8192K size 1024 blocksize loop: loaded (max 8 devices) nbd: registered device at major 43 PPP generic driver version 2.4.2 PPP Deflate Compression module registered PPP BSD Compression module registered PPP MPPE Compression module registered at91_ether: Your bootloader did not configure a MAC address. eth0: Link now 10-HalfDuplex eth0: AT91 ethernet at 0xfefbc000 int=24 10-HalfDuplex (36:b9:04:00:24:80) eth0: Davicom 9161 PHY (Copper) AT91RM9200-NOR:0x00800000 at 0x10000000 NOR flash on AT91RM9200DK: Found 1 x16 devices at 0x0 in 16-bit bank Intel/Sharp Extended Query Table at 0x0031 Using buffer write method cfi_cmdset_0001: Erase suspend on write enabled AT91RM9200-NOR:using static partition definition Creating 5 MTD partitions on "NOR flash on AT91RM9200DK": 0x00000000-0x00020000 : "U-boot" 0x00020000-0x00220000 : "Kernel" 0x00220000-0x00520000 : "RootFS" 0x00520000-0x007e0000 : "Jffs2" 0x007e0000-0x00800000 : "Parameters" at91_cf: irqs det #64, io #0 mice: PS/2 mouse device common for all mice TCP cubic registered NET: Registered protocol family 1 NET: Registered protocol family 17 JFFS2 notice: (1) jffs2_build_xattr_subsystem: complete building xattr subsystem, 0 of xdatum (0 unchecked, 0 orphan) and 0 of xref (0 dead, 0 orphan) found. VFS: Mounted root (jffs2 filesystem). Freeing init memory: 100K init started: BusyBox v1.9.1 (2008-03-20 14:53:52 CST) starting pid 710, tty '': '/etc/init.d/rcS' eth0: Link now 10-HalfDuplex 22 Mar 08:46:50 ntpdate[722]: step time server 210.72.145.44 offset 1206146805.770447 sec NFS client is on now and the mounted point is /mnt/nfs
******************************** made by lqm ********************************
starting pid 732, tty '': '/sbin/telnetd' starting pid 733, tty '': '/bin/login'
listentec login: root login[733]: root login on `console
|
我的引导信息(后来制作的,最初的还没有备份)。