这里的目标是创建一个最小的根文件系统,使其启动后进入shell命令行。
制作步骤:
一、 移植Busybox
Busybox将众多的命令集合进一个很小的可执行程序中,可用来替换GNU fileutils、shellutils等GNU核心工具集,它非常适合用在嵌入式系统。
获取源码:从http://www.busybox.net/downloads/ 下载busybox,我选的是1.15.0版本。
Busybox也有与Linux 内核类似的配置界面,在其顶层目录下执行make menuconfig即可对其配置。如果没有特别的要求,只需注意Build Options的配置选项,它决定busybox是否使用静态链接,其它的先按默认配置即可。
修改busybox顶层目录的Makefile,为ARCH和CROSS_COMPILE变量指定默认值:
ARCH ?=arm
CROSS_COMPILE ?=arm-linux-
执行make,编译busybox。
执行make CONFIG_PREFIX=/opt/nfsshare/fs_mini/ install,将busybox安装在/opt/nfsshare/fs_mini/目录之下,生成bin/、sbin/、usr/三个目录和一个链接文件linuxrc。
注意生成的linuxrc文件,它是bin/busybox这个可执行程序的符号链接,从uboot传给kernel的命令行参数可知,bin/busybox就是kernel启动所需的init程序。
二、 安装glibc库
对Build Options选项,如果指定静态链接,最好使用uclibc库,因为glibc库较大,不适合惜寸土如金的嵌入式系统。我这里选择动态链接,使用glibc库,因为glibc库提供的接口实现更加全面。
glibc库的来源可以是自己制作交叉编译工具链时生成的,也可以从http://ftp.gnu.org/gnu/glibc/中下载所需的版本,然后在某个目录下编译安装它。我就图个省事,直接从已经安装好的交叉编译工具链的相应目录下找到。有了glibc库,就可以把里面需要的文件拷贝到所构建的根文件系统lib目录下。(glibc库下的文件较多,有些是gcc工具本身生成的,并不属于glibc库,目前我只把重要的文件拷贝过去。)
我使用的工具链版本是4.3.2,它所使用的是glibc库是2.8版本,glibc库分布在两个不同的目录下:
/usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/armv4t/lib/
/usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/armv4t/usr/lib/
低级的版本一并放在一个目录,如:
/usr/local/arm/3.4.1/arm-linux/lib/
在fs_mini目录下新建lib/目录,将常用的库文件拷贝过去,包括加载器和常用的动态库:
ld-2.8.so ld-linux.so.3
libc-2.8.so libc.so.6
libm-2.8.so libm.so.6
libcrypt-2.8.so libcrypt.so.1
以上四对文件中,后者均是前者的符号连接。
对于busybox可执行程序,使用arm-linux-readelf –d busybox命令查看其依赖的动态库有libc.so.6和libm.so.6。
三、 构建根文件系统
继续构造最小根文件系统所需要的目录及相应文件。
1. etc/:
inittab文件——init进程根据该文件创建其它子进程,如调用脚本文件,启动shell等:
# /etc/inittab
::sysinit:/etc/init.d/rcS
s3c2410_serial0::askfirst:-/bin/sh
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a –r
fstab文件——指明当执行“mount –a”时,需要挂接的文件系统:
# 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
./init.d/rcS文件——shell脚本文件:
#!/bin/sh
ifconfig eth0 192.168.115.130
mount –a #挂接fstab文件指定的所有文件系统
mkdir /dev/pts
mount -t devpts devpts /dev/pts #支持外部网络连接(telnet)的虚拟终端
echo /sbin/mdev > /proc/sys/kernel/hotplug #有设备插拔时调用/bin/mdev程序
mdev –s #在/dev目录下生成内核支持的所有设备结点
2. dev/:使用mdev创建该目录下的设备文件,首先建立/dev目录。
udev是个用户程序,依赖于内核支持的sysfs文件系统,它能够根据系统中硬件设备的状态动态地更新设备文件,包括设备文件的创建、删除等。mdev是udev的简化版本。为减少对Nand Flash的读写,上面的fstab文件已设置将/dev挂载为tmpfs文件系统。
mdev是通过init进程来启动的,在使用mdev构造/dev之前,init进程至少要用到设备文件/dev/console、/dev/null,所以,在/dev目录下:
mknod console c 5 1
mknod null c 1 3
3. proc/、mnt/、tmp/、sys/、root/等:均为空目录
以上就在fs_mini目录下构建好了最小根文件系统,开发板可以将它作为网络根文件系统直接启动,若要烧入Nand Flash,还要就将它制作为映像文件。
四、 制作并烧写yaffs文件系统映像文件
制作不同类型的文件系统映像文件需要使用不同的工具,对于yaffs文件系统,其制作工具的源码在yaffs源码下的utils目录里,两个.c文件mkyaffsimage.c和mkyaffs2image.c分别能被编译成mkyaffsimage和mkyaffs2image两个工具,前者用来制作yaffs1映像文件,后者用来制作yaffs2映像文件。
起初,我想在我的系统上使用yaffs2文件系统,于是使用mkyaffs2image工具:
mkyaffs2image fs_mini rootfs.yaffs
打开tftp服务器,烧写过程如下:
tftp 0x33000000 rootfs.yaffs
nand erase 0x00400000 0x02800000
nand write.yaffs 0x33000000 0x00400000 $(filesize)
注:$(filesize)是rootfs.yaffs映像文件的大小,根据yaffs文件系统的特点,其值必须是Nand Flash的页大小(包括OOB区大小)的整数倍,对于64M的Nand Flash,应为528(512+16)的整数倍(还有页大小为(256+8)、(2048+64)的Nand Flash)。
然后通过boot命令启动系统,似乎根文件系统的制作将告一段落,而实际上,根本不是如我所愿,系统的启动信息让人大失所望,这也预示,接下来的工作绝不会一帆风顺。今年的“两会”刚刚闭幕,温总理就在中外记者会上引用古语:“行百里者半九十”。这提醒我们,在工作完成之前,绝不能高兴太早,更多的荆棘与挑战还在后头。
首先,上面的启动信息中,包含一堆系统检测出的坏块提示,而且提示的坏块均位于烧写yaffs的分区。经过一番百度后,得知这些坏块均是假坏块(Nand Flash若有坏块,在芯片出厂时就做了标记,不过一般寥寥无几,或者没有),也不奇怪,Nand Flash在使用中哪有那么容易出现坏块呢!然而,具体是什么原因造成这么多的假坏块,我折腾了很久也没有个结果。后来分析,既然系统检测出来的是坏块,那一定是那些块的OOB区里被设置了坏块标记(通常OOB区里存放坏块标记、ECC校验码和yaffs相关的信息标记tag)。yaffs文件系统映像文件的格式比较特别,文件本身就包含了OOB区数据,所以Nand Flash里的yaffs分区的OOB区的信息全部来自yaffs映像文件本身,问题就出在所烧写的rootfs.yaffs文件。那进一步想想,导致rootfs.yaffs出问题的罪魁祸首只可能在这三个之中:所制作的根文件系统fs_mini、uboot里的yaffs烧写命令nand write.yaffs、rootfs.yaffs的制作工具mkyaffs2image。不过,一般根文件系统如果制作的有问题,只会影响最终的启动,如init进程能否成功运行,文件系统能否成功挂载,不会影响烧写到OOB区的信息。对于uboot的nand write.yaffs命令,深入到其函数代码查看,似乎也没什么破绽。那难道是mkyaffs2image工具出了问题?但自己又懒得去看mkyaffs2image.c里的代码(其实如果看了也如同“鸡蛋里挑骨头”,无济于事)。一时问题陷入了僵局。不过,我还没放弃网络搜索,继续百度之…
一个偶然的帖子引起了我的注意,其实不是就我的问题而问,但它让我发现了我的一个认识错误。原来我的mkyaffs2image工具只能制作页大小为(2048+64)的yaffs2文件系统,所以必须烧写到128M或以上的Nand Flash才行。要获得页大小为(512+16)的yaffs2文件系统,即烧写到64M的Nand Flash中的,需要专门的yaffs2映像制作工具,友善有这个工具:mkyaffs2image-64M,不过我也没找到。后来从优快云上下到了由广州天嵌计算机科技有限公司制作的一套工具,里面有mkyaffs2image-64M。
在烧写yaffs映像之前,先得将上面造成的假坏块消除掉,而nand erase命令不会对标记为坏块的那些块进行操作,即跳过那些块;nand scrub命令会试图对标记为坏块的块进行擦除,这样可以把误标记的块擦成好块,不过也可能把出厂标记为坏块的那些标记擦掉,造成坏块变成好块,所以也慎用。还好,我的Nor Flash里还有supervivi,使用分区命令:bon part 0,就起到格式化整个Nand Flash芯片的作用,假坏块自然就化为乌有了。
随后问题就柳暗花明,使用makeyaffsimage-64M工具来制作yaffs2文件系统映像。结果,启动信息中再没有假坏块的提示了。这个问题搞定!
不过此时的启动信息中,没有yaffs根文件系统成功挂载的信息,却多了如下错误:
uncorrectable error : <3>uncorrectable error : <3>end_request: I/O error, dev mtdblock3, sector 64
isofs_fill_super: bread failed, dev=mtdblock3, iso_blknum=16, block=32
对于这个错误,是因为我把内核配置了下面的第二个选项:
--- NAND Device Support
[*] Verify NAND page writes
[ ] NAND ECC Smart Media byte order
上面的第一项是否选上不影响启动,但第二项不要选上,没搞清为什么,哪位大侠知道指出来,先谢了。
之后的启动信息阻塞在下面一句(此时yaffs文件系统已挂载),表明init进程不能成功启动:
Kernel panic - not syncing: Attempted to kill init!
出现这种现象一般都与带有EABI的工具链有关,所以要把内核的支持EABI的配置选项选上:
Kernel Features --->
[*] Use the ARM EABI to compile the kernel
[*] Allow old ABI binaries to run with this kernel (EXPERIMENTA)
因为采用的工具链支持EABI,内核编译时也要选上,否则用这个编译器编出来的用户程序无法运行,最典型的错误是busybox无法运行。
若还存在同样的问题,就可能是busybox采用动态链接而lib/库加的不正确,对于arm-linux-gcc-4.3.2工具链,其libc目录下包含三个不同用途的glibc库(不知为什么要这样划分,而以前的非EABI工具链只有一个),对于Samsung S3C2440A,必须使用libc/armv4t下的glibc库。
这个问题解决后,系统启动便畅通无阻,顺利进入了shell命令行,至此,最小根文件系统的制作在经历一番曲折后终于完成。以下是最终的系统启动信息:
Starting kernel ...
Uncompressing
Linux..............................................................................................................
........ done, booting the kernel.
Linux version 2.6.29.4 (root@My-Fedora-10) (gcc version 4.3.2 (Sourcery G++ Lite 2008q3-72) ) #7 Sun Mar 14
15:21:55 CST 2010
CPU: ARM920T [41129200] revision 0 (ARMv4T), cr=c0007177
CPU: VIVT data cache, VIVT instruction cache
Machine: SMDK2440
Memory policy: ECC disabled, Data cache writeback
CPU S3C2440A (id 0x32440001)
S3C24XX Clocks, (c) 2004 Simtec Electronics
S3C244X: core 405.000 MHz, memory 101.250 MHz, peripheral 50.625 MHz
CLOCK: Slow mode (1.500 MHz), fast, MPLL on, UPLL on
Built 1 zonelists in Zone order, mobility grouping on. Total pages: 16256
Kernel command line: noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0
irq: clearing subpending status 00000003
irq: clearing subpending status 00000002
PID hash table entries: 256 (order: 8, 1024 bytes)
Console: colour dummy device 80x30
console [ttySAC0] enabled
Dentry cache hash table entries: 8192 (order: 3, 32768 bytes)
Inode-cache hash table entries: 4096 (order: 2, 16384 bytes)
Memory: 64MB = 64MB total
Memory: 61012KB available (3364K code, 323K data, 144K init)
Calibrating delay loop... 201.93 BogoMIPS (lpj=504832)
Mount-cache hash table entries: 512
CPU: Testing write buffer coherency: ok
net_namespace: 716 bytes
NET: Registered protocol family 16
S3C2410 Power Management, (c) 2004 Simtec Electronics
S3C2440: Initialising architecture
S3C2440: IRQ Support
S3C24XX DMA Driver, (c) 2003-2004,2006 Simtec Electronics
DMA channel 0 at c4808000, irq 33
DMA channel 1 at c4808040, irq 34
DMA channel 2 at c4808080, irq 35
DMA channel 3 at c48080c0, irq 36
S3C244X: Clock Support, DVS off
bio: create slab <bio-0> at 0
SCSI subsystem initialized
usbcore: registered new interface driver usbfs
usbcore: registered new interface driver hub
usbcore: registered new device driver usb
NET: Registered protocol family 2
IP route cache hash table entries: 1024 (order: 0, 4096 bytes)
TCP established hash table entries: 2048 (order: 2, 16384 bytes)
TCP bind hash table entries: 2048 (order: 1, 8192 bytes)
TCP: Hash tables configured (established 2048 bind 2048)
TCP reno registered
NET: Registered protocol family 1
NetWinder Floating Point Emulator V0.97 (extended precision)
JFFS2 version 2.2. (NAND) (SUMMARY) ?? 2001-2006 Red Hat, Inc.
yaffs Mar 14 2010 14:18:23 Installing.
msgmni has been set to 119
io scheduler noop registered
io scheduler anticipatory registered (default)
io scheduler deadline registered
io scheduler cfq registered
Console: switching to colour frame buffer device 30x40
fb0: s3c2410fb frame buffer device
lp: driver loaded but no devices found
ppdev: user-space parallel port driver
Serial: 8250/16550 driver, 4 ports, IRQ sharing enabled
s3c2440-uart.0: s3c2410_serial0 at MMIO 0x50000000 (irq = 70) is a S3C2440
s3c2440-uart.1: s3c2410_serial1 at MMIO 0x50004000 (irq = 73) is a S3C2440
s3c2440-uart.2: s3c2410_serial2 at MMIO 0x50008000 (irq = 76) is a S3C2440
brd: module loaded
loop: module loaded
dm9000 Ethernet Driver, V1.31
Uniform Multi-Platform E-IDE driver
ide-gd driver 1.18
ide-cd driver 5.00
Driver 'sd' needs updating - please use bus_type methods
S3C24XX NAND Driver, (c) 2004 Simtec Electronics
s3c2440-nand s3c2440-nand: Tacls=3, 29ns Twrph0=7 69ns, Twrph1=3 29ns
NAND device: Manufacturer ID: 0xec, Chip ID: 0x76 (Samsung NAND 64MiB 3,3V 8-bit)
Scanning device for bad blocks
Bad eraseblock 2182 at 0x000002218000
Creating 5 MTD partitions on "NAND 64MiB 3,3V 8-bit":
0x000000000000-0x000000080000 : "Uboot"
0x000000080000-0x000000100000 : "Env Data"
0x000000100000-0x000000400000 : "Kernel"
0x000000400000-0x000002c00000 : "Yaffs"
0x000002c00000-0x000004000000 : "App"
usbmon: debugfs is not available
ohci_hcd: USB 1.1 'Open' Host Controller (OHCI) Driver
s3c2410-ohci s3c2410-ohci: S3C24XX OHCI
s3c2410-ohci s3c2410-ohci: new USB bus registered, assigned bus number 1
s3c2410-ohci s3c2410-ohci: irq 42, io mem 0x49000000
usb usb1: configuration #1 chosen from 1 choice
hub 1-0:1.0: USB hub found
hub 1-0:1.0: 2 ports detected
usbcore: registered new interface driver libusual
usbcore: registered new interface driver usbserial
USB Serial support registered for generic
usbcore: registered new interface driver usbserial_generic
usbserial: USB Serial Driver core
USB Serial support registered for FTDI USB Serial Device
usbcore: registered new interface driver ftdi_sio
ftdi_sio: v1.4.3:USB FTDI Serial Converters Driver
USB Serial support registered for pl2303
usbcore: registered new interface driver pl2303
pl2303: Prolific PL2303 USB to serial adaptor driver
mice: PS/2 mouse device common for all mice
S3C24XX RTC, (c) 2004,2006 Simtec Electronics
s3c2440-i2c s3c2440-i2c: slave address 0x10
s3c2440-i2c s3c2440-i2c: bus frequency set to 98 KHz
s3c2440-i2c s3c2440-i2c: i2c-0: S3C I2C adapter
S3C2410 Watchdog Timer, (c) 2004 Simtec Electronics
s3c2410-wdt s3c2410-wdt: watchdog inactive, reset disabled, irq enabled
TCP cubic registered
NET: Registered protocol family 17
RPC: Registered udp transport module.
RPC: Registered tcp transport module.
drivers/rtc/hctosys.c: unable to open rtc device (rtc0)
yaffs: dev is 32505859 name is "mtdblock3"
yaffs: passed flags ""
yaffs: Attempting MTD mount on 31.3, "mtdblock3"
yaffs: block 1926 is marked bad
block 1927 is bad
yaffs_read_super: isCheckpointed 0
VFS: Mounted root (yaffs filesystem) on device 31:3.
Freeing init memory: 144K
ifconfig: SIOCSIFADDR: No such device
Please press Enter to activate this console.
/ #
最小系统是搭建起来了,但它还不是健全的,一些外设仍不能拿来就用,如eth0、USB、LCD、LED等,因为这些硬件在系统启动时还没有初始化或正确初始化,虽然一些驱动已编译进内核。所以,要针对mini2440这个平台,修改内核的初始化部分,使系统启动时,以上硬件的驱动初始化程序能正确初始化硬件,即硬件被识别,这样,才能在这个嵌入式平台上进行后续的各种各样的开发。