How to use MTDJFFs2(中文) | |
| |
原文: http://www.enseirb.fr/~kadionik/embedded/uclinux/mtd/howto_mtd.html (中文没有版权,英文参考原文版权) ======================================= HOW TO USE MTD/JFFS2 UNDER µClinux (translated by Liang Alei) Patrice KADIONIK, Professor Assistant at the ENSEIRB School of Electrical Engineering, Telecommunication, and Computer Science kadionik@enseirb.fr http://www.enseirb.fr/~kadionik 1. MOTIVATIONS 本文将详细描述:怎样在µClinux 中step-by-step地构建一个MTD/JFFS2。 I'm currently teaching embedded system programming and propose to my students practical exercices on. In every 我目前在大学讲授“嵌入式系统编程”,并指导学生“µClinux on Motorola M5407C3 ColFire boards”的实验。一般在每个嵌入式系统中都存在有FLASH memory。通常可以用来存放配置参数(in a raw binary format)。而现在在embedded Linux中,我们可以在FLASH中放置一个文件系统,并在embedded Linux OS启动之后将其mount。这里采用的技术是MTD (Memory Technology Device),MTD将隐藏有关“物理(physical) FLASH”的编程细节(如:读/写/擦除扇区),并在MTD之上放置JFFS(2) 文件系统(Journalling Flash File System)----一种被Linux和µClinux支持的文件系统。JFFS2很robust,即在意外掉电(power failure)之后,再启动(reboot)之时不需要fsck检查。 JFFS JFFS2 MTD FLASH, RAM 另外一种使用FLASH memory的情况(或用途)是:将Linux kernel放在FLASH中,由bootloader在启动时将Linux kernel解压缩至RAM中,然后转移至RAM引导kernel。(在此我们不将深入讨论该问题) 强烈推荐:在阅读本文这个HOWTO之前,读--再读--多读以下文档: · The Memory Technology Device (MTD) Subsystem for Linux site. The Linux MTD, JFFS HOWTO. · JFFS2: The Journalling Flash File System, version 2. What is JFFS2? · A paper from David Woodhouse on JFFS2 · The David Woodhouse's presentation on JFFS2. He explains how works the Garbage Collector with JFFS2 · The www.embeddedlinuxworks.com site. JFFS- A practical guide. The list of FLASH memories supporting the MTD technology. · Using Flash Memory with µClinux by Greg Ungerer. · Find your Root File System with MTD by Phil Wilshire. · CFI presentation from AMD site I will also thank here Massimo Calo who helped me through his threads posted to the µClinux news server and his mails on MTD/JFFS. 2. MTD/JFFS/JFFS2 OVERVIEW 下面的内容摘录自我之前阅读的一篇文档(from the www.embeddedlinuxworks.com site, an article from Vipin Malik)。 " 2000年, Axis Communications AB (www.axis.com),发布了第一版的 JFFS文件系统,也是开源的(Open Sourced)。这是一个完全为嵌入式Linux系统设计的文件系统, JFFS直接设计在FLASH设备之上,能判断获知可擦除扇区的边界,以及FLASH的大小。 MTD可以看作是原始的FLASH芯片的“翻译层(translation layer)”,也正是由于MTD的存在,使得JFFS在Linux中能快速发展。基于MTD这个硬件抽象层(HAL),JFFS几乎可以被mount在任何可随机访问的设备上(如: RAM, FLASH(各种厂家的))-----只要MTD支持这些设备。 如果遇到新设备且驱动程序不存在,则找一个现存的驱动程序(做模板),然后修改其中的有关“read/write/erase”之函数,之后就可以将 JFFS mount到“新设备”上了(关键是你根本不需要知道JFFS是怎么工作的)。换句话说,将JFFS文件系统与设备相关的MTD (Memory Technology Device)(包含了很多“raw FLASH chip”之Linux驱动程序)相结合,你就得到了一个完整的解决方案----即由MTD向JFFS文件系统层提供一个抽象的设备层。 在这种方式下,JFFS不关心任何特定的存储(memory)技术。任何支持随机访问的设备(甚至象NAND FLASH这样的伪随机设备)都可以与MTD接口,从而在之上实现JFFS。在设计方面,JFFS(以及JFFS2)在文件系统层中保证一个“meta- data”(或文件系统的“格式”可靠性--- "formatting" reliability),这意味只要你的 write()系统调用返回了,则可以保证数据一定是“记录”下来的。换句话说,如果在write()命令的执行期间突然掉电了,而此时数据还没有完全写入FLASH芯片,则芯片内记录的数据要么是older数据、要么是 newer数据,或者是两者的混合,但关键是你的文件不会因此而“坏(corrupted)”了。 最初的JFFS是设计成 "append only"类型的文件系统,即“好”数据重来不会被“覆盖”( overwritten)(如:对一个已打开的文件先做rewind()操作,然后 fwrite(),没用!),新的数据总是被添加在上次“文件系统”(而不是文件)写操作的位置之后。与块数据同时被写入的“meta”数据将保证块数据在“逻辑”上已被写入文件的正确位置。当重启动(或mount)之时,整个文件系统将被扫描,零散的数据块被重新排列,以使得在读取文件之时,最新被“标记(stamped)”数据块----即那些在逻辑上覆盖了“older数据块”----被读出。而“older数据”则被标记为“回收(garbage collection)-----在适当的时候将被删除。这种“ append-only结构”的优点是“natural wear leveling on the FLASH”(译注:减少FLASH的擦除次数)。有关JFFS的“掉电可靠性(Power Down Reliability)”,我已经做一些扩展并提交了fixes(已包含在最新版本的 CVS之中),我观察的效果是500多次掉电实验大约10次失败。另外,系统中还存在一些bug,使得JFFS会随机地丢掉一些文件(甚至是静态文件)!我将 NOT推荐在产品中使用该文件系统(至少是当前版本)。 问:解决方案?答: JFFS2。 JFFS2是JFFS技术的第二版,它基于JFFS的设计思想,但是由Redhat (www.redhat.com)实现的。它采用了一种不同的方法实现“可靠性”,所有的 "erase sector"被独立管理,且可以“乱序(out-of-order)”寻址,因而当创建新文件或覆盖老文件之时,可以统一地申请一块“已擦除扇区(erase sector)”。为了保证“掉电可靠性”,在被确认已被成功写入FLASH之前(通过CRC和版本标签),文件的任何部分不会被真正覆盖。之后,老的数据块被标记为“回收”,则待到其所有的邻居(同一个扇区内的)也有相似的标记之时,该扇区被擦除。 好消息,JFFS2还支持压缩。文件数据在被写入时,通过zlib(可调整mod's)压缩;数据在被读出之时在线(on the fly)解压缩;所以事实上你无法感知你的数据是否被压缩了。因而现在你可以采用ASCII文件格式(而不是binary文件)来做日志(log)或配置(config)文件,当然二进制文件也会被压缩的。如果你的文件很“松散(sparse)”(如:其中有很多空格),呵呵,不用担心空间会浪费了。但缺点是,如果你将已经压缩过的数据写入时,系统仍将花费大量时间试图再压缩它。而此时你又无法动态关闭压缩功能。目前有些计划正在试图实现相关功能(即使是基于目录级别,对单个目录实现压缩的开关选项或属性)。 3. STEP 1: ENABLING MTD/JFFS2 UNDER µClinux 我的M5407C3 Motorola板子上,有一个16 bit FLASH内存(AMD Am29PL160C),内存映射空间是$7FE00000~$7FFFFFFF。 首先,你要认真、仔细地阅读有关你所使用的FLASH芯片的“数据手册”,查看它的扇区地址表: 我的FLASH芯片有11个扇区(大小不等)。在第一个256KB空间(SA0~SA3)中包含“dBUG Motorola monitor”代码,其余空间供用户使用(SA4~SA10,每扇区256 KB)。当然你也可以擦除“dBUG monitor”而使用整个地址空间(dBUG monitor代码可以通过BDM线缆重新安装)。我选择的方案是定义两个“MTD分区(partition)”: · dBUG分区:$7FE00000~$7FE3FFFF (256 Kbyte size)。(我不想将monitor去除。。。) · user分区:$7FE40000~$7FFFFFFF (1792 Kbyte size)。 如果你擦除“dBUG monitor”,则拥有一个大的user分区: · user分区:$7FE00000~$7FFFFFFF (2 Mbyte size). 注意:(参考µClinux文档)如果你使用的是JFFS(2),每个MTD分区至少包含6个连续扇区(原因:garbage collection)。 首先,配置µClinux之时,打开“MTD/JFFS2”: % cd uClinux-dist % make xconfig 看一下我的有关MTD的选项: % grep MTD linux-2.4.x/.config # Memory Technology Devices (MTD) CONFIG_MTD=y CONFIG_MTD_DEBUG=y CONFIG_MTD_DEBUG_VERBOSE=3 CONFIG_MTD_PARTITIONS=y CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_JEDECPROBE=y CONFIG_MTD_GEN_PROBE=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP=y CONFIG_MTD_PHYSMAP_START=0x7fe00000 CONFIG_MTD_PHYSMAP_LEN=0x200000 CONFIG_MTD_PHYSMAP_BUSWIDTH=2 其中,你已经打开CONFIG_MTD_PHYSMAP(参考uClinux-dist/linux-2.4.x/drivers/mtd/maps/physmap.c),这意味着基于一个MTD分区,你可以访问整个FLASH空间了。 为了定义多个MTD分区,我又创建了一个特殊的physmap.c文件(m5407c3.c,uClinux-dist/linux-2.4.x/drivers/mtd/maps/目录)。 之后,打开JFFS2(µClinux内核配置): · File systems menu: JFFS2 support, JFFS2 debugging verbosity 2. 选择MTD/JFFS2工具(userland area): · Flash Tools menu: mtd-utils with erase, mkfs.jff2. · BusyBox menu: BusyBox with dd, mount, mount: loop devices, umount. 创建自己的MTD之physmap文件 如果你需要多个MTD分区,你可以修改uClinux-dist/linux-2.4.x/drivers/mtd/maps/physmap.c 文件(参考:Phil Wildshire's document 之解释)。 我选择在µClinux distribution中创建自己的文件(在uClinux-dist/linux-2.4.x/drivers/mtd/maps/目录下又很多参考例子,我以m5272c3.c为例,这是一个专用于M5272C3 Motorola 开发板的)。 我的m5407c3.c 文件 #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> #include <asm/io.h> #include <linux/mtd/mtd.h> #include <linux/mtd/map.h> #include <linux/mtd/partitions.h> #include <linux/config.h> #define WINDOW_ADDR 0x7fe00000 #define WINDOW_SIZE 0x200000 #define BUSWIDTH 2 static struct mtd_info *mymtd; __u8 m5407c3_read8(struct map_info *map, unsigned long ofs) { return __raw_readb(map->map_priv_1 + ofs); } __u16 m5407c3_read16(struct map_info *map, unsigned long ofs) { return __raw_readw(map->map_priv_1 + ofs); } __u32 m5407c3_read32(struct map_info *map, unsigned long ofs) { return __raw_readl(map->map_priv_1 + ofs); } void m5407c3_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) { memcpy_fromio(to, map->map_priv_1 + from, len); } void m5407c3_write8(struct map_info *map, __u8 d, unsigned long adr) { __raw_writeb(d, map->map_priv_1 + adr); mb(); } void m5407c3_write16(struct map_info *map, __u16 d, unsigned long adr) { __raw_writew(d, map->map_priv_1 + adr); mb(); } void m5407c3_write32(struct map_info *map, __u32 d, unsigned long adr) { __raw_writel(d, map->map_priv_1 + adr); mb(); } void m5407c3_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) { memcpy_toio(map->map_priv_1 + to, from, len); } struct map_info m5407c3_map = { name: "MCF5407C3 flash device", size: WINDOW_SIZE, buswidth: BUSWIDTH, read8: m5407c3_read8, read16: m5407c3_read16, read32: m5407c3_read32, copy_from: m5407c3_copy_from, write8: m5407c3_write8, write16: m5407c3_write16, write32: m5407c3_write32, copy_to: m5407c3_copy_to }; /* * MTD 'PARTITIONING' STUFF */ static struct mtd_partition m5407c3_partitions[] = { { name: "dBUG (256K)", size: 0x40000, offset: 0x0 }, { name: "user (1792K)", size: 0x1c0000, offset: 0x40000 } }; int __init init_m5407c3(void) { printk(KERN_NOTICE "m5407c3 flash device: %x at %x/n", WINDOW_SIZE, WINDOW_ADDR); m5407c3_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE); if (!m5407c3_map.map_priv_1) { printk("Failed to ioremap/n"); return -EIO; } mymtd = do_map_probe("cfi_probe", &m5407c3_map); if (mymtd) { mymtd->module = THIS_MODULE; mymtd->erasesize = 0x40000; return add_mtd_partitions(mymtd, m5407c3_partitions, sizeof(m5407c3_partitions) / sizeof(struct mtd_partition)); } iounmap((void *)m5407c3_map.map_priv_1); return -ENXIO; } static void __exit cleanup_m5407c3(void) { if (mymtd) { del_mtd_partitions(mymtd); map_destroy(mymtd); } if (m5407c3_map.map_priv_1) { iounmap((void *)m5407c3_map.map_priv_1); m5407c3_map.map_priv_1 = 0; } } module_init(init_m5407c3); module_exit(cleanup_m5407c3); 最重要的是在mtd_partition m5407c3_partitions[]结构中,我定义了两个MTD分区。(其它内容我都是通过“替换”来修改的,即基于vi执行sed命令 :-))。 问:怎样将我的文件集成到µClinux distribution之中?我的做法是: 1. 在uClinux-dist/linux-2.4.x/drivers/mtd/maps/Config.in 文件中,添加下面行: if [ "$CONFIG_M5407C3" ]; then dep_tristate ' CFI Flash device mapped on Motorola M5407C3' CONFIG_MTD_M5407C3 $CONFIG_MTD_CFI fi 2. 在uClinux-dist/linux-2.4.x/drivers/mtd/maps/Makefile 文件中添加: obj-$(CONFIG_MTD_M5407C3) += m5407c3.o 于是,再次执行make xconfig,你将看到: % cd uClinux-dist % make xconfig 现在,我没有采用CONFIG_MTD_PHYSMAP默认选项: # Memory Technology Devices (MTD) CONFIG_MTD=y CONFIG_MTD_DEBUG=y CONFIG_MTD_DEBUG_VERBOSE=3 CONFIG_MTD_PARTITIONS=y CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_JEDECPROBE=y CONFIG_MTD_GEN_PROBE=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_M5407C3=y 3. STEP 2: MODIFYING THE µClinux KERNEL 3.1. Adding files from the Linux kernel distribution(添加文件) 你可以从某个地方(如:here )下载“Linux kernel version 2.4.19”,然后将linux-2.4.19/fs/jffs2/之中的pushpull.c, zlib.c, zlib.h文件拷贝到uClinux-dist/linux-2.4.x/fs/jffs2/目录下。 3.2. Modifying files from the µClinux kernel distribution(修改文件) 将这些文件中的BLKMEM_MAJOR值从“31”修改为“30”: · uClinux-dist/linux-2.4.x/drivers/block/blkmem.c (line 41). · uClinux-dist/linux-2.4.x/include/linux/major.h (line 66). 目的是避免造成MTD and BLKMEM之间“major”号的冲突。 3.3. Modifying files from the µClinux M5407C3 BSP port 在文件uClinux-dist/vendors/Motorola/M5407C3/Makefile 之中添加以下内容: DEVICES = / tty,c,5,0 console,c,5,1 cua0,c,5,64 cua1,c,5,65 / mtd0,c,90,0 mtd1,c,90,2 mtd2,c,90,4 mtd3,c,90,6 / mtd4,c,90,8 mtd5,c,90,10 mtd6,c,90,12 mtd7,c,90,14 / mtdblock0,b,31,0 mtdblock1,b,31,1 mtdblock2,b,31,2 mtdblock3,b,31,3 / mtdblock4,b,31,4 mtdblock5,b,31,5 mtdblock6,b,31,6 mtdblock7,b,31,7 / mem,c,1,1 kmem,c,1,2 null,c,1,3 / . . . 目的是在目标设备的uClinux目录结构之/dev目录下创建MTD and JFFS2所需要的设备文件。 4. STEP3: COMPILING(编译) 开始编译整个µClinux distribution: % cd uClinux-dist % make dep % make 4. STEP4: TESTING(测试) 最后,通过网络下载µClinux的“image”文件至M5407C3板,并启动µClinux内核: Hard Reset DRAM Size: 32M Copyright 1995-2001 Motorola, Inc. All Rights Reserved. ColdFire MCF5407 EVS Firmware v2e.1a.1b (Build 18 on Apr 20 2001 11:57:55) Enter 'help' for help. dBUG> dn (下载) Eth Mac Addr is 00:00:00:00:00:01 Downloading Image 'image.bin' from 192.168.4.1 Read 1891552 bytes (3695 blocks) dBUG> go 20000 (启动) 启动显示: Linux version 2.4.19-uc1 (root@localhost.localdomain) (gcc version 2.95.3 uClinux/COLDFIRE(m5407) COLDFIRE port done by Greg Ungerer, gerg@snapgear.com Flat model support (C) 1998,1999 Kenneth Albanowski, D. Jeff Dionne . . . Starting kswapd kmem_create: Forcing size word alignment - file lock cache JFFS2 version 2.1. (C) 2001 Red Hat, Inc., designed by Axis Communications AB. ColdFire internal UART serial driver version 1.00 ttyS0 at 0x100001c0 (irq = 73) is a builtin ColdFire UART ttyS1 at 0x10000200 (irq = 74) is a builtin ColdFire UART kmem_create: Forcing size word alignment - blkdev_requests ne.c:v1.10 9/23/94 Donald Becker (becker@scyld.com) Last modified Nov 1, 2000 by Paul Gortmaker NE*000 ethercard probe at 0x40000300: 00 00 00 00 00 01 eth0: NE2000 found at 0x40000300, using IRQ 27. SLIP: version 0.8.4-NET3.019-NEWTTY (dynamic channels, max=256). CSLIP: code copyright 1989 Regents of the University of California. Blkmem copyright 1998,1999 D. Jeff Dionne Blkmem copyright 1998 Kenneth Albanowski Blkmem 1 disk images: 0: 107FA4-2013A3 [VIRTUAL 107FA4-2013A3] (RO) RAMDISK driver initialized: 16 RAM disks of 4096K size 1024 blocksize PPP generic driver version 2.4.2 m5407c3 flash device: 200000 at 7fe00000 Amd/Fujitsu Extended Query Table v1.0 at 0x0040 number of CFI chips: 1 Creating 2 MTD partitions on "MCF5407C3 flash device": 0x00000000-0x00040000 : "dBUG (256K)" mtd: partition "dBUG (256K)" doesn't end on an erase block -- force read-only mtd: Giving out device 0 to dBUG (256K) 0x00040000-0x00200000 : "user (1792K)" mtd: Giving out device 1 to user (1792K) init_mtdchar: allocated major number 90. init_mtdblock: allocated major number 31. NET4: Linux TCP/IP 1.0 for NET4.0 IP Protocols: ICMP, UDP, TCP . . . Command: dhcpcd -p -a eth0 & [14] Command: cat /etc/motd . . . For further information check: http://www.uclinux.org/ Execution Finished, Exiting Sash command shell (version 1.1.1) 看到了?JFFS2和MTD都打开了,FLASH内存也被“CFI探测”发现了,2个 MTD分区也被创建了(/dev/mtd0和/dev/mtd1)。 查看一下MTD的分区列表: /> cd /proc /proc> cat mtd dev: size erasesize name mtd0: 00040000 00038000 "dBUG (256K)" mtd1: 001c0000 00040000 "user (1792K)" 尝试着在MTD的user分区(/dev/mtd1)上创建一个JFFS2 image: /proc> cd /tmp /var/tmp> mkdir fs /var/tmp> mkdir jffs2 /var/tmp> mkdir jffs2/bin /var/tmp> cd jffs2 /var/tmp/jffs2> vi file1 /var/tmp/jffs2> cat file1 coucou /var/tmp/jffs2> cd .. /var/tmp> mkfs.jffs2 -d jffs2 -o jffs2.img /var/tmp> erase /dev/mtd1 /var/tmp> cp jffs2.img /dev/mtd1 MTD_open MTD_write MTD_close “Mount”JFFS2分区: /var/tmp> mount -t jffs2 /dev/mtdblock1 /mnt mtdblock_open ok /var/tmp> cd /mnt /mnt> ls bin file1 toto /mnt> cd /proc /proc> cat mounts rootfs / rootfs rw 0 0 /dev/root / romfs ro 0 0 /proc /proc proc rw 0 0 /dev/ram1 /var ext2 rw 0 0 /dev/mtdblock1 /mnt jffs2 rw 0 0 查看一下所有相关的设备文件(/dev/目录): /proc> ls -l /dev . . . crw------- 1 0 0 90, 0 Jan 01 1970 mtd0 crw------- 1 0 0 90, 2 Jan 01 1970 mtd1 crw------- 1 0 0 90, 6 Jan 01 1970 mtd3 crw------- 1 0 0 90, 8 Jan 01 1970 mtd4 crw------- 1 0 0 90, 10 Jan 01 1970 mtd5 crw------- 1 0 0 90, 12 Jan 01 1970 mtd6 crw------- 1 0 0 90, 14 Jan 01 1970 mtd7 brw------- 1 0 0 31, 0 Jan 01 1970 mtdblock0 brw------- 1 0 0 31, 1 Jan 01 1970 mtdblock1 brw------- 1 0 0 31, 2 Jan 01 1970 mtdblock2 brw------- 1 0 0 31, 3 Jan 01 1970 mtdblock3 brw------- 1 0 0 31, 4 Jan 01 1970 mtdblock4 brw------- 1 0 0 31, 5 Jan 01 1970 mtdblock5 brw------- 1 0 0 31, 6 Jan 01 1970 mtdblock6 brw------- 1 0 0 31, 7 Jan 01 1970 mtdblock7 . . . 最后,你也可以“umount”JFFS2分区: /proc> umount /mnt mtdblock_release ok 就是这样了。 5. CONCLUSION(结论) 本文中,我描述了在µClinux 中怎样使用MTD/JFFS2 的方法(step by step),并在M5407C3板上通过测试: 相关的测试条件是: · Linux kernel version 2.4.19. · µClinux version 20020927. · m68k-elf-tools version 20020410. 另外,我使用的PC是Dell laptop (Inspiron 8200, P IV at 1,7 GHz) under RedHat 8.0. |
How to use MTDJFFs2(中文)
最新推荐文章于 2022-09-24 16:09:46 发布