网上有很多这方面的资料,但大多都是相互转载过来,转载过去,对于关键问题都一笔带过,语焉不详。
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看看,给你推荐一个:
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
给你推荐一个国内开源的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);
}
==============================================================
这个说法是不对的。 具体可以参考 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
其实我觉得可以将mkyaffs2image.c进行修改,让其在产生img是,将ECC给做了,有些yaffs版本yaffs_PackTags2是有3个参数的,最后一个参数是选择是否做ECC操作。
然后bootloader只负责将OOB区域写入FLash
#7
问题是mkyaffsimage生产的ECC是针对软件校验还是硬件校验?
#8
#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区域规划不一样),就会产生错误。
就是向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看看,给你推荐一个:
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
给你推荐一个国内开源的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);
}
==============================================================
这个说法是不对的。 具体可以参考 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
其实我觉得可以将mkyaffs2image.c进行修改,让其在产生img是,将ECC给做了,有些yaffs版本yaffs_PackTags2是有3个参数的,最后一个参数是选择是否做ECC操作。
然后bootloader只负责将OOB区域写入FLash
#7
问题是mkyaffsimage生产的ECC是针对软件校验还是硬件校验?
#8
#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区域规划不一样),就会产生错误。
就是向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计算方式一样的话,就没有问题了?