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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

uboot流程——命令行模式以及命令处理介绍

發布時間:2025/3/21 编程问答 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 uboot流程——命令行模式以及命令处理介绍 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
[uboot] (第六章)uboot流程——命令行模式以及命令處理介紹
2016年11月14日 20:39:26閱讀數:4323

以下例子都以project X項目tiny210(s5pv210平臺,armv7架構)為例

[uboot] uboot流程系列:?
[project X] tiny210(s5pv210)上電啟動流程(BL0-BL2)?
[project X] tiny210(s5pv210)從存儲設備加載代碼到DDR?
[uboot] (第一章)uboot流程——概述?
[uboot] (第二章)uboot流程——uboot-spl編譯流程?
[uboot] (第三章)uboot流程——uboot-spl代碼流程?
[uboot] (第四章)uboot流程——uboot編譯流程?
[uboot] (第五章)uboot流程——uboot啟動流程?
[uboot] (番外篇)global_data介紹?
[uboot] (番外篇)uboot relocation介紹

建議先看《[uboot] (第五章)uboot流程——uboot啟動流程》

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

一、說明

命令行模式就是指uboot執行完一切必要的初始化過程之后,等待終端輸入命令和處理命令的一個模式。?
所以后面的章節,我們先介紹命令如何存儲以及處理,再簡單說明命令行模式是如何工作的

1、需要打開哪些宏

  • CONFIG_CMDLINE?
    表示是否支持命令行模式,定義如下:?
    ./configs/bubblegum_defconfig:201:CONFIG_CMDLINE=y?
    ./configs/tiny210_defconfig:202:CONFIG_CMDLINE=y

  • CONFIG_SYS_GENERIC_BOARD?
    用于定義板子為通用類型的板子。打開這個宏之后,common/board_f.c和common/board_r.c才會被編譯進去,否則,需要自己實現。?
    ./configs/bubblegum_defconfig:7:CONFIG_SYS_GENERIC_BOARD=y?
    ./configs/tiny210_defconfig:7:CONFIG_SYS_GENERIC_BOARD=y?
    打開之后,board_r.c中最終會執行run_main_loop進入命令行模式。具體參考《[uboot] (第五章)uboot流程——uboot啟動流程》。

  • CONFIG_SYS_PROMPT?
    命令行模式下的提示符。在tiny210中定義如下:?
    ./configs/tiny210_defconfig:203:CONFIG_SYS_PROMPT=”TINY210 => “

  • CONFIG_SYS_HUSH_PARSER?
    表示使用使用hush來對命令行進行解析。后續會繼續說明。在tiny210中定義如下:?
    ./include/configs/tiny210.h:121:#define CONFIG_SYS_HUSH_PARSER /* use “hush” command parser */

  • 對應命令需要打開對應命令的宏?
    以bootm命令為例,如果要支持bootm,則需要打開CONFIG_CMD_BOOTM宏,具體可以參考cmd/Makefile?
    ./configs/bubblegum_defconfig:226:CONFIG_CMD_BOOTM=y?
    ./configs/tiny210_defconfig:226:CONFIG_CMD_BOOTM=y

2、結合以下幾個問題來看后面的章節

  • 命令的數據結構,也就是代碼里面如何表示一個命令?
  • 如何定義一個命令,我們如何添加一個自己的命令?
  • 命令的存放和獲取?
  • 命令行模式的處理流程?

3、API

  • U_BOOT_CMD?
    #define U_BOOT_CMD(_name, _maxargs, _rep, _cmd, _usage, _help)?
    定義一個命令。
  • cmd_process?
    enum command_ret_t cmd_process(int flag, int argc, char * const argv[], int *repeatable, ulong *ticks)?
    命令的處理函數,命令是作為argv[0]傳入。

具體參數意義和實現參考后面。

二、命令處理數據結構的存放

1、數據結構

uboot把所有命令的數據結構都放在一個表格中,我們后續稱之為命令表。表中的每一項代表著一個命令,其項的類型是cmd_tbl_t。?
數據結構如下:

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 * const []);char *usage; /* Usage message (short) */ #ifdef CONFIG_SYS_LONGHELPchar *help; /* Help message (long) */ #endif };typedef struct cmd_tbl_s cmd_tbl_t;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

參數說明如下:

  • name:定義一個命令的名字。?其實就是執行的命令的字符串。這個要注意。
  • maxargs:這個命令支持的最大參數
  • repeatable:是否需要重復
  • cmd:命令處理函數的地址
  • usage:字符串,使用說明
  • help:字符串,幫助

2、在dump里面的表示

通過以下命令解析出dump。

arm-none-linux-gnueabi-objdump -D u-boot > uboot_objdump.txt
  • 1

以bootm命令為例,提取一部分信息,加上了注釋信息:

23e364cc <_u_boot_list_2_cmd_2_bootm>: // bootm命令對應的數據結構符號是_u_boot_list_2_cmd_2_bootm,后續我們會說明,其起始地址是0x23e364cc 23e364cc: 23e2bbc2 mvncs fp, #198656 ; 0x30800 // 這里對應第一個成員name,其地址是0x23e2bbc2 23e364d0: 00000040 andeq r0, r0, r0, asr #32 // 這里對應第二個成員maxargs,maxargs=0x40 23e364d4: 00000001 andeq r0, r0, r1 // 這里對應第三個成員repeatable,repeatable=1 23e364d8: 23e02028 mvncs r2, #40 ; 0x28 // 這里對應第四個成員cmd,cmd命令處理函數的地址是0x23e02028,和下面的do_bootm的地址一致!!! 23e364dc: 23e2bbc8 mvncs fp, #204800 ; 0x32000 // 這里對應第五個成員usage,usage字符串的地址是0x23e2bbc8 23e364e0: 23e34cb0 mvncs r4, #45056 ; 0xb000 // 這里對應第六個成員help,help字符串的地址是0x23e34cb023e02028 <do_bootm>: 23e34cb0 <bootm_help_text>:
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

根據上述dump就可以把bootm命令的數據結構定義都找出來了。

3、命令數據結構在u-boot.map符號表中的位置定義

通過查看u-boot.map,過濾出和u_boot_list中cmd相關的部分,對應符號表如下:

*(SORT(.u_boot_list*)).u_boot_list_2_cmd_10x23e3649c 0x0 cmd/built-in.o.u_boot_list_2_cmd_10x23e3649c 0x0 common/built-in.o.u_boot_list_2_cmd_2_bootefi0x23e3649c 0x18 cmd/built-in.o0x23e3649c _u_boot_list_2_cmd_2_bootefi.u_boot_list_2_cmd_2_bootelf0x23e364b4 0x18 cmd/built-in.o0x23e364b4 _u_boot_list_2_cmd_2_bootelf.u_boot_list_2_cmd_2_bootm0x23e364cc 0x18 cmd/built-in.o0x23e364cc _u_boot_list_2_cmd_2_bootm .......u_boot_list_2_cmd_2_true0x23e3670c 0x18 cmd/built-in.o0x23e3670c _u_boot_list_2_cmd_2_true.u_boot_list_2_cmd_2_version0x23e36724 0x18 cmd/built-in.o0x23e36724 _u_boot_list_2_cmd_2_version.u_boot_list_2_cmd_30x23e3673c 0x0 cmd/built-in.o.u_boot_list_2_cmd_30x23e3673c 0x0 common/built-in.o
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

可以觀察到命令表是被定義在0x23e3649c( .u_boot_list_2_cmd_1)到0x23e3673c( .u_boot_list_2_cmd_3)的位置中。?
并且每一個項占用了24個字節,和cmd_tbl_t結構的大小是一致的。?
注意,根據注釋,.u_boot_list_2_cmd_1和.u_boot_list_2_cmd_3這兩個符號是由鏈接器自己生成的。?
這里簡單有個印象,bootm命令對應的數據結構符號是u_boot_list_2_cmd_2_bootm

4、如何定義一個命令

(1)我們以bootm命令的定義為例:?
cmd/bootm.c中

U_BOOT_CMD(bootm, CONFIG_SYS_MAXARGS, 1, do_bootm,"boot application image from memory", bootm_help_text ); // bootm就是我們的命令字符串 // 在tiny210.h中定義了最大參數數量是64 // #define CONFIG_SYS_MAXARGS 64 /* max number of command args */ // 1表示重復一次 // 對應命令處理函數是do_bootm // usage字符串是"boot application image from memory" // help字符串是bootm_help_text定義的字符串。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

通過上面,可以看出是通過U_BOOT_CMD來定義了bootm命令對應的數據結構!!!?
并且命令處理函數的格式如下:

int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
  • 1

當命令處理函數執行成功時,需要返回0.返回非0值?
所以可以參照如上方式自己定義一個命令。

5、介紹一下U_BOOT_CMD的實現

include/common.h

#define U_BOOT_CMD(_name, _maxargs, _rep, _cmd, _usage, _help) \U_BOOT_CMD_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, _help, NULL)#define U_BOOT_CMD_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, _help, _comp) \ll_entry_declare(cmd_tbl_t, _name, cmd) = \U_BOOT_CMD_MKENT_COMPLETE(_name, _maxargs, _rep, _cmd, \_usage, _help, _comp);#define U_BOOT_CMD_MKENT_COMPLETE(_name, _maxargs, _rep, _cmd, \_usage, _help, _comp) \{ #_name, _maxargs, _rep, _cmd, _usage, \_CMD_HELP(_help) _CMD_COMPLETE(_comp) }#define ll_entry_declare(_type, _name, _list) \_type _u_boot_list_2_##_list##_2_##_name __aligned(4) \__attribute__((unused, \section(".u_boot_list_2_"#_list"_2_"#_name)))ll_entry_declare(cmd_tbl_t, _name, cmd) // 以bootm為例 // _type=cmd_tbl_t // _name=bootm // _list=cmd // 這里最終會轉化為如下數據結構 // // cmd_tbl_t _u_boot_list_2_cmd_2_bootm= // { // _name=bootm, // _maxargs=CONFIG_SYS_MAXARGS, // _rep=1, // _cmd=do_bootm, // _usage="boot application image from memory", // _help=bootm_help_text, // _comp=NULL, // } // 并且這個數據結構給存放到了 .u_boot_list_2_cmd_2_bootm段中!!!和我們上述的完全一致。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

三、命令的處理

1、簡單流程說明:

假設傳進來的命令是cmd。?
* 獲取命令表?
* 從命令表中搜索和cmd匹配的項?
* 執行對應項中的命令

后續我們我們分成“查找cmd對應的表項”、“執行對應表項中的命令”兩部分進行說明

2、查找cmd對應的表項——find_cmd

通過find_cmd可以獲取命令對應的命令表項cmd_tbl_t 。

(1)原理簡單說明?
前面我們知道了可以觀察到命令表是被定義在 .u_boot_list_2_cmd_1到.u_boot_list_2_cmd_3的位置中。所以我們從這個區間獲取命令表。?
并且根據表項中的name是否和傳進來的命令是否匹配來判斷是否是我們需要的表項。

(2)對應代碼?
common/command.c

cmd_tbl_t *find_cmd(const char *cmd) {cmd_tbl_t *start = ll_entry_start(cmd_tbl_t, cmd); // 獲取命令表的地址,start表示指向命令表的指針,具體實現看后面const int len = ll_entry_count(cmd_tbl_t, cmd); // 獲取命令表的長度,具體實現看后面return find_cmd_tbl(cmd, start, len); // 以命令表的指針和命令表的長度為參數,查找和cmd匹配的表項,也就是cmd_tbl_t結構,并返回給調用者。 }/* find command table entry for a command */ cmd_tbl_t *find_cmd_tbl(const char *cmd, cmd_tbl_t *table, int table_len) { #ifdef CONFIG_CMDLINEcmd_tbl_t *cmdtp;cmd_tbl_t *cmdtp_temp = table; /* Init value */const char *p;int len;int n_found = 0;if (!cmd)return NULL;/** 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 = table; cmdtp != table + table_len; cmdtp++) { // 通過指針遞增的方式,查找table中的每一個cmd_tbl_t if (strncmp(cmd, cmdtp->name, len) == 0) {if (len == strlen(cmdtp->name))return cmdtp; /* full match */ // 如果是命令字符串和表項中的name完全匹配,包括長度一致的,則直接返回cmdtp_temp = cmdtp; /* abbreviated command ? */n_found++; // 如果命令字符串和表項中的name的前面部分匹配的話(我們稱為部分匹配),暫時保存下來,并且記錄有幾個這樣的表項,主要是為了支持自動補全的功能}}if (n_found == 1) { /* exactly one match */return cmdtp_temp; // 如果部分匹配的表項是唯一的話,則可以將這個表項返回,主要是為了支持自動補全的功能} #endif /* CONFIG_CMDLINE */return NULL; /* not found or ambiguous command */ }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48

include/linker_lists.h

#define ll_entry_start(_type, _list) \ ({ \static char start[0] __aligned(4) __attribute__((unused, \section(".u_boot_list_2_"#_list"_1"))); \(_type *)&start; \ }) // 因為傳進來的_list是cmd,所以這里就是獲取命令表的起始地址,也就是.u_boot_list_2_cmd_1的地址,#define ll_entry_end(_type, _list) \ ({ \static char end[0] __aligned(4) __attribute__((unused, \section(".u_boot_list_2_"#_list"_3"))); \(_type *)&end; \ }) // 因為傳進來的_list是cmd,所以這里就是獲取命令表的結束地址,也就是.u_boot_list_2_cmd_3的地址,#define ll_entry_count(_type, _list) \({ \_type *start = ll_entry_start(_type, _list); \_type *end = ll_entry_end(_type, _list); \unsigned int _ll_result = end - start; \_ll_result; \}) // 因為傳進來的_list是cmd,所以這里就是計算命令表的長度
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

3、執行對應表項中的命令——cmd_call

通過調用cmd_call可以執行命令表項cmd_tbl_t 中的命令?
common/command.c

static int cmd_call(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) {int result;result = (cmdtp->cmd)(cmdtp, flag, argc, argv); // 直接執行命令表項cmd_tbl_t 中的cmd命令處理函數if (result)debug("Command failed, result=%d\n", result); // 命令返回非0值時,報錯return result; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

4、命令處理函數——cmd_process

代碼如下:?
common/command.c

enum command_ret_t cmd_process(int flag, int argc, char * const argv[],int *repeatable, ulong *ticks) {enum command_ret_t rc = CMD_RET_SUCCESS;cmd_tbl_t *cmdtp;/* Look up command in command table */cmdtp = find_cmd(argv[0]);// 第一個參數argv[0]表示命令,調用find_cmd獲取命令對應的表項cmd_tbl_t。if (cmdtp == NULL) {printf("Unknown command '%s' - try 'help'\n", argv[0]);return 1;}/* found - check max args */if (argc > cmdtp->maxargs)rc = CMD_RET_USAGE;// 檢測參數是否正常/* If OK so far, then do the command */if (!rc) {if (ticks)*ticks = get_timer(0);rc = cmd_call(cmdtp, flag, argc, argv);// 調用cmd_call執行命令表項中的命令,成功的話需要返回0值if (ticks)*ticks = get_timer(*ticks);// 判斷命令執行的時間*repeatable &= cmdtp->repeatable;// 這個命令執行的重復次數存放在repeatable中的}if (rc == CMD_RET_USAGE)rc = cmd_usage(cmdtp);// 命令格式有問題,打印幫助信息return rc; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

返回0表示執行成功,返回非0值表示執行失敗。?
后續需要執行一個命令的時候,直接調用cmd_process即可。

四、命令行模式的流程

命令行模式有兩種簡單的方式。正常模式是簡單地獲取串口數據、解析和處理命令。?
hush模式則是指命令的接收和解析使用busybox的hush工具,對應代碼是hush.c。?
關于hush模式的作用和使用自己還不是很清楚,還要再研究一下。這里簡單的寫一點流程。

1、入口

通過《[uboot] (第五章)uboot流程——uboot啟動流程》,我們知道了uboot在執行完所有初始化程序之后,調用run_main_loop進入主循環。?
通過主循環進入了命令行模式。?
common/board_r.c

static int run_main_loop(void) {/* main_loop() can return to retry autoboot, if so just run it again */for (;;)main_loop(); // 這里進入了主循環,而autoboot也是在主循環里面實現return 0; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

main_loop實現如下:?
這里了解一個縮寫,cli,Command Line Interface,命令行接口,命令行界面。?
common/main.c

void main_loop(void) {const char *s;bootstage_mark_name(BOOTSTAGE_ID_MAIN_LOOP, "main_loop"); // 這里用于標記uboot的進度,對于tiny210來說起始什么都沒做cli_init(); // cli的初始化,主要是hush模式下的初始化run_preboot_environment_command(); // preboot相關的東西,后續有用到再說明s = bootdelay_process();if (cli_process_fdt(&s))cli_secure_boot_cmd(s);autoboot_command(s); // autoboot的東西,后續使用autoboot的時候再專門說明cli_loop(); // 進入cli的循環模式,也就是命令行模式panic("No CLI available"); }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

通過調用cli_loop進入了命令行模式,并且不允許返回。?
common/cli.c

void cli_loop(void) { #ifdef CONFIG_SYS_HUSH_PARSERparse_file_outer(); // 這里進入hush命令模式/* This point is never reached */for (;;); #elif defined(CONFIG_CMDLINE) // 這里進入通用命令行模式cli_simple_loop(); #else // 說明沒有打開CONFIG_CMDLINE宏,無法進入命令行模式,直接打印一個提示printf("## U-Boot command line is disabled. Please enable CONFIG_CMDLINE\n"); #endif /*CONFIG_SYS_HUSH_PARSER*/ }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

最終通過cli_simple_loop進入通用命令行模式,或者通過parse_file_outer進入hush命令行模式。?
因為通用命令行模式相對較為簡單,所以這邊先說明通用命令行模式。

2、通用命令行模式

代碼如下:

void cli_simple_loop(void) {static char lastcommand[CONFIG_SYS_CBSIZE + 1] = { 0, };int len;int flag;int rc = 1;for (;;) {len = cli_readline(CONFIG_SYS_PROMPT); // 打印CONFIG_SYS_PROMPT,然后從串口讀取一行作為命令,存儲在console_buffer中 // 在tiny210中定義如下:./configs/tiny210_defconfig:203:CONFIG_SYS_PROMPT="TINY210 => "flag = 0; /* assume no special flags for now */if (len > 0)strlcpy(lastcommand, console_buffer,CONFIG_SYS_CBSIZE + 1); // 如果獲得了一個新行時,命令會存儲在console_buffer,將命令復制到lastcommand中else if (len == 0)flag |= CMD_FLAG_REPEAT; // 只是得到一個單純的換行符時,設置重復標識,后續重復執行上一次命令if (len == -1)puts("<INTERRUPT>\n"); // 獲得非數據值時,直接打印中斷elserc = run_command_repeatable(lastcommand, flag); // 否則,執行lastcommand中的命令if (rc <= 0) {/* invalid command or not repeatable, forget it */lastcommand[0] = 0; // 命令執行出錯時,清空lastcommand,防止下一次重復執行這個命令}} }/* run_command_repeatable實現如下 */ int run_command_repeatable(const char *cmd, int flag) {return cli_simple_run_command(cmd, flag); }/* cli_simple_run_command實現如下 */ int cli_simple_run_command(const char *cmd, int flag) {char cmdbuf[CONFIG_SYS_CBSIZE]; /* working copy of cmd */char *token; /* start of token in cmdbuf */char *sep; /* end of token (separator) in cmdbuf */char finaltoken[CONFIG_SYS_CBSIZE];char *str = cmdbuf;char *argv[CONFIG_SYS_MAXARGS + 1]; /* NULL terminated */int argc, inquotes;int repeatable = 1;int rc = 0;debug_parser("[RUN_COMMAND] cmd[%p]=\"", cmd);if (DEBUG_PARSER) {/* use puts - string may be loooong */puts(cmd ? cmd : "NULL");puts("\"\n");}clear_ctrlc(); /* forget any previous Control C */if (!cmd || !*cmd)return -1; /* empty command */if (strlen(cmd) >= CONFIG_SYS_CBSIZE) {puts("## Command too long!\n");return -1;}strcpy(cmdbuf, cmd);/* Process separators and check for invalid* repeatable commands*/debug_parser("[PROCESS_SEPARATORS] %s\n", cmd);while (*str) { // 這里過濾掉一些對命令進行處理的部分代碼/* find macros in this token and replace them */cli_simple_process_macros(token, finaltoken);/* Extract arguments */argc = cli_simple_parse_line(finaltoken, argv); // 對命令進行加工處理,轉化成argv和argc格式。if (argc == 0) {rc = -1; /* no command at all */continue;}if (cmd_process(flag, argc, argv, &repeatable, NULL))rc = -1; // 調用cmd_process對命令進行處理 // 關于這個的實現我們在上述三、4中說明過了/* Did the user stop this? */if (had_ctrlc())return -1; /* if stopped then not repeatable */}return rc ? rc : repeatable; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105

3、hush命令行模式

hush的實現自己也沒搞太懂,簡單的說明一下流程

static int parse_file_outer(FILE *f) {int rcode;struct in_str input;setup_file_in_str(&input); // 安裝一個輸入流,具體沒怎么研究rcode = parse_stream_outer(&input, FLAG_PARSE_SEMICOLON); // 處理流數據return rcode; } 后續的流程簡單說明如下: parse_stream_outer ——》run_list ————》run_list_real ——————》run_pipe_real ————————》cmd_process
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

可以觀察到,最終還是調用了cmd_process來對命令進行處理,上述第三節已經說明了,這里不重復說明了。

總結

以上是生活随笔為你收集整理的uboot流程——命令行模式以及命令处理介绍的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。