[ 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/mtd2opt_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/mtd3xioctl(fd, MEMGETINFO, &meminfo);    // 获取内存信息mtdoffset = xstrtou(opt_s, 0);            // 获取mtd偏移量,默认为0if (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);    // 从获取标准输入中获取数据,大小为内存写入的大小,数据保存在filebufif (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.mzph.cn/news/139361.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于STM32控制直流电机加减速正反转仿真设计

**单片机设计介绍&#xff0c;基于STM32控制直流电机加减速正反转仿真设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 本设计由STM32F103、L298N电机驱动电路、按键电路组成。通过按键可以控制电机&#xff0c;正转、反转、加…

商越科技:渗透测试保障平台安全,推动线上采购高效运转

商越科技是数字化采购解决方案提供商&#xff0c;在同赛道企业中始终保持前列。商越科技通过自主研发的智能采购中台、SaaS应用及运营服务等为企业搭建专属的互联网采购平台&#xff0c;帮助企业实现采购数字化以及智能化转型&#xff0c;提高工作效率、降低采购成本。 打造数字…

Linux基础开发工具之调试器gdb

文章目录 1.编译成的可调试的debug版本1.1gcc test.c -o testdebug -g1.2readelf -S testdebug | grep -i debug 2.调试指令2.0quit退出2.1list/l/l 数字: 显示代码2.2run/r运行2.3断点相关1. break num/b num: 设置2. info b: 查看3. d index: 删除4. n: F10逐过程5. p 变量名…

Java必刷入门递归题×5(内附详细递归解析图)

目录 1.求N的阶乘 2.求12...N的和 3.顺序打印数字的每一位 4.求数字的每一位之和 5.求斐波拉契数列 1.求N的阶乘 &#xff08;1&#xff09;解析题目意思 比如求5的阶乘&#xff0c;符号表示就是5&#xff01;&#xff1b;所以5&#xff01;5*4*3*2*1我们下面使用简单的…

SSM图书管理系统开发mysql数据库web结构java编程计算机网页源码eclipse项目

一、源码特点 SSM 图书管理系统是一套完善的信息系统&#xff0c;结合springboot框架和bootstrap完成本系统&#xff0c;对理解JSP java编程开发语言有帮助系统采用SSM框架&#xff08;MVC模式开发&#xff09;&#xff0c;系统具有完整的源代码和 数据库&#xff0c;系统主要…

Linux-Docker的基础命令和部署code-server

1.安装docker 1.安装需要的安装包 yum install -y yum-utils2.设置镜像仓库 yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo3.安装docker yum install docker-ce docker-ce-cli containerd.io docker-buildx-plugin do…

多彩的树 -----题解(状压dp + 容斥原理)

目录 多彩的树 题目描述 输入描述: 输出描述: 输入 输出 思路解析&#xff1a; 代码实现&#xff1a; 多彩的树 时间限制&#xff1a;C/C 5秒&#xff0c;其他语言10秒 空间限制&#xff1a;C/C 262144K&#xff0c;其他语言524288K 64bit IO Format: %lld 题目描述 …

【Springboot】Vue3-Springboot引入JWT实现登录校验以及常见的错误解决方案

文章目录 前言一、JWT简单介绍二、token校验设计思路三、使用步骤Springboot部署JWT引入依赖&#xff1a;创建登录实体类后端&#xff1a;LoginController.java路由守卫函数 四、问题 前言 项目版本&#xff1a; 后端&#xff1a; Springboot 2.7、 Mybatis-plus、Maven 3.8.1…

C/C++轻量级并发TCP服务器框架Zinx-游戏服务器开发004:游戏核心消息处理 - 玩家类的实现

文章目录 0 代码仓库1 需求2 AOI设计2.1 AOI算法简介2.2 AOI数据结构及实现2.2.1 玩家2.2.2 网格对象2.2.3 游戏世界矩形2.2.4 获取周围玩家的实现2.2.5 代码测试 2.3 GameRole结合AOI创建玩家2.3.1 创建游戏世界全局对象-GameRole继承AOIWorld的Player2.3.2 把玩家到游戏世界的…

1.docker linux离线环境安装 20.1.0.12

目录 概述下载解压docker 卸载docker 安装检查安装环境常用命令结束 概述 docker离线环境安装 20.1.0.12 , centos 7.x 下载 安装包下载 解压 [roothadoop01 soft]# unzip docker_20_1_0_12.zip [roothadoop01 soft]# cd docker_20_1_0_12 [roothadoop01 docker_20_1_0_1…

数据结构:树的基本概念(二叉树,定义性质,存储结构)

目录 1.树1.基本概念1.空树2.非空树 2.基本术语1.结点之间的关系描述2.结点、树的属性描述3.有序树、无序树4.森林 3.树的常考性质 2.二叉树1.基本概念2.特殊二叉树1.满二叉树2.完全二叉树3.二叉排序树4.平衡二叉树 3.常考性质4.二叉树的存储结构1.顺序存储2.链式存储 1.树 1.…

亚马逊云AI应用科技创新下的Amazon SageMaker使用教程

目录 Amazon SageMaker简介 Amazon SageMaker在控制台的使用 模型的各项参数 pytorch训练绘图部分代码 Amazon SageMaker简介 亚马逊SageMaker是一种完全托管的机器学习服务。借助 SageMaker&#xff0c;数据科学家和开发人员可以快速、轻松地构建和训练机器学习模型&#…

ARM寄存器及功能介绍/R0-R15寄存器

1、ARM 寄存器组介绍 ARM 处理器一般共有 37 个寄存器&#xff0c;其中包括&#xff1a; &#xff08;1&#xff09; 31 个通用寄存器&#xff0c;包括 PC&#xff08;程序计数器&#xff09;在内&#xff0c;都是 32 位的寄存器。 &#xff08;2&#xff09; 6 个状态寄存器…

服务号如何升级订阅号

服务号和订阅号有什么区别&#xff1f;服务号转为订阅号有哪些作用&#xff1f;首先我们要知道服务号和订阅号有什么区别。服务号侧重于对用户进行服务&#xff0c;每月可推送4次&#xff0c;每次最多8篇文章&#xff0c;发送的消息直接显示在好友列表中。订阅号更侧重于信息传…

通信信道:无线信道中衰落的类型和分类

通信信道&#xff1a;无线信道中衰落的类型和分类 在进行通信系统仿真时&#xff0c;简单的情况下选择AWGN信道&#xff0c;但是AWGN信道和真是通信中的信道相差甚远&#xff0c;所以需要仿真各种其他类型的信道&#xff0c;为了更清楚理解仿真信道的特点&#xff0c;首先回顾…

linux安装并配置git连接github

git安装 sudo apt-get install git git信息配置 git config --global uer.name "yourname" git config --global user.email "youremail" 其中&#xff0c;yourname是你在github上配置的用户名&#xff0c;youremail是你在github上设置的邮箱 查看git…

Apinto 网关进阶教程,使用 API Mock 生成模拟数据

什么是 API Mock &#xff1f; API Mock 是一种技术&#xff0c;它允许程序员在不依赖后端数据的情况下&#xff0c;模拟 web服务器端 API 的响应。通常使用 API Mock 来测试前端应用程序&#xff0c;而无需等待后端程序构建完成。API Mock 可以模拟任何 HTTP 请求方法&#x…

谷歌提出 AGI 完整路线图:目前 ChatGPT 只处于 AGI 的第一阶段

本心、输入输出、结果 文章目录 谷歌提出 AGI 完整路线图:目前 ChatGPT 只处于 AGI 的第一阶段前言谷歌 DeepMind 发布 AGI 分级框架发展 AGI 必须遵循6个基本原则什么是AGI图灵测试详解六大原则AGI 的五大发展过程阶段原文参考弘扬爱国精神谷歌提出 AGI 完整路线图:目前 Cha…

LeetCode(7)买卖股票的最佳时机【数组/字符串】【简单】

目录 1.题目2.答案3.提交结果截图 链接&#xff1a; 121. 买卖股票的最佳时机 1.题目 给定一个数组 prices &#xff0c;它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 买入这只股票&#xff0c;并选择在 未来的某一个不同的日子 卖出该股票…

基于Python+Django的图书管理系统

项目介绍 图书是人类文明传播的一个重要方式&#xff0c;很多历史悠久的文明都是通过图书来进行传递的&#xff0c;虽然随着时代的进步电子信息技术发展很快&#xff0c;但是纸质图书的地位仍然是非常稳固的&#xff0c;为了能够让知识拥有更加快捷方便的传递方式我们开发了本…