- 论坛徽章:
- 0
|
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 |
|