在嵌入式Linux上实现JFFS文件系统

发 布 时 间 : 2008-11-17 来 源 : 来自网络 作 者 : 匿名 浏 览 :

摘要:本文通过在嵌入式操作系统uClinux上实现可读写JFFS文件系统的实例,介绍了在嵌入式系统中使用Flash芯片的方法。
关键词: 嵌入式系统;uClinux;Flash;JFFS文件系统

0 引言
近年来,随着电子技术的不断进步,嵌入式系统开发已成为热点,而Linux作为一个自由软件 ,也得到了极大的发展 ,嵌入式系统与Linux的结合,正日益被人们看好。Linux具有内核小,效率高,源代码开放等优点,还内含了完整的tcp/ip网络协议,很适合在嵌入式系统中使用。作为专门为嵌入式微处理器定制的小型化Linux,uClinux正是嵌入式Linux的优秀代表。在嵌入式系统开发中,Flash 芯片以相对低廉的价格提供了高可靠性和高密度的存储,已成为嵌入式系统的重要组成部分。在很多嵌入式系统中,操作系统及应用程序直接固化在Flash上,系统启动时,代码直接在Flash上开始运行。

1 在嵌入式系统中使用Flash
当前的嵌入式系统开发,需要方便灵活地使用Flash,以嵌入式的Web Server为例,在运行过程中,要求能够动态地保存一些数据,并且当系统重新启动时,保存的数据依然存在。又比如将嵌入式处理器应用于工控领域,可能整个系统都集成在一小块电路板上,一些重要的工艺参数在控制过程中需要动态地改变并保存,而使用硬盘等存储介质又显得不太现实,在这种场合下,仅仅地将Flash作为保存系统代码的ROM使用是“大材小用”,我们需要充分发挥Flash可擦写的优势,在系统运行过程中,动态地擦写Flash来保存数据。针对嵌入式系统多样、灵活、专用性强等特点,人们可以发挥嵌入式操作系统软件复用的优点,找到一种方便、快捷地使用Flash 的方法来缩短开发时间,提升系统性能,嵌入式Linux就提供了这样一条捷径。由遍布全世界的自由软件开发者为Linux提供支持,使得在嵌入式linux上使用Flash变的十分容易。

2 JFFS 文件系统简介
我们使用的uClinux系统采用ROMFS作为根文件系统,它相对于一般的EXT2文件系统,具有节约空间的优势。但是ROMFS是一种只读的文件系统,不支持动态擦写保存,对于系统需要动态保存的数据只能采用虚拟ram盘的方法(ram盘使用EXT2文件系统)。
针对ROMFS文件系统存在的问题,我们可以使用JFFS文件系统(Journaling Flash File System)。JFFS文件系统是瑞典的Axis Communications公司 (www.axis.com) 在GNU General Public License下发布的自由软件,主要用于嵌入式Linux。我们只需要在自己的嵌入式Linux中加入JFFS文件系统并做少量的改动,就可以使用JFFS文件系统。通过JFFS文件系统,可以用Flash来保存数据,即将Flash作为系统的硬盘来使用。可以像操作硬盘上的文件一样操作Flash芯片上的文件和数据。系统运行的参数可以实时保存到Flash芯片中,在系统断电后数据仍然存储在Flash芯片中。
作为一种EEPROM,Flash可分为两种主要类型:NOR Flash 和NAND Flash。一片没有使用过的Flash,每一位的值都是逻辑1,对Flash的写操作就是将特定位的逻辑1改变为逻辑0。而擦除就是将逻辑1改变为逻辑0。Flash的数据存储是以块(Block)为单位来组织的,Flash只能整块擦除,而Flash的寿命是以擦除次数来计算的,一般是每块100,000次。为了保证某块不早于其他块到达其寿命,就有必要将在所有块中尽可能地平均分配擦除次数,这就是“损耗平衡”。JFFS 文件系统是一种“追加式”的文件系统,新的数据总是被追加到上次写入数据的后面。这种“追加式”的结构就自然实现了“损耗平衡”。
要加入JFFS文件系统,需实现Linux下对Flash芯片的驱动,Axis Communications公司提供了实现代码。在笔者的系统中,代码包括uClinux/linux/drivers/block/flash.c 和uClinux/linux/include/linux/flash.h。
在flash.c中的设备的初始化函数 flash_init()里,将Flash作为块设备向系统注册。
#ifdef CONFIG_BLK_DEV_FLASH /* 向内核注册,主设备号MAJOR_NR=60 */
if(register_blkdev(MAJOR_NR, DEVICE_NAME, &flash_block_fops )) {
printk(KERN_ERR DEVICE_NAME ": Unable to get major %d ",
MAJOR_NR);
return -EBUSY;
}
/*注册实际的块I/O 操作及设备大小和块大小 */
blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
blk_size[MAJOR_NR] = flash_sizes;
blksize_size[MAJOR_NR] = flash_blk_sizes;
read_ahead[MAJOR_NR] = 1;
printk("Flash/ROM block device v2.1, (c) 1999 Axis Communications AB ");
#endif

3 开发环境简介
我们采用的是宿主机 目标板的开发模式,宿主机为PC redhat7.2 ,目标板为Motorola Coldfire5272 uClinux, uClinux版本为2.0.38,在宿主机上将uClinux和应用程序编译后,下载到目标板的Flash中运行。我们使用的Flash是2片AMD AM29LV160BT,大小为2M字节,工作在16bit双字节模式。对于Motorola Coldfire5272,其RAM,Flash,外设I/O 参与统一平坦编码,也没有地址变换。2片FLASH的地址范围设置为:0xffb00000-0xffcfffff 和0xffd00000-0xffefffff。每片FLASH共有共35个扇区,除前四个扇区不规则,大小分别为:16K,8K,8K,32K 外,剩余31个扇区均为64K字节大小。

4 实现JFFS 文件系统的实例
为实现Flash上的JFFS文件系统,我们需要:在内核中加入对JFFS文件系统和Flash设备的支持;针对具体的Flash 芯片修改设备驱动程序;生成设备节点并将JFFS文件系统挂接到Flash 设备上。
4.1 在内核中加入对JFFS文件系统和FLASH 设备的支持
标准 Linux可以以模块的形式加载各种类型的设备驱动,要求在设备驱动中编制两个入口点:init_module() 和 cleanup_module() ; uClinux 2.0 内核不支持内核模块 LKM(loadable kernel modules),设备驱动及文件系统要静态地编译进内核。我们需要:
(1) 修改uClinux/linux/.config文件,
将 # CONFIG_DEV_FLASH is not set
改为 CONFIG_DEV_FLASH = y
将 # CONFIG_JFFS_FS is not set
改为 CONFIG_JFFS_FS = y
(2) 修改uClinux/linux/include/linux/autoconf.h
将 #undef CONFIG_DEV_FLASH
改为 #define CONFIG_DEV_FLASH 1
将 #undef CONFIG_JFFS_FS
改为 #define CONFIG_JFFS_FS 1
完成上述修改并编译后,JFFS文件系统和Flash设备就被编译入内核,同时在系统引导时加入了对JFFS 文件系统和 Flash设备的初始化函数的调用。
4.2 针对具体设备修改FLASH设备驱动程序
Axis Communications在发布JFFS的同时,也给出了Flash 设备的驱动程序。此驱动程序支持AMD,Toshiba等公司的主流系列Flash芯片,我们需要根据自己系统中具体Flash芯片的型号及配置,修改驱动程序,使Flash设备能够在我们自己的嵌入式系统中正常工作。如果读者使用的是此驱动尚未支持的Flash芯片,只需仿照其他型号,将Flash型号加入此驱动程序即可。
下面,以笔者系统中的Flash为例,给出uClinux/linux/drivers/block/flash.c中需要的修改:
(1) 在文件的开头处,加入#define CONFIG_BLK_DEV_FLASH
(2) 在flash_probe(),chips[0].start = (unsigned char *)(0xf0200000),这个值取决于系统中实现JFFS的Flash芯片的起始地址,我们在第2片Flash上实现JFFS ,其起始地址为0xffd00000,所以将其改为 chips[0].start = (unsigned char *)(0xffd00000),随后,需要根据芯片型号设置4个起始扇区的大小,笔者系统中Flash的型号是AM29LV160BT,
以下代码定义了起始4个扇区的大小:
chip->bootsectorsize[0] = 0x8000;
chip->bootsectorsize[3] = 0x2000;
chip->bootsectorsize[0] = 0x2000;
chip->bootsectorsize[3] = 0x4000;
我们使用的Flash的起始4个扇区的大小前文已经给出,所以需要将这4个值依次改为0x4000,0x2000,0x2000,0x8000即可。
(3) 在uClinux/linux/drivers/block/ll-rw-blk.c中的blk_dev_init()函数中,在flash_init()前加入flash_probe()调用执行对flash的检测。
4.3 将JFFS文件系统挂接到FLASH设备上
首先在宿主机的uClinux/romfs/dev目录下新增设备节点:
mknod flash0 b 60 16
mknod flash1 b 60 17
mknod flash2 b 60 18
在Flash芯片上建立起分区。这样,当重新编译内核并将内核下载到Flash中后,在就可以在目标板的/dev目录下新增Flash设备文件供我们使用,目标板的uClinux系统启动之后,在目标板上执行mount –t jffs /dev/flash1 /mnt,就在flash1分区上建立起了了JFFS 文件系统,JFFS文件系统挂接在目标板 /mnt目录下,可在此挂接目录上执行建立、删除目录,文件等操作。

5 结束语
笔者的开发实例表明,开放源代码的Linux在嵌入式系统开发中有极大的优势,借助于Linux的开放性,我们能够灵活快捷地开发嵌入式系统应用。

参考文献 :
[1] Alessandro Rubini,Linux设备驱动程序 [M].北京 :中国电力出版社,2000,4.
[2] Daniel P.Bovet & Marco Cesati,深入理解Linux内核 [M].北京:中国电力出版社,2001,10.
[3] David Woodhouse,JFFS : The Journalling Flash File System http:/sources.redhat.com/ 2002.
[4] Advanced Micro Devices, Inc. Am29LV160B Datasheet http:/www.amd.com 1999,2.



上一篇:Linux操作系统的内核编译内幕详解 下一篇:嵌入式Linux系统下Microwindows的应用