移植根文件系统(关于嵌入式文件系统的知识这里推荐一篇文章:http://blog.chinaunix.net/u2/61663/showart_481219.html),系统启动的最后一个环节就是挂载根文件系统,根文件系统是对Linux进行文件操作的基础,根文件系统的目录结构和PC中Linxu的文件系统结构是相似的。在嵌入式上根文件系统是运行在Flash中的,所以必须挂载支持Flash读写的根文件系统,已知的有CRAMFS,JFFS,等,他们各有特点,这里采用比较先进的YAFFS文件系统。
a) 现在yaffs的移植变的很简单了,只要下载yaffs源码包然后给内核打上yaffs补丁就可以了。
b) 到下载源码包;
c) 解压源码包并进入解压后的yaffs2目录执行补丁脚本:
#tar zxvf root.tar.gz
#cd yaffs2
#./patch-ker.sh c /opt/linux-2.6.25.8
///opt/linux-2.6.25.8是要打补丁的内核源文件目录
此时在内核的/fs/目录下将能看到添加了一个yaffs2的目录,同时/fs/目录下的Makefile和Kconfig文件也已添加了yaffs2的配置和编译条件。【yaffs1和yaffs2的区别好像是在对NANDFlash块大小的支持上不同,yfss2可以支持更大的块】
d) #make menuconfig进入配置菜单,添加支持yaffs根文件系统“File systems——Miscellaneous filesystems——YAFFS2 file system support——在512byte/page devices中选择Let Yaffs do its own ECC,在2018byte(ro larger)/page devices中选择Disable lazy loading、Turn off wide tnodes、Force chunk erase check”
e) 保存配置菜单为.config然后重新编译,此时内核已经能够支持YAFFS根文件系统了。
6、 制作YAFFS根文件系统【对根文件系统还不是很清楚,对其在嵌入式Linux中扮演的角色还不明白】。首先需要用busybox编译出文件系统所需要的应用程序,其实busybox就是一个微型linux工具命令集合,我们在嵌入式Linux上如果要实现不同的命令的话就要拷贝或重新编译PC上/bin目录下的相关命令或文件,这样的话每个命令的可执行文件多是很大的,命令一多文件系统就变得异常庞大,这对嵌入式系统是不可取的。Busybox将所有命令编译成一个busybox可执行文件总大小最多才2M左右,而且一般只有几百KB,不同的命令都是连接到busybox可执行文件上的,我们只需再对照Linux增加一些必须的文件就可以构成一个基本的Linux系统了,这些文件和命令就称为根文件系统。
a) 到获取BusyBox源码;
b) 解压:#tar jxvf busybox-1.14.1.tar.bz2 –C /FamilyGate/
c) 修改顶层Makefile,更改交叉编译器版本和目标体系结构【应该是可以不改的,因为我已在系统中设置了环境变量了】:164行和189行
CROSS_COMPILE ?=/opt/eldk/usr/bin/arm-linux-
ARCH ?= arm
d) #make menuconfig进行配置,适当去掉一些没必要的命令可以减小busybox的体积!在Installation Options选项下可以设置安装路径。
e) 编译:#make&&make install,编译完后生成目录_install,若采用静态方式编译则自己写的arm-linux程序在这个根文件系统中是不能运行的,因为缺少共享程序库的支持。
如果选择Busybox Settings—Build Options---Build Shared libbusybox则为动态方式编译,这样编译出来的Busybox运行时还需要一些共享动态库,这些共享动态库必须拷贝到根文件系统的lib目录下。
f) 因为我是动态编译的,所以用#readelf –d busybox(arm-linux-readelf –d busybox | grep Shared)查下需要用到的库文件,以后将要拷贝这些文件到根文件系统的lib目录下(链接文件和原文件都要拷贝),最简单的方法是拷贝交叉编译工具下的整个lib库或者所有*.so库文件。然后通过arm-linux-strip工具来去掉库文件中包含的符号表和调试信息:#arm-linux-strip /root_2.6.28.6/lib/*.so
g) 创建根文件系统框架:
#cd ~/FamilyGate/
#mkdir root_2.6.28.6
拷贝_install目录下的所有文件到root_2.6.28.6目录下(拷贝的时候最好是将bin,sbin,usr目录打包后拷过去再解压,当初只是简单的cp过去结果启动内核的时候出现Kernel Panic,not syncing Attempted to kill init!错误,无法启动,最后通过压缩然后拷贝过去再解压就能顺利启动了,linuxrc文件就是/bin/busybox的链接可以直接使用这个也可以自己新建一个。),然后建立dev,etc,home,lib,mnt,opt,proc,root,sys,tmp,var,web目录,并在usr下建立lib目录
h) 因为内核挂载完文件系统后,init进程需要用到/dev/console和/dev/null这两个设备文件来调用mdev构建dev,所以必须在制作文件系统时静态创建这两个设备文件,否则将不能进入交互界面:
#cd ~/FamilyGate/ root_2.6.28.6/dev
#mknod console c 5 1
【mknod是用来建立块专用或字符专用文件的命令,有如下两种描述形式
Mknod Name {b|c} Major Minor(只能由root用户或组成员运行,用来创建面向块设备或面向字符设备的特殊文件,特殊文件不占用磁盘空间,仅仅为操作系统提供交流,不为数据存贮服务)b 表示特殊文件面向块设备;c 表示特殊文件面向字符设备;Major为主设备号;Minor为次设备号;可以用选项m指定文件模式。
Mknod Name {b}(创建FIFO(已命令的管道))】
#mknod null c 1 3
在网上还看到有命令为
#mknod –m 600 dev/console c 5 1
#mknod –m 666 dev/null c 1 3
这应该是指定了文件权限的
若不创建这两个设备文件会出现:Waring:unable to open an initial console
而且好像这两个特殊文件是不能够复制的,所以在将根文件系统复制到其他的文件夹的时候要重新创建这两个特殊设备文件。
i) 根据busybox/examples/inittab创建/etc/inittab文件,内容如下:
#/etc/inittab init configuration for BusyBox
::sysinit:/etc/init.d/rcS
S3c2410_serial0::askfirst:-/bin/sh
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount –a –r
按照这个例子的说明S3c2410_serial0处应该为串口设备名,但是天嵌文档说在内核驱动中用S3c2410_serial做了串口设备名所以改了。(在2.6.28.6内核中/drivers/serial/S3c2440.c的第158行指明S3C2440的串口驱动名为:s3c2440-uart,这里好像要做相应修改)
j) 创建一个mdevd设备配置文件,mdev.conf内容可空
k) 创建系统启动加载文件,根据/busybox/examples/bootfloppy/etc/init.d和/busybox/examples/bootfloppy/etc/init.d/rcS创建
/busybox/examples/bootfloppy/etc/init.d/rcS
#!/bin/sh
runlevel=S
prevlevel=N
umask 022
export runlevel prevlevel
hostname –F /etc/hostname
#设定主机名为文件/etc/hostname中指定的名字
mount –a
mkdir /dev/pts
mount –t devpts devpts /dev/pts
echo /sbin/mdev> /proc/sys/kernel/hotplug
mdev –s
mkdir –p /var/lock
ifconfig lo 127.0.0.1
ifconfig eth0 192.168.1.70
route add defaoult gw 192.168.1.1
再修改文件为可执行属性
l) 创建用户组文件/etc/group
可以参考Fedora10系统下/etc/group文件更改
创建用户文件可以参考/etc/passwd
passwd文件:
root:x:0:0:root:/:/bin/sh
nobody:x:99:99:Nobody:/:
第一个字段为登录名
第二个字段为口令,一般被映射到shadow文件中
第三个字段为UID
第四个字段为GID
第五个字段为用户名全称
第六个字段为用户根目录
第七个字段为用户所用SHELL的类型
group文件:
root:x:0:root
第一个字段为用户组名称
第二个字段为用户组密码,当为x时密码是映射到/etc/gshadow中的,是非逆的
第三个字段为GID,及组号,为正整数或0,0被付于了root用户组;系统通常会预留一些较靠前的GID给系统虚拟用户之用,每个系统预留的GID都不同,Fedora预留了500个,所以我们添加新用户组时是从500开始的。GID的范围由/etc/login.defs中的GID_MIN和GID_MAX决定
第四个字段为用户列表,每个用户间用逗号分隔
nobody:x:99:
若有选择支持SHADOW PASSWORD的话还要建立/etc/shadow文件,这是密码映射文件,用passwd命令更改密码时会自动修改这个文件。若没有选择支持SHADOW的话更改密码则会直接更改/etc/passwd文件
shadow文件:
root:::0:::::
nobody:::99:::::
若BUSYBOX的配置没有勾选“USE INTERNAL PASSWORD AND GROUP FUNCTIONS RATHER THAN SYSTEM FUNCTIONS”则必须将交叉编译器中libnss_*系列的shared library拷贝到文件系统的lib下,同时将系统中nsswitch.conf拷贝到/etc下才能进行正常的用户管理,否则当用#whoami命令时会出现:WHOAMI: UNKNOW UID 0(即UID和用户对应不起来,即使包含了group,passwd,shadow文件,且文件中也设定了UID对应的用户也是一样),用#ls –l会发现只能显示UID和GID而无法看到用户名。NSS(NAME SERVICE SWITCH)是管理用户名和DNS的服务。nsswitch.conf文件指定各名字服务使用什么样的文件来管理。因为有些程序用到了系统NSS所以建议不要用BUSYBOX内置的用户管理,而用系统的NSS。
m) 创建/etc/profile用户配置文件,参考/examples/bootfloppy/etc/profile
#/etc/profile: system-wide .profile file for the Bourne shells
#设置终端显示的用户:[root@home]#,还必须在etc目录下建立/sysconfig目录,在其下建立一个文件HOSTNAME文件内容下面介绍
USER=”’id -un’”
LOGNAME=$USER
PS1=’[\u@\h\W]#’
#PS1环境变量决定了Linux提示符的样式,参考《关于Linux操作系统提示符PS1定义的问题__Linux_eNet硅谷动力.htm》
export USER LOGNAME PS1
echo
echo –n “Processing /etc/profile… ”
#Set search library path
echo “Set search library path”
LD_LIBRARY_PATH=/lib:/usr/lib
export LD_LIBRARY_PATH
#Set user path
echo “Set user path”
PATH=/sbin:/bin:/usr/sbin:/usr/bin
export PATH
echo –n “Done”
echo
n) 创建/etc/hostname文件
HomeG
o) 建立/etc/fstab指明需要挂载的文件系统
#device mount-poing 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
var /dev tmpfs defaults 0 0
p) Lib目录用来存放常用的库文件,库文件为交叉编译工具lib目录下的*so*文件,也可以通过readelf –d (xxx为应用程序)来查看应用程序用到的动态库。
我用BusyBox1.14.3编译的根文件系统,必须要编译内核中Kernel Feture---EABI支持否则的话在内核载如根文件系统的时候出现Kernel panic not syncing Attempted to kill init!错误,被搞了好几天,最后还是到网上看到要编译内核支持EABI才解决的。
q) 奇怪的是再次编译内核的时候竟然出现“implicit declaration of function ‘__grab_cache_page’”的错误。定位到错误出现的地方:yaffs_fs.c的757行,发现只有当内核版本低于2.6.28时才会执行这个函数,而我的内核版本是2.6.28.6已经是高了怎么还会这样呢?这个函数的选择执行跟两个宏有关:LINUX_VERSION_CODE和KERNEL_VERSION,定义这两个宏,出现在/include/linux/version.h下,又发现version.h文件的创建时间竟然是我执行make的时间,可想而知,这个version.h是在make的时候生成的,那么里面关于那两个宏的定义肯定出现在顶层Makefile中,是不是Makefile生成这个两个宏的时候计算有问题呢?定位到Makefile,查找version关键字,在约1013行发现了关于version.h的生成,即那两个宏的定义:
LINUX_VERSION_CODE就是表达式$(VERSION)\*65535+$(PATCHLEVEL)\*256+$(SUBLEVEL),这个几个变量在Makefile中的值分别为:VERSION=2,PATCHLEVEL=6,SUBLEVEL=28,此外还有一个额外的变量EXTRAVERSION=.6,而KERNEL_VERSION(a,b,c)的值为((a)<<16+((b)<<8)+(c)),在yaffs_fs.c中a=2,b=6,c=28可见这两个值是一样的了,怪不得老是去找__grab_cache_page()函数,其实在2.6.28.1中这个函数就已经发生了更名了。为了解决这个问题要么更改Makefile中版本的计算公式,要么更改yaffs_fs.c,为了不影响到内核中的其他部分我修改yaffs_fs.c,注释掉#if LINUX_VERSION_CODE>KERNEL_VERSION(2,6,28),#else,pg=__grab_cache_page(mapping,index),#endif四行,再执行make在arch/arm/boot和arch/arm/boot/compressed目录下生成了镜像和压缩的镜像。
7、 然后就是利用工具mkyaffs2image生成yaffs文件镜像了,mkyaffs2image的源码在/yaffs2/utils目录下可以进到源码目录下,修改Makefile中的编译器的指定,然后编译就生成了。——STAGE3
阅读(968) | 评论(0) | 转发(0) |