免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 842 | 回复: 0
打印 上一主题 下一主题

HOW TO USE MTD/JFFS2 UNDER µClinux [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-04-14 15:51 |只看该作者 |倒序浏览

HOW TO USE MTD/JFFS2 UNDER µClinux
Patrice KADIONIK, Professor Assistant at the ENSEIRB School of Electrical Engineering, Telecommunication, and Computer Science
kadionik@enseirb.fr

http://www.enseirb.fr/~kadionik

UPDATED

  • 2004-01-07: 6 blocs at least for using JFFS2 and not 5. Thanks to Mike Konstantinides
  • 2004-01-08: Typo error. Thanks to Mark Gibson. Two URLS presenting JFFS2 added. Thanks to Aldo Dolfi


1. MOTIVATIONS
This HOWTO presents step by step how to enable and use MTD/JFFS2 features under µClinux.
I'm currently teaching embedded system programming and propose to my students practical exercices on µClinux on Motorola M5407C3 ColFire boards. In every embedded system, you have some FLASH memory. We can use it for saving configuration parameters in a raw binary format. With embedded Linux, it's now possible to put a file system in FLASH and mount it after from the embedded Linux OS. The technique used here is to enable the MTD (Memory Technology Device) technology in order to hide the physical FLASH programming methods (reading, erasing sector, writing...) and put abose a JFFS(2) file system (Journalling Flash File System) supported by Linux and µClinux. JFFS2 is a robust file system supporting power failure without fsck checking after reboot.
  
JFFS
JFFS2
MTD
FLASH, RAM
Another way of using FLASH memory is to put in it a Linux kernel with a bootloader that decompresses the Linux kernel into the RAM memory and launches it after. This point will be not discussed here.
I strongly recommand to read, read and read these following documents that should become familiar to you before reading this HOWTO:

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
This point is just a resume extracted from the preceding documents (from the www.embeddedlinuxworks.com
site,
an article from Vipin Malik).
"In the year 2000, Axis Communications AB (
www.axis.com
), released the first version of the JFFS file system. It was also Open Sourced. This was a system designed from the get-go for truly embedded Linux systems. JFFS is implemented directly on the FLASH devices, cognizant of the erase sector boundaries, and size of the FLASH device.

The adoption of the file system was further sped up by the fact that a raw FLASH chip translation layer was already available- in the form of MTD (Memory Technology Device) device drivers. Using this HAL (Hardware Abstraction Layer) JFFS could be mounted on any raw random access device (i.e. any RAM, FLASH from any mfg.) as long as a MTD driver was available for it.
If one was not available, all you had to do was take an existing driver and modify the read/write/erase routine to your particular chip and mount JFFS on it- without knowing anything about JFFS itself. Combining the JFFS system with the device specific MTD (Memory Technology Device) raw FLASH chip device drivers already being developed for Linux, you could now have a complete solution with the MTD driver layer providing a level of abstraction for the JFFS file system layer.
In this manner JFFS was (is) not tied directly with any particular memory technology. Any device that can support, random (or even pseudo random- like NAND FLASH) can be interfaced with MTD, and hence with JFFS. By design, JFFS (and subsequently JFFS2) is designed to guarantee 1 (more on this in a minute) meta-data or "formatting" reliability of the file system layer. This means that if your write() system call returned, the data are guaranteed to be there even if power fails. This also means that if the power failed during the write() command and complete data did not get written to the FLASH chip, then either older data, newer data or a combination is guaranteed to be there. Your file will not get corrupted, successful write or not- power fail or not!
The original JFFS file system was designed as a "append only" type of file system. What this means that good data was never overwritten, even if you did a rewind() on an open file and then fwrite() to it. New data was always appended to the end of the last write to the fs. Some meta data written along with the block would make sure that the written block was written "logically" to the correct place in the file being written to. On restart (or mount), the entire file system would be scanned and the scattered blocks be re-arranged so that newer "stamped" blocks, that have logically overwritten older blocks were returned when that portion of the file was read. The older blocks would be marked for "garbage collection", to be deleted at a later time. One beneficial side effect of this append-only structure is that it provides a natural wear leveling on the FLASH, regardless if the file is being written to or not (i.e. even the FLASH being used by the static portions of the file system are wear levelled). Power Down Reliability of JFFS- the Reality I have done some extensive testing on the system and have submitted fixes (that are in the latest version of the CVS) that increases the power fail reliability of the JFFS file system from about 10 power fails (when I found it) to about 500+ reliable power fails. There is still a bug in the system, that causes the JFFS file system to loose some files (even static files) at random! I would NOT recommend this file system (as it currently stands) for production.
The solution? JFFS2. JFFS2 is the second version in the JFFS anthology. It was based on the design concepts of JFFS, but was implemented by Redhat (
www.redhat.com
). It takes a different track to reliability. In this system, each "erase sector" is managed independently and can be addressed out-of-order. A collection of known erase sectors is always kept available to use to add new files to the system (or to even overwrite older files on the system). Again, to guarantee power down reliability, no part of an existing file is ever overwritten, before the part that overwrites it is successfully (with CRC and version stamp) stored on the FLASH device. Then the older part can be marked for garbage collection and deleted during the erase of the sector in which it resides when all its neighbors have been either similarly marked or moved to another sector.

As an added bonus, JFFS2 also supports compression. All file data being written to the system gets compressed using zlib (and some custom mod's to it). Data being read out of the system are also (obviously) decompressed on the fly. So you can never really tell that your data are being compressed. Now you can use ASCII files for log or config files rather than binary files. Of course your binary files will also be compressed. Plus if your files are very "sparse", i.e. with lots of empty space in them, you can store them on JFFS2 without a penalty. One down side to this is that if you are writing compressed data to the system, the CPU will spend time trying to compress it further. At this time of writing, compression cannot be turned off. There are some plans to implement this feature however (even turn it off on a directory by directory basis!)."

3. STEP 1: ENABLING MTD/JFFS2 UNDER µClinux
On my M5407C3 Motorola board, I have a 16 bit FLASH memory (AMD Am29PL160C) present in the memory mapping between $7FE00000 and $7FFFFFFF.
You have to read carefully the technical data on your FLASH memory chip and find its sector address table:

My FLASH memory has 11 sectors with different sizes. Its contains the dBUG Motorola monitor in the first 256 Kbytes (SA0 to SA3). The rest of the memory is available to the user (SA4 to SA10, 256 Kbytes each). It is also possible to erase the dBUG monitor and use the entire memory (the dBUG monitor can be installed again with the BDM cable). I've choosen to define 2 MTD partitions:

  • The dBUG partition: $7FE00000 to $7FE3FFFF (256 Kbyte size). I don't want to erase the monitor...
  • The user partition: $7FE40000 to $7FFFFFFF (1792 Kbyte size).

If you erase the dBUG monitor, you have just one big user partition:

  • The user partition: $7FE00000 to $7FFFFFFF (2 Mbyte size).

It's important to notice (read in the µClinux archive) that you have to create each MTD partition with at least 6contiguous sectors in order to use JFFS(2) (for garbage collection).
You have first to enable MTD/JFFS2 during the µClinux configuration.
% cd uClinux-dist
% make xconfig

These are the MTD options that I've enabled:
% grep MTD linux-2.4.x/.config# Memory Technology Devices (MTD)CONFIG_MTD=yCONFIG_MTD_DEBUG=yCONFIG_MTD_DEBUG_VERBOSE=3CONFIG_MTD_PARTITIONS=yCONFIG_MTD_CHAR=yCONFIG_MTD_BLOCK=yCONFIG_MTD_CFI=yCONFIG_MTD_JEDECPROBE=yCONFIG_MTD_GEN_PROBE=yCONFIG_MTD_CFI_AMDSTD=yCONFIG_MTD_PHYSMAP=yCONFIG_MTD_PHYSMAP_START=0x7fe00000CONFIG_MTD_PHYSMAP_LEN=0x200000CONFIG_MTD_PHYSMAP_BUSWIDTH=2
With these MTD options, you have enabled the CONFIG_MTD_PHYSMAP option (see the uClinux-dist/linux-2.4.x/drivers/mtd/maps/physmap.c file), and you access to the entire FLASH memory with just one MTD partition.
For defining several MTD partitions, I've created a special physmap.c file (m5407c3.c file under the uClinux-dist/linux-2.4.x/drivers/mtd/maps/ directory).

I've also enabled the JFFS2 support during the µClinux kernel configuration:

  • File systems menu: JFFS2 support, JFFS2 debugging verbosity 2.


I've also enabled MTD/JFFS2 tools in the userland area:

  • Flash Tools menu: mtd-utils with erase, mkfs.jff2.
  • BusyBox menu: BusyBox with dd, mount, mount: loop devices, umount.


If you want several MTD partitions, you may modify the uClinux-dist/linux-2.4.x/drivers/mtd/maps/physmap.c file (see the Phil Wildshire's
document
for more explanations). I've choosen to create my own file that I've included in the µClinux distribution. You have several examples under the uClinux-dist/linux-2.4.x/drivers/mtd/maps/ directory. I've used the m5272c3.c as an example (written for a M5272C3 Motorola board).
I've obtained the
m5407c3.c
file:
#include
#include
#include
#include
#include
#include
#include
#include

#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);

The most important thing is the mtd_partition m5407c3_partitions[] structure that defines my 2 MTD partitions. (the rest was modified by a sed command under vi :-)).
In order to integrate this file in the µClinux distribution, I have:
  • added the following lines in the uClinux-dist/linux-2.4.x/drivers/mtd/maps/
    Config.in
    file:
    if [ "$CONFIG_M5407C3" ]; then dep_tristate ' CFI Flash device mapped on Motorola M5407C3' CONFIG_MTD_M5407C3 $CONFIG_MTD_CFI fi
  • added the following line in the uClinux-dist/linux-2.4.x/drivers/mtd/maps/
    Makefile
    file:
    obj-$(CONFIG_MTD_M5407C3) += m5407c3.o

    If you perform again a make xconfig, you have now:
    % cd uClinux-dist
    % make xconfig


    I don't use now the CONFIG_MTD_PHYSMAP default option:
    # 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
    You have to retrieve the Linux kernel version 2.4.19 (from
    here
    for example) and copy the files pushpull.c, zlib.c, zlib.h from the linux-2.4.19/fs/jffs2/ Linux kernel source directory under the uClinux-dist/linux-2.4.x/fs/jffs2/ µClinux source directory.

    3.2. Modifying files from the µClinux kernel distribution
    you have to modify the BLKMEM_MAJOR value from 31 to 30 in the files:

    • uClinux-dist/linux-2.4.x/drivers/block/blkmem.c (line 41).
    • uClinux-dist/linux-2.4.x/include/linux/major.h (line 66).

    in order to have no confusion on major numbers between MTD and BLKMEM.

    3.3. Modifying files from the µClinux M5407C3 BSP port
    You have to add to the file uClinux-dist/vendors/Motorola/M5407C3/
    Makefile
    the following lines:
    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 \
    . . .
    in order to create the device files used by MTD and JFFS2 under the /dev/ µClinux directory on the target device.

    4. STEP3: COMPILING
    You have now to compile all the µClinux distribution:
    % cd uClinux-dist
    % make dep
    % make

    4. STEP4: TESTING
    The last but not the least. You download the µClinux image file into the M5407C3 board by the network and launch the µClinux kernel:
    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

    These are the traces I've had on screen :
    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)

    You can see that JFFS2 and MTD are enabled. The FLASH memory has been found by CFI probing and 2 MTD partitions (/dev/mtd0 and /dev/mtd1) have been created.

    You can see the MTD partition listing:
    /> cd /proc
    /proc> cat mtd
    dev: size erasesize name
    mtd0: 00040000 00038000 "dBUG (256K)"
    mtd1: 001c0000 00040000 "user (1792K)"

    You can now create a JFFS2 image that you copy on the user MTD partition (/dev/mtd1):
    /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

    You can now mount the JFFS2 partition:
    /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

    You may control that you have all the requested device files under the /dev/ directory:
    /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
    . . .

    And finally, you can umount the JFFS2 partition:
    /proc> umount /mnt
    mtdblock_release
    ok
    That's all folks!

    5. CONCLUSION
    In this article, I've described step by step how to enable and use MTD/JFFS2 under µClinux. It was tested on a M5407C3 Motorola board.
    It was tested with:

    • Linux kernel version 2.4.19.
    • µClinux version 20020927.
    • m68k-elf-tools version 20020410.

    I've also used a Dell laptop (Inspiron 8200, P IV at 1,7 GHz) under RedHat 8.0.

    Nobody is perfect. If you find inaccurate informations, you can contact
    me
    .


    本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u3/93615/showart_1900086.html
  • 您需要登录后才可以回帖 登录 | 注册

    本版积分规则 发表回复

      

    北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
    未成年举报专区
    中国互联网协会会员  联系我们:huangweiwei@itpub.net
    感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

    清除 Cookies - ChinaUnix - Archiver - WAP - TOP