在uboot執行到第二個階段後,會進入到main_loop函式中,該函式有乙個作用就是處理使用者所輸入的命令,下面詳細分析命令處理的流程:
一、命令的結構及定義
在uboot裡面,命令的建立是通過巨集定義u_boot_cmd來實現的,該巨集定義在檔案include/command.h檔案中,
#define u_boot_cmd(name,maxargs,rep,cmd,usage,help) \
cmd_tbl_t
__u_boot_cmd_##name struct_section =
從以上巨集定義可以看出,通過u_boot_cmd(name,maxargs,rep,cmd,usage,help)定義出來的命令,展開後的結果就是:
cmd_tbl_t __u_boot_cmd_##name struct_section =
對於以上的語句,重點講述以下三點: 1、
cmd_tbl_t 是命令格式的資料結構,它定義在include/command.h
struct cmd_tbl_s ;
2、##name是指直接用u_boot_cmd裡面的name引數替換,#name表示將u_boot_cmd裡面的name引數加上雙引號(「」),然後替換
3、struct_section是個巨集定義,定義在common/command.h
#define struct_section __attribute__((unused,section(".u_boot_cmd")))
它表示將該處的內容放入u_boot_cmd段(具體u_boot_cmd段的資訊可以參看u-boot.lds連線檔案)
例如,定義了如下命令u_boot_cmd(command,1,0,fun,」short help」,」long help」)
將其按照上述巨集展開後得到如下結論:
cmd_tbl_t __u_boot_cmd_command __attribute__((unused.section(".u_boot_cmd")))=
並且該」command」命令已經加入到.u_boot_cmd段裡面了
二、處理控制台的輸入命令
在將命令的處理之前,先看幾個重要的資料結構:
1、struct p_context ;
該資料結構變數是乙個命令索引,關鍵的就是其中的兩個成員,struct pipe *list_head和struct pipe *pipe;
再來看資料結構struct pipe
struct pipe;
該資料結構用來儲存使用者的輸入命令的,命令儲存在成員變數struct child_prog* progs裡面,其中的next用來指向下乙個struct pipe資料結構變數(當一次輸入多個命令時用到)
struct child_prog ;
該資料結構中的char ** argv就是存放命令的地方,argc表示該命令含有的引數的個數
總的來說,他們的關係是:p_context的head_list成員變數指向第乙個pipe結構變數(用來儲存第一條命令),第乙個pipe結構的next指向下乙個pipe結構(用來儲存下一條命令)
1) 當使用者輸入的命令為command1時,
p_context.head_list->progs->argc= 1
p_context.head_list->progs->argv[0]=command1
2) 當使用者輸入的命令為command1 command2時
p_context.head_list->progs->argc= 2
p_context.head_list->progs->argv[0]=command1
p_context.head_list->progs->argv[1]=command2
3) 當使用者輸入的命令為command1 command2; command3 command4時(;表示前後輸入的是兩條命令)
p_context.head_list->progs->argc= 2
p_context.head_list->progs->argv[0]=command1
p_context.head_list->progs->argv[1]=command2
p_context.head_list->next->progs->argc= 2
p_context.head_list->next->progs->argv[0]=command3
p_context.head_list->next->progs->argv[1]=command4
當使用者的命令按照以上的方式儲存之後,就進入到parse_stream_outer函式:
int parse_stream_outer(struct in_str *inp, int flag)(common/hush.c){
......
code = run_list(ctx.list_head);
...... }
run_list(ctx.list_head)就是處理命令的入口函式,其中ctx是p_context結構變數,裡面儲存了使用者所輸入的命令,真正將處理落到實處的函式是
static int run_pipe_real(struct pipe *pi)(common/hush.c){
......
if((cmdtp = find_cmd(child->argv[i])) == null
)....... }
其中find_cmd函式的引數child->argv[i]通常情況下是child->argv[0],即認為整個命令的第一部分(第乙個空格之前的字元)作為命令名稱,其他的作為引數。它的作用就是到.u_boot_cmd段裡面尋找child->argv[0],如果沒找到,就返回null,並提示無效的命令;如果找到了,就將該命令以cmd_tbl_t結構變數的形式返回,繼續往下執行
static int run_pipe_real(struct pipe *pi)(common/hush.c){
.....
if((child->argc-i) > cmdtp->maxargs)
return cmd_usage(cmdtp);
......
rcode = (cmdtp->cmd)(cmdtp,flag,child->argc-i,&child->argv[i]);
...... }
如果發現輸入的引數個數大於命令裡面所定義的最大引數個數,就輸出該命令的usage資訊並退出,否則執行該命令的函式指標所指向的函式,它就是命令所需要執行的操作了。
### main_loop: bootcmd="run setargs_mmc boot_normal"
#if defined(config_cmd_run)
u_boot_cmd_complete(
run, config_sys_maxargs, 1, do_run,
"run commands in an environment variable",
"var [...]\n"
" - run the commands in the environment variable(s) 'var'",
var_complete);
#endif
int do_run (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv)
#ifndef config_sys_hush_parser
if (run_command (arg, flag) == -1)
return 1;
#else
if (parse_string_outer(arg,
flag_parse_semicolon | flag_exit_from_loop) != 0)
return 1;
#endif
}return 0;}
nginx http處理過程分析之細節
在之前的綜述中提到過兩篇不錯的部落格,對nginx的http的處理過程分析的很到位,這裡還有一些細節需要拿出來跟大家分享一下。題外話 在認真思考過每一行 之前,不要說真正理解了它!這是我說的,大家覺得搞笑就來噴我吧。這句話實際上是在告訴我們,隱藏在乙份 中的諸多細節,是需要你去仔細翻閱的,許多地方並...
nginx http處理過程分析之細節
在之前的綜述中提到過兩篇不錯的部落格,對nginx的http的處理過程分析的很到位,這裡還有一些細節需要拿出來跟大家分享一下。題外話 在認真思考過每一行 之前,不要說真正理解了它!這是我說的,大家覺得搞笑就來噴我吧。這句話實際上是在告訴我們,隱藏在乙份 中的諸多細節,是需要你去仔細翻閱的,許多地方並...
ARM的中斷處理過程
1.首先就是知道 arm狀態下的通用暫存器和程式計數器,綠顏色的就是相應模式下的私有暫存器。就是說程式一般執行在系統和使用者模式下,使用的是系統和使用者模式下的通用暫存器,當有異常發生時,比如 fiq,那麼系統將切換到 fiq模式下,相應的就會採用 fiq模式下的暫存器,其中綠顏色的就是只在 fiq...