这里的目标是创建一个最小的根文件系统,使其启动后进入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,不过我也没找到。后来从CSDN上下到了由广州天嵌计算机科技有限公司制作的一套工具,里面有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这个平台,修改内核的初始化部分,使系统启动时,以上硬件的驱动初始化程序能正确初始化硬件,即硬件被识别,这样,才能在这个嵌入式平台上进行后续的各种各样的开发。