织梦CMS - 轻松建站从此开始!

罗索

Create Jffs2 for Linux Kernel 2.4(for arm and mips)

jackyhwei 发布于 2010-03-16 18:01 点击:次 
本文前面很多介绍的内容均来自于《HOW TO use MTD-JFFS2 under µClinux 》,文中介绍的方法在arm与mips上经过多次实验,没有问题
TAG:

Create Jffs2 for Linux Kernel 2.4

 

        本文前面很多介绍的内容均来自于《HOW TO use MTD-JFFS2 under µClinux 》,文中介绍的方法在arm与mips上经过多次实验,没有问题,如果读者在按照本文章讲到的方法进行mtd驱动加载,jffs2文件系 统构建的过程中遇到这里没有讲到的异常情况,可以联系我:guohui.great@gmail.com, 很乐意大家一起讨论。

 

         本文方法在arm与mips上面都经过测试,支持良好,无异常情况,在这里需要特别说明的是如果读者使用的是mips处理器,需要注意其寻址方式的不同, 由于mips是big-endian,而arm与x86是little-endian,所以它们的启动地起是不一样的,对于mips,复位地址是 0xbfc00000,对应的物理地址是0x1fc00000,在mtd驱动中,我们将使用实际的物理地址与长度。

         mips的程序地址和物理地址不会相等,但对于kseg0和kseg1虚拟地址和物理地址对应起来很方便。
mips cpu有用户模式与特权模式,在用户模式下,地址最高位为1的任何程序都会导致cpu的一个自陷。有些指令在用户态也会异常。
mips cpu:
0x00000000 ------- 0x80000000(2G)    user space, kuseg
0x80000000 ------- 0xa0000000(512M)    unmapped cached, kseg0
0x80000000 ------- 0xc0000000(512M)   unmapped uncached, kseg1
0xc0000000 ------- 0xffffffff(1G)    Mapped, kseg2
kuseg:用户态可见地址,在有mmu的机器中,这些地址将一概被转换。除非 mmu已经被设置好,否则不应该使用这些地址。
kseg0: 该区域的地址,几乎总要通过高速缓存来取,所以在告诉缓存适当初始化以前,不应该使用。这个区域在有MMU的系统中用来存放操作系统的核心。该区域地址通 过把最高位清零来映射到物理地址。
kseg1:系统 重启的入口点0xbfc00000房子这个区域。入口点相应的物理地址是0x1fc00000,这是什么意思?所以我们需要这个区域来存取系统初始的 rom,大多数人也把该区域用作IO寄存器空间。该区域地址通过把最高3位清零来映射到物理地址。
kseg2:该区域只能在核心态下使用,并且要经过MMU的转换。在MMU被设置之前,不要使用。可以 看出,这快区域被用来存放操作系统。
kseg0,kseg1和物理地址有非常简单的映射关系,不需要mmu转换。
程序地址就是我们送给 cpu的指令中所使用的地址。我们一开始会在程序地址的0xbfc00000处,但这个地址会被cpu映射到物理地址的0x1fc00000处。也就是说 最后cpu的地址总线送出去的其实是0x1fc00000这个地址,而我们在start.S中使用的是0xbfc00000这个地址。这个地址属于 kseg2,可以直接在核心态下使用,不会被mmu转换。   

1. MOTIVATIONS

This HOWTO presents step by step how to enable and use MTD/JFFS2 features under linux.

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.

 

 embeded fs

I strongly recommand to read, read and read these following documents that should become familiar to you before reading this 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

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 (http://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 (http://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 linux

Let us see,on the  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:

2

 

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 linux 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 linux configuration.

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=0x1fc00000//实际物理地址

CONFIG_MTD_PHYSMAP_LEN=0x200000

CONFIG_MTD_PHYSMAP_BUSWIDTH=2

With these MTD options, you have enabled the CONFIG_MTD_PHYSMAP option (see the 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 linux-2.4.x/drivers/mtd/maps/ directory). 

I've also enabled the JFFS2 support during the linux 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 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 linux distribution. You have several examples under the linux-2.4.x/drivers/mtd/maps/ directory. I've used the myownphysmap.c as an example (written for a ipmux board).

I've obtained the myownphysmap.c file:

/*

 * $Id: physmap.c,v 1.15 2001/10/02 15:05:14 dwmw2 Exp $

 *

 * Normal mappings of chips in physical memory

 */

 

#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/config.h>

 

#include <linux/mtd/partitions.h>

#include <linux/mtd/cfi.h>

//

//#define WINDOW_ADDR CONFIG_MTD_PHYSMAP_START

//#define WINDOW_SIZE CONFIG_MTD_PHYSMAP_LEN

//#define BUSWIDTH CONFIG_MTD_PHYSMAP_BUSWIDTH

#define WINDOW_ADDR 0x1fc00000

#define WINDOW_SIZE 0x00800000

#define BUSWIDTH 2

static struct mtd_info *mymtd;

__u8 physmap_read8(struct map_info *map, unsigned long ofs)

{

    return __raw_readb(map->map_priv_1 + ofs);

}

 

__u16 physmap_read16(struct map_info *map, unsigned long ofs)

{

    return __raw_readw(map->map_priv_1 + ofs);

}

 

__u32 physmap_read32(struct map_info *map, unsigned long ofs)

{

    return __raw_readl(map->map_priv_1 + ofs);

}

 

void physmap_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)

{

    memcpy_fromio(to, map->map_priv_1 + from, len);

}

 

void physmap_write8(struct map_info *map, __u8 d, unsigned long adr)

{

    __raw_writeb(d, map->map_priv_1 + adr);

    mb();

}

 

void physmap_write16(struct map_info *map, __u16 d, unsigned long adr)

{

    __raw_writew(d, map->map_priv_1 + adr);

    mb();

}

void physmap_write32(struct map_info *map, __u32 d, unsigned long adr)

{

    __raw_writel(d, map->map_priv_1 + adr);

    mb();

}

void physmap_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 physmap_map = {

    name: "Physically mapped flash",

    size: WINDOW_SIZE,

    buswidth: BUSWIDTH,

    read8: physmap_read8,

    read16: physmap_read16,

    read32: physmap_read32,

    copy_from: physmap_copy_from,

    write8: physmap_write8,

    write16: physmap_write16,

    write32: physmap_write32,

    copy_to: physmap_copy_to

};

#ifdef CONFIG_MTD_PARTITIONS

static struct mtd_partition incaip_partitions[] = {

    {

      name:    "U-Boot",  /* U-Boot firmware */

      size:    0x00030000,   /*  192KB */  

      offset:  0x00000000,

      //offset:   0x00000000

/*    mask_flags: MTD_WRITEABLE,       force read-only */

    },

    {

      name:    "Environment",    /* default kernel image */

      size:    0x00010000, /* 64kb */

      offset:  0x00030000,

       //offset:  0x00040000    

/*    mask_flags: MTD_WRITEABLE,       force read-only */

    },

    {

      name:    "Linux",   /* default kernel image */

      size:    0x00340000, /* 704KB+2560KB */

      offset:  0x00040000,

       //offset:  0x00040000    

       

/*    mask_flags: MTD_WRITEABLE,     force read-only */

    },

//  {

//    name:    "rootfs",  /* default root filesystem */

//    size:    0x00280000,/* 64kb*40=2560KB*/

//    offset:  0x000f0000,      

/*    mask_flags: MTD_WRITEABLE,     force read-only */

//  },

       {

      name:    "Jffs2",   /* default root filesystem */

      size:    0x00080000,/**/

      offset:  0x00380000,      

    }

};

#endif

int __init init_physmap(void)

{

       printk(KERN_NOTICE "physmap flash device: %x at %x\n", WINDOW_SIZE, WINDOW_ADDR);

    physmap_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE);

    //printk("physmap_map.map_priv_1 =0x%x",physmap_map.map_priv_1 );

    if (!physmap_map.map_priv_1) {

       printk("Failed to ioremap\n");

       return -EIO;

    }

    mymtd = do_map_probe("cfi_probe", &physmap_map);

    if(!mymtd)

       {

           mymtd = do_map_probe("jedec_probe", &physmap_map);         

       }

    if (mymtd)

       {

           mymtd->module = THIS_MODULE;

           //add_mtd_device(mymtd);

           //printk("add_mtd_device is Ok! ");

           mymtd->erasesize = 0x10000;//64KB

           return add_mtd_partitions(mymtd, incaip_partitions,sizeof(incaip_partitions)/sizeof(struct mtd_partition));

           //return 0;

       }

    iounmap((void *)physmap_map.map_priv_1);

    return -ENXIO;

}

static void __exit cleanup_physmap(void)

{

    if (mymtd) {

       //del_mtd_device(mymtd);

       del_mtd_partitions(mymtd);

       map_destroy(mymtd);

    }

    if (physmap_map.map_priv_1) {

       iounmap((void *)physmap_map.map_priv_1);

       physmap_map.map_priv_1 = 0;

    }

}

module_init(init_physmap);

module_exit(cleanup_physmap);

MODULE_LICENSE("GPL");

MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");

MODULE_DESCRIPTION("Generic configurable MTD map driver");

 NOTICE:实际上直接对physmap.c文件进行更改并不是一个很好的办法,这会破坏代码结构,最好还是建立自 己新的驱动文件,找一个相似的驱动文件进行对照更改。

The most important thing is the mtd_partition incaip_partitions[] structure that defines my 4 MTD partitions. (the rest was modified by a sed command under vi :-)).

In order to integrate this file in the linux distribution, mine is define:

  1. added the following lines in the linux-2.4.x/drivers/mtd/maps/Config.in file:

dep_tristate '  CFI Flash device in physical memory map' CONFIG_MTD_PHYSMAP $CONFIG_MTD_GEN_PROBE

if [ "$CONFIG_MTD_PHYSMAP" = "y" -o "$CONFIG_MTD_PHYSMAP" = "m" ]; then

   hex '    Physical start address of flash mapping' CONFIG_MTD_PHYSMAP_START 0x8000000

   hex '    Physical length of flash mapping' CONFIG_MTD_PHYSMAP_LEN 0x4000000

   int '    Bus width in octets' CONFIG_MTD_PHYSMAP_BUSWIDTH 2

fi

  1. added the following line in the linux-2.4.x/drivers/mtd/maps/Makefile file:

obj-$(CONFIG_MTD_INCAIP) += incaip.o 

If you perform again a make menuconfig, you have now:

% cd linux-2.4.20

% make menuconfig

 

 3

 

4

 

5

 

 

 对于.config生成的autoconfig.h文件我们不要修改!

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

3. STEP 2: MODIFYING THE linux KERNEL

3.1. Modifying files from the linux kernel distribution

you have to modify the MTD_BLOCK_MAJOR 31 value from 31 to 30 in the files:

  • linux-2.4.x/include/linux/mtd/mtd.h

由于ROM设备和MTDBlock设备的主设备号(major)都是31,所以如果你不想把JFFS2作为根文件系统的话,必须修改他们之一的 major。 

4. STEP3: COMPILING

You have now to compile all the linux distribution:

% cd linux-2.4.20

% make dep

% make

5. STEP4: TESTING

下载编译好的kernel,并启动:启动过程将会输出MTD分区信息,这样MTD基本配置好了。

进入系统后,如果没有在fstab中添加proc虚拟文件系统的自动挂载,我们就需要手动挂载一下,

#mount -t proc none /proc

#cat /proc/mtd

这样我们就可以看到我们在phpsmap.c中的分区信息,MTD对应的设备挂载点在/dev/mtdblock/下面。

现在我们要制作一个jffs2文件系统,对jffs2文件系统的操作才能真正确定我们的MTD支持 是否成功添加。

#./mkfs.jffs2  -b e 0x10000 -s 0x20000  -d jffs2/ -o jffs2.img

Mkfs.jffs2有很多参数,具体开发的时候适情况而定。We use the -r option to specify the location of the directory containing the root filesystem, and the -o option to specify the name of the output file where the filesystem image should be stored. In addition to these options, we could use -l or -b to create little endian or big endian images, respectively. The JFFS2 compression ratio is much smaller than CRAMFS. For a root filesystem containing 7840 KB, for example, the resulting JFFS2 image is 6850 KB in size. The compression ratio is a little above 10%.

Emergnecy help:

 -c            Check device for bad blocks before building file system.

 -O            Provide case-insensitive support for OS/2 compatability.

 -q            Quiet execution.

 -V            Print version information only.

 -L vol_label  Set volume label for the file system.

 -s log_size   Set log size (in megabytes).

#erase /dev/mtdblock/3

# cp jffs2.img /dev/mtdblock/3

MTD_open

MTD_write

MTD_close

 也可以在uboot里面通过uboot命令烧录。

You can now mount the JFFS2 partition:

# mount -t jffs2 /dev/mtdblock/3 /mnt

mtdblock_open

ok

#ls /mnt

就可以看到jffs2文件系统中的文件了,可以在其中读写文件,重启后验证一下写入的数据是否依然存在。

6.JFFS2作为根文件系统

1.设置内核启动参数

    在U-BOOT的命令终端设置如下:

    #setenv bootargs root=/dev/mtdblock/4 rootfstype=jffs2 rw console=ttySAC0,38400 init=/linuxrc mem=1024M

2.配置内核支持JFFS2文件系统

     File systems ---> Miscellaneous filesystems --->

     <*>JournallingFlash File System v2 (JFFS2) support

     [*]JFFS2write-bufferingsupport

     [*]AdvancedcompressionoptionsforJFFS2

     [*]JFFS2ZLIBcompressionsupport

     [*]JFFS2RTIMEcompressionsupport

     [*] JFFS2 RUBIN compression support

小结:

本文档面向有一定经验的实际开发人员,有很多常识性的东西我就没有必要去浪费文字,比如:几种文件系统的区别?如何选择自己合适的文件系统?如何制 作各种不同的文件系统?如何加载文件系统?flash的datasheet中的提到的一些操作知识,等等一系列常识性的问题我就没有作详细分析,如果读者 不太明白其中某些概念,建议阅读《Building Embedded Linux Systems》,你将从中找到 大部分你需要的答案。开发过程中有许多简单的具体操作细节在此并没有说明,在具体开发的时候应该适具体开发环境和需求而定。

(罗国辉)
本站文章除注明转载外,均为本站原创或编译欢迎任何形式的转载,但请务必注明出处,尊重他人劳动,同学习共成长。转载请注明:文章转载自:罗索实验室 [http://www.rosoo.net/a/201003/8778.html]
本文出处:CSDN博客 作者:罗国辉
顶一下
(0)
0%
踩一下
(0)
0%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片
栏目列表
将本文分享到微信
织梦二维码生成器
推荐内容