mapleft的笔记 https://bbs.21ic.com/?41444 [收藏] [复制] [RSS]

日志

nuc980 uboot ubi 文件系统挂载失败解决

已有 1431 次阅读2020-2-12 13:30 |个人分类:工蚁手记|系统分类:兴趣爱好

mtdparts

device nand0 <nand0>, # parts = 3
 #: name                size            offset          mask_flags
 0: u-boot              0x00200000      0x00000000      0
 1: kernel              0x01400000      0x00200000      0
 2: rootfs              0x06a00000      0x01600000      0

active partition: nand0,0 - (u-boot) 0x00200000 @ 0x00000000

defaults:
mtdids  : nand0=nand0
mtdparts: mtdparts=nand0:0x200000@0x0(u-boot),0x1400000@0x200000(kernel),-(rootfs)
=> mtdparts default
=> nand erase.part rootfs

NAND erase.part: device 0 offset 0x1600000, size 0x6a00000
Erasing at 0x7fe0000 -- 100% complete.
OK
=> ubi part rootfs 2048
ubi0: attaching mtd1
UBI init error 22
=> 
挂载分配的nand rootfs失败, 提示UBI init error 22

排除这种问题只能是看UBOOT 的源码,打印运行结果去判断问题所在了,  ^_^ 这不是废话么

以老莫这种又笨又懒的人,肯定是不会用新唐官方的nuwriter, 不断的拔拨码开关,不断重虚拟机COPY文件到WINDONS, 用nuwriter去刷NAND ,写NAND; 

修改UBOOT 的默认环境变量
/usr/nuc980/u-boot-2016.11/include/configs/nuc980_iot.h
/* Extra Environments */
#define CONFIG_EXTRA_ENV_SETTINGS \
        "bootcmd=run netnfs\0" \
        "ethaddr=00:00:00:11:66:88\0"\
        "serverip=192.168.0.23\0"\
        "ipaddr=192.168.0.28\0"\
        "kernel_addr_r=7fc0\0"                                \
        "bootfile=980uimage\0"                                \
        "Ubootfile=u-boot.bin\0"                                \
        "Uboot_addr_r=100000\0"                                \
        "bootargs_ramfs=root=/dev/ram0 console=ttyS0,115200n8 rdinit=/sbin/init mem=64M\0" \
        "bootargs_nfs=mem=64M console=ttyS0,115200n8 noinitrd rw ip=192.168.0.28:192.168.0.23:192.168.0.1:255.255.255.0 " \
        "root=/dev/nfs " \
        "nfsroot=192.168.0.23:/usr/nuc980/buildroot-2019.02.9/output/target,nolock " \
        "rdinit=/sbin/init\0" \
        "netnfs=tftp ${kernel_addr_r} ${bootfile}; "        \
                 "setenv bootargs ${bootargs_ramfs}; " \
                "bootm ${kernel_addr_r}\0"        \
        "wruboot=tftp ${kernel_addr_r} ${Ubootfile}; "        \
                 "nand erase ${Uboot_addr_r} 80000; " \
                "nand write ${kernel_addr_r} ${Uboot_addr_r} 80000\0"        \

wruboot 脚本是后来新增加的,功能是UBOOT启动时,运行wruboot 脚本,把虚拟机上的u-boot.bin文件烧写到nand 上

通过在源码中查找 “UBI init error” 字段和分析定位

终于在\drivers\mtd\ubi\Build.c 文件中函数 io_init()发现异常的位置
ubi->max_write_size = ubi->mtd->writebufsize;
if (ubi->max_write_size < ubi->min_io_size ||
            ubi->max_write_size % ubi->min_io_size ||
            !is_power_of_2(ubi->max_write_size)) {
                ubi_err(ubi, "bad write buffer size %d for %d min. I/O unit",
                        ubi->max_write_size, ubi->min_io_size);
                return -EINVAL;
        }
控制台打印出:
ubi0: bad write buffer size 0 for 2048 min. I/O unit
ubi->max_write_size 即>max_write_size  == 0; 在座的吃瓜群众们在上幼儿园时已经知道凡是MAX的玩意等于0都是有幺蛾子的 ^_^ 
(老莫小时候在你们上幼儿园时还在家里玩鸡屎呢)

找到代码退出的地方,问题是不是就解决呢? 肯定不是呢,现在只是知道挂载异常的原因是 max_write_size变量为0,还要找出哪里导致改变量变为0。

吃瓜群众们脑海里不要有妹子答应和你们去吃饭看电影,你们惦记着哪里的酒店环境比较好的想法!

上面的代码有一句 ubi->max_write_size = ubi->mtd->writebufsize;
也就是要找 ubi->mtd->writebufsize为啥为0, 然后源码查找 ubi->mtd->writebufsize 变量;


控制台敲出 “ubi part rootfs ”命令后, UBOOT 即执行U_BOOT_CMD ( )函数

U_BOOT_CMD(
        ubi, 6, 1, do_ubi,
        "ubi commands",
        "detach"
                " - detach ubi from a mtd partition\n"
        "ubi part [part] [offset]\n"
                " - Show or set current partition (with optional VID"
                " header offset)\n"
        "ubi info [l[ayout]]"
                " - Display volume and ubi layout information\n"
        "ubi check volumename"
                " - check if volumename exists\n"
        "ubi create[vol] volume [size] [type] [id]"
                " - create volume name with size\n"
        "ubi write[vol] address volume size"
                " - Write volume from address with size\n"
        "ubi write.part address volume size [fullsize]\n"
                " - Write part of a volume from address\n"
        "ubi read[vol] address volume [size]"
                " - Read volume to address with size\n"
        "ubi remove[vol] volume"
                " - Remove volume\n"
        "[Legends]\n"
        " volume: character name\n"
        " size: specified in bytes\n"
        " type: s[tatic] or d[ynamic] (default=dynamic)"
);

函数的调用过程如下
//cmd\ubi.c
static int do_ubi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 
     int ubi_part(char *part_name, const char *vid_header_offset)     <---------  (从队列中获取MTD设备数据)
         --> 
            ubi_dev_scan(struct mtd_info *info, char *ubidev,
                                     const char *vid_header_offset)  
              -->
                 add_mtd_partitions(info, &mtd_part, 1); 
                      --> 
                        //drivers\mtd\ubi\Build.c
                        int ubi_init(void)
                                   -->
                                      int ubi_attach_mtd_dev()
                                            -->
                                                err = io_init(ubi, max_beb_per1024);  (报告错误所在的函数)



do_ubi 函数是通过过控制台传入的命令“ubi part rootfs ”中的rootfs分区名字,去扫描已经注册的MTD设备,

是否和分区名字匹配,然后在提取MTD信息,包括上文中提及的 writebufsize  变量信息;

//cmd\ubi.c
int ubi_part(char *part_name, const char *vid_header_offset)
{
        int err = 0;
        char mtd_dev[16];
        struct mtd_device *dev;
        struct part_info *part;
        u8 pnum;

        ubi_detach();
        /*
        * Search the mtd device number where this partition
        * is located
        */
        if (find_dev_and_part(part_name, &dev, &pnum, &part)) {
                printf("Partition %s not found!\n", part_name);
                return 1;
        }
        sprintf(mtd_dev, "%s%d", MTD_DEV_TYPE(dev->id->type), dev->id->num);
        ubi_dev.mtd_info = get_mtd_device_nm(mtd_dev);  //获取MTD设备数据,



在ubi_part()函数中打印出writebufsize  变量 依旧为0;也就是在设备注册以前这个变量已经是错的了;

然后翻查spi_nand_init()函数,该函数的后面会调用nand_register()注册设备;

//dirvers\mtd\spi\spi_nand.c
int spi_nand_init(void)
{
        struct spi_flash *flash;
        struct mtd_info *mtd;
        struct nand_chip *chip;
        struct ipq40xx_spinand_info *info;
        int ret;

        info = (struct ipq40xx_spinand_info *)malloc(
                       sizeof(struct ipq40xx_spinand_info));
        if (!info) {
                printf ("Error in allocating mem\n");
                return -ENOMEM;
        }
        memset(info, '0', sizeof(struct ipq40xx_spinand_info));

        flash = spi_flash_probe(0, 0, 30000000, 3);

        if (!flash) {
                free(info);
                spi_print("Id could not be mapped\n");
                return -ENODEV;
        }

        //mtd = nand_info[0];
        mtd = (struct mtd_info *)malloc(
                      sizeof(struct mtd_info));
        if (!mtd) {
                printf ("Error in allocating mem\n");
                return -ENOMEM;
        }
        memset(info, '0', sizeof(struct ipq40xx_spinand_info));
        chip = &nand_chip[0];

        mtd->priv = chip;
        mtd->writesize = flash->page_size;
        mtd->erasesize = spi_nand_flash_tbl[0].erase_size;
        mtd->oobsize = spi_nand_flash_tbl[0].oob_size;
        mtd->size = flash->size;
        mtd->type = MTD_NANDFLASH;
        mtd->flags = MTD_CAP_NANDFLASH;
#ifndef __UBOOT__
        mtd->_point = NULL;
        mtd->_unpoint = NULL;
#endif
        mtd->_read = spi_nand_read;
        mtd->_write = spi_nand_write;
        mtd->_erase = spi_nand_erase;
        mtd->_read_oob = spi_nand_read_oob;
        mtd->_write_oob = spi_nand_write_oob;
        mtd->_block_isbad = spi_nand_block_isbad;
        mtd->_block_markbad = spi_nand_block_markbad;

        chip->page_shift = ffs(mtd->writesize) - 1;
        chip->phys_erase_shift = ffs(mtd->erasesize) - 1;
        chip->chipsize = flash->size;
        chip->pagemask = (chip->chipsize >> chip->page_shift) - 1;
        chip->badblockpos = 0;
        chip->buffers = kmalloc(sizeof(*chip->buffers), GFP_KERNEL);
        chip->oob_poi = chip->buffers->databuf + mtd->writesize;

        /* One of the NAND layer functions that the command layer
        * tries to access directly.
        */
        chip->scan_bbt = spi_nand_scan_bbt_nop;

        // an ugly hack. cannot register our own probe function to set params, so assign correct one here.
        info->params = &spi_nand_flash_tbl[0];//params;
        info->flash = flash;
        info->mtd = mtd;
        info->chip = chip;
        chip->priv = info;
        mtd->writebufsize = mtd->writesize;  // 这行是我加进去的
        //注册MTD 设备
        if ((ret = nand_register(/*CONFIG_IPQ_SPI_NAND_INFO_IDX*/0, mtd)) < 0) {
                free(info);
                spi_print("Failed to register with MTD subsystem\n");
                return ret;
        }

        ret = spinand_unlock_protect(mtd);
        if (ret) {
                free(info);
                printf("Failed to unlock blocks\n");
                return -1;
        }

        spinand_internal_ecc(mtd, 1);

        return 0;
}


我对比过nand init (并行nand ) 和  spi_nand_init()

并行nand初始化函数中,在MTD设备注册前会调用 nand_scan_tail()去设置MTD设备的参数

其中就包括了>writebufsize 参数,
函数中有该行代码:
   mtd->writebufsize = mtd->writesize; 
即设置>writebufsize 参数;

而SPI 函数是没有调用nand_scan_tail()函数的;

后来我在spi_nand_init()函数中加上mtd->writebufsize = mtd->writesize; 
重新编译UOOT, 该问题就解决了

QQ交流群:761781147



路过

鸡蛋

鲜花

握手

雷人

评论 (0 个评论)