免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2308 | 回复: 1
打印 上一主题 下一主题

初步解决yaffs文件系统的nand flash烧写 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-06-08 17:31 |只看该作者 |倒序浏览


文件:
yaffs.tar.gz
大小:
143KB
下载:
下载


初步解决yaffs文件系统的nand flash烧写

1)获取yaffs工具
可以到
http://www.aleph1.co.uk/cgi-bin/viewcvs.cgi/
下载yaffs源码
解压后进入yaffs目录下的utils目录。
make
得到两个工具:mkyaffs mkyaffsimage

2)创建测试的yaffs image
mkdir yaffs
拷贝文件系统的所有文件到yaffs文件夹下
mkyaffsimage yaffs yaffs.img

3)写入nand flash
(注意这里使用到flash-eraseall,nandwrite等工具哦,再我的另一篇文章里有讲到mtd-utils工具,大家可以照着装上该工具)
flash-eraseall /dev/mtd2
nandwrite –a –o /dev/mtd2 yaffs.img
挂载yaffs mtd
mount –t yaffs /dev/mtdblock2 /mnt
发现mount报错,  只有一个lost+found目录, 其余空空如也. 看来只好分析yaffs和nand flash代码了.

4)代码分析
我使用的是8bit 512bytes+16bytes oob/page 的128M nand flash, 分析yaffs与nand flash驱动代码, 发现yaffs中调用yaffs_mtdif.c中的nandmtd_WriteChunkToNAND函数将它的chunk写入FLASH,包含一个512字节的数据与yaffs_Spare结构, 512字节数据对应nand flash 一page, 所以不需要关心他的512字节数据区; yaffs_Spare结构,在yaffs_guts.h中定义的

typedef struct {
__u8 tagByte0;
__u8 tagByte1;
__u8 tagByte2;
__u8 tagByte3;
__u8 pageStatus; /* set to 0 to delete the chunk */
__u8 blockStatus;
__u8 tagByte4;
__u8 tagByte5;
__u8 ecc1[3];
__u8 tagByte6;
__u8 tagByte7;
__u8 ecc2[3];
} yaffs_Spare;

正好是16字节, 那就是使用这16字节作为OOB. 其中ecc1与ecc2是用来计算ECC的, 只有使用yaffs自身的ECC时才用到, 我们这里使用mtd的硬件ECC, 可以忽略不计, 省下了YAFFS用来存放文件系统相关的信息(yaffs_Tags)8个bytes. 而mx27 nand flash 其 oob定义如下:

static struct nand_ecclayout nand_hw_eccoob_8 = {
    .eccbytes = 5,
    .eccpos = {6, 7, 8, 9, 10},
    .oobfree = {{0, 5}, {11, 5}}
};

Oobfree有两块, {0,5}, {11,5}总共10个字节. 需要将这8个字节保存到OOB区中, 就需要一个转换.  继续分析yaffs_mtdif.c时,发现2.6.19内核在yaffs写入oob时先使用translate_spare2oob将yaffs_Spare转换为一个8bytes数据块,然后通过mtd->write_oob使用MTD_OOB_AUTO方式写入oob数据;

#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
    __u8 spareAsBytes[8]; /* OOB */

    //只有数据
    if (data && !spare)
        retval = mtd->write(mtd, addr, dev->nDataBytesPerChunk,
                &dummy, data);
else if (spare) {
        //使用nand 硬件ECC
        if (dev->useNANDECC) {
            //转换tag为8bytes数据块
            translate_spare2oob(spare, spareAsBytes);
            //使用MTD_OOB_AUTO方式将8bytes块写入到oobfree
            ops.mode = MTD_OOB_AUTO;
            ops.ooblen = 8; /* temp hack */
        } else {
            //使用yaffs自身ECC时, 直接将yaffs_Spare数据作为OOB
            ops.mode = MTD_OOB_RAW;
            ops.ooblen = YAFFS_BYTES_PER_SPARE;
        }
        ops.len = data ? dev->nDataBytesPerChunk : ops.ooblen;
        ops.datbuf = (u8 *)data;
        ops.ooboffs = 0;
        ops.oobbuf = spareAsBytes;
        retval = mtd->write_oob(mtd, addr, &ops);
}
#endif

继续深入分析,  发现mtd-write_oob实际上是调用的是nand_do_write_ops或nand_do_write_oob(都在driver/mtd/nand/nand_base.c), 在这两个函数中在处理oob数据时都调用了同一个函数nand_fill_oob:
static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob,
                  struct mtd_oob_ops *ops)
{
    size_t len = ops->ooblen;

    switch(ops->mode) {

    case MTD_OOB_PLACE:
    case MTD_OOB_RAW:
        memcpy(chip->oob_poi + ops->ooboffs, oob, len);
        return oob + len;

    case MTD_OOB_AUTO: {
        struct nand_oobfree *free = chip->ecc.layout->oobfree;
        uint32_t boffs = 0, woffs = ops->ooboffs;
        size_t bytes = 0;

        for(; free->length && len; free++, len -= bytes) {
            /* Write request not from offset 0 ? */
            if (unlikely(woffs)) {
                if (woffs >= free->length) {
                    woffs -= free->length;
                    continue;
                }
                boffs = free->offset + woffs;
                bytes = min_t(size_t, len,
                          (free->length - woffs));
                woffs = 0;
            } else {
                bytes = min_t(size_t, len, free->length);
                boffs = free->offset;
            }
            memcpy(chip->oob_poi + boffs, oob, bytes);
            oob += bytes;
        }
        return oob;
    }
    default:
        BUG();
    }
    return NULL;
}
可以看出nand_fill­_oob使用了2种方式来组织oob的处理方式: MTD_OOB_PLACE与MTD_OOB_RAW为一种, 直接将OOB数据复制到要写入oob的数据缓存chip->oob_poi; MTD_OOB_AUTO讲oob数据复制到要写入oob的数据缓存oobfree位置上. 这就是MTD_OOB_RAW与MTD_OOB_AUTO的最终解释了.

再来看mkyaffsimage的代码:
static int write_chunk(__u8 *data, __u32 objId, __u32 chunkId, __u32 nBytes)
{
    yaffs_Tags t;
    yaffs_Spare s;
   
    error = write(outFile,data,512);
    if(error

    memset(&t,0xff,sizeof (yaffs_Tags));
    memset(&s,0xff,sizeof (yaffs_Spare));

    t.chunkId = chunkId;
    t.serialNumber = 0;
    t.byteCount = nBytes;
    t.objectId = objId;

    if (convert_endian)
    {
        little_to_big_endian(&t);
    }

   yaffs_CalcTagsECC(&t);
    yaffs_LoadTagsIntoSpare(&s,&t);
    yaffs_CalcECC(data,&s);

    nPages++;
    return write(outFile,&s,sizeof(yaffs_Spare));
}
他在512字节之后是包含了16字节yaffs_Spare的,这个16字节的yaffs_Spare就是他的oob结构. 但是这个16字节并没有通过translate_spare2oob转换, 而是直接写入image中了.
再看通过nandwrite -a -o 写入mtd时的代码
if (!noecc) {
                int i, start, len;
                /*
                 *  We use autoplacement and have the oobinfo with the autoplacement
                 * information from the kernel available
                 *
                 * Modified to support out of order oobfree segments,
                 * such as the layout used by diskonchip.c
                 */
                if (!oobinfochanged && (old_oobinfo.useecc ==   MTD_NANDECC_AUTOPLACE)) {
                    for (i = 0;old_oobinfo.oobfree[1]; i++) {
                        /* Set the reserved bytes to 0xff */
                        start = old_oobinfo.oobfree[0];
                        len = old_oobinfo.oobfree[1];
                        printf( "oob:[%d:%d]\n", start, len );
                        memcpy(oobbuf + start,
                            oobreadbuf + start,
                            len);
                    }
                } else {
                    /* jffs2 or yaffs */
                    /* Set at least the ecc byte positions to 0xff */
                    start = old_oobinfo.eccbytes;
                    len = meminfo.oobsize - start;

                    memcpy(oobbuf + start,
                        oobreadbuf + start,
                        len);
                }
            }
可见nandwrite在写入oob时是也是通过MTD_NANDECC_AUTOPLACE(等同MTD_OOB_AUTO)方式写入的.

比较一下yaffs流程与mkyaffsimage流程:
yaffs流程是通过translate_spare2oob将8bytes的yaffs_tags转为8bytes数据块,然后通过write_oob将这8bytes写入到OOB的oobfree块区; 读出来的时候反过来translate_oob2spare, 就可以还原成yaffs_tags; 而mkyaffsimage创建yaffs image时却是直接将yaffs_Spare写入文件, 通过nandwrite -a -o 写入mtd时, 直接使用这块yaffs_Spare作为oob数据写入, 虽然使用方式也是MTD_OOB_AUTO; 这就造成yaffs读取chunk时无法读取正确的yaffs_Spare数据了;

由此可见只要在mkyaffsimage写入yaffs_Spare时, 只要将写入的数据转换为yaffs中写入flash之前一致的数据即可.

5)修改代码
以下是修改过的 write_chunk
static int write_chunk(__u8 *data, __u32 objId, __u32 chunkId, __u32 nBytes)
{
    yaffs_Tags t;
    yaffs_Spare s;
    __u8 oobdata[16];

    error = write(outFile,data,512);
    if(error

    memset(&t,0xff,sizeof (yaffs_Tags));
    memset(&s,0xff,sizeof (yaffs_Spare));

    t.chunkId = chunkId;
    t.serialNumber = 0;
    t.byteCount = nBytes;
    t.objectId = objId;

    if (convert_endian)
    {
        little_to_big_endian(&t);
    }

    yaffs_CalcTagsECC(&t);
    yaffs_LoadTagsIntoSpare(&s,&t);
    yaffs_CalcECC(data,&s);

    nPages++;
#if 0
    return write(outFile,&s,sizeof(yaffs_Spare));
#else
    memset(oobdata,0xff,16);
    translate_spare2oob( &s, oobdata )

//因为采用的是硬件ECC, 这里忽略了yaffs自身的ECC
return write(outFile, oobdata, 16);
#endif
}

6)
再次重新编译mkyaffsimage工具,并制作yaffs.img
我使用了U盘,将yaffs.img文件等都拷贝到U盘里面了。

7)
flash-eraseall /dev/mtd2
nandwrite –a –o /dev/mtd2 /mnt/yaffs.img
挂载yaffs mtd
mount –t yaffs /dev/mtdblock2 /mnt
这回可以正确mount到mtdblock2,但还是只有一个lost+found目录, 其余空空如也.
umount /mnt/

8)
使用mkyaffs工具对mtd2格式化
mkyaffs /dev/mtd2

9)
mount –t yaffs /dev/mtdblock2 /tmp/
再mount,发现还是只有lost+found目录,但是mtd3已经可以读写了。拷贝所有文件系统要使用的目录及文件到mnt目录,重启,再mount,原来的文件还在,说明yaffs盘(即mtd2)可以使用了。

10)
在PC上打包文件系统
tar -zcvf yaffs.tgz yaffs/
拷贝yaffs.tgz文件到USB中,插到开发板上,挂载U盘。
cd /tmp/
tar zxvf ../mnt/yaffs.tgz
看到一系列的解压写入过程后,看到tmp目录下多了个yaffs目录,接下来
mv -f ./yaffs/* ./
rm -rf lost+found/
rm -rf ./yaffs/
ls
可以看到,tmp目录下已经包含我们要的根文件系统所要的所有文件了。

11)
烧写不带ramdisk的内核进mtd0并指定root启动参数:
"root=/dev/mtdblock2"
重启。
可以进入文件系统啦。

12)
有待解决问题:
为什么我nandwrite进mtd2的yaffs.img里面的内容不能被直接mount出来?
我的本意是直接烧写一个img文件就可以使用mtd盘了。

至今还没找到好的解决方法,使用烧写yaffs.img的工具用过flashcp flash-dd nandwrite都不能将整个文件系统拷进mtd里面并正确读取。只看到一个lost+found目录。

还有,我看到重启后的文件系统是只读的,如何修改成可读写的属性呢?

有什么高手可以指教并帮我解决下吗?

使用硬件参数:
CPU:海山HS3210
NAND FLASH:Samsung K9F2G08



本文参考CSDN博客:
http://blog.csdn.net/force_eagle/archive/2008/02/28/2128407.aspx
[/url]



本文来自ChinaUnix博客,如果查看原文请点:[url]http://blog.chinaunix.net/u1/37510/showart_1958911.html

论坛徽章:
0
2 [报告]
发表于 2013-05-13 17:09 |只看该作者
yaffs整个过程分析值得参考。。。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP