一、补充文件系统知识
Linux根文件系统是
存放tool软件、lib文件、script(脚本)、配置文件、其他特殊文件、自己开发的应用程序的地方。嵌入式linux的根文件系统rootfs就像windows操作系统的C、D盘这种概念机制,FLASH对应硬盘。但linux是挂载点的概念,根文件系统是一个整体,组织到一个树状的目录结构中。这种文件组织遵守文件系统科学分类标准FHS,一种国际标准。运行、维护系统所必须的各种
在开发、测试阶段,基本上都是使用NFS(网络文件系统),NFS文件系统是在你的开发主机HOST里,不是在你的板子里。制作嵌入式产品根文件系统,就是要把NFS指向的文件系统文件夹里所有的内容,通过其他少数几种的Linux文件系统打包生产一个2进制镜像文件,然后以某种方式烧写到FLASH芯片内。开发阶段,特别是应用程序开发、动态加载的驱动模块开发,使用NFS,可以省去麻烦的根文件系统镜像文件的下载和烧写过程,便可以在自己板子上运行这些开发的程序和模块。
Linux支持超过50种文件系统,但是只有少数几种在嵌入式OS中常用,见下图。linux嵌入式产品的根文件系统是需要烧写到Flash芯片里。
Cramfs文件系统:(Compressed ROM File System)是个简单,压缩的,只读的文件系统。除了可以用于MTD下只读并且极少更新img的NOR/NAND,IDE的CF,FTL/NFTL的NOR/NAND,可作为RAM disk的IMG存储。由于简单,Cramfs有一些限制,例如最大支持16M(?256M),没有当前(.)和父(..)目录,页大小固定为4096,gid(8位)最大为255,所有的链接文件计数都是1等等。在cramfs文件系统中,每一页(4KB)被单独压缩,可以随机页访问,其压缩比高达2:1,为嵌入式系统节省大量的Flash存储空间,使系统可通过更低容量的FLASH存储相同的文件,从而降低系统成本。Cramfs文件系统以压缩方式存储,在运行时解压缩,所以不支持应用程序以XIP方式运行,所有的应用程序要求被拷到RAM里去运行,但这并不代表比Ramfs需求的RAM空间要大一点,因为Cramfs是采用分页压缩的方式存放档案,在读取档案时,不会一下子就耗用过多的内存空间,只针对目前实际读取的部分分配内存,尚没有读取的部分不分配内存空间,当我们读取的档案不在内存时,Cramfs文件系统自动计算压缩后的资料所存的位置,再即时解压缩到RAM中。另外,它的速度快,效率高,其只读的特点有利于保护文件系统免受破坏,提高了系统的可靠性。由于以上特性,Cramfs在嵌入式系统中应用广泛。但是它的只读属性同时又是它的一大缺陷,使得用户无法对其内容对进扩充。
制作Cramfs根文件系统命令如下:
#mkcramfs [-h] [-e edition] [-i file] [-n name] dirname outfile
mkcramfs的各个参数解释如下:
-h:显示帮助信息
-e edition:设置生成的文件系统中的版本号
-i file:将一个文件映像插入这个文件系统之中(只能在Linux2.4.0以后的内核版本中使用)
-n name:设定cramfs文件系统的名字
dirname:指明需要被压缩的整个目录树
outfile:最终输出的文件
cramfsck的命令格式:
cramfsck [-hv] [-x dir] file
cramfsck的各个参数解释如下:
-h:显示帮助信息
-x dir:释放文件到dir所指出的目录中
-v:输出信息更加详细
file:希望测试的目标文件
例子:
#mkcramfs rootfs rootfs.cramfs生成rootfs.cramfs文件系统镜像.其中rootfs是你调试的根文件系统的文件夹,rootfs.cramfs是生产镜像文件的名字。
Squashfs文件系统:是压缩的只读的fs,保留了Cramfs很多优点,去掉它的限制。压缩比更高。是一个不错的文件系统。命令为:#mksquashfs [source] [dest]
JFFS2文件系统:可写、保留数据、压缩、掉电保护,提供wear leveling,适合板载NOR、NAND和Doc。JFFS2提供垃圾回收机制,通常可以很好地工作。但是当文件系统接近极限或者要求更新一个非常大的文件,垃圾回收的时间会很长,将会延迟文件系统的操作,这会对没有考虑到这种情况的某些实时要求的软件带来负面的影响。当空间满的时候,尝试更新或者阶段文件内容会被提示文件系统已满并失败,即使看起来不要求添加存储block,这是因为日志结构文件系统,需要在log中增加log。在使用的时候,我们应保证存储空间的充足,上面的应用能够容忍时延(避免快满时候垃圾回收的消耗影响)。 JFFS2用途很广,但是对于现在容量巨大的闪存不适合,新的UBI文件系统出现。JFFS2的不可扩展性是最大的问题,作为JFFS2的升级,JFFS3支持大容量的闪存。JFFS2使用MTD工具:
#mkfs.jffs2 –r ottfs/ –o images/rootfs-jffs2.img –e 128kiB 其中
128是指擦写block的大小,如果超过实际闪存的大小,会引起文件系统的崩溃,如果太小,block内有部分存储空间没能利用。
#sumtool –i rootfs-jffs2.img –o rootfs-jffs2-summed.img –e 128KiB 增减
erase block的summary node。
YAFFS2文件系统:是可写,下电保护的文件系统,广泛引用于Linux和RTOSeS。和JFFS2相比,它减少一些功能,因此速度更快、占用内存资源更少。YAFFS2自带NAND芯片的驱动,是专门为NAND闪存设计的。以前的YAFFS只支持512-BYTE/Page的NAND,而YAFFS2不但兼容512-BYTE/Page,还支持目前流行的2048-BYTE/Page大容量NAND FLASH。YAFFS2文件系统的镜像工具是mkyaffs2img。随便在GOOGLE上输入mkyaffs2img就可以找到满屏幕的制作方法,这里不用介绍。
RAMFS文件系统:
讨论RAMFS,就不得不讨论RAM disk,在RAM中,而作为一个block设备,内核可以同时支持多个RAM disk。通常用于保存磁盘文件系统中压缩的img。这在嵌入式操作系统的初始化中使用,kernel可以从存储设备中提取initial RAM disk(initrd)img作为的他的根文件系统。一开始,kernel根据boot的参数是否表面intrid,如果是,他将从特定的存贮介质提取文件系统的img并放入RAM disk,同时mount为根文件系统。initrd的机制是以最简单的方式提供一个带根文件系统的内核在RAM中。对于新的系统,推荐使用Initramfs机制。
Tmpfs文件系统:也是RAM disk的一种,可以使用物理内存,是一个存放在虚拟memory的文件系统,不提供永久保存,适合于存储临时的数据,例如/tmp,用于Linux的page cache和dentry chache。
RAM disk的特点就是速度快,因为在RAM运行的。缺点就是每次重新启动系统时,前面的工作就无法保存。创建RAM Disk使用的命令式mke2fs。
有关嵌入式常用的文件系统详细介绍和制作命令、方法,大家可以在网上搜索得到。
二、TI davinci根文件系统target介绍
在mv_pro_5.0.0/montavista/pro/devkit/arm/v5t_le目录下,有个target的文件夹,这个就是TI EVM的根文件系统了。Target里的内容,见下图,本人是单独COPY出来到自己工作目录下,这点在《开发环境篇》有介绍。TI在这个target文件系统包里放置很多开发工具,其实就是一个开发应用程序的环境,你进到usr目录下就明白这点,里边包括交叉编译命令、很多头文件和应用程序的源代码、usr/lib里的lib文件,等等。其实这些东西肯定是不能全部烧到自己的板子里的。单单这个usr里相关的文件大小就达1G!!!因为TI EVM东西多,复杂,所以我们裁减的时候,最好做好备份。当然,有些朋友是自己手动重新制作根文件系统,再借助“Busybox”这个大名鼎鼎的嵌入式linux瑞士军刀,一个精简的文件系统就出来了。本人在S3C2440、2410的板子上玩过,挺不错的,非常精简。本文暂且不讨论这种方法。
三、TI davinci根文件系统target的裁减
进入自己工作的target文件夹里,见上图:
bin文件夹:里边主要是一些linux shell命令,所有用户都可以使用的、基本的命令,都是很基本的东西,暂时不用动它,保留。
boot文件夹:是存放编译内核的一些相关文件,比如uImage等,这些东西没必要放到板子上的文件系统里,删除掉。
dev文件夹:存放非常多的设备节点,如果你对这些节点不是很熟悉,分不清哪些是你系统用到的,哪些是不用的,可以保留,整个dev只有16~17k的大小。当然节点太多也不好。
etc文件夹:存放很多启动的脚本文件、系统配置文件,这是下面移植要讨论的重点。整个文件夹有6~7M,像samba、apt这种在普通嵌入式产品不常用的东西可以删除掉。如果产品不是带LCD图像界面的产品,X11(
X Window 系统版本 11,简称 X11,是一个对网络透明的客户/服务器架构的图形显示系统。它支持应用程序在你的屏幕上绘制象素,线条,文字,图象等等。 X11 还包括一些其它的辅助的函数库,使得它可以容易地绘制用户界面,例如:按钮,文本输入区等等)这个可以删除掉,单这个文件夹就有2.85M。
home文件夹:空的文件夹,系统运行会用到,普通用户的主目录,一定要保留。
lib文件夹:很多工具和应用程序使用的库文件,不是高高手,最好不要删掉里边的文件。
media文件夹:空的文件夹,保留。
mnt文件夹:空文件夹,以后使用U盘和SD卡时,会挂到该目录,所以保留。
opt文件夹:空文件夹,自己开发的一些应用程序可以放到这里,比如TI evm的一些应用程序就放在/opt/dvsdk/dm6446/,存放encode,decode,encodedecode的应用程序,等等。
proc文件夹:空的文件夹,系统运行会用到,proc文件系统的挂载点,保留。
root文件夹:空的文件夹,系统运行会用到,root用户的主目录,一定要保留。
sbin文件夹:存放很多工具和基本的系统命令,它们用于启动系统、修复系统,在嵌入式产品里,可以把不常用的mkfs.xx的文件全部去掉。其他有很多工具和命令,要根据你自己的产品,不用到的都删掉,裁减sbin建议再单独备份一下sbin,通过NFS,一边删除,一边测试,保证删除掉后你的产品还很好地工作。这是一种笨办法,毕竟要全部理解里边的每个命令和工具的作用也需要很多时间。建议这个文件夹最好不要动太多手脚。
srv文件夹:空的文件夹,保留。
sys文件夹:空的文件夹,系统运行会用到,比如sysfs,保留。
tmp文件夹:空的文件夹,系统运行会用到,存放临时文件,保留。
usr文件夹:上面提到,这个文件有很多在产品出厂不用到的东西,armv5tl-montavista-linux-gnueabi文件夹直接删除掉;bin文件夹里的arm_v5t_le-XXXXX和armv5tl-montavista-linux-gnueabi-XXX也去掉吧;include、local、share、src、X11R6文件夹全部去掉;Usr/lib/tcng/test干掉;然后根据自己产品的,像perl5、python2.4、X11等等,不用到就搞定它们。笨办法就是使用NFS和板子共同测试,这样下来usr就小多了。
var文件夹:存放可变的数据,var/cache/cracklib里的文件很大,不知在TI EVM有什么用,本人不用;varlib
pm里的文件本人也不用;var/www/html/manual是在开发html的时候用到,本人不用。这几个都是var里耗空间的文件夹。另外,在使用NFS调试的时候,var/log下的文件会保存每次内核启动的打印信息,测试多了,debug,kern.log,messages等文件也加大,所以制作时要注意这些文件的裁减。
按照上面的动作下来,一个可以用的根文件系统也出来了,但还不是简洁高效的,有些东西还得根据自己的板子要支持的功能选择性保留和裁减。有些工具、命令、应用程序开始没用到,但是后来升级产品会用到,所以,裁减要有针对性和规划性。特别是有些产品使用小于等于64M NAND的嵌入式产品,要做的工作就更多,这里仅供学习和参考。
四、TI davinci根文件系统target的移植
1、系统的分区:
在linux-2.6.18移植的博客文章介绍了FLASH的分区,这里就不用重复了,一般分区是: Bootloader(UBL+U-BOOT)+参数 为mtdblock0,kernel为mtdblock1,根文件系统rootfs为mtdblock2。也有这样分的:Bootloader(UBL+U-BOOT) 为mtdblock0,参数为mtdblock1,kernel为mtdblock2,根文件系统为mtdblock3。Bootloader要从FLASH 加载根文件系统,比如jffs2的根文件系统,u-boot的bootargs应该是:mem=118M console=ttyS0,115200n8 rootfstype=jffs2 root=/dev/mtdblock2 noinitrd rw ip=off或者是其他类型的文件系统。同时,u-boot对根文件系统的烧写要支持,因为jffs2,cramfs,yaffs2等每种文件系统的烧写格式都不一样,烧写的地址一定要和内核的FLASH分区地址一一对应。(补充:在DVSDK2.0中,U-BOOT的参数mem=118M,不再是120M,因为TI DVSDK2.0 CODEC ENGINE要求分配给cmem的大小是10M)。
2、内核选择支持对应的文件系统
通过make menuconfig的配置界面,你的板子要支持什么样的文件系统,是cramfs,Squashfs,jffs2还yaffs2,则要对对MTD等相关选项进行选择,见linux-2.6.18移植的博客。
3、对根文件系统权限操作
Target下每个目录的权限不是全部一样的,根据自己的文件系统的类型,比如yaffs2,tmp、var等目录可以使用chmod –R 777 tmp , chmod –R 777 var命令设置,文件夹域的设置使用chown的命令。为什么要这样强调呢?也许很多人调试DAVINCI 板子会碰到:Starting OpenBSD Secure Shell server: sshd/var/empty/sshd must be owned by root and not group or world-writable. failed (255: ).这个就是根文件系统权限和域得设置有问题。
4、etc目录下的移植
A、拷贝你的LINUX开发主机etc目录下的passwd、group、shadow文件到etc目录下。这样目标板就使用和你LINUX主机一样的登录账号和密码了。如果passwd、group、shadow被破坏了,如何都进不去板子的shell命令行,而且你的产品没有严重网络安全要求,这里还有一个绝招:把target/etc 下的securetty文件改个名字,不用securetty就可以了,这样输入账号直接回车就可以了。
B、etc目录下新建一个目录sysconfig,并新建文件HOSTNAME,内容为“你公司名字或你喜欢的名字”。同时在etc/init.d/下RcS文件最后面加入:/bin/hostname –F /etc/sysconfig/HOSTNAME,在profile最后面加入:
USER="`id -un`" (注意 ` 是键盘1旁边的 ` )
LOGNAME=$USER
PS1='[u@h W]# ' (注意 ‘ 是键盘 ; 旁边的 ‘ 在linux文件下显示不一样)
PATH=$PATH
HOSTNAME=`/bin/hostname` (注意 ` 是键盘1旁边的 ` )
export USER LOGNAME PS1 PATH
这样在板子上进入shell的命令行时,会显示“[root@你定义的名字~]#”的格式。
C、etc/fstab文件修改:目前这个本人直接使用TI的,但是自己的产品有时会定义
sysfs
/sys sysfs noauto 0 0
tmpfs
/dev/shm tmpfs noauto 0 0
目前没有验证,如果哪个网友对这方面熟悉,可以在博客上讨论。
D、流程介绍
根文件系统挂接到VFS(linux虚拟文件系统,一种软件接口机制,原理这里不描述)成功后,会根据脚本和配置一步一步运行。我们可以通过以下流程去熟悉:
先看inittab
次看init.d/rcS
然后etc/rc.d/rcS.d,rcS.x等文件,开机是启动/etc/rc.d/rcS.d/下的脚本,然后是/etc/rc.d/rc3.d/下的脚本。只需把用户的程序编译称shell脚本,放在rc3.d下面就可以了。
S开头的脚本基本上是系统运行初始化要做的工作,K开头就是关机要做的工作。
客户如果要在开机运行自己的某些应用程序,也可以修改etc/init.d/rcS,在
for i in /etc/rc.d/rcS.d/S??*
do
# Ignore dangling symlinks for now.
[ ! -f "$i" ] && continue
case "$i" in
*.sh)
# Source shell script for speed.
(
trap - INT QUIT TSTP
set start
. $i
)
;;
*)
# No sh extension, so fork subprocess.
$i start
;;
esac
done
在这后面加自己的运行命令就可以了。
E、制作根文件系统映像文件
就是使用mkcramfs、mkyaffs2image这些命令对整个修改的target文件进行镜像打包了,格式上面已经介绍了。
五、点评
以上是本人的经验之谈,肯定有描述不足的地方,希望网友能在博客里指出来,大家一起学习。到目前为止,有关DM6446开发攻略的主架构的文章,基本上接近尾声,最后1篇,有关自己开发的GPIO驱动移植的文章,近期也会出来。以后要写也是某个环节的补充。其实写这些文章,就是希望有这方面的开发高手过来点评一下,指出不足和错误的地方。毕竟本人在这方面还有很多东西要学习。