日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

uboot启动 及命令分析(3)

發(fā)布時間:2025/3/8 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 uboot启动 及命令分析(3) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

?

u-boot命令

先貼一個重要結(jié)構(gòu),位于uboot/include/command.h,這個結(jié)構(gòu)代表每個uboot命令

struct?cmd_tbl_s?{

???char?????*name;???/* Command Name???????*/

???int??????maxargs;????/* maximum number of arguments*/

???int??????repeatable;/* autorepeat allowed????*/

???????????????????/* Implementation function??*/

???int??????(*cmd)(struct?cmd_tbl_s?*,?int,?int,?char?*[]);

???char?????*usage;?????/* Usage message???(short)簡短用法信息*/

#ifdefCFG_LONGHELP

???char?????*help;???/* Help??message???(long)?長的幫助信息*/

#endif

#ifdef?CONFIG_AUTO_COMPLETE

???????????????????/* do auto completion on the arguments */

???int??(*complete)(intargc,?char?*argv[],?charlast_char,?intmaxv,?char*cmdv[]);

#endif

};

?

typedef struct?cmd_tbl_s????cmd_tbl_t;

============================================================

?

uboot的第一階段:硬件相關(guān)初始化

0.reset?執(zhí)行arm920t/start.s??過程如下

1.設(shè)置cpu svc管理模式

2.關(guān)看門狗中斷,mmu等

3.設(shè)置時鐘,sdram,外部總線

4.代碼重定位,搬運(yùn)代碼,從flash到sdram

5.設(shè)置棧,bss段清零, bss用于未初始化的全局變量和靜態(tài)變量

6.ldr pc, _start_armboot

???即進(jìn)入uboot啟動的第二階段,調(diào)用c函數(shù)start_armboot()

?

從start_armboot?開始

經(jīng)過一系列外設(shè)初始化

比如

falsh_init

nand_init

...

最后循環(huán)調(diào)用mian_loop()

main_loop主要流程

{

???1.?生成環(huán)境變量mtdparts,?調(diào)用mtdparts_init

???2.?在啟動過程中

??????若無空格鍵按下則boot_zImage,即run_command(getenv("bootcmd"),0)

??????有空格鍵按下則?run_command("menu",0)

???3. shell過程,讀取用戶的輸入并執(zhí)行相應(yīng)的命令

??????{

?????????從控制臺獲得命令,保存在全局變量comsole_buffer中

?????????解析命令行字符串,分割命令與參數(shù),最后執(zhí)行?run_command(...);

??????}????????????????????

}

?

也就是說在mian_loop中,是處理環(huán)境變量和控制臺人機(jī)交互,

mian_loop調(diào)用readline ()讀取命令行到console_buffer,

再把console_buffer復(fù)制到lastcommand中去,

還要設(shè)置flag,最后調(diào)用run_command (lastcommand, flag)函數(shù),

run_command (lastcommand, flag)函數(shù)中,首先定義cmd_tbl_t *cmdtp,再解析命令行。

再調(diào)用find_cmd(argv[0])函數(shù),其中argv[0]應(yīng)該是命令本身,參數(shù)已經(jīng)被剝離,

這個函數(shù)返回的是一個cmd_tbl_t結(jié)構(gòu)體,

就是說每個命令都有一個cmd_tbl_t結(jié)構(gòu)體相對應(yīng),關(guān)于run_command函數(shù)后面再分析

?

mian_loop中有

#define CONFIG_BOOTDELAY 3??//設(shè)置啟動延時時間

//如果延時大于等于零,并且沒有在延時過程中接收到按鍵,則引導(dǎo)內(nèi)核

if (bootdelay >=?0?&& s && !abortboot (bootdelay)) { //

# ifdef?CONFIG_AUTOBOOT_KEYED

??????intprev?= disable_ctrlc(1);/* disable Control C checking */

# endif???//狀態(tài)設(shè)置

?

# ifndef?CFG_HUSH_PARSER

????????{

?????????????printf("Booting Linux ...\n");???????//啟動?linux???

?????????run_command?(s,?0);??//運(yùn)行引導(dǎo)內(nèi)核的命令,s=getenv("bootcmd")??????????

????????}

?

加載linux內(nèi)核時將使用變量“bootcmd”和?“bootargs”,

變量“bootcmd”和?“bootargs”的值可以在在加載linux內(nèi)核前,

uboot的命令控制臺中進(jìn)行修改

?

bootcmd=nand read.jffs2 0x30007FC0 kernel;?bootm?0x30007FC0

第一條命令??從flash上讀出內(nèi)核???kernel是一個分區(qū)標(biāo)志

第二條命令??啟動命令指示了啟動地址

?

而bootargs是其它參數(shù)信息

而?run_command (getenv ("bootcmd"), flag)

?

bootcmd中的bootm,即boot application image from memory

參數(shù)形式:"bootm addr"

當(dāng)addr省略的時候bootm加載默認(rèn)的配置宏

#define CONFIG_SYS_LOAD_ADDR??0x30008000??/* default load address */

?

uboot中,"bootm"命令的執(zhí)行函數(shù)為do_bootm(),這個是由U_BOOT_CMD綁定的函數(shù)指針,

在do_bootm()中執(zhí)行了do_bootm_linux(),

do_bootm_linux()函數(shù)中獲取了"bootargs"環(huán)境變量的值,最終將此值傳遞給linux內(nèi)核,

并調(diào)用theKernel函數(shù),完成對linux內(nèi)核的加載啟動

?

linux內(nèi)核的啟動,主要就是執(zhí)行環(huán)境變量bootcmd和bootargs所定義的命令.

============================================================

?

uboot的核心功能是用run_command()來執(zhí)行的

run_command是怎么實(shí)現(xiàn)的?

?

int?run_command (const?char?*cmd,?intflag)

{

???cmd_tbl_t?*cmdtp;

???charcmdbuf[CFG_CBSIZE];????/* working copy of cmd??????*/

???char?*token;??????????/* start of token in cmdbuf*/

???char?*sep;???????????????/* end of token (separator) in cmdbuf */

???charfinaltoken[CFG_CBSIZE];

???char?*str?=?cmdbuf;

???char?*argv[CFG_MAXARGS +?1];???/* NULL terminated*/

???intargc,?inquotes;

???intrepeatable?=?1;

???intrc?=?0;

???...

???if ((cmdtp =?find_cmd(argv[0])) == NULL) {

?????????printf ("Unknown command '%s' - try 'help'\n", argv[0]);

?????????rc = -1;/* give up after bad command */

?????????continue;

??????}

???...

???if ((cmdtp->cmd) (cmdtp, flag, argc, argv)?!= 0) {

??????rc = -1;

???}

???...

}

?

run_command(...)????//流程解析

{

???1.?對\;解析,分割出一個個命令

???2.?然后對每一個完整的命令執(zhí)行

?????{

??????parse_line

??????{

?????????line是整條的命令行bootcmd的值

?????????例如line =?nand read.jffs2 0x30007FC0 kernel;?bootm?0x30007FC0

?????????先去掉開頭的空格,

?????????然后對命令進(jìn)行解析,找到空格之后將空格替換為\0,這樣解析出命令和參數(shù)

??????}

?

??????find_cmd(argv[0])

??????{

?????????從?__u_boot_cmd_start?到?__u_boot_cmd_end?的array進(jìn)行遍歷,

?????????從找到的cmd_tbl_t中,字符串尋找cmdtp->name與argv[0]相同的命令

??????}

??????找到匹配的命令后,調(diào)用cmd_tbl_t->cmd執(zhí)行

?????}

}

?

run_command函數(shù)中的parse_line函數(shù)主要代碼如下

int?parse_line?(char *line, char *argv[])

{

???...

???while ((*line == ' ') || (*line == '\t'))

???{

??????++line;

???}

???...

}

============================================================

run_command函數(shù)中的find_cmd()

cmd_tbl_t *find_cmd (const?char?*cmd)

{

???cmd_tbl_t *cmdtp;

???cmd_tbl_t *cmdtp_temp?= &__u_boot_cmd_start;???/*Init value */

???const?char?*p;

???intlen;

???intn_found?=?0;

?

???/*

????* Some commands allow length modifiers (like "cp.b");

????* compare command name only until first dot.

????*/

???len?= ((p?=?strchr(cmd,?'.')) ==?NULL) ??strlen?(cmd) : (p?-?cmd);

?

???for (cmdtp??= &__u_boot_cmd_start;

????????cmdtp?!= &__u_boot_cmd_start;

????????cmdtp++) {

??????if (strncmp?(cmd,?cmdtp->name,?len) ==?0) {

?????????if (len?==?strlen?(cmdtp->name))

????????????return?cmdtp;???/* full match */

?????????//如果名字匹配,就返回這個結(jié)構(gòu)體,否則比較下一個

?????????cmdtp_temp?=?cmdtp;???/* abbreviated command ? */

?????????n_found++;

??????}

???}

?

???if (n_found?==?1) {?????????/* exactly one match */

??????return?cmdtp_temp;

???}

?

???return?NULL;/* not found or ambiguous command */

}

?

其中__u_boot_cmd_start和__u_boot_cmd_start是怎么來的?

查找發(fā)現(xiàn)只有在command.h中有聲明

extern cmd_tbl_t??__u_boot_cmd_start;

extern cmd_tbl_t??__u_boot_cmd_end;

?

而__u_boot_cmd_start是在鏈接腳本uboot.lds里面定義的

?

???. = .;

???__u_boot_cmd_start = .;

???.u_boot_cmd : { *(.u_boot_cmd) }??//所有u_boot_cmd宏命令都保存在這個段

???__u_boot_cmd_end = .;

?

在command.h中有

#define Struct_Section??__attribute__ ((unused,section (".u_boot_cmd")))

?

#define?U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) \

cmd_tbl_t?__u_boot_cmd_##name Struct_Section = {#name, maxargs, rep, cmd, usage, help}

?

?

搜索到在cmd_bootm.c中有?U_BOOT_CMD的實(shí)參

U_BOOT_CMD(

???bootm,CFG_MAXARGS,1,do_bootm,

???"bootm???- boot application image from memory\n",

???"[addr [arg ...]]\n????- boot application image stored in memory\n"

???"\tpassing arguments 'arg ...'; when booting a Linux kernel,\n"

???"\t'arg' can be the address of an initrd image\n"

#ifdef CONFIG_OF_FLAT_TREE

???"\tWhen booting a Linux kernel which requires a flat device-tree\n"

???"\ta third argument is required which is the address of the of the\n"

???"\tdevice-tree blob. To boot that kernel without an initrd image,\n"

???"\tuse a '-' for the second argument. If you do not pass a third\n"

???"\ta bd_info struct will be passed instead\n"

#endif

);

?

將這個宏展開并替換

#define?U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) \

cmd_tbl_t?__u_boot_cmd_bootm?__attribute__ ((unused,section (".u_boot_cmd"))) =

{"bootm", CFG_MAXARGS, 1, do_bootm, "bootm???- boot application image from memory\n", "陰影部分"}

參數(shù)說明---------------

名稱:bootm

將段屬性設(shè)置為: .u_boot_cmd

最大參數(shù)個數(shù):CFG_MAXARGS

是否可重復(fù):1 ,?可重復(fù),即下一次按回車時可重復(fù)執(zhí)行

cmd對應(yīng)do_bootm,這是在cmd_tblt_t中定義的函數(shù)指針,命令就是在這個函數(shù)中實(shí)現(xiàn)

usage:使用概要?"bootm???- boot application image from memory\n"

help:詳細(xì)幫助:那一大段陰影部分

?

?

?

總結(jié):

每個U_BOOT_CMD宏組成的命令實(shí)質(zhì)上是一個個cmd_tbl_t結(jié)構(gòu),

它們在鏈接時全部被定位保存到__u_boot_cmd_start起始地址開始的段中,也就是.u_boot_cmd段中.

?

當(dāng)上電后,若啟動的是默認(rèn)的linux內(nèi)核,執(zhí)行run_command (getenv ("bootcmd"), flag),

由bootcmd字串中得知bootm,bootm的執(zhí)行函數(shù)是do_bootm(),

在do_bootm()中執(zhí)行了do_bootm_linux(...),

do_bootm_linux()函數(shù)中獲取了"bootargs"環(huán)境變量的值,

最終將此值傳遞給linux內(nèi)核,并調(diào)用theKernel函數(shù),完成對linux內(nèi)核的加載啟動

?

當(dāng)上電后,若用戶按空格并輸入命令,先同樣執(zhí)行run_command函數(shù),調(diào)用find_cmd遍歷每一個cmd_tbl_t結(jié)構(gòu),

比較cmdtp->name,當(dāng)名稱匹配時,就通過cmd_tbl_t結(jié)構(gòu)的(*cmd)(...)函數(shù)指針來執(zhí)行命令功能,

即執(zhí)行cmd_tbl_t->cmd

?

============================================================

?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??添加uboot命令

在uboot/include/configs/xxx.h文件中,添加#define CONFIG_CMD_HELLO啟用我們的自定義命令

也可以在uboot/include/config_cmd_default.h文件中添加,不過這個define在這里不是必須的

?

在common目錄,命令都是在cmd_xxx.c文件中實(shí)現(xiàn)的,這個是命名規(guī)范,必須是cmd_xxx.c形式,

所以我們在common目錄新建一個文件cmd_myCmd.c

?

#include <common.h>

?#include <command.h>

#ifdef?CONFIG_CMD_HELLO

int do_hello (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])

{

?  int i;

?  printf("hello the word!,%d\n",argc);

?

?  for(is = 0;i < argc;i++) ?

?  { ???

    printf("argv[%d]:%s\n",i,argv[i]); ?

?  } ? ?

return 0;

}

?

U_BOOT_CMD( ??hello,?CFG_MAXARGS,?1,?do_hello,

   ??"hello?? - just for test\n", ??

    "hello,long help .................\n"

);???

#endif

?

?

?

U_BOOT_CMD這里3個hello寫法最好一致,為什么?

第一個hello是uboot命令

第二個hello是在命令行輸入help時輸出的概要信息

第三個hello是當(dāng)輸入help myTest的時候顯示的詳細(xì)信息

?

最后,修改common下的Makefile文件,將cmd_myCmd.o加入編譯

輸入hello a b c d e f

輸出

hello the word!,7            
argv[0]:hello
argv[1]:a
argv[2]:b
argv[3]:c
argv[4]:d
argv[5]:e
argv[6]:f

?

========================================================

?

?

轉(zhuǎn)載于:https://www.cnblogs.com/CZM-/p/5069920.html

總結(jié)

以上是生活随笔為你收集整理的uboot启动 及命令分析(3)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。