uboot系列之 命令的處理過程 原始碼

2021-06-22 04:37:08 字數 3902 閱讀 7302

在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...