• u-boot支持yaffs映像烧写的补丁


    u-boot的nand flash驱动有两个版本,似乎是以u-boot1.1.5为分界点的,之前的版本使用的是自己写的nand flash驱动,而后面的版本使用的是linux内核中nand flash的驱动。这两个版本有可能在同一个u-boot中存在,都存放在
    driver目录下面,一个为nand,一个为nand_legacy,意思为传统的nand flash驱动。两者使用一个宏开关
    CFG_NAND_LEGACY来打开,如果定义这个宏的话,将使用传统的nand flash驱动,否则使用最新的flash驱动。
    关于传统的flash驱动中的yaffs文件映像的下载问题,我已经解决,可以看我的另外的一篇文章,使用的内核版本是2.6.15,你去看内核的yaffs代码,2.6.17是内核中yaffs的一个分界点,所以你2.6.17的内核可能可以使用我说的方法,2.618的内核可能就不能用我说的那个方法,2.6.18以上的内核没有验证过,热心的朋友可以帮忙使用2.6.18以上的内核帮忙验证一下,然后在这里告诉一下在下。
    最新的flash中的yaffs文件映像烧写的问题,我放出一个老外的驱动,我验证过映像下载是没有问题,但是产生了一些其他的问题,我一直没有解决,所以这篇文章也拖到现在。
                  
                    diff --git a/common/cmd_nand.c b/common/cmd_nand.c
    index b011b5e..2760874 100644
    --- a/common/cmd_nand.c
    +++ b/common/cmd_nand.c
    @@ -351,6 +351,23 @@ #endif
                     opts.quiet      = quiet;
                     ret = nand_write_opts(nand, &opts);
                 }
    +#ifdef CFG_NAND_YAFFS_WRITE
    +        } else if (!read && s != NULL &&
    +               (!strcmp(s, ".yaffs") || !strcmp(s, ".yaffs1"))) {
    +            nand_write_options_t opts;
    +            memset(&opts, 0, sizeof(opts));
    +            opts.buffer    = (u_char*) addr;
    +            opts.length    = size;
    +            opts.offset    = off;
    +            opts.pad    = 0;
    +            opts.blockalign = 1;
    +            opts.quiet      = quiet;
    +            opts.writeoob    = 1;
    +            opts.autoplace    = 1;
    +            if (s[6] == '1')
    +                opts.forceyaffs = 1;
    +            ret = nand_write_opts(nand, &opts);
    +#endif
             } else {
                 if (read)
                     ret = nand_read(nand, off, &size, (u_char *)addr);
    @@ -462,6 +479,10 @@ U_BOOT_CMD(nand, 5, 1, do_nand,
         "nand read[.jffs2]     - addr off|partition size
    "
         "nand write[.jffs2]    - addr off|partiton size - read/write `size' bytes starting
    "
         "    at offset `off' to/from memory address `addr'
    "
    +#ifdef CFG_NAND_YAFFS_WRITE
    +    "nand write[.yaffs[1]] - addr off|partition size - write `size' byte yaffs image
    "
    +    "    starting at offset `off' from memory address `addr' (.yaffs1 for 512+16 NAND)
    "
    +#endif
         "nand erase [clean] [off size] - erase `size' bytes from
    "
         "    offset `off' (entire device if not specified)
    "
         "nand bad - show bad blocks
    "
    diff --git a/drivers/nand/nand_util.c b/drivers/nand/nand_util.c
    index 10bf036..bea5c1e 100644
    --- a/drivers/nand/nand_util.c
    +++ b/drivers/nand/nand_util.c
    @@ -343,6 +343,10 @@ int nand_write_opts(nand_info_t *meminfo
             struct nand_oobinfo *oobsel =
                 opts->forcejffs2 ? &jffs2_oobinfo : &yaffs_oobinfo;
    
    +#ifdef CFG_NAND_YAFFS1_NEW_OOB_LAYOUT
    +        /* jffs2_oobinfo matches 2.6.18+ MTD nand_oob_16 ecclayout */
    +        oobsel = &jffs2_oobinfo;
    +#endif
             if (meminfo->oobsize == 8) {
                 if (opts->forceyaffs) {
                     printf("YAFSS cannot operate on "
    @@ -443,6 +447,28 @@ int nand_write_opts(nand_info_t *meminfo
                 memcpy(oob_buf, buffer, meminfo->oobsize);
                 buffer += meminfo->oobsize;
    
    +            if (opts->forceyaffs) {
    +#ifdef CFG_NAND_YAFFS1_NEW_OOB_LAYOUT
    +                /* translate OOB for yaffs1 on Linux 2.6.18+ */
    +                oob_buf[15] = oob_buf[12];
    +                oob_buf[14] = oob_buf[11];
    +                oob_buf[13] = (oob_buf[7] & 0x3f)
    +                    | (oob_buf[5] == 'Y' ? 0 : 0x80)
    +                    | (oob_buf[4] == 0 ? 0 : 0x40);
    +                oob_buf[12] = oob_buf[6];
    +                oob_buf[11] = oob_buf[3];
    +                oob_buf[10] = oob_buf[2];
    +                oob_buf[9]  = oob_buf[1];
    +                oob_buf[8]  = oob_buf[0];
    +                memset(oob_buf, 0xff, 8);
    +#else
    +                /* set the ECC bytes to 0xff so MTD will
    +                   calculate it */
    +                int i;
    +                for (i = 0; i  meminfo->oobinfo.eccbytes; i++)
    +                    oob_buf[meminfo->oobinfo.eccpos[i]] = 0xff;
    +#endif
    +            }
                 /* write OOB data first, as ecc will be placed
                  * in there*/
                 result = meminfo->write_oob(meminfo,
    
    自己选择性的添加吧。
    
    这个补丁主要完成了一个oob字节顺序的改变。
    
    
    注意同时要查看一下你的mkyaffsimage命令的源文件里面的oob的字节的顺序!
    
    这样制作的u-boot下载yaffs文件系统映像没有问题,但是垃圾回收(garbage collection)机制有问题,对该文件系统进行写入操作(mkdir、 touch)时,系统提示:
    
    page 1302 in gc has no object: 0 0 0
    .
    .
    .
    page 1311 in gc has no object : 0 0 0
    
    具体原因待查!
    
    
    内核的一个编译选项的意义:
    Device Drivers->Memory Technolovy Devices->FTL(Flash Translation Layer) Support
    这个选项的意义在于?
    由于无法重复的在flash的同一块存储位置上做写入的操作(必须事先擦除该快之后才能写入),因此一般在硬盘上使用的文件系统,如:fat16,fat32,ntfs,ext2,ext3等将无法直接用到flash上,为了沿用这些文件系统,则必须透过一层转换层来将逻辑地址对应到flash的存储器的物理位置上,使系统能把flash当作普通的硬盘来使用,我们将这一层称之为ftl(flash translation layer),flash主要用于nor flash上,而nftl则应用于nand flash上。
    最简单的ftl的实现方法就是一对一的映射,那么当上层的文件系统要写一个块设备的扇区的时候,闪存做下面的操作来完成这个请求。
    1、将这个扇区的所在的擦处块读到内存中,放入缓冲
    2、按照写要求更新该缓冲块
    3、对该快进行擦除
    4、回写
    存在的问题:
    1、效率低,一个chunk更新要对整个block进行擦除
    2、没有磨损均衡策略
    3、非常不安全!容易引起数据的丢失,如果3步与第4步之间,数据将全部丢失
    
    所以闪存转换层采用的算法比这个复杂一点
    
    在flash上,尽量避免使用传统的依赖闪存转换层的文件系统,最好采用专门的针对flash的文件系统,如
    jffs3和yaffs2
    
    问题:加载cramfs文件系统分区(mount -t cramfs /dev/mtdblock1 /mnt/flash1)的时候,报出如下的错误:
    end_request: I/O error, dev mtdblock2, sector 0
    Buffer I/O error on device mtdblock2, logical block 0
    end_request: I/O error, dev mtdblock2, sector 0
    Buffer I/O error on device mtdblock2, logical block 0
    end_request: I/O error, dev mtdblock2, sector 8
    Buffer I/O error on device mtdblock2, logical block 1
    end_request: I/O error, dev mtdblock2, sector 8
    Buffer I/O error on device mtdblock2, logical block 1
    end_request: I/O error, dev mtdblock2, sector 16
    Buffer I/O error on device mtdblock2, logical block 2
    end_request: I/O error, dev mtdblock2, sector 16
    开始以为是硬件错误,后来仔细一检查发现:其实是uboot写入cramfs文件系统映像时使用的ecc校验算法和内核使用的校验算法不一致导致的,如果我们将内核中的mtd层ecc校验NAND_ECC_SOFT关掉,在/drivers/mtd/at91_nand.c文件中有定义。则系统在加载的时候将不再报错,验证了这是校验的问题,解觉的办法是什么?
    首先在uboot中,使用nand erase 将cramfs分区擦除干净,以nfs的方式启动linux,然后使用
    cp root_fs_cramfs.img /dev/mtd1
    将cramfs映像文件拷贝到相应的字符设备中。
    然后使用mount -t cramfs /dev/mtdblock1 /mnt/flash1。
    则cramfs文件系统加载正常。
    
    这样我们可以不使用ramdisk技术来加载根文件系统,可以省去读内存的时间,加快启动速度。
    这时的内核启动参数为:
    noinitrd init=/linuxrc root=/dev/mtdblock1 ro console=ttyS0,115200 mem=64M ip=192.168.0.11 netmask=255.255.255.0
    修改u-boot的bootcmd ,就可以加快启动速度,同时节省ram的空间!直接从cramfs的nandflash上启动
  • 相关阅读:
    理解C语言中指针常量和常量指针区别!不要再搞混了~
    哪座城市可以安放程序员的灵魂,一线城市与二三线城市该如何择别?
    Linux 之父如何定义 "Linux" !主要想让黑客、计算机学生使用,学习和享受!
    程序员的凡尔赛文学!作为低调人群的程序员,“凡”起来又是怎样的一番景象呢?
    40个Java集合面试问题和答案
    从关系型数据库到非关系型数据库
    redis安装报错
    redis简介
    不满足依赖关系
    EL表达式中引用隐式变量
  • 原文地址:https://www.cnblogs.com/timssd/p/4086281.html
Copyright © 2020-2023  润新知