[ Linux Busybox ] nandwrite 命令解析

文章目录

    • 相关结构体
    • nandwrite 函数实现
    • nandwrite 实现流程图


文件路径:busybox-1.20.2/miscutils/nandwrite.c

相关结构体

MTD 相关信息结构体

struct mtd_info_user {
    __u8 type;              // MTD 设备类型
    __u32 flags;            // MTD设备属性标志
    __u32 size;             // mtd设备的大小
    __u32 erasesize;        // MTD设备的擦除单元大小,对于 NandFlash来说就是 Block的大小
    __u32 writesize;        // MTD设备的读写单元大小,对于 NandFlash来说就是page 的大小
    __u32 oobsize;          // oob区域大小
    __u64 padding;          // 有效的oob区域大小
};

nandwrite 函数实现

假如要将 mtd2 拷贝到 mtd3 分区中,使用的命令是:nandwrite /dev/mtd3 /dev/mtd2

int nandwrite_main(int argc UNUSED_PARAM, char **argv)
{
    /* Buffer for OOB data */
    unsigned char *oobbuf;
    unsigned opts;
    int fd;
    ssize_t cnt;
    unsigned mtdoffset, meminfo_writesize, blockstart, limit;
    unsigned end_addr = ~0;
    struct mtd_info_user meminfo;
    struct mtd_oob_buf oob;
    unsigned char *filebuf;
    const char *opt_s = "0", *opt_f = "-", *opt_l;

    if (IS_NANDDUMP) {                            // 从命令行获取参数
        opt_complementary = "=1";
        opts = getopt32(argv, "os:bf:l:", &opt_s, &opt_f, &opt_l);
    } else { /* nandwrite */
        opt_complementary = "-1:?2";
        opts = getopt32(argv, "ps:", &opt_s);
    }
    argv += optind;

    if (IS_NANDWRITE && argv[1])                    // argv[1]为  /dev/mtd2
        opt_f = argv[1];
    if (!LONE_DASH(opt_f)) {                        // 判断输入的参数是否为文件,根据命令为文件添加权限
        int tmp_fd = xopen(opt_f,
            IS_NANDDUMP ? O_WRONLY | O_TRUNC | O_CREAT : O_RDONLY
        );
        xmove_fd(tmp_fd, IS_NANDDUMP ? STDOUT_FILENO : STDIN_FILENO);   // 将文件内容放在标准输出或者标准输入中。
    }

    fd = xopen(argv[0], O_RDWR);        // 打开文件,argv[0]为/dev/mtd3
    xioctl(fd, MEMGETINFO, &meminfo);    // 获取内存信息

    mtdoffset = xstrtou(opt_s, 0);            // 获取mtd偏移量,默认为0
    if (IS_NANDDUMP && (opts & OPT_l)) {
        unsigned length = xstrtou(opt_l, 0);
        if (length < meminfo.size - mtdoffset)
            end_addr = mtdoffset + length;
    }

    /* Pull it into a CPU register (hopefully) - smaller code that way */
    meminfo_writesize = meminfo.writesize;        // 获取每次写入内存的大小(一般为页大小)

    if (mtdoffset & (meminfo_writesize - 1))        // 判断写入的地址是否页对齐
        bb_error_msg_and_die("start address is not page aligned");

    filebuf = xmalloc(meminfo_writesize);            // 根据每次写入的大小分配buf和oob内存
    oobbuf = xmalloc(meminfo.oobsize);

    oob.start  = 0;                    // 开始地址
    oob.length = meminfo.oobsize;        // oob大小
    oob.ptr    = oobbuf;                // oob值

    blockstart = mtdoffset & ~(meminfo.erasesize - 1);        // 获得块起始地址
    if (blockstart != mtdoffset) {
        unsigned tmp;
        /* mtdoffset is in the middle of an erase block, verify that
         * this block is OK. Advance mtdoffset only if this block is
         * bad.
         */
        tmp = next_good_eraseblock(fd, &meminfo, blockstart);
        if (tmp != blockstart) {
            /* bad block(s), advance mtdoffset */
            if (IS_NANDDUMP & !(opts & OPT_b)) {
                int bad_len = MIN(tmp, end_addr) - mtdoffset;
                dump_bad(&meminfo, bad_len, !(opts & OPT_o));
            }
            mtdoffset = tmp;
        }
    }

    cnt = -1;
    limit = MIN(meminfo.size, end_addr);                // 获取写入总空间,meminfo.size为mtd总空间大小
    while (mtdoffset < limit) {                            // 循环往mtd写入数值,直到超出mtd总空间大小
        int input_fd = IS_NANDWRITE ? STDIN_FILENO : fd;    // 若为IS_NANDWRITE指令,将输入input_fd指向标准输入,输出output_fd指向文件
        int output_fd = IS_NANDWRITE ? fd : STDOUT_FILENO;

        blockstart = mtdoffset & ~(meminfo.erasesize - 1);   // 获得块起始地址
        if (blockstart == mtdoffset) {                // 若是对齐的,开始检测坏块
            /* starting a new eraseblock */
            mtdoffset = next_good_eraseblock(fd, &meminfo, blockstart);         // 检测坏块,若检测到跳过,具体实现见下面一个函数
            if (IS_NANDWRITE)
                printf("Writing at 0x%08x\n", mtdoffset);
            else if (mtdoffset > blockstart) {
                int bad_len = MIN(mtdoffset, limit) - blockstart;
                dump_bad(&meminfo, bad_len, !(opts & OPT_o));
            }
            if (mtdoffset >= limit)        // 偏移量超出mtd总大小跳出
                break;
        }
        xlseek(fd, mtdoffset, SEEK_SET);    // 将读写位置移到文件开头

        /* get some more data from input */
        cnt = full_read(input_fd, filebuf, meminfo_writesize);    // 从获取标准输入中获取数据,大小为内存写入的大小,数据保存在filebuf
        if (cnt == 0) {
            /* even with -p, we do not pad past the end of input
             * (-p only zero-pads last incomplete page)
             */
            break;
        }
        if (cnt < meminfo_writesize) {            // 从标准输出中获取到数据的大小 若小于 写入的标准大小
            if (IS_NANDDUMP)
                bb_error_msg_and_die("short read");
            if (!(opts & OPT_p))
                bb_error_msg_and_die("input size is not rounded up to page size, "
                        "use -p to zero pad");
            /* zero pad to end of write block */
            memset(filebuf + cnt, 0, meminfo_writesize - cnt);    // 在数据后面填充0
        }
        xwrite(output_fd, filebuf, meminfo_writesize);        // 将filebuf数据拷贝到 mtd中

        if (IS_NANDDUMP && !(opts & OPT_o)) {
            /* Dump OOB data */
            oob.start = mtdoffset;
            xioctl(fd, MEMREADOOB, &oob);
            xwrite(output_fd, oobbuf, meminfo.oobsize);
        }

        mtdoffset += meminfo_writesize;            // 指向下个要写入的地址
        if (cnt < meminfo_writesize)                // 若本次获取数据的量小于写入的大小,则跳出
            break;
    }

    if (IS_NANDWRITE && cnt != 0) {         // 填满了整个MTD,但是我们在输入时达到EOF了吗
        /* We filled entire MTD, but did we reach EOF on input? */
        if (full_read(STDIN_FILENO, filebuf, meminfo_writesize) != 0) {
            /* no */
            bb_error_msg_and_die("not enough space in MTD device");
        }
    }

    if (ENABLE_FEATURE_CLEAN_UP) {
        free(filebuf);
        close(fd);
    }

    return EXIT_SUCCESS;
}

标准输出输出定义

#define  STDIN_FILENO   0  /* Standard input.  */
#define  STDOUT_FILENO  1  /* Standard output.  */
#define  STDERR_FILENO  2  /* Standard error output.  */

检测坏块实现

static unsigned next_good_eraseblock(int fd, struct mtd_info_user *meminfo,
        unsigned block_offset)
{
    while (1) {            // 循环检测,便于跳过坏块
        loff_t offs;

        if (block_offset >= meminfo->size) {                // 1、传入的块偏移量大于等于mtd总大小
            if (IS_NANDWRITE)
                bb_error_msg_and_die("not enough space in MTD device");
            return block_offset; /* let the caller exit */    // 返回
        }
        offs = block_offset;
        if (xioctl(fd, MEMGETBADBLOCK, &offs) == 0)        // 2、判断是否为坏块
            return block_offset;                           // 若不是返回地址
        /* ioctl returned 1 => "bad block" */
        if (IS_NANDWRITE)                                    // 若是坏块跳过,并指向下一块的地址检测
            printf("Skipping bad block at 0x%08x\n", block_offset);
        block_offset += meminfo->erasesize;
    }
}

nandwrite 实现流程图

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/131696.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

(免费版?)CLion Nova 强势登陆 C 和 C++ 开发领域

系列文章目录 文章目录 系列文章目录前言一、CLion Nova二、目标三、优势和改进四、显著差异五、如何安装 CLion Nova六、分享您的反馈意见总结 阿纳斯塔西娅-卡扎科娃 2023 年 11 月 9 日 前言 今天&#xff0c;我们宣布推出免费的 CLion 早期预览版&#xff0c;它使用 ReSh…

400G OSFP SR8光模块最新解决方案

数字化时代&#xff0c;意味着网络速度、能效和成本成为数据中心和通信网络关注的焦点。为了满足这些需求不断催生和进化新的产品&#xff0c;因此在这一背景下400G OSFP SR8光模块最新解决方案成为了很好的助力。该方案不仅提高了网络速度&#xff0c;还实现了节能降耗&#x…

ARM 基础学习记录 / ARM 裸机编程

汇编程序调用 C 程序详情 在 C 程序和 ARM 汇编程序之间相互调用时必须遵守 ATPCS 规则&#xff0c;其是基于 ARM 指令集和 THUMB 指令集过程调用的规范&#xff0c;规定了调用函数如何传递参数&#xff0c;被调用函数如何获取参数&#xff0c;以何种方式传递函数返回值。 寄存…

95. 费解的开关

题目 思路 因为最优解是每个灯只操作一次所以顺序无所谓只要确定了第一行后&#xff0c;下面都可以确定当前灯不亮就操作它下面的格子即可点亮它我觉得这种方法是唯一不会互相干扰的方法还是不太理解… 代码 #include <cstdio> #include <cmath> #include <c…

2023最新版本 从零基础入门C++与QT(学习笔记) -1- C++输入与输出

&#x1f38f;说在前面 &#x1f388;我预计是使用两个月的时间玩转C与QT &#x1f388;所以这是一篇学习笔记 &#x1f388;根据学习的效率可能提前完成学习,加油&#xff01;&#xff01;&#xff01; 输入(代码如下方代码块) &#x1f384;分析一下构成 &#x1f388;…

Rocksdb LSM Tree Compaction策略

RocksDB读写简介 直接画图说明。这张图取自Flink PMC大佬Stefan Richter在Flink Forward 2018演讲的PPT&#xff0c;笔者重画了一下。 RocksDB的写缓存&#xff08;即LSM树的最低一级&#xff09;名为memtable&#xff0c;对应HBase的MemStore&#xff1b;读缓存名为block cac…

CV计算机视觉每日开源代码Paper with code速览-2023.11.8

精华置顶 墙裂推荐&#xff01;小白如何1个月系统学习CV核心知识&#xff1a;链接 点击CV计算机视觉&#xff0c;关注更多CV干货 论文已打包&#xff0c;点击进入—>下载界面 点击加入—>CV计算机视觉交流群 1.【基础网络架构】&#xff08;WACV2024&#xff09;SBCFo…

Vue3-ref函数、reactive函数的响应式

Vue3-ref函数、reactive函数的响应式 在这之前&#xff0c;先讲Vue2的响应式处理 Vue2原本使用的是Object.defineProperty的响应式处理方式 methods方法中的this.name指的是vm.namereturn的name属性在通过this.name的间接调用时&#xff0c;通过了Object.defineProperty响应式…

火山引擎公共云·城市分享会:共享云经验,一起向未来

数智化时代的来临&#xff0c;不仅激发了行业对云计算的资源需求&#xff0c;也重构了云计算的技术架构及产品布局&#xff0c;给业务场景带来更多可能性&#xff0c;让云计算成为企业走向高效治理的一剂“良方”。随着业务的多样化、复杂化&#xff0c;企业应该如何借助云计算…

极兔面试:微服务爆炸,如何解决?Uber 是怎么解决2200个微服务爆炸的?

尼恩说在前面 在40岁老架构师 尼恩的读者交流群(50)中&#xff0c;最近有小伙伴拿到了一线互联网企业如阿里、滴滴、极兔、有赞、希音、百度、网易、美团的面试资格&#xff0c;遇到很多很重要的面试题&#xff1a; 谈谈你的DDD落地经验&#xff1f; 谈谈你对DDD的理解&#x…

【ubuntu 快速熟悉】

ubuntu 快速熟悉 2.ubuntu桌面管理器3.ubuntu常见文件夹说明4.ubuntu任务管理器4.1 gnome桌面的任务管理器4.2 实时监控GPU4.3 top 命令 5.ubuntu必备命令5.1 .deb文件5.2 查找命令5.2.1 find文件搜索5.2.2 which查找可执行文件的路径5.2.3 which的进阶&#xff0c;whereis5.2.…

Linux学习教程(第一章 简介)2

第一章 Linux简介 四、类UNIX系统是什么鬼? 《三、UNIX和Linux的区别》中讲到了 UNIX 系统的历史,UNIX 是操作系统的开山鼻祖,是操作系统的发源地,后来的 Windows 和 Linux 都参考了 UNIX。 有人说,这个世界上只有两种操作系统: UNIX 和类 UNIX 操作系统;其它操作系统…

解决:Git报错same change IDs

当使用git review的时候&#xff0c;review失败&#xff0c;报错multi commit …same change ids。。 错误&#xff1a; same Change-Id in multiple changes 意思是说&#xff0c;有多个commit记录的change ids是相同的&#xff0c;这change id概念出现在gerrit&#xff0…

数电发票接口服务商怎么选择?

自2023年11月1日起&#xff0c;除了港澳台、西藏外&#xff0c;全国范围内都开展了数电票开票试点&#xff0c;对于那些已经习惯使用传统税控开票接口的企业&#xff0c;如今在数电发票的试点下&#xff0c;原本的税控开票接口如同老去的侠客&#xff0c;曾经的荣光已经不再。在…

Zynq-Linux移植学习笔记之65- 国产ZYNQ在linux下usleep时间精度不准问题解决

1、背景介绍 采用复旦微的ZYNQ&#xff0c;跑linux操作系统&#xff0c;在应用程序中使用usleep进行延时时&#xff0c;发现存在10ms以下采用usleep试验都为10ms的情况 2、解决办法 使能设备树中的PS TTC设备&#xff0c;默认不是打开的 timere0024000 {compatible "s…

Android—幸运抽奖火箭发射倒计时(第六次作业)

Android—幸运抽奖&&点火发射&#xff08;第六次作业&#xff09; 创建项目 准备工作 修改按钮的颜色&#xff0c;如果不修改这行代码&#xff0c;那么后期给按钮添加background属性的时候&#xff0c;按钮并不会发生变化。 设置按钮的样式文件btn_press_blue.xml&am…

【原创分享】Mentor PADS将PCB封装直接添加到PCB的教程

一般&#xff0c;批量添加封装到PCB板上有以下方法&#xff1a; 第一步&#xff1a;点击菜单栏“ECO模式--添加元器件”如图&#xff0c;点击以后弹出如图界面。 1&#xff09;元件类型 PCB封装必须得添加完元件类型&#xff0c;才能通过ECO模式添加到PCB界面里面&#xff0c…

北斗卫星为油气行业发展注入新动力

北斗卫星为油气行业发展注入新动力 北斗卫星是中国自主研发的卫星导航系统&#xff0c;在全球范围内具有广泛应用。随着科技的进步和社会的发展&#xff0c;北斗卫星的智慧应用也逐渐在各行各业中崭露头角。特别是在油气行业&#xff0c;北斗卫星的智慧应用发挥了非常重要的作用…

elemetui 解决同个页面,同时使用多个el-table表格组件导致的数据错乱

1、背景 在一个页面中&#xff0c;使用了饿了么框架的3个el-table表格&#xff0c;3个表格平级&#xff0c;只不过是根据条件判断渲染哪个表格。本来以为使用v-if就可以隔离&#xff0c;没想到还是出现了问题&#xff0c;因为3个表格中有几列绑定的字段一模一样&#xff0c;导…

Python编程必备:itertools库功能全解析!

大家好&#xff0c;我是涛哥&#xff0c;今天为大家分享itertools库常用功能&#xff0c;并且为大家提供示例&#xff0c;全文5000字&#xff0c;大约阅读15分钟。 什么是 itertools&#xff1f; itertools是Python的一个内置模块&#xff0c;它提供了一系列用于迭代的函数&…
最新文章