分类:
2009-04-16 18:06:11
2,基于Flash的uClinux系统
传统意义上嵌入式系统的存储系统通常由Flash和RAM组成。Flash的成本通常又高于RAM的成本。因此系统的存储系统由多大容量的RAM多大容量的FLASH组成,通常根据产品的需求和成本的考虑来决定。
在基于uClinux的嵌入式系统中,Flash是整个系统代码和数据的储存器件。通常的做法是将uClinux核心的起始代码放在处理器加电所运行的地址
处。这个地址必定是在FLASH中的。因为NOR Flash里面的代码可以直接执行。在很多的应用中采用了不使用RAM,直接让uClinux在
Flash里面运行。而出于速度和成本的考虑更多的做法是将uClinux系统存放在Flash中根据系统运行的情况把要执行的部分拷贝到RAM中执行。
为了实现上述思想我们通常把Flash分区。当然这里分区的概念和我们给硬盘分区的含义大不一样。这里的分区十分简单,就是把Flash按照地址分成不同的区间在特定的区间中放入不同的代码或者数据。使得整个系统比较有序和容易调试开发。
一个典型的例子,比如:
块号 地址 用途
0 0x0—0x? 启动代码
1
2 0x….. uClinux 核心
3
4 0x… 根文件系统
5
在这个例子中第0个分区,也就是Flash的起始位置我们放置了系统启动代码。第1个分区我们可以放置一些配置数据之类的数据。接下来的一个分区我们存放着uClinux的核心。并且我们用另外的一些分区来放置系统的根文件系统。
以此可见,我们完全可以根据自己的需要把Flash分成不同的区来使用。在以后的讨论中我们可以直到uClinux的块设备驱动支持我们这样的操作。因此我们的焦点将集中在如何划分不同的区域来达到我们的应用。
通过上面的介绍我们知道Flash的擦写需要根据Flash的扇区来进行。一次擦写至少要擦除一个扇区内所有的内容。因此我们给Flash分区的时候最先要确定的是每个分区需要多少个Flash的扇区。从第几个到第几个,这样以后的操作才可*简单。
从上面的例子来看,uClinux的内核和根文件系统并不在一个分区。内核放在一个特定的地址。要访问内核必须从某个地址开始整个的访问。而不同于我们同用的桌面版或者服务器版的Linux可以把内核作为一个文件来存放在文件系统中。
那么这两种方法有什么不同呢?
在我们的例子,把内核单独放在一个分区中。这需要启动的时候启动程序把整个内核拷贝到RAM里面然后运行它。或者采用我们前面提到的XIP技术在Flash里面运行。而传统的Linux则需要启动程序来确定内核的位置和需要把内核的那部分加载到RAM里面来运行(类似于台式机Linux系统上的LILO或者GRIUB)。
那么如何选择Flash的分区,以及各个分区存放的内容呢?我想这个要根据各自产品的特点和开发的周期来考虑。接下来我们列出在uClinux系统中常用的几种分区方法并且讨论它们各自的优劣。
a) 内核和根文件系统都在固定的分区固定的地址
b) 内核在根文件系统之后或者之前
c) 压缩的内核作为根文件系统下的一个文件
a的优势在与系统主要的组成部分都有各自固定的地址。启动程序可以直到内核所在的地址,而内核直到根文件系统的地址。这样启动程序加载内核或者内核挂装根文
件系统的时候所进行的操作比较简单。并且我们可以很方便的升级这些组成部分。缺点就是将不可避免的造成内核和根文件系统之间Flash的浪费。
b的做法节约了一部分Flash的空间。但是它把内核同根文件系统一快编译成了一个二进制文件。这样你必须同时升级内核和根文件系统。不过这样作的好处是编译选项比较简单。容易维护。初次开发建议使用这种方法。
c的做法由于使用了压缩的核心所有节约了大量的空间。但是必须需要一个启动程序来把内核解压缩到RAM中。这样就需要一个比较充裕的RAM空间。启动程序增
加了复杂度。不过一旦你写好这个驱动程序,你就可以不再修改它而将所有精力放在uClinux核心和根文件系统的开发上。
当然,根据产品需要我们不排除使用多个文件系统的选择。原因很简单,比如你需要对你的某个分区进行读/写操作而对其他一个区只要进行只读操作。由于Flash的读/写特性您就要作比较复杂的设计。对于这种情况,下文有所提及。
3,uClinux系统的bootloader
作为系统的启动程序,最先要考虑的是CPU在加电的
时候运行那个地址的代码。有些CPU比如X86,ARM在加电的时候运行固定地址的代码;也有些CPU比如m68k, ColdFire,在加电的时候读
取一个固定的地址,然后用这个地址的值作为最先执行代码的的地址。在现有的系统中这个地址是在Falsh里面的。
那么我们要考虑的就是在这个地址里面放入我们的代码,以便CPU加电后就执行这行代码。我
们允许CPU加电后直接运行uClinux的内核代码。这时候uClinux的代码需要作一系列的事情。比如初始化硬件,比如初始化RAM;把uClinux内核中的数据段拷贝到RAM中去;清空BSS段等。不过最重要的还是将它的首行代码放到合适的地方。
使用BootLoader我们就可以做根多的事情。比如我们可以初始化硬件,比如RAM和系统的I/O设备等。同时它还可以装载写在Flash上的不同内核,或者通过外部设备传输过一个内核并且装载运行它。
在现阶段的开发板上,很多都采用了这种方式通过串口或者网口加载Pc机上编译好的uClinux内核或者根文件系统。
除此以外,一个好的bootloader还能够保证内核影像的正确执行,防止新传输来的内核影像不完整等等。一般情况下bootloader都是固定的烧
写在Flash上面并且一般采用锁定的方法防止被擦除。目前有很多成数的bootloader可以在互联网上自由下载。它们支持各种开发板上的uClinux的开发。比较著名的有CoLilo, My Right Boot (MRB),
PPCboot and Motorola dBUG。它们功能强大并且可以很方面的移植到你自己的开发板上。
4,uClinux内核的块设备驱动
对于uClinux 的根文件系统,目前有三种块设备的驱动可以选择它们分别是:
a) Blkmem 驱动
b) MTD 驱动
c) RAM disk 驱动
Blkmem 驱动是专门为uClinux开发的一种块设备驱动。是uClinux系统中最为古老和通用块设备驱动。它原理相对简单但是配置比较复杂,需要根据你即的Flash的分区使用情况来修
改代码。当然修改的结果是它可以对一些NOR型的Flash进行读写操作。不过目前支持的Flash类型不够多。如果新加入对一种Flash的支持需要作的工作量比较大。
Linux的MTD驱动是标准Linux的Flash驱动。它支持大量的设备,有足够的功能来定义Flash的分区,进行地址映射等等。使用MTD你可以
在一个系统中使用不同类型的Flash。它可以将不同的Flash组合成一个线性的地址让你来使用。在标准的Linux 2.4内核中MTD有一系列的选相,你可以根据个人系统的需要来选择定制。
另外一种选择就是RAM disk
驱动。在PC上它经常用于没有硬盘的Linux的启动过程。它和Flash没有直接的关系。不过当Flash上启动的是经过压缩的内核时。
RAM disk
可以作为根文件系统。MTD 驱动提供了对Flash强大的支持,你通过它甚至可以在Flash上运行一个可以读写的真正的文件系统,比如JFFS2。而
Blkmem驱动则望尘莫及。
5,uClinux的文件系统
在uClinux下根文件系统有集中选择。ROMfs是最常用的一种。它的特点是紧凑,只读。它把所有的文件按照一个文件的次序组合成一定的次序。并且它可以让它的应用程序直接在FLAH里面运行(XIP)。这样以来就减少了运行时对RAM尺寸的要求。在目前基于AMR和ColdFire等CPU的
uClinux开发中绝大多数使用这种文件系统作为根文件系统。
Cramfs是在Linux内核2.4版本以后出现的新的文件系统,它的特点是把只读的文件系统进行压缩。从而可以在Flash上存储更多的应用程序。不过因为压缩它不能本地执行应用程序,而必须解压到RAM中运行。要求比较多的RAM。
在一些系统中需要可以读写的根文件系统。在uClinux系统中利用MTD驱动,我们可以实现一些基于Flash的日志文件系统比如JFFS 或
者 JFFS2。这个文件系统的优点在于它可以避免突然断电对系统存储的影响(在标准Linux中ETX2文件系统掉电会造成数据丢失)。同时因为它们是
和为Flash设计它可以保证在Flash中实现读写。如果你使用RAM disk
那么ETX2 就成为首选的文件系统。因为它是标准Linux的文件系统。所以很多操作非常方面。不过缺点是ETX2文件系统不是为嵌入式操作系统所作,
所以并没有考虑存储空间的问题。由于RAM disk的特性你在该文件系统上所作的改动下次启动后将不会再有。
当然Linux支持很多文件系统,你可以根据你的喜好随意选择。不过以上说说的是uClinux系统中最常用的。
那么我们怎么在Flash上建立一个根文件系统呢?
通常的做法是先在开发机上(通常是PC)作好这个文件系统的镜像。然后通过烧写Flash的工具直接烧写到Flash中去。也可以通过阅读一些文件系统自带的工具来进行构建。这里不一一赘述。
6,uClinux 的Flash工具
在uClinux的源码包中带有一些对Flash操作的应用程序。当你采用MTD的时候这些工具变得非常有用,它们分别是:
erase -- 擦除Flash的某些扇区
eraseall -- 擦除整个Flash
lock -- 锁住Flash(写不进去)
unlock -- 解锁
mkfs.jffs -- 建立一个目录结构的JFFS2文件系统
mkfs.jffs2 – 建立一个目录结构的JFFS2文件系统的镜像
除此之外,还有一些更为复杂的程序是和其他应用相关的。比如和JTAG相关,Net相关等等。可以根据这个工具的说明来加以应用。
7,应用实例
现在我们看一个实例。首先说一下我们的硬件平台。这个平台是基于ARM940T核心的CPU+2M的AMD Flash + 4M
SDRAM。在这个平台上我们运行uClinux
2.4 的内核,采用MTD驱动。因为我们不需要对Flash进行读写操作,所以选择了ROMfs。这样使得开发和维护想对比较简单。AMD的Flash,我所选用的是可启动型的。因为ARM的CPU在加电的时候从零地址开始运行。因此Flash的地址分配为从0X0到0X1FFFFF。根据这个Flash的扇区大小,我们把整个Flash的分区如下:
2M Flash ---MTD 6
启动代码 (16K)MTD1
启动所需参数 (8K)MTD2
设备配置信息(8K)MTD3
备用空间(32K)MTD4
系统运行参数表(64K)MTD5
内核和根文件系统(1984K)MTD6
在内核的MTD驱动的选项中,我们根据所需要的分区信息对代码进行配置。运行的时候,MTD驱动会找到这个设备,并且按照以上我们的分区方案对Flash的地址进行分配。一些详细的信息和细节,在MTD驱动的代码部分有详细的描述。
完成了这个分区,我们就可以利用我们手头的工具,把我们事先做好的系统启动程序和内核,根文件系统写入Flash。
常用的方法有:
1)建立整个Flash的影像,使用烧录工具烧到Flash中
2)书写一个Bootloader,使用系统所带的外部接口将内核还有根文件系统传送到系统RAM中,然后写入Flash。常用的有通过串口和网口的。此类的程序有很多比如netflash等等,具体的用法请参照各命令的手册。
运行完这些,uClinux系统已经在我们的开发板上安装好了。
系统设计