第1阶段——uboot分析之通过nand命令读内核(8)

本节主要学习: 详细分析UBOOT中"bootcmd=nand read.jffs2 0x30007FC0 kernel;bootm 0x30007FC0" 怎么实现nand命令读内核. 1. nand read.jffs2 0x30007FC0 kernel 步骤a: 从NAND FILSHE中kernel分区读出 步骤b: 放到0x30007FC0去

1.1 kernel分区: 是flash中内核区 其中在flash中定义了4大分区: | bootloader | :一开机直接运行u-boot |boot parameters | :存放一些可以设置的参数,供u-boot使用 | kernel | :存放内核区 |root filesystem | :根文件系统,挂载(mount)后才能使用文件系统中的应用程序 这几个分区通过配置文件已在flash地址上是写好了,位于 u-boot-1.1.6/include/configs/100ask24x0.h:

#define MTDIDS_DEFAULT "nand0=nandflash0" #define MTDPARTS_DEFAULT "mtdparts=nandflash0:256k@0(bootloader)," \ "128k(params)," \ "2m(kernel)," \ "-(root)" 在100ask24x0.h里定义了一个MTDPARTS_DEFAULT宏定义, “mtdparts=nandflash0:”表示mtdparts分区位于nandflash上 "256k@0(bootloader),"表示从0开始共256kb是bootloader分区 "128k(params),"表示接下来128kb用来存放参数,是params分区 "2m(kernel)," 表示接下来2Mb用来存放内核,是kernel分区 "-(root)" 表示剩下的容量存放根文件系统,是root分区 1.2 可以通过在uboot界面输入"mtd"命令,查看4个分区的位置情况: #: name size offset mask_flags 0:bootloader 0X00040000 0X00000000 0 1:params 0X00020000 0X00040000 0 2:kernel 0X00200000 0X00060000 0 3:root 0X0fda0000 0X00260000 0

从上面可以看出bootloader基地址是0x0000 0000,该分区大小为0x0004 000,所以结束地址为0X0003 FFFF。 为什么0X00040000等于256kb? 因为在ARM920t中,每隔4个地址保存了一个32位数据(4个字节) 所以0X00040000=0X00040000个字节=0x100(256)*0x400(1024)=256Kb

1.3 所以 nand read.jffs2 0x30007FC0 kernel 最终扩展开为: nand read.jffs2 0x30007FC0 0X00060000 0X00200000

1.4 nand命令位于./common/cmd_nand.c(所有命令文件都是存在common中,以cmd_xx.c形式保存) 其中nand命令执行时调用的是do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])函数 进入do_nand()函数:

int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
{ 
int i, dev, ret;
ulong addr, off, size;
char *cmd, *s;
nand_info_t *nand;
int quiet = 0;
const char *quiet_str = getenv("quiet"); //获取环境变量quiet


if (argc < 2) //判断nand命令参数个数若小于2,将goto到usage,打印cmdtp->usage(nand命令短的帮助说明)
goto usage;
...
cmd = argv[1]; //cmd="read.jffs2"
...
if (strcmp(cmd, "info") == 0) //cmd不等于"info",不执行
{...}
...
if (strcmp(cmd, "bad") != 0 && strcmp(cmd, "erase") != 0 &&
strncmp(cmd, "dump", 4) != 0 &&
strncmp(cmd, "read", 4) != 0 && strncmp(cmd, "write", 5) != 0 &&
strcmp(cmd, "scrub") != 0 && strcmp(cmd, "markbad") != 0 &&
strcmp(cmd, "biterr") != 0 &&
strcmp(cmd, "lock") != 0 && strcmp(cmd, "unlock") != 0 )
goto usage; //若argv[1]都不满足的话,表示使用命令在语法上有错误,打印短的帮助说明
....
if (strncmp(cmd, "read", 4) == 0 || strncmp(cmd, "write", 5) == 0) //cmd==read为真
{
int read;

if (argc < 4) // "nand read.jffs2 0x30007FC0 0X00060000 0X00200000"共5个参数,这里不执行
goto usage;

addr = (ulong)simple_strtoul(argv[2], NULL, 16); //将argv[2]的"0x30007FC0"字符型转换成数值型

read = strncmp(cmd, "read", 4) == 0; 
//strncmp():判断cmd和"read"前4个字节若相等返回0,不相等返回大于0的数
//这里cmd与"read"相等,所以strncmp()返回0,read=(0==0)为真,所以read=1 
printf("\nNAND %s: ", read ? "read" : "write"); //由于read=1,所以打印"\nNAND read:" 

if (arg_off_size(argc - 3, argv + 3, nand, &off, &size) != 0)
return 1;

s = strchr(cmd, '.'); //strchr():查找'.'字符,若没找到返回NULL。
if (s != NULL &&
(!strcmp(s, ".jffs2") || !strcmp(s, ".e") || !strcmp(s, ".i"))) //if为真,argv[1]=read.jffs2
{ 
if (read) { //read==1,执行if
/* read */
nand_read_options_t opts;
memset(&opts, 0, sizeof(opts));
opts.buffer = (u_char*) addr; //设置buffer=0x30007FC0
opts.length = size; //设置size=0X00200000=2097152 byte
opts.offset = off; //设置offset=0X00060000
opts.quiet = quiet;
ret = nand_read_opts(nand, &opts); 
//nand_read_opts():读取nandflash的kernel分区到 buffer地址,如读取成功返回0
} else {
/* write */
...
}
}
else if ( s != NULL && !strcmp(s, ".yaffs")){
...
}else if ( s != NULL && !strcmp(s, ".raw")){
...
} else {
...
}

printf(" %d bytes %s: %s\n", size, 
read ? "read" : "written", ret ? "ERROR" : "OK"); //打印"2097152 bytes read : OK\n"

return ret == 0 ? 0 : 1; //read读取kernel分区成功返回0,失败返回1
}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏ytkah

用laravel dingo/api创建简单的api

如果你曾经使用过 API 你就会知道大多数服务都来自子域或前缀。前缀或子域是必须的,但只需要一个。请避免使用版本号作为你的前缀或子域,因为版本控制是通过 hea...

1005
来自专栏漏斗社区

代码审计| 这是一款适合练手的漏洞

0x00 背景 本周,斗哥分析了下zzcms8.2的源码,发现蛮多问题的,觉得这个源码适合萌新们练手或入坑PHP的代码审计。今天决定发出一些发现的问题,当然这个...

3598
来自专栏程序员宝库

NGINX 宏观手记

任何一个工具都有它的灵魂所在,作为一个PHP程序员,我们可能仅仅使用了它的一小部分,这篇文章让你更加了解Nginx,本章大多都是总结、翻译、整理 ,希望你可以知...

391
来自专栏老马说编程

(56) 文件概述 / 计算机程序的思维逻辑

我们在日常电脑操作中,接触和处理最多的,除了上网,大概就是各种各样的文件了,从本节开始,我们就来探讨文件处理,本节主要介绍文件有关的一些基本概念和常识,Java...

1855
来自专栏向治洪

Vue.js快速入门

Vue.js简介 Vue.js(读音 /vjuː/, 类似于view)是一套构建用户界面的渐进式框架。与其他重量级框架不同的是,Vue 采用自底向上增量开发的设...

2169
来自专栏码神联盟

Shiro系列 | 《Shiro开发详细教程》第三章:Shiro授权流程-下

subject.checkPermissions("user:update");

712
来自专栏向治洪

Vue.js简介

Vue.js简介 Vue.js(读音 /vjuː/, 类似于view)是一套构建用户界面的渐进式框架。与其他重量级框架不同的是,Vue 采用自底向上增量开发的设...

2427
来自专栏Java技术分享

SpringBoot第5小节:事务管理

场景:执行2条sql语句,要么同时成功,要么同时失败。 同时操作1条或多条数据时,建议给方法加个@Transactional,查询的时候不用加事务。 ?

3166
来自专栏编程心路

SSH框架之旅-hibernate(1)

什么是框架呢?个人觉得在软件设计中,框架可以看作是架构组件。如果把整个程序看作是一个人的话,那么框架可以看出是一个人的骨架,我们要做的的就是在这个框架的基础上进...

783
来自专栏深度学习之tensorflow实战篇

mysql、mongodb、python(dataframe).聚合函数的形式,以及报错解决方案

1、mysql select * from table_name group by name,id 有的时候执行下面语句报错sql_mode=only_ful...

2874

扫码关注云+社区