uClinux下使用MTD和jffs2方法

admin @ 2014-03-25 , reply:0

概述
       uCLinux默認的根文件系統是romfs,由於romfs是一個只讀的文件系統,當你的嵌入式設備動態的修改了一些文件……

        uCLinux默認的根文件系統是romfs,由於romfs是一個只讀的文件系統,當你的嵌入式設備動態的修改了一些文件,它無法保存。雖然 uClinux在預設配置下在DRAM中開闢了一塊區域用作 RAMDISK保存生成的文件,但是當設備在複位后所有在DRAM的數據都將消失。怎麼才能保存動態生成的數據,如果需要存儲的文件容量又不大(1M左右),JFFS是一個不錯的選擇。它可以動態的把DRAM中的數據燒入Flash中,它的垃圾收集功能可以清除過時的數據。JFFS2是它的第二版,由REDHAT公司開發。下面我就將闡述我是如何在uClinux下使用JFFS2的。
        目前只有LINUX支持JFFS(JFFS2),據說eCos將要支持它,不過具體情況我不是很清楚。我用的uClinux是uClinux-dist-20030522.tar.gz。patch是由dailzh寫的補丁,請到它的網址(http://www.dailzh.com/)下載。我使用的Mcu是Samsung公司的s3c4510b。
       要使用JFFS2,必須先啟用MTD,MTD把文件系統和具體的Flash設備相隔離,上層的文件系統不用關心你使用的是什麼flash,自有MTD幫你處理Flash的具體操作(例如erase,write,read)。如果你想進一步了解MTD,請參閱附錄的相關內容。所以,我必須先要修改MTD。

Step1:
由於ROM設備和MTDBlock設備的主設備號(major)都是31,所以如果你不想把JFFS2作為根文件系統的話,必須修改他們之一的major。如果你要修改JFFS2的設備major,在uClinux-dist\linux-2.4.x\include\linux\mtd\mtd.h中把
#defineMTD_BLOCK_MAJOR 31
改成
#defineMTD_BLOCK_MAJOR 30
如果你要修改ROM的major,在uClinux-dist\linux-2.4.x\include\linux\major.h和uClinux-dist\linux-2.4.x\drivers\block\blkmem.c中把
#defineBLKMEM_MAJOR31
改成
#defineBLKMEM_MAJOR30

 Step2:
 添加MTD設備。在uClinux-dist\vendors\Samsung\4510B\Makefile中添加MTD的字元設備和塊設備。
mtd0,c,90,0mtd1,c,90,2 \
mtdblock0,b,30,0mtdblock1,b,30,1 \
添加設備的數目根據你自己的需要酌情確定,另一點要說明的是:mtd字元設備次設備號(minor)偶數是可擦寫的,奇數是只讀的。

Step3:
添加在flash上的map文件。在uClinux-dist\linux-2.4.x\drivers\mtd\maps下添加自己mcu的map,例如我添加的是s3c4510b.c,它是仿照m5272c3.c修改的,內容如下:
/*
 *NormalmappingsofchipsonSamsungs3c4510binphysicalmemory
 */

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

#defineWINDOW_ADDR0x01000000
#defineWINDOW_SIZE0x100000
#defineBUSWIDTH2

staticstructmtd_info *mymtd;

__u8s3c4510b_read8(structmap_info *map,unsignedlongofs)
{
return__raw_readb(map->map_priv_1 +ofs);
}

__u16s3c4510b_read16(structmap_info *map,unsignedlongofs)
{
return__raw_readw(map->map_priv_1 +ofs);
}

__u32s3c4510b_read32(structmap_info *map,unsignedlongofs)
{
return__raw_readl(map->map_priv_1 +ofs);
}

voids3c4510b_copy_from(structmap_info *map,void *to,unsignedlongfrom,ssize_tlen)
{
memcpy(to, (void *)(map->map_priv_1 +from),len);
}

voids3c4510b_write8(structmap_info *map,__u8d,unsignedlongadr)
{
__raw_writeb(d,map->map_priv_1 +adr);
}

voids3c4510b_write16(structmap_info *map,__u16d,unsignedlongadr)
{
__raw_writew(d,map->map_priv_1 +adr);
}

voids3c4510b_write32(structmap_info *map,__u32d,unsignedlongadr)
{
__raw_writel(d,map->map_priv_1 +adr);
}

voids3c4510b_copy_to(structmap_info *map,unsignedlongto,constvoid *from,ssize_tlen)
{
memcpy((void *)(map->map_priv_1 +to),from,len);
}

structmap_infos3c4510b_map = {
name: "S3C4510Bflashdevice",
size:WINDOW_SIZE,
buswidth:BUSWIDTH,
read8:s3c4510b_read8,
read16:s3c4510b_read16,
read32:s3c4510b_read32,
copy_from:s3c4510b_copy_from,
write8:s3c4510b_write8,
write16:s3c4510b_write16,
write32:s3c4510b_write32,
copy_to:s3c4510b_copy_to
};

staticstructmtd_partitions3c4510b_partitions[] = {
        {
               name: "reservedforbootloader (64K)",
               size:0x010000,
               offset:0x0,
 mask_flags:MTD_WRITEABLE
        },
 {
 name: "user (960K)",
 size:0xF0000,
 offset:0x10000
 }
};

int__initinit_s3c4510b(void)
{
       printk(KERN_NOTICE "s3c4510bflashdevice: %xat %x\n",WINDOW_SIZE,WINDOW_ADDR);
s3c4510b_map.map_priv_1 = (unsignedlong)ioremap(WINDOW_ADDR,WINDOW_SIZE);

if (!s3c4510b_map.map_priv_1) {
 printk("Failedtoioremap\n");
 return-EIO;
 }
mymtd =do_map_probe("jedec_probe", &s3c4510b_map);
if (mymtd) {
 mymtd->module =THIS_MODULE;
 mymtd->erasesize =0x10000;
 returnadd_mtd_partitions(mymtd,s3c4510b_partitions,sizeof(s3c4510b_partitions) /sizeof(structmtd_partition));
 }
iounmap((void *)s3c4510b_map.map_priv_1);
return-ENXIO;
}

staticvoid__exitcleanup_s3c4510b(void)
{
if (mymtd) {
 del_mtd_partitions(mymtd);
 map_destroy(mymtd);
 }
if (s3c4510b_map.map_priv_1) {
 iounmap((void *)s3c4510b_map.map_priv_1);
 s3c4510b_map.map_priv_1 =0;
 }
}

module_init(init_s3c4510b);
module_exit(cleanup_s3c4510b);
需要說明的幾點
1. 我使用的flash是hy29f800tt,它的容量是1mbyte(或者512kword),
#defineWINDOW_ADDR0x01000000
#defineWINDOW_SIZE0x100000
#defineBUSWIDTH2
定義它的基地址,容量和寬度,它的基地址和容量可參看
uClinux-dist\linux-2.4.x\include\asm-armnommu\arch-snds100\hardware.h中的聲明,BUSWIDTH =2表示是16bit。
2. 在m5272c3.c中的函數memcpy_fromio和memcpy_toio改有memcpy,原因是當使用前二個函數時cp命令不能使用,具體是什麼原因目前我也不清楚。
3.
staticstructmtd_partitions3c4510b_partitions[] = {
        {
               name: "reservedforbootloader (64K)",
               size:0x010000,
               offset:0x0,
 mask_flags:MTD_WRITEABLE
        },
 {
 name: "user (960K)",
 size:0xF0000,
 offset:0x10000
 }
};
是在你的flash設備中分區情況,我是分了二個區,你根據需要自己加減,mask_flags:MTD_WRITEABLE表示此區只讀。
4.mymtd->erasesize =0x10000;表示擦除的大小,hy29f800tt是64kbyte。
為了把它集成到uClinux配置中,要修改uClinux-dist\linux-2.4.x\drivers\mtd\maps\config.in
if [ "$CONFIG_S3C4510B" ];then
   dep_tristate 'CFIFlashdevicemappedonSamsungS3C4510B'CONFIG_MTD_S3C4510B $CONFIG_MTD_CFI
fi
不過我沒有成功,應該是要選上另一個配置選項才能顯示它,我在這裡取了個巧,我把它加到
if [ "$CONFIG_ARM" = "y" ];then
dep_tristate ' CFIFlashdevicemappedonSamsungS3C4510B'CONFIG_MTD_S3C4510B $CONFIG_MTD_CFI
中去。
和uClinux-dist\linux-2.4.x\drivers\mtd\maps\Makefile
obj-$(CONFIG_MTD_S3C4510B) +=s3c4510b.o

Step4:
添加flash的驅動。(norflash分cfi 和jedec兩種介面.)
uClinux-dist\linux-2.4.x\drivers\mtd\chips下的是chip的驅動層程序(《LinuxMTD源代碼分析》有很好的說明),由於hy29f800tt不在支持範圍之內,但它和AM29F800BT兼容,只不過Manufacturersid不同,所以我在jedec_table[]中添加
{
 mfr_id:MANUFACTURER_HYNIX,
 dev_id:HY29F800TT,
 name: "HYNIXHY29F800TT",
 DevSize:SIZE_1MiB,
 NumEraseRegions:4,
 regions: {ERASEINFO(0x10000,15),
    ERASEINFO(0x08000,1),
    ERASEINFO(0x02000,2),
    ERASEINFO(0x04000,1)
  }
 }
其他不支持的flash晶元的驅動如何添加,我沒有試。

Step5:
在makemenuconfig下配置選項。
在linuxKernelv2.4.20-uc0Configuration下
MemoryTechnologyDevices(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 
 RAM/ROM/Flashchipdrivers下
  CONFIG_MTD_CFI=Y
    CONFIG_MTD_JEDECPROBE=Y
    CONFIG_MTD_CFI_AMDSTD=Y
 Mappingdriversforchipaccess下
  CONFIG_S3C4510B=Y
Filesystems下
 CONFIG_JFFS2_FS=Y
   CONFIG_JFFS2_FS_DEBUG=2
在uClinuxv1.3.4Configuration下
FlashTools下
 CONFIG_USER_MTDUTILS=Y
   CONFIG_USER_MTDUTILS_ERASE=Y
   CONFIG_USER_MTDUTILS_ERASEALL=Y
   CONFIG_USER_MTDUTILS_MKFSJFFS2=Y
BusyBox下選中cat ,cp ,dd,mount,umount,mkdir工具。

還有要說明的幾點:(可能是uClinux的bugs吧,不是很清楚!)
(1)在uClinux-dist\user\mtd-utils\mkfs.jffs2.c中註釋#include<libgen.h>
(2)JFFS2是採用壓縮格式,我沒有採用zlib庫,而是把uClinux-dist\user\pppd\pppdump\zlib.c和zlib.h拷貝到uClinux-dist\user\mtd-utils下,在它的Makefile中改成
JFFS2_OBJS =crc32.omkfs.jffs2.ocompr_zlib.ocompr_rtime.ozlib.o
mkfs.jffs2: $(JFFS2_OBJS)
 $(CC) $(LDFLAGS) $(CFLAGS)-o $@ $^ $(LDPATH)  -lz $(LDLIBS) –lz不要




[admin via 研發互助社區 ] uClinux下使用MTD和jffs2方法已經有2757次圍觀

http://cocdig.com/docs/show-post-42533.html