现在正在看uboot烧写yaffs2的代码,有点疑问
输入命令后执行do_nand,然后执行到
nand_write_opts
int nand_write_opts(nand_info_t *meminfo, const nand_write_options_t *opts) { 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。 。。。。。。。。。。。。。。。。。。。。。。。。。。。。 ? ?? ???memcpy(data_buf, buffer, readlen); ? ?? ???buffer += readlen;
? ?? ???if (opts->writeoob) { ? ?? ?? ?? ?/* read OOB data from input memory block,exit ? ?? ?? ?? ? * on failure */ ? ?? ?? ?? ?memcpy(oob_buf, meminfo->oobsize); ? ?? ?? ?? ? ? ?? ?? ?? ?buffer += meminfo->oobsize;
? ?? ?? ?? ?/* write OOB data first,as ecc will be placed ? ?? ?? ?? ? * in there*/ ? ?? ?? ?? ?result = meminfo->write_oob(meminfo, ? ?? ?? ?? ?? ?? ?? ?? ? mtdoffset, ? ?? ?? ?? ?? ?? ?? ?? ? meminfo->oobsize, ? ?? ?? ?? ?? ?? ?? ?? ? &written, ? ?? ?? ?? ?? ?? ?? ?? ? (unsigned char *) ? ?? ?? ?? ?? ?? ?? ?? ? &oob_buf); ? ?? ?? ?? ?。。。。。。。。。。。。。。。。。。。。。。? ??? ? ?? ?? ?? ?。。。。。。。。。。。。。。。。。。。。。 ? ?? ?? ?? ?}
? ?? ???result = meminfo->write(meminfo, ? ?? ?? ?? ?? ?? ???mtdoffset, ? ?? ?? ?? ?? ?? ???meminfo->oobblock, ? ?? ?? ?? ?? ?? ???&written, ? ?? ?? ?? ?? ?? ???(unsigned char *) &data_buf);
|
在这段代码中,
opts->writeoob=1,先执行了
meminfo->write_oob,写了flash的OOB区,然后执行到了meminfo->write,meminfo->write=nand_write
static int nand_write (struct mtd_info *mtd,loff_t to,size_t len,size_t * retlen,const u_char * buf) { ? ? return (nand_write_ecc (mtd,to,len,retlen,buf,NULL,NULL)); }
static int nand_write_ecc (struct mtd_info *mtd, ? ?? ?? ?? ? size_t * retlen,const u_char * buf,u_char * eccbuf,struct nand_oobinfo *oobsel) {。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。 ? ???oobbuf = nand_prepare_oobbuf (mtd,eccbuf,oobsel,autoplace,numpages); ? ???while (written < len) { ? ?? ?? ???this->data_poi = (u_char*) &buf[written];
? ?? ?? ?? ?ret = nand_write_page (mtd,this,page,&oobbuf[oob],(--numpages > 0)); ? ? 。。。。。。。。。。。。。。。。。。 ? ? } 。。。。。。。。。。。。。。。。。。。。。。? ? }
|
在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的代码:
? ?? ?? ?? ?? ? if (opts->writeyaffs) ? ?? ?? ?? ?? ? { ? ?? ?? ?? ?? ?? ?? ?? ?/* read page data from input memory buffer */ ? ?? ?? ?? ?? ?? ?? ?? ?memcpy(data_buf, readlen); ? ?? ?? ?? ?? ?? ?? ?? ?buffer += readlen; ? ?? ?? ?? ?? ?? ?? ?? ?/* read OOB data from input memory block,exit ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?* on failure */ ? ?? ?? ?? ?? ?? ?? ?? ?memcpy(oob_buf, meminfo->oobsize); ? ?? ?? ?? ?? ?? ?? ?? ?buffer += meminfo->oobsize;
? ?? ?? ?? ?? ?? ?? ?? ?result = meminfo->write_ecc(meminfo, ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?mtdoffset, ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?meminfo->oobblock, ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?&written, ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?(unsigned char *) &data_buf, ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?(unsigned char *)&oob_buf, ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? NULL);
? ?? ?? ?? ?? ?? ?? ?? ?if (result != 0) { ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???printf("writing NAND page at offset 0x%lx failedn", ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? mtdoffset); ? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???goto restoreoob; ? ?? ?? ?? ?? ?? ?? ?? ?} ? ?? ?? ?? ?? ?? ?? ?? ?imglen -= meminfo->oobsize; ? ?? ?? ?? ?? ?? ?? ?? ?imglen -= readlen;
? ?? ?? ?? ?? ? } else {。。。。} |
此处就是直接把oob数据,页数据,一次性地准备好,然后调用write_ecc, 就可以一次性地写入页数据和oob数据了,就不用像前面那种方法一样,这么让人难以看懂了。。。
(编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|