总体来说,嵌入式Linux内核和根文件的引导与PC机差不多。
嵌入式linux内核和根文件系统可以存放在各种可能的存储设备中,一般情况下我们将内核和根文件系统直接烧入到Flash中(包括NOR和NAND flash),这种方法的缺点是在内核和根文件系统出现修改时我们就不得不得重新对flash进行擦除和烧写工作,这个非常耗时,在产品开发调试阶段非常不适合,只有在最终成品时才比较适用。哪在开发阶段采用哪种方式比较好呢?先还是看看现在都有些常用的存储设备吧。我们常见的存储设备有:硬盘,U 盘,SD卡,Flash,还有一种其实是借助网络而将其存储到远程机器上的方法,我们常听说的网络硬盘,就是借助TCP/IP协议从远处将数据下载到机器来进行工作,很多网吧就采用这样的“无盘系统”技术,其实并不是没有盘,而只是这个存储设备不在本地机器上而已。
从上面这些我们可以得出几种加载引导linux内核的方法:
1.网络。即将内核和根文件系统存储在PC机上,通过网络协议来将数据下载到开发板中。内核和根文件系统都可以通过tftp或者ftp下载到目标板上,当然根文件系统其实是没有必要下载到目标板上,我们可以采用NFS文件系统来挂载。
2.SD/MMC 卡引导。将内核和根文件系统存储在SD卡中,在启动时通过读SD卡,来将内核读入到内存中。根文件可以读到内存中,也可以由内核直接将SD卡直接挂载为根文件系统。这里需要文件系统的支持,常用的有FAT和EXT2。这样在内核和根文件系统更新时,只需要从新写SD卡就可以了。
3.U盘引导。这个需要目标板有USB HOST接口。同时也需要文件系统支持。其操作与SD卡引导类似。
4.硬盘/CF卡引导。这个也前面两个类似,只需要其操作起来也不方便。主要因为硬盘目前不支持热拔插,而且对目标板也有要求,一般的嵌入式设备很少需要硬盘。
5.flash引导。这个就是我们最常用的,可以常用非常多中方式和多种文件系统,包括ext2,jffs2,yaffs2,cramfs等等。
另外一种引导的方式就是通过串口直接下载内核和文件系统到内存中,或者使用调试器与仿真器通过调试通道将内核和根文件系统加载到内核,然后在调试器中通过命令引导内核。
要实现这些引导方式,那么bootloader就必须要支持上面需要的功能,我们来看看这个bootloader可能的需求:
1.支持TCP/IP协议,并实现tftp或者ftp协议。
2.文件系统的支持。可能需要支持fat,ext2,jffs2,yaffs2,cramfs等。
3.SD/MMC协议支持
4.USB Host驱动代码
5.基于MTD的Flash驱动和设备的支持。
6.IDE/CF接口的支持(不必要)。
要完成这些功能并不简单,从零开发的话,可以说是非常大的项目,如果再加一个调度器的话那就是一个小的操作系统了,还是先看看现有的各种bootloader吧。常见的有:
1.uboot
2.redboot
3.vivi
其实uboot中就已经实现了我们需要的所有功能了,而且它支持非常多的目标板和体系结构。redboot是ecos的一部分,其功能没有uboot那么强大,而且其移植也并不那么简单,支持的开发板也少,而且资料不怎么太好找。vivi主要从的三星的芯片上,功能也不多,而且局限很多。所以推荐使用 uboot,最新的uboot应该是u-boot-2009.08。其与原来的uboot-1.1.6修改很多,配置方面有所修改。
上面这几种引导方式,在开发阶段选择一种就好了。把一种调试好了就进行内核和驱动的开发吧。当然花费在其上的时间是不会浪费的。“磨刀不误砍柴工”。推荐使用网络引导方案,先通过tftp下载内核到内存,再通过NFS挂载根文件系统,调试和开发都方便。如果没有网络可用,可以考虑SD或U盘引导,SD卡引导要简单点,最后实在没办法那就直接烧写flash吧。对于学习我们可以试尝用这几种方法来比较一下,并好好总结,等到上战场的时候就可以用上了。最好要有积累。如果我们做的好的话,各种功能都是模块化,就算开发开发一个bootloader也只是一个各种模块的组装和平台相关的移植。
最后当然也可以自己动手去实现一个bootloader,这个虽然很费时间,但意义还是很重大的。各种功能可以慢慢的加上,先设计可以基本功能的 bootloader,可以边做边参考uboot,你会发现自己在写代码的水平会有一个很大的飞跃。像如何编写平台无关代码;怎样进行代码抽象;如何编写可移植性,适应性强,健壮的代码;C语言的各种特性的使用特别是指针和函数的使用;学会如何实现程序的可配置等等。
-------------------------------------------------------------网络方式示例-------------------------------------------------------------
驱动开发前期准备工作(NFS挂载):
那为什么要用NFS挂载来作为驱动开发的首选呢?因为你在未开发正确的驱动的时候,你要不停地做修改,如果你每改一次就要烧写一次根文件系统这样很浪费时间,而NFS挂载是把你的根文件系统放在你的开发机上,而开发板上并没有,所以有修改,立刻可以体现在开发板上。
言归正传,首先讲一下应该怎样NFS挂载根文件系统,我也是网上搜集了一些资料和跟同事要了一些资料,如果跟别人写的一样的,那请见谅,因为这些资料我也不知道来源。
平台:Windows7用虚拟机Fedora14
准备已经编译好的u-boot.bin uImage rootfs。
一、u-boot编译与烧写
1、打开DNW,选择NOR端口,输入“v”,讲u-boot.bin烧写进nand flash
2、选择NAND端口,重启开发板,出现以下界面:(此为超级终端下运行)
二、U-BOOT相关设置
1、在超级终端下键入u-boot的命令
# setenv ipaddr ****** (开发板IP)
# setenv serverip ****** (虚拟机IP)
# setenv gatewayip ****** (网关)
(以上为设置环境参数)
# saveenv (保存环境参数到flash)
(由于要进行tftp下载,所以要先搭建tftp服务器)
三、TFTP服务器搭建(Linux环境下)
1.安装以下两个软件(安装程序见TFTP安装包)
[root@localhost Packages]# rpm -ivhxinetd-2.3.14-32.fc14.i686.rpm
[root@localhost Packages]# rpm -ivhtftp-server-0.49-6.fc14.i686.rpm
2.修改配置文件
修改文件vi /etc/xinetd.d/tftp。
主要是设置TFTP服务器的根目录,开启服务。修改后的文件如下:
service tftp
{
socket_type =dgram
protocol =udp
wait =yes
user =root
server =/usr/sbin/in.tftpd
server_args =-s /home/user/tftproot -c
disable =no
per_source =11
cps =100 2
flags =IPv4
}
修改项server_args= -s -c,其中处可以改为你的tftp-server的根目录,参数-s指定chroot,-c指定了可以创建文件
3.创建tftp根目录,启动tftp-server
#mkdir /home/user/tftpboot
#chmod 777 /home/user/tftpboot
#/etc/init.d/xinetd restart
这样,tftp-server就启动了。
4.测试
可以使用#netstat -a |grep tftp命令察看是否启动tftp服务,如果出现
udp 0 0 *:tftp *:* 则起动了
检查tftp服务是否打开
[root@localhostbtools]#chkconfig –list
(查看是否有xinetd这一项)
如果tftp的服务没有打开,则用下面命令打开tftp服务开关
[root@localhostbtools]#chkconfig tftp on
重启服务
#/etc/init.d/xinetdrestart
四、下载内核到开发板内存
1、先确定开发板是否能ping通虚拟机下的Linux,如果是:host192.168.1.111 is alive,那么就表示连接 成功。
2、将编译好的uImage放入/home/user/tftpboot目录中。(Linux下)
3、在超级终端下输入:
# tftp uImage (将uImage镜像下载到开发板的SDRAM的0x30008000位置)
# nand erase 80000 size (擦除Nand Flash中80000开始大小为size的空间)
# nand write 30008000 80000 size (将内存中30008000位置开始的内容拷贝到NandFlash 中80000开始的位置大小为size)
备注:TFTP下载内核映像时传输的数据总量会在完成时显示(down_size),而烧写 nand_flash时数据大小必须是2k对齐的,所以我们要对下载的数据大小做一点小小的改变以适应nand_flash,如果down_size百位>8,则size= down_size+1000 后把低3位清零;如果down_size百位<8,则size = down_size低3位清零+800。比如down_size **a967,则size = **b000;down_size **a567,则size = **a800。
如:
五、利用nfs挂载根文件系统
1、在Linux下设置共享目录
运行命令:gedit/etc/exports
编辑nfs服务的配置文件(第一次打开时文件是空的),添加以下内容
/opt/rootfs *(rw,sync,no_root_squash) //自己根文件系统路径
*:表示所有的客户机都可以挂载此目录
rw:表示挂接此目录的客户机对该目录有读写的权限
no_root_squash:表示允许挂接此目录的客户机享有该主机的root身份
2、运行命令:service iptables stop 关闭防火墙
3、启动NFS 服务
在命令行下运行:
#/etc/init.d/nfs start
这将启动nfs 服务,可以输入以下命令检验 nfs 该服务是否启动。
# mkdir /mnt/nfs
# mount -t nfs -o nolock 192.168.1.232(主机IP):/opt/rootfs(需要挂载的文件的路径) /mnt/nfs
如果没有出现错误信息,您将可以浏览到 /mnt/nfs 目录中的内容和/opt/rootfs 是一致的。
使用这个命令可以停止 nfs 服务:
#/etc/init.d/nfs stop
六、在U-BOOT设置环境变量
1、setenv bootargs "noinitrd root=/dev/nfs rw nfsroot=192.168.1.232:/opt/rootfs/ ip=192.168.1.25:192.168.1.232:192.168.1.254:255.255.255.0 console=ttySAC0,115200 init=/linuxrc mem=64M"
(192.168.1.25)是开发板的临时IP
(192.168.1.232)开发主机IP
(192.168.1.254)目标板上网关
(255.255.255.0)子网掩码
注意:如果使用的是虚拟机,则使用虚拟机的IP。
2、# setenv bootcmd “nand read 30008000 80000500000;bootm 30008000”
(将bootcmd命令改成上面的内容,因为我们内核镜像在Nand Flash的位置是80000,所以u-boot执行完之后,内核的入口点就在80000这个位置。)
3、重启开发板。