uboot启动 及命令分析(3)
?
u-boot命令
先貼一個重要結構,位于uboot/include/command.h,這個結構代表每個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的第一階段:硬件相關初始化
0.reset?執行arm920t/start.s??過程如下
1.設置cpu svc管理模式
2.關看門狗中斷,mmu等
3.設置時鐘,sdram,外部總線
4.代碼重定位,搬運代碼,從flash到sdram
5.設置棧,bss段清零, bss用于未初始化的全局變量和靜態變量
6.ldr pc, _start_armboot
???即進入uboot啟動的第二階段,調用c函數start_armboot()
?
從start_armboot?開始
經過一系列外設初始化
比如
falsh_init
nand_init
...
最后循環調用mian_loop()
main_loop主要流程
{
???1.?生成環境變量mtdparts,?調用mtdparts_init
???2.?在啟動過程中
??????若無空格鍵按下則boot_zImage,即run_command(getenv("bootcmd"),0)
??????有空格鍵按下則?run_command("menu",0)
???3. shell過程,讀取用戶的輸入并執行相應的命令
??????{
?????????從控制臺獲得命令,保存在全局變量comsole_buffer中
?????????解析命令行字符串,分割命令與參數,最后執行?run_command(...);
??????}????????????????????
}
?
也就是說在mian_loop中,是處理環境變量和控制臺人機交互,
mian_loop調用readline ()讀取命令行到console_buffer,
再把console_buffer復制到lastcommand中去,
還要設置flag,最后調用run_command (lastcommand, flag)函數,
run_command (lastcommand, flag)函數中,首先定義cmd_tbl_t *cmdtp,再解析命令行。
再調用find_cmd(argv[0])函數,其中argv[0]應該是命令本身,參數已經被剝離,
這個函數返回的是一個cmd_tbl_t結構體,
就是說每個命令都有一個cmd_tbl_t結構體相對應,關于run_command函數后面再分析
?
mian_loop中有
#define CONFIG_BOOTDELAY 3??//設置啟動延時時間
//如果延時大于等于零,并且沒有在延時過程中接收到按鍵,則引導內核
if (bootdelay >=?0?&& s && !abortboot (bootdelay)) { //
# ifdef?CONFIG_AUTOBOOT_KEYED
??????intprev?= disable_ctrlc(1);/* disable Control C checking */
# endif???//狀態設置
?
# ifndef?CFG_HUSH_PARSER
????????{
?????????????printf("Booting Linux ...\n");???????//啟動?linux???
?????????run_command?(s,?0);??//運行引導內核的命令,s=getenv("bootcmd")??????????
????????}
?
加載linux內核時將使用變量“bootcmd”和?“bootargs”,
變量“bootcmd”和?“bootargs”的值可以在在加載linux內核前,
uboot的命令控制臺中進行修改
?
bootcmd=nand read.jffs2 0x30007FC0 kernel;?bootm?0x30007FC0
第一條命令??從flash上讀出內核???kernel是一個分區標志
第二條命令??啟動命令指示了啟動地址
?
而bootargs是其它參數信息
而?run_command (getenv ("bootcmd"), flag)
?
bootcmd中的bootm,即boot application image from memory
參數形式:"bootm addr"
當addr省略的時候bootm加載默認的配置宏
#define CONFIG_SYS_LOAD_ADDR??0x30008000??/* default load address */
?
uboot中,"bootm"命令的執行函數為do_bootm(),這個是由U_BOOT_CMD綁定的函數指針,
在do_bootm()中執行了do_bootm_linux(),
do_bootm_linux()函數中獲取了"bootargs"環境變量的值,最終將此值傳遞給linux內核,
并調用theKernel函數,完成對linux內核的加載啟動
?
linux內核的啟動,主要就是執行環境變量bootcmd和bootargs所定義的命令.
============================================================
?
uboot的核心功能是用run_command()來執行的
run_command是怎么實現的?
?
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.?然后對每一個完整的命令執行
?????{
??????parse_line
??????{
?????????line是整條的命令行bootcmd的值
?????????例如line =?nand read.jffs2 0x30007FC0 kernel;?bootm?0x30007FC0
?????????先去掉開頭的空格,
?????????然后對命令進行解析,找到空格之后將空格替換為\0,這樣解析出命令和參數
??????}
?
??????find_cmd(argv[0])
??????{
?????????從?__u_boot_cmd_start?到?__u_boot_cmd_end?的array進行遍歷,
?????????從找到的cmd_tbl_t中,字符串尋找cmdtp->name與argv[0]相同的命令
??????}
??????找到匹配的命令后,調用cmd_tbl_t->cmd執行
?????}
}
?
run_command函數中的parse_line函數主要代碼如下
int?parse_line?(char *line, char *argv[])
{
???...
???while ((*line == ' ') || (*line == '\t'))
???{
??????++line;
???}
???...
}
============================================================
run_command函數中的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 */
?????????//如果名字匹配,就返回這個結構體,否則比較下一個
?????????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是怎么來的?
查找發現只有在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的實參
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", "陰影部分"}
參數說明---------------
名稱:bootm
將段屬性設置為: .u_boot_cmd
最大參數個數:CFG_MAXARGS
是否可重復:1 ,?可重復,即下一次按回車時可重復執行
cmd對應do_bootm,這是在cmd_tblt_t中定義的函數指針,命令就是在這個函數中實現
usage:使用概要?"bootm???- boot application image from memory\n"
help:詳細幫助:那一大段陰影部分
?
?
?
總結:
每個U_BOOT_CMD宏組成的命令實質上是一個個cmd_tbl_t結構,
它們在鏈接時全部被定位保存到__u_boot_cmd_start起始地址開始的段中,也就是.u_boot_cmd段中.
?
當上電后,若啟動的是默認的linux內核,執行run_command (getenv ("bootcmd"), flag),
由bootcmd字串中得知bootm,bootm的執行函數是do_bootm(),
在do_bootm()中執行了do_bootm_linux(...),
do_bootm_linux()函數中獲取了"bootargs"環境變量的值,
最終將此值傳遞給linux內核,并調用theKernel函數,完成對linux內核的加載啟動
?
當上電后,若用戶按空格并輸入命令,先同樣執行run_command函數,調用find_cmd遍歷每一個cmd_tbl_t結構,
比較cmdtp->name,當名稱匹配時,就通過cmd_tbl_t結構的(*cmd)(...)函數指針來執行命令功能,
即執行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文件中實現的,這個是命名規范,必須是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是當輸入help myTest的時候顯示的詳細信息
?
最后,修改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
?
========================================================
?
?
轉載于:https://www.cnblogs.com/CZM-/p/5069920.html
總結
以上是生活随笔為你收集整理的uboot启动 及命令分析(3)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【python】编程学习练习题-2
- 下一篇: Tomcat版本与Servlet、JSP