現在正在看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, buffer, 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, loff_t to, size_t len,
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], oobsel, (--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, buffer, readlen);
buffer += readlen;
/* read OOB data from input memory block, exit
* on failure */
memcpy(oob_buf, buffer, 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 failed/n",
mtdoffset);
goto restoreoob;
}
imglen -= meminfo->oobsize;
imglen -= readlen;
} else {。。。。} |
此處就是直接把oob資料,頁資料,一次性地準備好,然後調用write_ecc,
就可以一次性地寫入頁資料和oob資料了,就不用像前面那種方法一樣,這麼讓人難以看懂了。。。