1. 程式人生 > >第1階段——uboot通過nand命令讀內核分析(8)

第1階段——uboot通過nand命令讀內核分析(8)

opts turn [] 轉換成 default conf 最終 off unlock

本節主要學習:
詳細分析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:[email protected](bootloader)," \
"128k(params)," \
"2m(kernel)," \
"-(root)"

在100ask24x0.h裏定義了一個MTDPARTS_DEFAULT宏定義,
“mtdparts=nandflash0:”表示mtdparts分區位於nandflash上
"[email protected]

/* */(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
}

第1階段——uboot通過nand命令讀內核分析(8)