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

罗索

uboot烧写yaffs2过程中,如何写入oob数据的

落鹤生 发布于 2010-05-22 17:28 点击:次 
uboot烧写yaffs2过程中,如何写入oob数据的?关于uboot 写yaffs2文件系统代码。现在正在看uboot烧写yaffs2的代码,有点疑问
TAG:

求助:关于uboot 写yaffs2文件系统代码

http://linux.chinaunix.net/bbs/thread-1125671-1-4.html

现在正在看uboot烧写yaffs2的代码,有点疑问
输入命令后执行do_nand,然后执行到nand_write_opts

  1. int nand_write_opts(nand_info_t *meminfo, 
  2.  const nand_write_options_t *opts) 
  3. ... 
  4. memcpy(data_buf, buffer, readlen); 
  5. buffer += readlen; 
  6.  
  7. if (opts->writeoob) { 
  8. /* read OOB data from input memory block, exit on failure */ 
  9. memcpy(oob_buf, buffer, meminfo->oobsize); 
  10.          
  11. buffer += meminfo->oobsize; 
  12.  
  13. /* write OOB data first, as ecc will be placed in there*/ 
  14. result = meminfo->write_oob(meminfo, 
  15.   mtdoffset, 
  16.   meminfo->oobsize, 
  17.   &written, 
  18.   (unsigned char *) 
  19.   &oob_buf); 
  20. ... 
  21.  
  22. result = meminfo->write(meminfo, 
  23.   mtdoffset, 
  24.   meminfo->oobblock, 
  25.   &written, 
  26.   (unsigned char *) &data_buf); 
在这段代码中,opts->writeoob=1,先执行了meminfo->write_oob,写了flash的OOB区,然后执行到了meminfo->write,meminfo->write=nand_write
  1. static int nand_write (struct mtd_info *mtd, loff_t to, 
  2.  size_t len, size_t * retlen, const u_char * buf) 
  3. return (nand_write_ecc (mtd, to, len, retlen, buf, NULL, NULL)); 
  4.  
  5. static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, 
  6.  size_t * retlen, const u_char * buf, 
  7.  u_char * eccbuf, struct nand_oobinfo *oobsel) 
  8. ... 
  9.  oobbuf = nand_prepare_oobbuf (mtd, eccbuf, oobsel, autoplace, numpages); 
  10.  while (written < len) { 
  11.   this->data_poi = (u_char*) &buf[written]; 
  12.  
  13.   ret = nand_write_page (mtd, this, page, &oobbuf[oob], 
  14.     oobsel, (--numpages > 0)); 
  15. ... 
  16. ... 
在nand_write_page 中又重新写了一遍OOB区,用的是上面函数的oobbuf,可是nand_prepare_oobbuf返回的指针是nand chip结构体中的oob_buf。所以最终flash的OOB区写入的是 nand chip结构体中的oob_buf。可纵观该程序没发现把文件中的OOB区读到oob_buf的步骤,所以很不理解 
【解答】
刚看到此问题,自己去看了足够长的时间的代码后,也还是没搞懂。
最后是问了同事,听了其解释,才明白是怎么回事。

【简单解释】
在详细解释之前,用最简单的语言解答此疑问就是:
第二次写oob的时候,oob_buf中前半部分都是0xFF,后半部分是ecc数据,
由于nand flash的特性,0xFF写入之后,原先的数据,仍然不变,
所以,nand flash上oob的后半部分是你第一次写的时候,保证是0xFF,此处第二次写ecc数据,也才能写入。
即,第二次写入的时候,oob前半部分由于是0xFF,写入nand对原先oob数据无影响;
Oob后半部分是ecc数据,可以正常的写入。
这样,隐晦地,保证了数据按照期望的写入nand flash。

【详细解释】
具体一点解释就是:

在解释下面内容之前,先简单说一下此处的一些假设,
1.假设是2K的pagesize的nand flash,对应的oob是64字节。
2.ECC在oob中的存放位置,按照nand_oob_64定义的,ECC放在32-63。
3.yaffs2数据存放在2-31部分,而byte0,byte1,是为了和坏块标记所兼容,放的是0xFF.

此段uboot写yaffs2的程序之所以能实现我们所期望的功能,最后写入了正确的值,主要是因为,nand flash的特性:
1.        在写入数据之前,一定要擦除(成0xFF),也即数据只能从1变成0,所以,如果想要写入数据(不全是0xFF)的话,就要保证写入前,已经全是0xFF。
2.        在nand flash里面已经写入数据之后,再写入0xFF的时候,里面的数据不变。

1.        第一次写oob数据的时候,前半部分是yaffs2的数据,后半部分是自己要保证是0xFF,写入后,nand flash上对应的oob就是 yaffs2+0xFF,类似于这样的数据:
OOB:
       ff ff 00 10 00 00 01 00
       00 00 00 00 00 00 ff ff
       00 00 30 23 84 bf 05 00
       00 00 05 00 00 00 ff ff
       ff   ff   ff ff ff ff ff ff
       ff   ff ff ff ff ff ff ff
       ff   ff   ff ff   ff   ff   ff ff
       ff   ff ff   ff ff   ff ff ff
其中,后半部分是你写之前要自己保证是0xFF的,以便后面写ecc的数据时候,能够写入。

2.       
第二次写入的时候的oob的数据,即oob_buf,其是从nand_write_page传进来的参数,是从
前面nand_prepare_oobbuf中返回的指针,看代码可以知道,即this->oob_buf,
这个this->oob_buf也就是mtd->priv-> oob_buf,其是在nand_scan的最后,全是赋值0xFF的:
       /* Preset the internal oob buffer */
       memset(this->oob_buf, 0xff, mtd->oobsize << (this->phys_erase_shift - this->page_shift));

此处被上面写完页数据的同时,在对应位置填充了ECC的数据后,就类似于这样的:
OOB:
       ff ff ff ff ff ff ff ff
       ff ff ff ff ff ff ff ff
       ff ff ff ff ff ff ff ff
       ff ff ff ff ff ff ff ff
       f0 ec 72 7b 9e 2f 0f 00
       07 d1 75 e5 47 72 0f 00
       fd 7d 33 5b 1d 2c 0e 00
       95 26 41 7c 61 aa 08 00

把这样的数据写入nand flash对应的oob的位置,就和上面说的,吻合了:
前面半部分是0xFF,写入后,不影响原有的数据,即不会影响第一次写入的oob的前半部分,即yaffs2的数据,后半部分,正好是我们要写的ECC,由于前面已经保证了是0xFF,所以这里可以正常写入。

【总结】
上述实现,估计是为了兼容其他不同类型的数据的写入,而把简单的事情,实现的这么复杂和隐晦的。
对于写yaffs2,很简单的办法,实际应该是,和我之前看到的,好像是1.1.6中的uboot中有的,关于写yaffs的代码:
  1. if (opts->writeyaffs) 
  2. /* read page data from input memory buffer */ 
  3. memcpy(data_buf, buffer, readlen); 
  4. buffer += readlen; 
  5. /* read OOB data from input memory block, exit on failure */ 
  6. memcpy(oob_buf, buffer, meminfo->oobsize); 
  7. buffer += meminfo->oobsize; 
  8.  
  9. result = meminfo->write_ecc(meminfo, 
  10.   mtdoffset, 
  11.   meminfo->oobblock, 
  12.   &written, 
  13.   (unsigned char *) &data_buf, 
  14.   (unsigned char *)&oob_buf, 
  15.   NULL); 
  16.  
  17. if (result != 0) { 
  18.   printf("writing NAND page at offset 0x%lx failed\n"
  19.    mtdoffset); 
  20.   goto restoreoob; 
  21. imglen -= meminfo->oobsize; 
  22. imglen -= readlen; 
  23. else {...} 
此处就是直接把oob数据,页数据,一次性地准备好,然后调用write_ecc,就可以一次性地写入页数据和oob数据了,就不用像前面那种方法一样,这么让人难以看懂了。。。
(serial_story)
本站文章除注明转载外,均为本站原创或编译欢迎任何形式的转载,但请务必注明出处,尊重他人劳动,同学习共成长。转载请注明:文章转载自:罗索实验室 [http://www.rosoo.net/a/201005/9466.html]
本文出处:百度博客 作者:serial_story
顶一下
(5)
100%
踩一下
(0)
0%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片
栏目列表
将本文分享到微信
织梦二维码生成器
推荐内容