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=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

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).

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: