求解:关于nand flash中的ECC效验的问题---内核、uboot、yaffs的ECC冲突

时间:2022-10-28 04:52:41
    前两天在对博创up-2410s的arm实验箱做文件系统移植,发现cramfs文件系统的移植,烧写,挂载都很顺利,但是做yaffs文件系统移植,烧写后挂载不上,查了很多资料才注意到nand flash的ECC效验这个问题。
    网上有很多这方面的资料,但大多都是相互转载过来,转载过去,对于关键问题都一笔带过,语焉不详。

   1.我的情况:
   ------我用的u-boot是按照网上Tekkaman  Ninja大侠《移植U-Boot.1.2.0到博创2410-S(S3C2410A)》来做的,关键是他选择了打开CFG_NAND_LEGACY,沿用老式的nand驱动。按照u-boot自己的方式进行ECC效验。
   ------kernel是用的博创公司提供的linux-2.6.18-2410,drivers/mtd/nand/s3c2410.c中,我发现关于ECC效验是chip->ecc.mode=NAND_ECC_HW。应该是硬件产生ECC效验码。---网上提到改成NONE,也有人说用不着。

   结果:下载u-boot到sdram,再用nand write写到nand flash,同理烧写内核,cramfs,最后发现u-boot引导内核成功,挂载cramfs文件系统也挂在上了。yaffs挂载失败----当然,yaffs本省带ECC效验,其组织模式与cramfs也不同。

   2.网上的资料:
   ------内核采用的是s3c2410硬件产生的ECC效验,新版本的内核也可以选择利用软件效验的方式。
   ------u-boot老版本是采用的自己的效验方式。现版本也可以选择基于mtd的ECC效验方式。当要使用老版本驱动方式时,打开CFG_NAND_LEGACY宏。
   ------yaffs文件系统在制作时,已近加入了自己的ECC效验码。
还有什么u-boot与内核ECC效验冲突,导致u-boot不能引导内核,u-boot烧写yaffs时二者ECC效验冲突,导致烧写yaffs失败,内核挂载yaffs时效验码冲突,导致挂载不上文件系统。
   
    3.我的问题
   -------内核、u-boot、yaffs的ECC效验码是在什么时期产生的,谁控制生成的,谁控制读取。读取ECC效验时一方面的ECC效验码是nand flash中存储的,另一方面用于对比的ECC码时谁控制生成的,怎么控制。
   例如:内核镜像zImage.img中是否含ECC效验码(我想应该是不包含的),u-boot.bin中呢?yaffs文件系统中应该是包含的。
   u-boot烧写本身(从SDRAM中到nand flash中)时,应该是用u-boot的ECC 产生机制生成ECC码,烧写内核,文件系统时呢?假如烧写内核时用的u-boot的ECC,而u-boot引导内核时也是与自己产生的ECC码对比效验,怎么网上有内核、uboot的ECC效验冲突一说?
    我用u-boot烧写cramfs到nand,由于打开CFG_NAND_LEGACY宏,而内核是硬件产生ECC(由于chip->ecc.mode=NAND_ECC_HW),按照网上的说法二者是不一样的,怎么会没冲突,顺利挂载?
    我在cramfs文件系统下读文件,在yaffs文件系统下读写文件,ECC效验有什么不同。

 -------内核chip->ecc.mode=NAND_ECC_选择HW.NONE.SOFT,到底有什么区别?u-boot打开CFG_NAND_LEGACY宏,或不打开,对ECC效验有什么影响?mtd ECC到底是怎么回事?
       



希望对这方面有自己理解的朋友们谈一下自己的理解、看法,更期待有高手、大侠予以点拨。如果是完全从网上摘抄的内容就免了,因为网上资料鱼目混珠,我能力有限难以辨别。













































   

10 个解决方案

#1



几点建议。

1. 关掉 ECC 校验, 不管是硬件的还是 yaffs 文件系统的。
MTD_NAND_S3C2410_HWECC
YAFFS_DOES_ECC                                                                           

2. 其实你的问题更多是烧写和 yaffs 的 oob 布局的问题,简单点说是烧写的时候, oob 信息不正确。


3。 贴出你的 错误信息。

4. cramfs 文件系统 能顺利挂载应该也不奇怪, 因为这个文件系统根本就不关心 ECC 信息,也不使用 oob 区域。



#2


mark一下,楼主提出了太多问题。

#3


分别回答楼主的三个问题:
1 标准内核好像不支持yaffs文件系统,需要通过打补丁的方式使得内核支持yaffs,这点你确认做过了么?如果内核不支持yaffs,挂载显然会失败;
2 NAND Flash的ECC功能可以通过软件或者硬件方式实现,如果bootloader和kernel的都是通过硬件来实现ECC,一般不会导致冲突,因为都是通过NAND Flash controller产生ECC校验码,楼主所说的产生冲突可能是由bootloader和kernel使用的软件ECC算法不同导致的,但是一般情况下,bootloader中的ECC算法基本都是从内核中移植过去的(kernel中ecc算法实现driver/mtd/nand/nand_ecc.c),楼主可以尝试换个版本的kernel引导试试看,因为不同kernel版本中ECC算法的实现是有差异的,不过我做过测试,2.6.28和2.6.30的ECC算法实现虽然看上去差异很大,但是功能其实是一样的,说得简单点,就是28的ECC算法和30的ECC算法是兼容的;
3 ECC的原理,说得简单点,就是向NAND Flash写数据时,每256或512字节会生成一个校验码写在每个page的OOB区,当从NAND Flash读数据时,每读取256或512字节数据,也会生成一个ECC校验码,拿这个校验码与存放在OOB区的校验吗对比看看是否一致,就可以知道读取的数据是否正确,ECC校验码可以由硬件或者软件生成。从这个原理来看,rootfs的img文件里面是不可能包含ECC校验码的。
  不知道这样能不能回答楼主的三个问题。
  如果还是不能解决的话,可以尝试着更换一个bootloader看看,给你推荐一个:
 

#4


  接着上面一帖。
  给你推荐一个国内开源的bootloader:g-bios,我关注这个项目很久了,也拿它和uboot做过对比,无论从代码的质量还是架构方面,都比uboot要优秀,当然,支持的板子没有uboot多。不过对2410是支持的,引导kernel挂在yaffs的文件系统,这个我下载测试了一下,没问题。
  获取g-bios源码的方式:
  git clone git://github.com/maxwit/g-bios

#5


 ECC校验码可以由硬件或者软件生成。从这个原理来看,rootfs的img文件里面是不可能包含ECC校验码的。
==============================================================
这个说法是不对的。 具体可以参考 mkyaffs2image.c 中的 
static int write_chunk(__u8 *data, __u32 objId, __u32 chunkId, __u32 nBytes)
{
        char spare[spareSize];
        yaffs_ExtendedTags t;
        yaffs_PackedTags2 *pt = (yaffs_PackedTags2 *)spare;

        memset(spare, 0xff, spareSize);

        error = write(outFile,data,chunkSize);
        if(error < 0) return error;

        yaffs_InitialiseTags(&t);

        t.chunkId = chunkId;

        t.serialNumber = 1;    
        t.byteCount = nBytes;
        t.objectId = objId;

        t.sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;
        t.chunkUsed = 1;
        nPages++;

        yaffs_PackTags2(pt,&t);

        if (convert_endian)
        {
                little_to_big_endian(pt);
        }

// 这里写入的就是 oob 信息,当然也是包括 ECC 信息的,而这个 ECC 信息是由yaffs_PackTags2 算出来的。
// 关于这一点,需要查看 nand flash 的 oob 布局 
        return write(outFile,spare, spareSize);  
}


 

#6


引用 5 楼 pottichu 的回复:
ECC校验码可以由硬件或者软件生成。从这个原理来看,rootfs的img文件里面是不可能包含ECC校验码的。
==============================================================
这个说法是不对的。 具体可以参考 mkyaffs2image.c 中的 
static int write_chunk(__u8 *data, __u32 o……

其实我觉得可以将mkyaffs2image.c进行修改,让其在产生img是,将ECC给做了,有些yaffs版本yaffs_PackTags2是有3个参数的,最后一个参数是选择是否做ECC操作。
然后bootloader只负责将OOB区域写入FLash

#7


问题是mkyaffsimage生产的ECC是针对软件校验还是硬件校验?

#8


该回复于2011-03-15 17:03:49被版主删除

#9


ECC的原理:
就是向NAND Flash写数据时,每256或512字节会生成一个校验码写在每个page的OOB区,当从NAND Flash读数据时,每读取256或512字节数据,也会生成一个ECC校验码,拿这个校验码与存放在OOB区的校验吗对比看看是否一致,就可以知道读取的数据是否正确.

一般来说,kernel与cramfs是通过U-BOOT烧写到NAND Flash中,这个过程是向NAND Flash写数据,会产生ECC码,使用的是U—BOOT的ECC机制产生的(不管是硬件产生还是软件产生),然后这些ECC码会存放在NAND Flash的OOB区域。
当你启动Kernel时,会从NAND Flash中读数据,这是时候也会产生ECC码。使用的还是U—BOOT的ECC机制产生的,因为这个读NAND操作是还是处在U-Boot运行状态下。然后这个ECC码会与写Kernel时产生的ECC码(保存在OOB区域)做比较,看是否有错误。由于写Kernel与读Kernel都用的是U-BOOT的ECC产生机制,所以一般不会出错。

但你读Cramfs时,这个时候已经是内核状态啦。所以读Cramfs时用的Kernel的ECC产生机制,前面写Cramfs用的U-Boot机制,如果两种机制不一致(包括一个是硬件产生,一个是软件产生,或是软件产生算法不一样,或是OOB区域规划不一样),就会产生错误。

#10


这么说来,只要关闭内核中nandflash驱动不使用ECC,同时打开yaffs的YAFFS_DOES_ECC开关,mkyafsimage代码中oob数据跟内核中yaffs计算方式一样的话,就没有问题了?

#1



几点建议。

1. 关掉 ECC 校验, 不管是硬件的还是 yaffs 文件系统的。
MTD_NAND_S3C2410_HWECC
YAFFS_DOES_ECC                                                                           

2. 其实你的问题更多是烧写和 yaffs 的 oob 布局的问题,简单点说是烧写的时候, oob 信息不正确。


3。 贴出你的 错误信息。

4. cramfs 文件系统 能顺利挂载应该也不奇怪, 因为这个文件系统根本就不关心 ECC 信息,也不使用 oob 区域。



#2


mark一下,楼主提出了太多问题。

#3


分别回答楼主的三个问题:
1 标准内核好像不支持yaffs文件系统,需要通过打补丁的方式使得内核支持yaffs,这点你确认做过了么?如果内核不支持yaffs,挂载显然会失败;
2 NAND Flash的ECC功能可以通过软件或者硬件方式实现,如果bootloader和kernel的都是通过硬件来实现ECC,一般不会导致冲突,因为都是通过NAND Flash controller产生ECC校验码,楼主所说的产生冲突可能是由bootloader和kernel使用的软件ECC算法不同导致的,但是一般情况下,bootloader中的ECC算法基本都是从内核中移植过去的(kernel中ecc算法实现driver/mtd/nand/nand_ecc.c),楼主可以尝试换个版本的kernel引导试试看,因为不同kernel版本中ECC算法的实现是有差异的,不过我做过测试,2.6.28和2.6.30的ECC算法实现虽然看上去差异很大,但是功能其实是一样的,说得简单点,就是28的ECC算法和30的ECC算法是兼容的;
3 ECC的原理,说得简单点,就是向NAND Flash写数据时,每256或512字节会生成一个校验码写在每个page的OOB区,当从NAND Flash读数据时,每读取256或512字节数据,也会生成一个ECC校验码,拿这个校验码与存放在OOB区的校验吗对比看看是否一致,就可以知道读取的数据是否正确,ECC校验码可以由硬件或者软件生成。从这个原理来看,rootfs的img文件里面是不可能包含ECC校验码的。
  不知道这样能不能回答楼主的三个问题。
  如果还是不能解决的话,可以尝试着更换一个bootloader看看,给你推荐一个:
 

#4


  接着上面一帖。
  给你推荐一个国内开源的bootloader:g-bios,我关注这个项目很久了,也拿它和uboot做过对比,无论从代码的质量还是架构方面,都比uboot要优秀,当然,支持的板子没有uboot多。不过对2410是支持的,引导kernel挂在yaffs的文件系统,这个我下载测试了一下,没问题。
  获取g-bios源码的方式:
  git clone git://github.com/maxwit/g-bios

#5


 ECC校验码可以由硬件或者软件生成。从这个原理来看,rootfs的img文件里面是不可能包含ECC校验码的。
==============================================================
这个说法是不对的。 具体可以参考 mkyaffs2image.c 中的 
static int write_chunk(__u8 *data, __u32 objId, __u32 chunkId, __u32 nBytes)
{
        char spare[spareSize];
        yaffs_ExtendedTags t;
        yaffs_PackedTags2 *pt = (yaffs_PackedTags2 *)spare;

        memset(spare, 0xff, spareSize);

        error = write(outFile,data,chunkSize);
        if(error < 0) return error;

        yaffs_InitialiseTags(&t);

        t.chunkId = chunkId;

        t.serialNumber = 1;    
        t.byteCount = nBytes;
        t.objectId = objId;

        t.sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;
        t.chunkUsed = 1;
        nPages++;

        yaffs_PackTags2(pt,&t);

        if (convert_endian)
        {
                little_to_big_endian(pt);
        }

// 这里写入的就是 oob 信息,当然也是包括 ECC 信息的,而这个 ECC 信息是由yaffs_PackTags2 算出来的。
// 关于这一点,需要查看 nand flash 的 oob 布局 
        return write(outFile,spare, spareSize);  
}


 

#6


引用 5 楼 pottichu 的回复:
ECC校验码可以由硬件或者软件生成。从这个原理来看,rootfs的img文件里面是不可能包含ECC校验码的。
==============================================================
这个说法是不对的。 具体可以参考 mkyaffs2image.c 中的 
static int write_chunk(__u8 *data, __u32 o……

其实我觉得可以将mkyaffs2image.c进行修改,让其在产生img是,将ECC给做了,有些yaffs版本yaffs_PackTags2是有3个参数的,最后一个参数是选择是否做ECC操作。
然后bootloader只负责将OOB区域写入FLash

#7


问题是mkyaffsimage生产的ECC是针对软件校验还是硬件校验?

#8


该回复于2011-03-15 17:03:49被版主删除

#9


ECC的原理:
就是向NAND Flash写数据时,每256或512字节会生成一个校验码写在每个page的OOB区,当从NAND Flash读数据时,每读取256或512字节数据,也会生成一个ECC校验码,拿这个校验码与存放在OOB区的校验吗对比看看是否一致,就可以知道读取的数据是否正确.

一般来说,kernel与cramfs是通过U-BOOT烧写到NAND Flash中,这个过程是向NAND Flash写数据,会产生ECC码,使用的是U—BOOT的ECC机制产生的(不管是硬件产生还是软件产生),然后这些ECC码会存放在NAND Flash的OOB区域。
当你启动Kernel时,会从NAND Flash中读数据,这是时候也会产生ECC码。使用的还是U—BOOT的ECC机制产生的,因为这个读NAND操作是还是处在U-Boot运行状态下。然后这个ECC码会与写Kernel时产生的ECC码(保存在OOB区域)做比较,看是否有错误。由于写Kernel与读Kernel都用的是U-BOOT的ECC产生机制,所以一般不会出错。

但你读Cramfs时,这个时候已经是内核状态啦。所以读Cramfs时用的Kernel的ECC产生机制,前面写Cramfs用的U-Boot机制,如果两种机制不一致(包括一个是硬件产生,一个是软件产生,或是软件产生算法不一样,或是OOB区域规划不一样),就会产生错误。

#10


这么说来,只要关闭内核中nandflash驱动不使用ECC,同时打开yaffs的YAFFS_DOES_ECC开关,mkyafsimage代码中oob数据跟内核中yaffs计算方式一样的话,就没有问题了?