main_loop 的代码如下:
44
43 void main_loop (void)
42 {
41 #ifndef CONFIG_SYS_HUSH_PARSER
E 40 ▎ static char lastcommand[CONFIG_SYS_CBSIZE] = { 0, }; ■ Use of undeclared identifier 'CONFIG_SYS_CBSIZE'
39 ▎ int len;
38 ▎ int rc = 1;
37 ▎ int flag;
36 #endif
35 ▎
34 #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
33 ▎ char *s;
32 ▎ int bootdelay;
31 #endif
30 #ifdef CONFIG_PREBOOT
29 ▎ char *p;
28 #endif
27 #ifdef CONFIG_BOOTCOUNT_LIMIT
26 ▎ unsigned long bootcount = 0;
25 ▎ unsigned long bootlimit = 0;
24 ▎ char *bcs;
23 ▎ char bcs_set[16];
22 #endif /* CONFIG_BOOTCOUNT_LIMIT */
21 ▎
20 #ifdef CONFIG_BOOTCOUNT_LIMIT
19 ▎ bootcount = bootcount_load();
18 ▎ bootcount++;
17 ▎ bootcount_store (bootcount);
16 ▎ sprintf (bcs_set, "%lu", bootcount);
15 ▎ setenv ("bootcount", bcs_set);
14 ▎ bcs = getenv ("bootlimit");
13 ▎ bootlimit = bcs ? simple_strtoul (bcs, NULL, 10) : 0;
12 #endif /* CONFIG_BOOTCOUNT_LIMIT */
11 ▎
10 #ifdef CONFIG_MODEM_SUPPORT
9 ▎ debug ("DEBUG: main_loop: do_mdm_init=%d\n", do_mdm_init);
8 ▎ if (do_mdm_init) {
7 ▎ ▎ char *str = strdup(getenv("mdm_cmd"));
6 ▎ ▎ setenv ("preboot", str); /* set or delete definition */
5 ▎ ▎ if (str != NULL)
4 ▎ ▎ ▎ free (str);
3 ▎ ▎ mdm_init(); /* wait for modem connection */
2 ▎ }
1 #endif /* CONFIG_MODEM_SUPPORT */
322 ▎
1 #ifdef CONFIG_VERSION_VARIABLE
2 ▎ {
3 ▎ ▎ setenv ("ver", version_string); /* set version variable */
4 ▎ }
5 #endif /* CONFIG_VERSION_VARIABLE */
6 ▎
7 #ifdef CONFIG_SYS_HUSH_PARSER
8 ▎ u_boot_hush_start ();
9 #endif
#if defined(CONFIG_HUSH_INIT_VAR)
42 ▎ hush_init_var ();
41 #endif
40 ▎
39 #ifdef CONFIG_PREBOOT
38 ▎ if ((p = getenv ("preboot")) != NULL) {
37 # ifdef CONFIG_AUTOBOOT_KEYED
36 ▎ ▎ int prev = disable_ctrlc(1); /* disable Control C checking */
35 # endif
34 ▎ ▎
33 ▎ ▎ run_command_list(p, -1, 0);
32 ▎ ▎
31 # ifdef CONFIG_AUTOBOOT_KEYED
30 ▎ ▎ disable_ctrlc(prev); /* restore Control C checking */
29 # endif
28 ▎ }
27 #endif /* CONFIG_PREBOOT */
26 ▎
25 #if defined(CONFIG_UPDATE_TFTP)
24 ▎ update_tftp (0UL);
23 #endif /* CONFIG_UPDATE_TFTP */
22 ▎
21 #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
20 ▎ s = getenv ("bootdelay");
19 ▎ bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;
18 ▎
17 ▎ debug ("### main_loop entered: bootdelay=%d\n\n", bootdelay);
16 ▎
15 #if defined(CONFIG_MENU_SHOW)
14 ▎ bootdelay = menu_show(bootdelay);
13 #endif
12 # ifdef CONFIG_BOOT_RETRY_TIME
11 ▎ init_cmd_timeout ();
10 # endif /* CONFIG_BOOT_RETRY_TIME */
9 ▎
8 #ifdef CONFIG_POST
7 ▎ if (gd->flags & GD_FLG_POSTFAIL) {
6 ▎ ▎ s = getenv("failbootcmd");
5 ▎ }
4 ▎ else
3 #endif /* CONFIG_POST */
2 #ifdef CONFIG_BOOTCOUNT_LIMIT
1 ▎ if (bootlimit && (bootcount > bootlimit)) {
376 ▎ ▎ printf ("Warning: Bootlimit (%u) exceeded. Using altbootcmd.\n",
1 ▎ ▎ ▎ (unsigned)bootlimit);
2 ▎ ▎ s = getenv ("altbootcmd");
3 ▎ }
4 ▎ else
5 #endif /* CONFIG_BOOTCOUNT_LIMIT */
6 ▎ ▎ s = getenv ("bootcmd");
7 ▎
8 ▎ debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>");
9 ▎
if (bootdelay != -1 && s && !abortboot(bootdelay)) {
42 # ifdef CONFIG_AUTOBOOT_KEYED
41 ▎ ▎ int prev = disable_ctrlc(1); /* disable Control C checking */
40 # endif
39 ▎ ▎
38 ▎ ▎ run_command_list(s, -1, 0);
37 ▎ ▎
36 # ifdef CONFIG_AUTOBOOT_KEYED
35 ▎ ▎ disable_ctrlc(prev); /* restore Control C checking */
34 # endif
33 ▎ }
32 ▎
31 # ifdef CONFIG_MENUKEY
30 ▎ if (menukey == CONFIG_MENUKEY) {
29 ▎ ▎ s = getenv("menucmd");
28 ▎ ▎ if (s)
27 ▎ ▎ ▎ run_command_list(s, -1, 0);
26 ▎ }
25 #endif /* CONFIG_MENUKEY */
24 #endif /* CONFIG_BOOTDELAY */
23 ▎
22 ▎ /*
21 ▎ ▎* Main Loop for Monitor Command Processing
20 ▎ ▎*/
19 #ifdef CONFIG_SYS_HUSH_PARSER
18 ▎ parse_file_outer();
17 ▎ /* This point is never reached */
16 ▎ for (;;);
15 #else
14 ▎ for (;;) {
13 #ifdef CONFIG_BOOT_RETRY_TIME
12 ▎ ▎ if (rc >= 0) {
11 ▎ ▎ ▎ /* Saw enough of a valid command to
10 ▎ ▎ ▎ ▎* restart the timeout.
9 ▎ ▎ ▎ ▎*/
8 ▎ ▎ ▎ reset_cmd_timeout();
7 ▎ ▎ }
6 #endif
E 5 ▎ ▎ len = readline (CONFIG_SYS_PROMPT); ■■ Use of undeclared identifier 'CONFIG_SYS_PROMPT'
4 ▎ ▎
3 ▎ ▎ flag = 0; /* assume no special flags for now */
2 ▎ ▎ if (len > 0)
E 1 ▎ ▎ ▎ strcpy (lastcommand, console_buffer); ■ Call to undeclared library function 'strcpy' with type 'char *(char *, const char *)'; ISO C99 and later do not s
429 ▎ ▎ else if (len == 0)
E 1 ▎ ▎ ▎ flag |= CMD_FLAG_REPEAT; ■ Use of undeclared identifier 'CMD_FLAG_REPEAT'
2 #ifdef CONFIG_BOOT_RETRY_TIME
3 ▎ ▎ else if (len == -2) {
4 ▎ ▎ ▎ /* -2 means timed out, retry autoboot
5 ▎ ▎ ▎ ▎*/
6 ▎ ▎ ▎ puts ("\nTimed out waiting for command\n");
7 # ifdef CONFIG_RESET_TO_RETRY
8 ▎ ▎ ▎ /* Reinit board to run initialization code again */
9 ▎ ▎ ▎ do_reset (NULL, 0, 0, NULL);
43 # else
42 ▎ ▎ ▎ return; /* retry autoboot */
41 # endif
40 ▎ ▎ }
39 #endif
38 ▎ ▎
37 ▎ ▎ if (len == -1)
36 ▎ ▎ ▎ puts ("<INTERRUPT>\n");
35 ▎ ▎ else
E 34 ▎ ▎ ▎ rc = run_command(lastcommand, flag); ■ Call to undeclared function 'run_command'; ISO C99 and later do not support implicit function declarations
33 ▎ ▎
32 ▎ ▎ if (rc <= 0) {
31 ▎ ▎ ▎ /* invalid command or not repeatable, forget it */
30 ▎ ▎ ▎ lastcommand[0] = 0;
29 ▎ ▎ }
28 ▎ }
27 #endif /*CONFIG_SYS_HUSH_PARSER*/
26 }
25
这段代码 表示 所有的命令使用哈希表。
281 #ifndef CONFIG_SYS_HUSH_PARSER
E 1 ▎ static char lastcommand[CONFIG_SYS_CBSIZE] = { 0, }; ■ Use of undeclared identifier 'CONFIG_SYS_CBSIZE'
2 ▎ int len;
3 ▎ int rc = 1;
4 ▎ int flag;
5 #endif
但是我们没有 使能这个宏定义,我们使用的是 顺序查找的方式。
所以这段不用看了。
据这个老师讲 哈希表的方式比顺序查找的方式 更有效率。
这段代码 ,我们定义了, s 指向的是一个 字符串, 而 bootdelay 是一个整数。
36 #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
35 ▎ char *s;
34 ▎ int bootdelay;
33 #endif
直接跳转到这段代码出执行
13 #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
12 ▎ s = getenv ("bootdelay");
11 ▎ bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;
10 ▎
9 ▎ debug ("### main_loop entered: bootdelay=%d\n\n", bootdelay);
getenv ("bootdelay"); 这句没有 找到 getenv 的定义
bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY; 这句中,是在将 字符串 转换为数字。它的函数是 首先看一下 能不能从环境变量中 拿到 bootdelya , 如果能拿到的话,就开始转换成数字, 如果拿不到的话,就使用宏定义的值。
看一下 函数 simple_strtol 的代码
94 long simple_strtol(const char *cp,char **endp,unsigned int base)
1 {
2 ▎ if(*cp=='-')
3 ▎ ▎ return -simple_strtoul(cp+1,endp,base);
4 ▎ return simple_strtoul(cp,endp,base);
5 }
我们肯定是执行 if 之外的代码。
在看一下 函数 simple_strtout函数
19 unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
18 {
17 ▎ unsigned long result = 0,value;
16 ▎
15 ▎ if (*cp == '0') {
14 ▎ ▎ cp++;
E 13 ▎ ▎ if ((*cp == 'x') && isxdigit(cp[1])) { ■ Call to undeclared library function 'isxdigit' with type 'int (int)';
12 ▎ ▎ ▎ base = 16;
11 ▎ ▎ ▎ cp++;
10 ▎ ▎ }
9 ▎ ▎ if (!base) {
8 ▎ ▎ ▎ base = 8;
7 ▎ ▎ }
6 ▎ }
5 ▎ if (!base) {
4 ▎ ▎ base = 10;
3 ▎ }
E 2 ▎ while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp) ■■ Call to undeclared library function 'isl
E 1 ▎ ▎ ? toupper(*cp) : *cp)-'A'+10) < base) { ■ Call to undeclared library function 'toupper' with type 'int (int)'; 62 ▎ ▎ result = result*base + value;
1 ▎ ▎ cp++; 2 ▎ }
3 ▎ if (endp) 4 ▎ ▎ *endp = (char *)cp;
5 ▎ return result; 6 }
首先将 base 设置成了 0
然后就是这段代码
E 2 ▎ while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp) ■■ Call to undeclared library function 'isl
E 1 ▎ ▎ ? toupper(*cp) : *cp)-'A'+10) < base) { ■ Call to undeclared library function 'toupper' with type 'int (int)'; 62 ▎ ▎ result = result*base + value;
1 ▎ ▎ cp++; 2 ▎ }
我整理了一下。
isxdigit 判断是不是16进制数, isdigit 判断是不是 10 进制数, 具体实现我不管。
后面难看懂的地方我 整理了一下。
while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp) ? toupper(*cp) : *cp)-'A'+10) < base)
这一通下来 ,实际上我是得到了一个10 以内的 整数。
然后关键的是这一句。 result = result*base + value;
这是 从最大的数 往 最小的数 在遍历。
每往后挪一位 ,前面的数字要 乘以 10
然后最后 返回一个整数 。
这部分分析完了,
接下来 继续往下分析代码。
代码如下:
s = getenv ("bootcmd");
35 ▎
34 ▎ debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>");
33 ▎
32 ▎ if (bootdelay != -1 && s && !abortboot(bootdelay)) {
31 # ifdef CONFIG_AUTOBOOT_KEYED
30 ▎ ▎ int prev = disable_ctrlc(1); /* disable Control C checking */
29 # endif
28 ▎ ▎
27 ▎ ▎ run_command_list(s, -1, 0);
26 ▎ ▎
25 # ifdef CONFIG_AUTOBOOT_KEYED
24 ▎ ▎ disable_ctrlc(prev); /* restore Control C checking */
23 # endif
22 ▎ }
21 ▎
20 # ifdef CONFIG_MENUKEY
19 ▎ if (menukey == CONFIG_MENUKEY) {
18 ▎ ▎ s = getenv("menucmd");
17 ▎ ▎ if (s)
16 ▎ ▎ ▎ run_command_list(s, -1, 0);
15 ▎ }
14 #endif /* CONFIG_MENUKEY */
13 #endif /* CONFIG_BOOTDELAY */
12 ▎
11 ▎ /*
10 ▎ ▎* Main Loop for Monitor Command Processing
9 ▎ ▎*/
8 #ifdef CONFIG_SYS_HUSH_PARSER
7 ▎ parse_file_outer();
6 ▎ /* This point is never reached */
5 ▎ for (;;);
4 #else
3 ▎ for (;;) {
2 #ifdef CONFIG_BOOT_RETRY_TIME
1 ▎ ▎ if (rc >= 0) {
418 ▎ ▎ ▎ /* Saw enough of a valid command to
1 ▎ ▎ ▎ ▎* restart the timeout.
2 ▎ ▎ ▎ ▎*/
3 ▎ ▎ ▎ reset_cmd_timeout();
4 ▎ ▎ }
5 #endif
len = readline (CONFIG_SYS_PROMPT); ■■ Use of undeclared identifier 'CONFIG_SYS_PROMPT'
41 ▎ ▎
40 ▎ ▎ flag = 0; /* assume no special flags for now */
39 ▎ ▎ if (len > 0)
E 38 ▎ ▎ ▎ strcpy (lastcommand, console_buffer); ■ Call to undeclared library function 'strcpy' with type 'char *(char *, const char *)'; ISO C99 and later do not s
37 ▎ ▎ else if (len == 0)
E 36 ▎ ▎ ▎ flag |= CMD_FLAG_REPEAT; ■ Use of undeclared identifier 'CMD_FLAG_REPEAT'
35 #ifdef CONFIG_BOOT_RETRY_TIME
34 ▎ ▎ else if (len == -2) {
33 ▎ ▎ ▎ /* -2 means timed out, retry autoboot
32 ▎ ▎ ▎ ▎*/
31 ▎ ▎ ▎ puts ("\nTimed out waiting for command\n");
30 # ifdef CONFIG_RESET_TO_RETRY
29 ▎ ▎ ▎ /* Reinit board to run initialization code again */
28 ▎ ▎ ▎ do_reset (NULL, 0, 0, NULL);
27 # else
26 ▎ ▎ ▎ return; /* retry autoboot */
25 # endif
24 ▎ ▎ }
23 #endif
22 ▎ ▎
21 ▎ ▎ if (len == -1)
20 ▎ ▎ ▎ puts ("<INTERRUPT>\n");
19 ▎ ▎ else
E 18 ▎ ▎ ▎ rc = run_command(lastcommand, flag); ■ Call to undeclared function 'run_command'; ISO C99 and later do not support implicit function declarations
17 ▎ ▎
16 ▎ ▎ if (rc <= 0) {
15 ▎ ▎ ▎ /* invalid command or not repeatable, forget it */
14 ▎ ▎ ▎ lastcommand[0] = 0;
13 ▎ ▎ }
12 ▎ }
11 #endif /*CONFIG_SYS_HUSH_PARSER*/
10 }
来看一下 这段代码:
30 ▎ ▎ s = getenv ("bootcmd");
29 ▎
28 ▎ debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>");
27 ▎
26 ▎ if (bootdelay != -1 && s && !abortboot(bootdelay)) {
25 # ifdef CONFIG_AUTOBOOT_KEYED
24 ▎ ▎ int prev = disable_ctrlc(1); /* disable Control C checking */
23 # endif
22 ▎ ▎
21 ▎ ▎ run_command_list(s, -1, 0);
20 ▎ ▎
19 # ifdef CONFIG_AUTOBOOT_KEYED
18 ▎ ▎ disable_ctrlc(prev); /* restore Control C checking */
17 # endif
16 ▎ }
这段的含义是, 如果说 在规定的时间内,没有按下键盘,那么就执行了 if 里面的内容。
接下来一句一句的分析。
s = getenv ("bootcmd"); 这句得到了 bootcmd 的值,并且保存到了 s 中。
我们来看一下 bootcmd 是什么。
文件位置:common/env_common.c
那么 BOOTCOMMAND 又是什么呢?
文件位置: include/configs/s5p_goni.h
可以看到是 run ubifastboot .
接下来分析这段代码 :if (bootdelay != -1 && s && !abortboot(bootdelay))
S是有值的, bootdelay != -1 这句我不用管。
!abortboot(bootdelay) 这句的意思是 ,如果倒计时到 0 , 那么就返回0 , 那么
if 条件成立, 执行, if 的内容。
接下里看一下 abortboot() 函数。
代码如下:
42 #ifndef CONFIG_MENU
41 static inline
40 #endif
39 int abortboot(int bootdelay)
38 {
37 ▎ int abort = 0;
36 ▎
35 #ifdef CONFIG_MENUPROMPT
34 ▎ printf(CONFIG_MENUPROMPT);
33 #else
32 ▎ if (bootdelay >= 0)
31 ▎ ▎ printf("Hit any key to stop autoboot: %2d ", bootdelay);
30 #endif
29 ▎
28 #if defined CONFIG_ZERO_BOOTDELAY_CHECK
27 ▎ /*
26 ▎ ▎* Check if key already pressed
25 ▎ ▎* Don't check if bootdelay < 0
24 ▎ ▎*/
23 ▎ if (bootdelay >= 0) {
22 ▎ ▎ if (tstc()) { /* we got a key press */
21 ▎ ▎ ▎ (void) getc(); /* consume input */
20 ▎ ▎ ▎ puts ("\b\b\b 0");
19 ▎ ▎ ▎ abort = 1; /* don't auto boot */
18 ▎ ▎ }
17 ▎ }
16 #endif
15 ▎
14 ▎ while ((bootdelay > 0) && (!abort)) {
13 ▎ ▎ int i;
12 ▎ ▎
11 ▎ ▎ --bootdelay;
10 ▎ ▎ /* delay 100 * 10ms */
9 ▎ ▎ for (i=0; !abort && i<100; ++i) {
8 ▎ ▎ ▎ if (tstc()) { /* we got a key press */
7 ▎ ▎ ▎ ▎ abort = 1; /* don't auto boot */
6 ▎ ▎ ▎ ▎ bootdelay = 0; /* no more delay */
5 # ifdef CONFIG_MENUKEY
4 ▎ ▎ ▎ ▎ menukey = getc();
3 # else
2 ▎ ▎ ▎ ▎ (void) getc(); /* consume input */
1 # endif
257 ▎ ▎ ▎ ▎ break;
1 ▎ ▎ ▎ }
2 ▎ ▎ ▎ udelay(10000);
3 ▎ ▎ }
4 ▎ ▎
5 ▎ ▎ printf("\b\b\b%2d ", bootdelay);
6 ▎ }
7 ▎
8 ▎ putc('\n');
16 #ifdef CONFIG_SILENT_CONSOLE
15 ▎ if (abort)
14 ▎ ▎ gd->flags &= ~GD_FLG_SILENT;
13 #endif
12 ▎
11 ▎ return abort;
10 }
9 # endif /* CONFIG_AUTOBOOT_KEYED */
8 #endif /* CONFIG_BOOTDELAY >= 0 */
接下来分析这段代码:
14 ▎ while ((bootdelay > 0) && (!abort)) {
13 ▎ ▎ int i;
12 ▎ ▎
11 ▎ ▎ --bootdelay;
10 ▎ ▎ /* delay 100 * 10ms */
9 ▎ ▎ for (i=0; !abort && i<100; ++i) {
8 ▎ ▎ ▎ if (tstc()) { /* we got a key press */
7 ▎ ▎ ▎ ▎ abort = 1; /* don't auto boot */
6 ▎ ▎ ▎ ▎ bootdelay = 0; /* no more delay */
5 # ifdef CONFIG_MENUKEY
4 ▎ ▎ ▎ ▎ menukey = getc();
3 # else
2 ▎ ▎ ▎ ▎ (void) getc(); /* consume input */
1 # endif
257 ▎ ▎ ▎ ▎ break;
1 ▎ ▎ ▎ }
2 ▎ ▎ ▎ udelay(10000);
3 ▎ ▎ }
4 ▎ ▎
5 ▎ ▎ printf("\b\b\b%2d ", bootdelay);
6 ▎ }
while ((bootdelay > 0) && (!abort)) 这句中 bootdelay 大于0 , abort 是0 , 所以执行 while
这个for 循环的代码如下:
10 ▎ ▎ /* delay 100 * 10ms */
9 ▎ ▎ for (i=0; !abort && i<100; ++i) {
8 ▎ ▎ ▎ if (tstc()) { /* we got a key press */
7 ▎ ▎ ▎ ▎ abort = 1; /* don't auto boot */
6 ▎ ▎ ▎ ▎ bootdelay = 0; /* no more delay */
5 # ifdef CONFIG_MENUKEY
4 ▎ ▎ ▎ ▎ menukey = getc();
3 # else
2 ▎ ▎ ▎ ▎ (void) getc(); /* consume input */
1 # endif
257 ▎ ▎ ▎ ▎ break;
1 ▎ ▎ ▎ }
2 ▎ ▎ ▎ udelay(10000);
3 ▎ ▎ }
也就是说,他假定 ,执行命令是不花时间的, 没存循环的时间 是 udelay 在起作用,并且他不是一直 循环遍历, 而是没10ms 遍历一次。
来看一下 tstc() 函数的实现。
20 int tstc(void)
19 {
18 #ifdef CONFIG_DISABLE_CONSOLE
17 ▎ if (gd->flags & GD_FLG_DISABLE_CONSOLE)
16 ▎ ▎ return 0;
15 #endif
14 ▎
13 ▎ if (!gd->have_console)
12 ▎ ▎ return 0;
11 ▎
10 ▎ if (gd->flags & GD_FLG_DEVINIT) {
9 ▎ ▎ /* Test the standard input */
8 ▎ ▎ return ftstc(stdin);
7 ▎ }
6 ▎
5 ▎ /* Send directly to the handler */
4 ▎ return serial_tstc();
3 }
只会 执行下面的代码,
10 ▎ if (gd->flags & GD_FLG_DEVINIT) {
9 ▎ ▎ /* Test the standard input */
8 ▎ ▎ return ftstc(stdin);
7 ▎ }
也就是执行 ftstc(stdin)
来看一下 代码
7 int ftstc(int file)
6 {
5 ▎ if (file < MAX_FILES)
4 ▎ ▎ return console_tstc(file);
3 ▎
2 ▎ return -1;
1 }
那么也就是会执行, console_tstc(file)
176 static inline int console_tstc(int file)
1 {
2 ▎ return stdio_devices[file]->tstc();
3 }
可以看到 , 这里 的file 只是一个数字, 最终反映到 stdio_devices[file] 中第几个结构体。
我们知道 , 所有的结构体都是指向 serial0 的。
也就是调用的 serial0 的 tstc() 函数。
那么看一下 这个函数。
最终会调用 serail_tstc_dev 函数。
8 /*
7 ▎* Test whether a character is in the RX buffer
6 ▎*/
5 int serial_tstc_dev(const int dev_index)
4 {
3 ▎ struct s5p_uart *const uart = s5p_get_base_uart(dev_index);
2 ▎
1 ▎ return (int)(readl(&uart->utrstat) & 0x1);
169 }
也就是 最终会使用 (int)(readl(&uart->utrstat) & 0x1); 函数查看 是不是 1 。
readl 函数的代码如下:
18 /*
17 ▎* TODO: The kernel offers some more advanced versions of barriers, it might
16 ▎* have some advantages to use them instead of the simple one here.
15 ▎*/
14 #define dmb() __asm__ __volatile__ ("" : : : "memory")
13 #define __iormb() dmb()
12 #define __iowmb() dmb()
11
10 #define writeb(v,c) ({ u8 __v = v; __iowmb(); __arch_putb(__v,c); __v; })
9 #define writew(v,c) ({ u16 __v = v; __iowmb(); __arch_putw(__v,c); __v; })
8 #define writel(v,c) ({ u32 __v = v; __iowmb(); __arch_putl(__v,c); __v; })
7
6 #define readb(c) ({ u8 __v = __arch_getb(c); __iormb(); __v; })
5 #define readw(c) ({ u16 __v = __arch_getw(c); __iormb(); __v; })
4 #define readl(c) ({ u32 __v = __arch_getl(c); __iormb(); __v; })
2 #define __arch_getb(a) (*(volatile unsigned char *)(a))
1 #define __arch_getw(a) (*(volatile unsigned short *)(a))
72 #define __arch_getl(a) (*(volatile unsigned int *)(a))
1 ▎
2 #define __arch_putb(v,a) (*(volatile unsigned char *)(a) = (v))
3 #define __arch_putw(v,a) (*(volatile unsigned short *)(a) = (v))
4 #define __arch_putl(v,a) (*(volatile unsigned int *)(a) = (v))
readl 最后的实现 就是 根据地址 去 内存中找 值。
&uart->utrstat 这句就是 Uart寄存器中 state 寄存器的地址。
也就是看看这一位 有没有置 1 .
如果置1 , 说明 有了 信息的传输。
看一下 这个寄存器。
可以看到 第0 位 就是管 接收的。
如果是 有按键按下的话,那么 就进入的 if 内。
就执行这一段。
7 ▎ ▎ ▎ ▎ abort = 1; /* don't auto boot */
6 ▎ ▎ ▎ ▎ bootdelay = 0; /* no more delay */
5 # ifdef CONFIG_MENUKEY
4 ▎ ▎ ▎ ▎ menukey = getc();
3 # else
2 ▎ ▎ ▎ ▎ (void) getc(); /* consume input */
1 # endif
257 ▎ ▎ ▎ ▎ break;
分析一下 getc() 函数。
12 int getc(void)
11 {
10 #ifdef CONFIG_DISABLE_CONSOLE
9 ▎ if (gd->flags & GD_FLG_DISABLE_CONSOLE)
8 ▎ ▎ return 0;
7 #endif
6 ▎
5 ▎ if (!gd->have_console)
4 ▎ ▎ return 0;
3 ▎
2 ▎ if (gd->flags & GD_FLG_DEVINIT) {
1 ▎ ▎ /* Get from the standard input */
306 ▎ ▎ return fgetc(stdin);
1 ▎ }
2 ▎
3 ▎ /* Send directly to the handler */
4 ▎ return serial_getc();
5 }
这个函数 最终 会执行 fgetc(stdin);
然后进入 到 serial_fgetc_dev 函数
5 /*
4 ▎* Read a single byte from the serial port. Returns 1 on success, 0
3 ▎* otherwise. When the function is succesfull, the character read is
2 ▎* written into its argument c.
1 ▎*/
128 int serial_getc_dev(const int dev_index)
1 {
2 ▎ struct s5p_uart *const uart = s5p_get_base_uart(dev_index);
3 ▎
4 ▎ /* wait for character to arrive */ 5 ▎ while (!(readl(&uart->utrstat) & 0x1)) {
6 ▎ ▎ if (serial_err_check(dev_index, 0))
7 ▎ ▎ ▎ return 0;
8 ▎ }
9 ▎
10 ▎ return (int)(readb(&uart->urxh) & 0xff);
11 }
这句中 (int)(readb(&uart->urxh) & 0xff) , uart->urxh 代表的是接收寄存器。
就是这个。
如果他 拿到了一个值, 会将这个值 返回去。
但是这里显示 他什么也没做,直接退出循环了。
总结:也就是说,如果有 键盘上的任意按键 按下的话,我就跳出 倒计时的循环了。
执行的是下面的代码。
25 ▎ for (;;) {
24 #ifdef CONFIG_BOOT_RETRY_TIME
23 ▎ ▎ if (rc >= 0) {
22 ▎ ▎ ▎ /* Saw enough of a valid command to
21 ▎ ▎ ▎ ▎* restart the timeout.
20 ▎ ▎ ▎ ▎*/
19 ▎ ▎ ▎ reset_cmd_timeout();
18 ▎ ▎ }
17 #endif
E 16 ▎ ▎ len = readline (CONFIG_SYS_PROMPT); ■■ Use of undeclared identifier 'CONFIG_SYS_PROMPT'
15 ▎ ▎
14 ▎ ▎ flag = 0; /* assume no special flags for now */
13 ▎ ▎ if (len > 0)
E 12 ▎ ▎ ▎ strcpy (lastcommand, console_buffer); ■ Call to undeclared library function 'strcpy' with type 'char *(char *, const char *)'; ISO C99 and later do not s
11 ▎ ▎ else if (len == 0)
E 10 ▎ ▎ ▎ flag |= CMD_FLAG_REPEAT; ■ Use of undeclared identifier 'CMD_FLAG_REPEAT'
9 #ifdef CONFIG_BOOT_RETRY_TIME
8 ▎ ▎ else if (len == -2) {
7 ▎ ▎ ▎ /* -2 means timed out, retry autoboot
6 ▎ ▎ ▎ ▎*/
5 ▎ ▎ ▎ puts ("\nTimed out waiting for command\n");
4 # ifdef CONFIG_RESET_TO_RETRY
3 ▎ ▎ ▎ /* Reinit board to run initialization code again */
2 ▎ ▎ ▎ do_reset (NULL, 0, 0, NULL);
1 # else
440 ▎ ▎ ▎ return; /* retry autoboot */
1 # endif
2 ▎ ▎ }
3 #endif
这就是在 等待 用户的输入,然后解析命令,然后执行命令。
我接下来 分析一下 他是怎么解析命令的,
首先是这句代码的分析
len = readline (CONFIG_SYS_PROMPT);
readline 函数如下:
16 /*
15 ▎* Prompt for input and read a line.
14 ▎* If CONFIG_BOOT_RETRY_TIME is defined and retry_time >= 0,
13 ▎* time out when time goes past endtime (timebase time in ticks).
12 ▎* Return: number of read characters
11 ▎* -1 if break
10 ▎* -2 if timed out
9 ▎*/
8 int readline (const char *const prompt)
7 {
6 ▎ /*
5 ▎ ▎* If console_buffer isn't 0-length the user will be prompted to modify
4 ▎ ▎* it instead of entering it from scratch as desired.
3 ▎ ▎*/
2 ▎ console_buffer[0] = '\0';
1 ▎
E 926 ▎ return readline_into_buffer(prompt, console_buffer, 0); ■ Call to undeclared function 'readline_into_buffer'; ISO C99 and later do not support implicit function
1 }
2
它的作用就是 读取你在键盘上输入的一行命令。
然后看一下 readline_into_buffer(prompt, console_buffer, 0); 函数。
42 int readline_into_buffer(const char *const prompt, char *buffer, int timeout)
41 {
40 ▎ char *p = buffer;
39 #ifdef CONFIG_CMDLINE_EDITING
38 ▎ unsigned int len = CONFIG_SYS_CBSIZE;
37 ▎ int rc;
36 ▎ static int initted = 0;
35 ▎
34 ▎ /*
33 ▎ ▎* History uses a global array which is not
32 ▎ ▎* writable until after relocation to RAM.
31 ▎ ▎* Revert to non-history version if still
30 ▎ ▎* running from flash.
29 ▎ ▎*/
28 ▎ if (gd->flags & GD_FLG_RELOC) {
27 ▎ ▎ if (!initted) {
26 ▎ ▎ ▎ hist_init();
25 ▎ ▎ ▎ initted = 1;
24 ▎ ▎ }
23 ▎ ▎
22 ▎ ▎ if (prompt)
21 ▎ ▎ ▎ puts (prompt);
20 ▎ ▎
19 ▎ ▎ rc = cread_line(prompt, p, &len, timeout);
18 ▎ ▎ return rc < 0 ? rc : len;
17 ▎ ▎
16 ▎ } else {
15 #endif /* CONFIG_CMDLINE_EDITING */
14 ▎ char * p_buf = p;
13 ▎ int n = 0; /* buffer index */
12 ▎ int plen = 0; /* prompt length */
11 ▎ int col; /* output column cnt */
10 ▎ char c;
9 ▎
8 ▎ /* print prompt */
7 ▎ if (prompt) {
E 6 ▎ ▎ plen = strlen (prompt); ■ Call to undeclared library function 'strlen' with type 'unsigned long (const char *)'; ISO C99 and later do not support implicit fu
5 ▎ ▎ puts (prompt);
4 ▎ }
3 ▎ col = plen;
2 ▎
43 ▎ for (;;) {
42 #ifdef CONFIG_BOOT_RETRY_TIME
41 ▎ ▎ while (!tstc()) { /* while no incoming data */
40 ▎ ▎ ▎ if (retry_time >= 0 && get_ticks() > endtime)
39 ▎ ▎ ▎ ▎ return (-2); /* timed out */
38 ▎ ▎ ▎ WATCHDOG_RESET();
37 ▎ ▎ }
36 #endif
E 35 ▎ ▎ WATCHDOG_RESET(); /* Trigger watchdog, if needed */ ■ Call to undeclared function 'WATCHDOG_RESET'; ISO C99 and later do not support implicit function
34 ▎ ▎
33 #ifdef CONFIG_SHOW_ACTIVITY
32 ▎ ▎ while (!tstc()) {
31 ▎ ▎ ▎ show_activity(0);
30 ▎ ▎ ▎ WATCHDOG_RESET();
29 ▎ ▎ }
28 #endif
E 27 ▎ ▎ c = getc(); ■ Too few arguments to function call, single argument '__stream' was not specified
26 ▎ ▎
25 ▎ ▎ /*
24 ▎ ▎ ▎* Special character handling
23 ▎ ▎ ▎*/
22 ▎ ▎ switch (c) {
21 ▎ ▎ case '\r': /* Enter */
20 ▎ ▎ case '\n':
19 ▎ ▎ ▎ *p = '\0';
18 ▎ ▎ ▎ puts ("\r\n");
17 ▎ ▎ ▎ return (p - p_buf);
16 ▎ ▎ ▎
15 ▎ ▎ case '\0': /* nul */
14 ▎ ▎ ▎ continue;
13 ▎ ▎ ▎
12 ▎ ▎ case 0x03: /* ^C - break */
11 ▎ ▎ ▎ p_buf[0] = '\0'; /* discard input */
10 ▎ ▎ ▎ return (-1);
9 ▎ ▎ ▎
8 ▎ ▎ case 0x15: /* ^U - erase line */
7 ▎ ▎ ▎ while (col > plen) {
6 ▎ ▎ ▎ ▎ puts (erase_seq);
5 ▎ ▎ ▎ ▎ --col;
4 ▎ ▎ ▎ }
3 ▎ ▎ ▎ p = p_buf;
2 ▎ ▎ ▎ n = 0;
1 ▎ ▎ ▎ continue;
1014 ▎ ▎ ▎
1 ▎ ▎ case 0x17: /* ^W - erase word */
2 ▎ ▎ ▎ p=delete_char(p_buf, p, &col, &n, plen);
3 ▎ ▎ ▎ while ((n > 0) && (*p != ' ')) {
4 ▎ ▎ ▎ ▎ p=delete_char(p_buf, p, &col, &n, plen);
5 ▎ ▎ ▎ }
6 ▎ ▎ ▎ continue;
7 ▎ ▎ ▎
8 ▎ ▎ case 0x08: /* ^H - backspace */
9 ▎ ▎ case 0x7F: /* DEL - backspace */
39 ▎ ▎ ▎ p=delete_char(p_buf, p, &col, &n, plen);
38 ▎ ▎ ▎ continue;
37 ▎ ▎
36 ▎ ▎ default:
35 ▎ ▎ ▎ /*
34 ▎ ▎ ▎ ▎* Must be a normal character then
33 ▎ ▎ ▎ ▎*/
E 32 ▎ ▎ ▎ if (n < CONFIG_SYS_CBSIZE-2) { ■ Use of undeclared identifier 'CONFIG_SYS_CBSIZE'
31 ▎ ▎ ▎ ▎ if (c == '\t') { /* expand TABs */
30 #ifdef CONFIG_AUTO_COMPLETE
29 ▎ ▎ ▎ ▎ ▎ /* if auto completion triggered just continue */
28 ▎ ▎ ▎ ▎ ▎ *p = '\0';
27 ▎ ▎ ▎ ▎ ▎ if (cmd_auto_complete(prompt, console_buffer, &n, &col)) {
26 ▎ ▎ ▎ ▎ ▎ ▎ p = p_buf + n; /* reset */
25 ▎ ▎ ▎ ▎ ▎ ▎ continue;
24 ▎ ▎ ▎ ▎ ▎ }
23 #endif
22 ▎ ▎ ▎ ▎ ▎ puts (tab_seq+(col&07));
21 ▎ ▎ ▎ ▎ ▎ col += 8 - (col&07);
20 ▎ ▎ ▎ ▎ } else {
19 ▎ ▎ ▎ ▎ ▎ ++col; /* echo input */
E 18 ▎ ▎ ▎ ▎ ▎ putc (c); ■ Too few arguments to function call, expected 2, have 1
17 ▎ ▎ ▎ ▎ }
16 ▎ ▎ ▎ ▎ *p++ = c;
15 ▎ ▎ ▎ ▎ ++n;
14 ▎ ▎ ▎ } else { /* Buffer full */
E 13 ▎ ▎ ▎ ▎ putc ('\a'); ■ Too few arguments to function call, expected 2, have 1
12 ▎ ▎ ▎ }
11 ▎ ▎ }
10 ▎ }
9 #ifdef CONFIG_CMDLINE_EDITING
8 ▎ }
7 #endif
6 }
我们有定义
CONFIG_CMDLINE_EDITING
这个宏定义 可以 通过键盘 翻看 历史命令,相当于 windows 的 上下键。
所以只会执行这一段代码
30 ▎ unsigned int len = CONFIG_SYS_CBSIZE;
29 ▎ int rc;
28 ▎ static int initted = 0;
27 ▎
26 ▎ /*
25 ▎ ▎* History uses a global array which is not
24 ▎ ▎* writable until after relocation to RAM.
23 ▎ ▎* Revert to non-history version if still
22 ▎ ▎* running from flash.
21 ▎ ▎*/
20 ▎ if (gd->flags & GD_FLG_RELOC) {
19 ▎ ▎ if (!initted) {
18 ▎ ▎ ▎ hist_init();
17 ▎ ▎ ▎ initted = 1;
16 ▎ ▎ }
15 ▎ ▎
14 ▎ ▎ if (prompt)
13 ▎ ▎ ▎ puts (prompt);
12 ▎ ▎
11 ▎ ▎ rc = cread_line(prompt, p, &len, timeout);
10 ▎ ▎ return rc < 0 ? rc : len;
9 ▎ ▎
unsigned int len = CONFIG_SYS_CBSIZE; 这句定义了最大的字符数量,就是 256 .
由于 gd->flags & GD_FLG_RELOC 有值。所以执行下面的代码
20 ▎ if (gd->flags & GD_FLG_RELOC) {
19 ▎ ▎ if (!initted) {
18 ▎ ▎ ▎ hist_init();
17 ▎ ▎ ▎ initted = 1;
16 ▎ ▎ }
hist_init() 代码如下, 这是在初始化,历史命令的设置。
24 char* hist_list[HIST_MAX];
23 char hist_lines[HIST_MAX][HIST_SIZE + 1]; /* Save room for NULL */
22
21 #define add_idx_minus_one() ((hist_add_idx == 0) ? hist_max : hist_add_idx-1)
20
19 static void hist_init(void)
18 {
17 ▎ int i;
16 ▎
15 ▎ hist_max = 0;
14 ▎ hist_add_idx = 0;
13 ▎ hist_cur = -1;
12 ▎ hist_num = 0;
11 ▎
10 ▎ for (i = 0; i < HIST_MAX; i++) {
9 ▎ ▎ hist_list[i] = hist_lines[i];
8 ▎ ▎ hist_list[i][0] = '\0';
7 ▎ }
6 }
相当于 将二维数组的每一行都初始化为0 。
疑问: 但他为什么用两个数组呢? 一个不就行了。
这句代码 打印出了 提示符。
3 ▎ ▎ if (prompt)
2 ▎ ▎ ▎ puts (prompt);
接下来分析 这段代码 ,
▎ rc = cread_line(prompt, p, &len, timeout);
代码如下:
38 static int cread_line(const char *const prompt, char *buf, unsigned int *len,
37 ▎ ▎ int timeout)
36 {
35 ▎ unsigned long num = 0;
34 ▎ unsigned long eol_num = 0;
33 ▎ unsigned long wlen;
32 ▎ char ichar;
31 ▎ int insert = 1;
30 ▎ int esc_len = 0;
29 ▎ char esc_save[8];
28 ▎ int init_len = strlen(buf);
27 ▎ int first = 1;
26 ▎
25 ▎ if (init_len)
24 ▎ ▎ cread_add_str(buf, init_len, 1, &num, &eol_num, buf, *len);
23 ▎
22 ▎ while (1) {
21 #ifdef CONFIG_BOOT_RETRY_TIME
20 ▎ ▎ while (!tstc()) { /* while no incoming data */
19 ▎ ▎ ▎ if (retry_time >= 0 && get_ticks() > endtime)
18 ▎ ▎ ▎ ▎ return (-2); /* timed out */
17 ▎ ▎ ▎ WATCHDOG_RESET();
16 ▎ ▎ }
15 #endif
14 ▎ ▎ if (first && timeout) {
13 ▎ ▎ ▎ uint64_t etime = endtick(timeout);
12 ▎ ▎ ▎
11 ▎ ▎ ▎ while (!tstc()) { /* while no incoming data */
10 ▎ ▎ ▎ ▎ if (get_ticks() >= etime)
9 ▎ ▎ ▎ ▎ ▎ return -2; /* timed out */
8 ▎ ▎ ▎ ▎ WATCHDOG_RESET();
7 ▎ ▎ ▎ }
6 ▎ ▎ ▎ first = 0;
5 ▎ ▎ }
4 ▎ ▎
3 ▎ ▎ ichar = getcmd_getch();
2 ▎ ▎
1 ▎ ▎ if ((ichar == '\n') || (ichar == '\r')) {
715 ▎ ▎ ▎ putc('\n');
1 ▎ ▎ ▎ break;
2 ▎ ▎ }
▎
43 ▎ ▎ /*
42 ▎ ▎ ▎* handle standard linux xterm esc sequences for arrow key, etc.
41 ▎ ▎ ▎*/
40 ▎ ▎ if (esc_len != 0) {
39 ▎ ▎ ▎ if (esc_len == 1) {
38 ▎ ▎ ▎ ▎ if (ichar == '[') {
37 ▎ ▎ ▎ ▎ ▎ esc_save[esc_len] = ichar;
36 ▎ ▎ ▎ ▎ ▎ esc_len = 2;
35 ▎ ▎ ▎ ▎ } else {
34 ▎ ▎ ▎ ▎ ▎ cread_add_str(esc_save, esc_len, insert,
33 ▎ ▎ ▎ ▎ ▎ ▎ &num, &eol_num, buf, *len);
32 ▎ ▎ ▎ ▎ ▎ esc_len = 0;
31 ▎ ▎ ▎ ▎ }
30 ▎ ▎ ▎ ▎ continue;
29 ▎ ▎ ▎ }
28 ▎ ▎ ▎
27 ▎ ▎ ▎ switch (ichar) {
26 ▎ ▎ ▎
25 ▎ ▎ ▎ case 'D': /* <- key */
24 ▎ ▎ ▎ ▎ ichar = CTL_CH('b');
23 ▎ ▎ ▎ ▎ esc_len = 0;
22 ▎ ▎ ▎ ▎ break;
21 ▎ ▎ ▎ case 'C': /* -> key */
20 ▎ ▎ ▎ ▎ ichar = CTL_CH('f');
19 ▎ ▎ ▎ ▎ esc_len = 0;
18 ▎ ▎ ▎ ▎ break; /* pass off to ^F handler */
17 ▎ ▎ ▎ case 'H': /* Home key */
16 ▎ ▎ ▎ ▎ ichar = CTL_CH('a');
15 ▎ ▎ ▎ ▎ esc_len = 0;
14 ▎ ▎ ▎ ▎ break; /* pass off to ^A handler */
13 ▎ ▎ ▎ case 'A': /* up arrow */
12 ▎ ▎ ▎ ▎ ichar = CTL_CH('p');
11 ▎ ▎ ▎ ▎ esc_len = 0;
10 ▎ ▎ ▎ ▎ break; /* pass off to ^P handler */
9 ▎ ▎ ▎ case 'B': /* down arrow */
8 ▎ ▎ ▎ ▎ ichar = CTL_CH('n');
7 ▎ ▎ ▎ ▎ esc_len = 0;
6 ▎ ▎ ▎ ▎ break; /* pass off to ^N handler */
5 ▎ ▎ ▎ default:
4 ▎ ▎ ▎ ▎ esc_save[esc_len++] = ichar;
3 ▎ ▎ ▎ ▎ cread_add_str(esc_save, esc_len, insert,
2 ▎ ▎ ▎ ▎ ▎ &num, &eol_num, buf, *len);
1 ▎ ▎ ▎ ▎ esc_len = 0;
762 ▎ ▎ ▎ ▎ continue;
1 ▎ ▎ ▎ }
2 ▎ ▎ }
switch (ichar) {
43 ▎ ▎ case 0x1b:
42 ▎ ▎ ▎ if (esc_len == 0) {
41 ▎ ▎ ▎ ▎ esc_save[esc_len] = ichar;
40 ▎ ▎ ▎ ▎ esc_len = 1;
39 ▎ ▎ ▎ } else {
38 ▎ ▎ ▎ ▎ puts("impossible condition #876\n");
37 ▎ ▎ ▎ ▎ esc_len = 0;
36 ▎ ▎ ▎ }
35 ▎ ▎ ▎ break;
34 ▎ ▎ ▎
33 ▎ ▎ case CTL_CH('a'):
32 ▎ ▎ ▎ BEGINNING_OF_LINE();
31 ▎ ▎ ▎ break;
30 ▎ ▎ case CTL_CH('c'): /* ^C - break */
29 ▎ ▎ ▎ *buf = '\0'; /* discard input */
28 ▎ ▎ ▎ return (-1);
27 ▎ ▎ case CTL_CH('f'):
26 ▎ ▎ ▎ if (num < eol_num) {
25 ▎ ▎ ▎ ▎ getcmd_putch(buf[num]);
24 ▎ ▎ ▎ ▎ num++;
23 ▎ ▎ ▎ }
22 ▎ ▎ ▎ break;
21 ▎ ▎ case CTL_CH('b'):
20 ▎ ▎ ▎ if (num) {
19 ▎ ▎ ▎ ▎ getcmd_putch(CTL_BACKSPACE);
18 ▎ ▎ ▎ ▎ num--;
17 ▎ ▎ ▎ }
16 ▎ ▎ ▎ break;
15 ▎ ▎ case CTL_CH('d'):
14 ▎ ▎ ▎ if (num < eol_num) {
13 ▎ ▎ ▎ ▎ wlen = eol_num - num - 1;
12 ▎ ▎ ▎ ▎ if (wlen) {
11 ▎ ▎ ▎ ▎ ▎ memmove(&buf[num], &buf[num+1], wlen);
10 ▎ ▎ ▎ ▎ ▎ putnstr(buf + num, wlen);
9 ▎ ▎ ▎ ▎ }
8 ▎ ▎ ▎ ▎
7 ▎ ▎ ▎ ▎ getcmd_putch(' ');
6 ▎ ▎ ▎ ▎ do {
5 ▎ ▎ ▎ ▎ ▎ getcmd_putch(CTL_BACKSPACE);
4 ▎ ▎ ▎ ▎ } while (wlen--);
3 ▎ ▎ ▎ ▎ eol_num--;
2 ▎ ▎ ▎ }
1 ▎ ▎ ▎ break;
810 ▎ ▎ case CTL_CH('k'):
1 ▎ ▎ ▎ ERASE_TO_EOL();
2 ▎ ▎ ▎ break;
3 ▎ ▎ case CTL_CH('e'):
4 ▎ ▎ ▎ REFRESH_TO_EOL();
5 ▎ ▎ ▎ break;
6 ▎ ▎ case CTL_CH('o'):
7 ▎ ▎ ▎ insert = !insert;
8 ▎ ▎ ▎ break;
9 ▎ ▎ case CTL_CH('x'):
10 ▎ ▎ case CTL_CH('u'):
▎ BEGINNING_OF_LINE();
39 ▎ ▎ ▎ ERASE_TO_EOL();
38 ▎ ▎ ▎ break;
37 ▎ ▎ case DEL:
36 ▎ ▎ case DEL7:
35 ▎ ▎ case 8:
34 ▎ ▎ ▎ if (num) {
33 ▎ ▎ ▎ ▎ wlen = eol_num - num;
32 ▎ ▎ ▎ ▎ num--;
31 ▎ ▎ ▎ ▎ memmove(&buf[num], &buf[num+1], wlen);
30 ▎ ▎ ▎ ▎ getcmd_putch(CTL_BACKSPACE);
29 ▎ ▎ ▎ ▎ putnstr(buf + num, wlen);
28 ▎ ▎ ▎ ▎ getcmd_putch(' ');
27 ▎ ▎ ▎ ▎ do {
26 ▎ ▎ ▎ ▎ ▎ getcmd_putch(CTL_BACKSPACE);
25 ▎ ▎ ▎ ▎ } while (wlen--);
24 ▎ ▎ ▎ ▎ eol_num--;
23 ▎ ▎ ▎ }
22 ▎ ▎ ▎ break;
21 ▎ ▎ case CTL_CH('p'):
20 ▎ ▎ case CTL_CH('n'):
19 ▎ ▎ {
18 ▎ ▎ ▎ char * hline;
17 ▎ ▎ ▎
16 ▎ ▎ ▎ esc_len = 0;
15 ▎ ▎ ▎
14 ▎ ▎ ▎ if (ichar == CTL_CH('p'))
13 ▎ ▎ ▎ ▎ hline = hist_prev();
12 ▎ ▎ ▎ else
11 ▎ ▎ ▎ ▎ hline = hist_next();
10 ▎ ▎ ▎
9 ▎ ▎ ▎ if (!hline) {
8 ▎ ▎ ▎ ▎ getcmd_cbeep();
7 ▎ ▎ ▎ ▎ continue;
6 ▎ ▎ ▎ }
5 ▎ ▎ ▎
4 ▎ ▎ ▎ /* nuke the current line */
3 ▎ ▎ ▎ /* first, go home */
2 ▎ ▎ ▎ BEGINNING_OF_LINE();
1 ▎ ▎ ▎
861 ▎ ▎ ▎ /* erase to end of line */
1 ▎ ▎ ▎ ERASE_TO_EOL();
2 ▎ ▎ ▎
3 ▎ ▎ ▎ /* copy new line into place and display */
4 ▎ ▎ ▎ strcpy(buf, hline);
5 ▎ ▎ ▎ eol_num = strlen(buf);
6 ▎ ▎ ▎ REFRESH_TO_EOL();
7 ▎ ▎ ▎ continue;
8 ▎ ▎ }
39 #ifdef CONFIG_AUTO_COMPLETE
38 ▎ ▎ case '\t': {
37 ▎ ▎ ▎ int num2, col;
36 ▎ ▎ ▎
35 ▎ ▎ ▎ /* do not autocomplete when in the middle */
34 ▎ ▎ ▎ if (num < eol_num) {
33 ▎ ▎ ▎ ▎ getcmd_cbeep();
32 ▎ ▎ ▎ ▎ break;
31 ▎ ▎ ▎ }
30 ▎ ▎ ▎
29 ▎ ▎ ▎ buf[num] = '\0';
28 ▎ ▎ ▎ col = strlen(prompt) + eol_num;
27 ▎ ▎ ▎ num2 = num;
26 ▎ ▎ ▎ if (cmd_auto_complete(prompt, buf, &num2, &col)) {
25 ▎ ▎ ▎ ▎ col = num2 - num;
24 ▎ ▎ ▎ ▎ num += col;
23 ▎ ▎ ▎ ▎ eol_num += col;
22 ▎ ▎ ▎ }
21 ▎ ▎ ▎ break;
20 ▎ ▎ }
19 #endif
18 ▎ ▎ default:
17 ▎ ▎ ▎ cread_add_char(ichar, insert, &num, &eol_num, buf, *len);
16 ▎ ▎ ▎ break;
15 ▎ ▎ }
14 ▎ }
13 ▎ *len = eol_num;
12 ▎ buf[eol_num] = '\0'; /* lose the newline */
11 ▎
10 ▎ if (buf[0] && buf[0] != CREAD_HIST_CHAR)
9 ▎ ▎ cread_add_to_hist(buf);
8 ▎ hist_cur = hist_add_idx;
7 ▎
6 ▎ return 0;
5 }
4
3 #endif /* CONFIG_CMDLINE_EDITING */
它的逻辑是这样的,如果说我一直输入的是 普通的字符, 那么它会进入这个分支,
3 ▎ ▎ default:
2 ▎ ▎ ▎ cread_add_char(ichar, insert, &num, &eol_num, buf, *len);
1 ▎ ▎ ▎ break;
894 ▎ ▎ }
如果说 我命令输入完了, 按了一下回车 ,他会进入这个分支。
20 ▎ ▎ if ((ichar == '\n') || (ichar == '\r')) {
19 ▎ ▎ ▎ putc('\n');
18 ▎ ▎ ▎ break;
17 ▎ ▎ }
直接退出 while 循环了, 然后执行最后的命令。
15 ▎ *len = eol_num;
14 ▎ buf[eol_num] = '\0'; /* lose the newline */
13 ▎
12 ▎ if (buf[0] && buf[0] != CREAD_HIST_CHAR)
11 ▎ ▎ cread_add_to_hist(buf);
10 ▎ hist_cur = hist_add_idx;
9 ▎
8 ▎ return 0;
这个命令就是 将读取的命令,直接放到了 二位数组中。
好接下来, 开始一句一句的分析。
这句直接跳过, 因为 init_len 是最开始应该是0
33 ▎ if (init_len)
32 ▎ ▎ cread_add_str(buf, init_len, 1, &num, &eol_num, buf, *len);
这个代码应该是 说 有没有 重复执行的命令,不如想 ping -t 3 之类了。
35 #ifdef CONFIG_BOOT_RETRY_TIME
34 ▎ ▎ while (!tstc()) { /* while no incoming data */
33 ▎ ▎ ▎ if (retry_time >= 0 && get_ticks() > endtime)
32 ▎ ▎ ▎ ▎ return (-2); /* timed out */
31 ▎ ▎ ▎ WATCHDOG_RESET();
30 ▎ ▎ }
29 #endif
这段代码 不理解。
33 ▎ ▎ if (first && timeout) {
32 ▎ ▎ ▎ uint64_t etime = endtick(timeout);
31 ▎ ▎ ▎
30 ▎ ▎ ▎ while (!tstc()) { /* while no incoming data */
29 ▎ ▎ ▎ ▎ if (get_ticks() >= etime)
28 ▎ ▎ ▎ ▎ ▎ return -2; /* timed out */
27 ▎ ▎ ▎ ▎ WATCHDOG_RESET();
26 ▎ ▎ ▎ }
25 ▎ ▎ ▎ first = 0;
24 ▎ ▎ }
这个代码 应该就是 去读取 键盘了。
22 ▎ ▎ ichar = getcmd_getch();
这个函数 定义如下;
#define getcmd_getch() getc()
这个getc() 最后应该是 调用的 这个函数。
5 /*
4 ▎* Read a single byte from the serial port. Returns 1 on success, 0
3 ▎* otherwise. When the function is succesfull, the character read is
2 ▎* written into its argument c.
1 ▎*/
128 int serial_getc_dev(const int dev_index)
1 {
2 ▎ struct s5p_uart *const uart = s5p_get_base_uart(dev_index);
3 ▎
4 ▎ /* wait for character to arrive */
5 ▎ while (!(readl(&uart->utrstat) & 0x1)) {
6 ▎ ▎ if (serial_err_check(dev_index, 0))
7 ▎ ▎ ▎ return 0;
8 ▎ }
9 ▎
10 ▎ return (int)(readb(&uart->urxh) & 0xff);
11 }
12
这个是判断是不是 回车
24 ▎ ▎ if ((ichar == '\n') || (ichar == '\r')) {
23 ▎ ▎ ▎ putc('\n');
22 ▎ ▎ ▎ break;
21 ▎ ▎ }
这段代码是在 兼容 xterm ,不懂。
40 ▎ ▎ /*
39 ▎ ▎ ▎* handle standard linux xterm esc sequences for arrow key, etc.
38 ▎ ▎ ▎*/
37 ▎ ▎ if (esc_len != 0) {
36 ▎ ▎ ▎ if (esc_len == 1) {
35 ▎ ▎ ▎ ▎ if (ichar == '[') {
34 ▎ ▎ ▎ ▎ ▎ esc_save[esc_len] = ichar;
33 ▎ ▎ ▎ ▎ ▎ esc_len = 2;
32 ▎ ▎ ▎ ▎ } else {
31 ▎ ▎ ▎ ▎ ▎ cread_add_str(esc_save, esc_len, insert,
30 ▎ ▎ ▎ ▎ ▎ ▎ &num, &eol_num, buf, *len);
29 ▎ ▎ ▎ ▎ ▎ esc_len = 0;
28 ▎ ▎ ▎ ▎ }
27 ▎ ▎ ▎ ▎ continue;
26 ▎ ▎ ▎ }
25 ▎ ▎ ▎
24 ▎ ▎ ▎ switch (ichar) {
23 ▎ ▎ ▎
22 ▎ ▎ ▎ case 'D': /* <- key */
21 ▎ ▎ ▎ ▎ ichar = CTL_CH('b');
20 ▎ ▎ ▎ ▎ esc_len = 0;
19 ▎ ▎ ▎ ▎ break;
18 ▎ ▎ ▎ case 'C': /* -> key */
17 ▎ ▎ ▎ ▎ ichar = CTL_CH('f');
16 ▎ ▎ ▎ ▎ esc_len = 0;
15 ▎ ▎ ▎ ▎ break; /* pass off to ^F handler */
14 ▎ ▎ ▎ case 'H': /* Home key */
13 ▎ ▎ ▎ ▎ ichar = CTL_CH('a');
12 ▎ ▎ ▎ ▎ esc_len = 0;
11 ▎ ▎ ▎ ▎ break; /* pass off to ^A handler */
10 ▎ ▎ ▎ case 'A': /* up arrow */
9 ▎ ▎ ▎ ▎ ichar = CTL_CH('p');
8 ▎ ▎ ▎ ▎ esc_len = 0;
7 ▎ ▎ ▎ ▎ break; /* pass off to ^P handler */
6 ▎ ▎ ▎ case 'B': /* down arrow */
5 ▎ ▎ ▎ ▎ ichar = CTL_CH('n');
4 ▎ ▎ ▎ ▎ esc_len = 0;
3 ▎ ▎ ▎ ▎ break; /* pass off to ^N handler */
2 ▎ ▎ ▎ default:
1 ▎ ▎ ▎ ▎ esc_save[esc_len++] = ichar;
759 ▎ ▎ ▎ ▎ cread_add_str(esc_save, esc_len, insert,
1 ▎ ▎ ▎ ▎ ▎ &num, &eol_num, buf, *len);
2 ▎ ▎ ▎ ▎ esc_len = 0;
3 ▎ ▎ ▎ ▎ continue;
4 ▎ ▎ ▎ }
5 ▎ ▎ }
从这里开始 的一坨,就是 对于 特殊字符的判断。
▎ ▎
41 ▎ ▎ switch (ichar) {
40 ▎ ▎ case 0x1b:
39 ▎ ▎ ▎ if (esc_len == 0) {
38 ▎ ▎ ▎ ▎ esc_save[esc_len] = ichar;
37 ▎ ▎ ▎ ▎ esc_len = 1;
36 ▎ ▎ ▎ } else {
35 ▎ ▎ ▎ ▎ puts("impossible condition #876\n");
34 ▎ ▎ ▎ ▎ esc_len = 0;
33 ▎ ▎ ▎ }
32 ▎ ▎ ▎ break;
31 ▎ ▎
30 ▎ ▎ case CTL_CH('a'):
29 ▎ ▎ ▎ BEGINNING_OF_LINE();
28 ▎ ▎ ▎ break;
27 ▎ ▎ case CTL_CH('c'): /* ^C - break */
26 ▎ ▎ ▎ *buf = '\0'; /* discard input */
25 ▎ ▎ ▎ return (-1);
24 ▎ ▎ case CTL_CH('f'):
23 ▎ ▎ ▎ if (num < eol_num) {
22 ▎ ▎ ▎ ▎ getcmd_putch(buf[num]);
21 ▎ ▎ ▎ ▎ num++;
20 ▎ ▎ ▎ }
19 ▎ ▎ ▎ break;
18 ▎ ▎ case CTL_CH('b'):
17 ▎ ▎ ▎ if (num) {
16 ▎ ▎ ▎ ▎ getcmd_putch(CTL_BACKSPACE);
15 ▎ ▎ ▎ ▎ num--;
14 ▎ ▎ ▎ }
13 ▎ ▎ ▎ break;
感觉这个应该是跟 补全相关的。
30 #ifdef CONFIG_AUTO_COMPLETE
29 ▎ ▎ case '\t': {
28 ▎ ▎ ▎ int num2, col;
27 ▎ ▎ ▎
26 ▎ ▎ ▎ /* do not autocomplete when in the middle */
25 ▎ ▎ ▎ if (num < eol_num) {
24 ▎ ▎ ▎ ▎ getcmd_cbeep();
23 ▎ ▎ ▎ ▎ break;
22 ▎ ▎ ▎ }
21 ▎ ▎ ▎
20 ▎ ▎ ▎ buf[num] = '\0';
19 ▎ ▎ ▎ col = strlen(prompt) + eol_num;
18 ▎ ▎ ▎ num2 = num;
17 ▎ ▎ ▎ if (cmd_auto_complete(prompt, buf, &num2, &col)) {
16 ▎ ▎ ▎ ▎ col = num2 - num;
15 ▎ ▎ ▎ ▎ num += col;
14 ▎ ▎ ▎ ▎ eol_num += col;
13 ▎ ▎ ▎ }
12 ▎ ▎ ▎ break;
11 ▎ ▎ }
10 #endif
接下里分析一下 这个代码
896 ▎ *len = eol_num;
1 ▎ buf[eol_num] = '\0'; /* lose the newline */
2 ▎
3 ▎ if (buf[0] && buf[0] != CREAD_HIST_CHAR)
4 ▎ ▎ cread_add_to_hist(buf);
5 ▎ hist_cur = hist_add_idx;
*len = eol_num; 这句中 eol_num 是在上面的 if 判断中 赋值的。
继续往下分析。
buf[eol_num] = '\0'; 这句添加了 字符串的结束。
这段代码是在操作 存储命令的数组。
1 ▎ if (buf[0] && buf[0] != CREAD_HIST_CHAR)
900 ▎ ▎ cread_add_to_hist(buf);
1 ▎ hist_cur = hist_add_idx;
2 ▎
大致看一下 函数 cread_add_to_hist(buf);
533 static void cread_add_to_hist(char *line)
1 {
2 ▎ strcpy(hist_list[hist_add_idx], line);
3 ▎
4 ▎ if (++hist_add_idx >= HIST_MAX)
5 ▎ ▎ hist_add_idx = 0;
6 ▎
7 ▎ if (hist_add_idx > hist_max)
8 ▎ ▎ hist_max = hist_add_idx;
9 ▎
10 ▎ hist_num++;
11 }
他这种处理方式挺有意思的, hist_list[hist_add_idx], 实际上是 指向 二维数组的 一个 指针。
剩下的我就不分析了。
然后继续往下分析代码
3 ▎ ▎ flag = 0; /* assume no special flags for now */
2 ▎ ▎ if (len > 0)
E 1 ▎ ▎ ▎ strcpy (lastcommand, console_buffer); ■ Call to undeclared library function 'strcpy' with type 'char *(char *, const char *)'; ISO C99 and later do not s
429 ▎ ▎ else if (len == 0)
E 1 ▎ ▎ ▎ flag |= CMD_FLAG_REPEAT; ■ Use of undeclared identifier 'CMD_FLAG_REPEAT'
2 #ifdef CONFIG_BOOT_RETRY_TIME
3 ▎ ▎ else if (len == -2) {
4 ▎ ▎ ▎ /* -2 means timed out, retry autoboot
5 ▎ ▎ ▎ ▎*/
6 ▎ ▎ ▎ puts ("\nTimed out waiting for command\n");
7 # ifdef CONFIG_RESET_TO_RETRY
8 ▎ ▎ ▎ /* Reinit board to run initialization code again */
9 ▎ ▎ ▎ do_reset (NULL, 0, 0, NULL);
10 # else
11 ▎ ▎ ▎ return; /* retry autoboot */
12 # endif
13 ▎ ▎ }
14 #endif
strcpy (lastcommand, console_buffer); 这句表示 将指令拷贝到 lastcommand 中。
然后继续往下分析。
16 ▎ ▎ if (len == -1)
15 ▎ ▎ ▎ puts ("<INTERRUPT>\n");
14 ▎ ▎ else
E 13 ▎ ▎ ▎ rc = run_command(lastcommand, flag); ■ Call to undeclared function 'run_command'; ISO C99 and later do not support implicit function declarations
12 ▎ ▎
11 ▎ ▎ if (rc <= 0) {
10 ▎ ▎ ▎ /* invalid command or not repeatable, forget it */
9 ▎ ▎ ▎ lastcommand[0] = 0;
8 ▎ ▎ }
7 ▎ }
6 #endif /*CONFIG_SYS_HUSH_PARSER*/
5 }
4
最关键的就是 这句代码了。
rc = run_command(lastcommand, flag);
代码如下:
8 /*
7 ▎* Run a command using the selected parser.
6 ▎*
5 ▎* @param cmd Command to run
4 ▎* @param flag Execution flags (CMD_FLAG_...)
3 ▎* @return 0 on success, or != 0 on error.
2 ▎*/
1 int run_command(const char *cmd, int flag)
1367 {
1 #ifndef CONFIG_SYS_HUSH_PARSER
2 ▎ /*
3 ▎ ▎* builtin_run_command can return 0 or 1 for success, so clean up
4 ▎ ▎* its result.
5 ▎ ▎*/
6 ▎ if (builtin_run_command(cmd, flag) == -1)
7 ▎ ▎ return 1;
8 ▎
9 ▎ return 0;
10 #else
11 ▎ return parse_string_outer(cmd,
12 ▎ ▎ ▎ FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP);
13 #endif
14 }
由于没有定义 , CONFIG_SYS_HUSH_PARSER , 所以会执行。
builtin_run_command(cmd, flag) 这句代码。
34 static int builtin_run_command(const char *cmd, int flag)
33 {
32 ▎ char cmdbuf[CONFIG_SYS_CBSIZE]; /* working copy of cmd */
31 ▎ char *token; /* start of token in cmdbuf */
30 ▎ char *sep; /* end of token (separator) in cmdbuf */
29 ▎ char finaltoken[CONFIG_SYS_CBSIZE];
28 ▎ char *str = cmdbuf;
27 ▎ char *argv[CONFIG_SYS_MAXARGS + 1]; /* NULL terminated */
26 ▎ int argc, inquotes;
25 ▎ int repeatable = 1;
24 ▎ int rc = 0;
23 ▎
22 #ifdef DEBUG_PARSER
21 ▎ printf ("[RUN_COMMAND] cmd[%p]=\"", cmd);
20 ▎ puts (cmd ? cmd : "NULL"); /* use puts - string may be loooong */
19 ▎ puts ("\"\n");
18 #endif
17 ▎
16 ▎ clear_ctrlc(); /* forget any previous Control C */
15 ▎
14 ▎ if (!cmd || !*cmd) {
13 ▎ ▎ return -1; /* empty command */
12 ▎ }
11 ▎
10 ▎ if (strlen(cmd) >= CONFIG_SYS_CBSIZE) {
9 ▎ ▎ puts ("## Command too long!\n");
8 ▎ ▎ return -1;
7 ▎ }
6 ▎
5 ▎ strcpy (cmdbuf, cmd);
4 ▎
3 ▎ /* Process separators and check for invalid
2 ▎ ▎* repeatable commands
1 ▎ ▎*/
40 #ifdef DEBUG_PARSER
39 ▎ printf ("[PROCESS_SEPARATORS] %s\n", cmd);
38 #endif
37 ▎ while (*str) {
36 ▎ ▎
35 ▎ ▎ /*
34 ▎ ▎ ▎* Find separator, or string end
33 ▎ ▎ ▎* Allow simple escape of ';' by writing "\;"
32 ▎ ▎ ▎*/
31 ▎ ▎ for (inquotes = 0, sep = str; *sep; sep++) {
30 ▎ ▎ ▎ if ((*sep=='\'') &&
29 ▎ ▎ ▎ ▎ (*(sep-1) != '\\'))
28 ▎ ▎ ▎ ▎ inquotes=!inquotes;
27 ▎ ▎ ▎
26 ▎ ▎ ▎ if (!inquotes &&
25 ▎ ▎ ▎ ▎ (*sep == ';') && /* separator */
24 ▎ ▎ ▎ ▎ ( sep != str) && /* past string start */
23 ▎ ▎ ▎ ▎ (*(sep-1) != '\\')) /* and NOT escaped */
22 ▎ ▎ ▎ ▎ break;
21 ▎ ▎ }
20 ▎ ▎
19 ▎ ▎ /*
18 ▎ ▎ ▎* Limit the token to data between separators
17 ▎ ▎ ▎*/
16 ▎ ▎ token = str;
15 ▎ ▎ if (*sep) {
14 ▎ ▎ ▎ str = sep + 1; /* start of command for next pass */
13 ▎ ▎ ▎ *sep = '\0';
12 ▎ ▎ }
11 ▎ ▎ else
10 ▎ ▎ ▎ str = sep; /* no more commands for next pass */
9 #ifdef DEBUG_PARSER
8 ▎ ▎ printf ("token: \"%s\"\n", token);
7 #endif
6 ▎ ▎
5 ▎ ▎ /* find macros in this token and replace them */
4 ▎ ▎ process_macros (token, finaltoken);
3 ▎ ▎
2 ▎ ▎ /* Extract arguments */
1 ▎ ▎ if ((argc = parse_line (finaltoken, argv)) == 0) {
1343 ▎ ▎ ▎ rc = -1; /* no command at all */
1 ▎ ▎ ▎ continue;
2 ▎ ▎ }
3 ▎ ▎
4 ▎ ▎ if (cmd_process(flag, argc, argv, &repeatable))
5 ▎ ▎ ▎ rc = -1;
6 ▎ ▎
7 ▎ ▎ /* Did the user stop this? */
8 ▎ ▎ if (had_ctrlc ())
9 ▎ ▎ ▎ return -1; /* if stopped then not repeatable */
10 ▎ }
20 ▎ return rc ? rc : repeatable;
19 }
18 #endif
clear_ctrlc(); 这句代码实现如下:
1 void clear_ctrlc(void)
493 {
1 ▎ ctrlc_was_pressed = 0;
2 }
只是做了一个标记, 不知道 要干什么。
strcpy (cmdbuf, cmd); 这句是将 命令 拷贝到了 临时的变量中。
接下来就是 这一段代码了。
40 ▎ while (*str) {
39 ▎ ▎
38 ▎ ▎ /*
37 ▎ ▎ ▎* Find separator, or string end
36 ▎ ▎ ▎* Allow simple escape of ';' by writing "\;"
35 ▎ ▎ ▎*/
34 ▎ ▎ for (inquotes = 0, sep = str; *sep; sep++) {
33 ▎ ▎ ▎ if ((*sep=='\'') &&
32 ▎ ▎ ▎ ▎ (*(sep-1) != '\\'))
31 ▎ ▎ ▎ ▎ inquotes=!inquotes;
30 ▎ ▎ ▎
29 ▎ ▎ ▎ if (!inquotes &&
28 ▎ ▎ ▎ ▎ (*sep == ';') && /* separator */
27 ▎ ▎ ▎ ▎ ( sep != str) && /* past string start */
26 ▎ ▎ ▎ ▎ (*(sep-1) != '\\')) /* and NOT escaped */
25 ▎ ▎ ▎ ▎ break;
24 ▎ ▎ }
23 ▎ ▎
22 ▎ ▎ /*
21 ▎ ▎ ▎* Limit the token to data between separators
20 ▎ ▎ ▎*/
19 ▎ ▎ token = str;
18 ▎ ▎ if (*sep) {
17 ▎ ▎ ▎ str = sep + 1; /* start of command for next pass */
16 ▎ ▎ ▎ *sep = '\0';
15 ▎ ▎ }
14 ▎ ▎ else
13 ▎ ▎ ▎ str = sep; /* no more commands for next pass */
12 #ifdef DEBUG_PARSER
11 ▎ ▎ printf ("token: \"%s\"\n", token);
10 #endif
9 ▎ ▎
8 ▎ ▎ /* find macros in this token and replace them */
7 ▎ ▎ process_macros (token, finaltoken);
6 ▎ ▎
5 ▎ ▎ /* Extract arguments */
4 ▎ ▎ if ((argc = parse_line (finaltoken, argv)) == 0) {
3 ▎ ▎ ▎ rc = -1; /* no command at all */
2 ▎ ▎ ▎ continue;
1 ▎ ▎ }
1346 ▎ ▎
1 ▎ ▎ if (cmd_process(flag, argc, argv, &repeatable))
2 ▎ ▎ ▎ rc = -1;
3 ▎ ▎
4 ▎ ▎ /* Did the user stop this? */
5 ▎ ▎ if (had_ctrlc ())
6 ▎ ▎ ▎ return -1; /* if stopped then not repeatable */
7 ▎ }
这段是在 处理 分号 ; ,我就不看了。
34 ▎ ▎ for (inquotes = 0, sep = str; *sep; sep++) {
33 ▎ ▎ ▎ if ((*sep=='\'') &&
32 ▎ ▎ ▎ ▎ (*(sep-1) != '\\'))
31 ▎ ▎ ▎ ▎ inquotes=!inquotes;
30 ▎ ▎ ▎
29 ▎ ▎ ▎ if (!inquotes &&
28 ▎ ▎ ▎ ▎ (*sep == ';') && /* separator */
27 ▎ ▎ ▎ ▎ ( sep != str) && /* past string start */
26 ▎ ▎ ▎ ▎ (*(sep-1) != '\\')) /* and NOT escaped */
25 ▎ ▎ ▎ ▎ break;
24 ▎ ▎ }
这几句 让 token 指向了 字符串
27 ▎ ▎ token = str;
26 ▎ ▎ if (*sep) {
25 ▎ ▎ ▎ str = sep + 1; /* start of command for next pass */
24 ▎ ▎ ▎ *sep = '\0';
23 ▎ ▎ }
22 ▎ ▎ else
21 ▎ ▎ ▎ str = sep; /* no more commands for next pass */
20 #ifdef DEBUG_PARSER
19 ▎ ▎ printf ("token: \"%s\"\n", token);
18 #endif
接下来就是 这段代码了。
9 ▎ ▎ /* find macros in this token and replace them */
8 ▎ ▎ process_macros (token, finaltoken);
7 ▎ ▎
6 ▎ ▎ /* Extract arguments */
5 ▎ ▎ if ((argc = parse_line (finaltoken, argv)) == 0) {
4 ▎ ▎ ▎ rc = -1; /* no command at all */
3 ▎ ▎ ▎ continue;
2 ▎ ▎ }
1 ▎ ▎
1347 ▎ ▎ if (cmd_process(flag, argc, argv, &repeatable))
1 ▎ ▎ ▎ rc = -1;
2 ▎ ▎
3 ▎ ▎ /* Did the user stop this? */
4 ▎ ▎ if (had_ctrlc ())
5 ▎ ▎ ▎ return -1; /* if stopped then not repeatable */
6 ▎ }
7 ▎
process_macros (token, finaltoken); 这句是在 替换 命令中的宏, 不知道什么意思。
先跳过。
然后就是 if ((argc = parse_line (finaltoken, argv)) == 0) 这一句了。
看一下 pase_line() 函数。
38 int parse_line (char *line, char *argv[])
37 {
36 ▎ int nargs = 0;
35 ▎
34 #ifdef DEBUG_PARSER
33 ▎ printf ("parse_line: \"%s\"\n", line);
32 #endif
E 31 ▎ while (nargs < CONFIG_SYS_MAXARGS) { ■ Use of undeclared identifier 'CONFIG_SYS_MAXARGS'
30 ▎ ▎
29 ▎ ▎ /* skip any white space */
E 28 ▎ ▎ while (isblank(*line)) ■ Call to undeclared library function 'isblank' with type 'int (int)'; ISO C99 and later do not support implicit function declarations
27 ▎ ▎ ▎ ++line;
26 ▎ ▎
25 ▎ ▎ if (*line == '\0') { /* end of line, no more args */
24 ▎ ▎ ▎ argv[nargs] = NULL;
23 #ifdef DEBUG_PARSER
22 ▎ ▎ printf ("parse_line: nargs=%d\n", nargs);
21 #endif
20 ▎ ▎ ▎ return (nargs);
19 ▎ ▎ }
18 ▎ ▎
17 ▎ ▎ argv[nargs++] = line; /* begin of argument string */
16 ▎ ▎
15 ▎ ▎ /* find end of string */
14 ▎ ▎ while (*line && !isblank(*line))
13 ▎ ▎ ▎ ++line;
12 ▎ ▎
11 ▎ ▎ if (*line == '\0') { /* end of line, no more args */
10 ▎ ▎ ▎ argv[nargs] = NULL;
9 #ifdef DEBUG_PARSER
8 ▎ ▎ printf ("parse_line: nargs=%d\n", nargs);
7 #endif
6 ▎ ▎ ▎ return (nargs);
5 ▎ ▎ }
4 ▎ ▎
3 ▎ ▎ *line++ = '\0'; /* terminate current arg */
2 ▎ }
1 ▎
E 1131 ▎ printf ("** Too many args (max. %d) **\n", CONFIG_SYS_MAXARGS); ■ Use of undeclared identifier 'CONFIG_SYS_MAXARGS'
1 ▎
2 #ifdef DEBUG_PARSER
3 ▎ printf ("parse_line: nargs=%d\n", nargs);
4 #endif
5 ▎ return (nargs);
6 }
这段代码是 值得我去学习的。
他将一句话 ,依据 空格 分割出单词。
每个单词 都放到了 argv[] 中。 argv[] 实际上是 字符指针数组。
char *argv[CONFIG_SYS_MAXARGS + 1]; /*
这些个 字符串的真正的存放位置 是 finaltoken. 它实际上是 字符数组,是一个局部变量。
▎ char finaltoken[CONFIG_SYS_CBSIZE];
这个函数最后返回的是 参数的个数,即 argc .
注意 :由于字符存放在 字符数组中,所以是可以这样修改的。
这样做 实际上 是将 原本的 空格变成了 \0 。
继续往下分析代码。
然后就是 这句代码, if (cmd_process(flag, argc, argv, &repeatable))
代码如下:
33 enum command_ret_t cmd_process(int flag, int argc, char * const argv[],
32 ▎ ▎ ▎ int *repeatable)
31 {
30 ▎ enum command_ret_t rc = CMD_RET_SUCCESS;
29 ▎ cmd_tbl_t *cmdtp;
28 ▎
27 ▎ /* Look up command in command table */
26 ▎ cmdtp = find_cmd(argv[0]);
25 ▎ if (cmdtp == NULL) {
24 ▎ ▎ printf("Unknown command '%s' - try 'help'\n", argv[0]);
23 ▎ ▎ return 1;
22 ▎ }
21 ▎
20 ▎ /* found - check max args */
19 ▎ if (argc > cmdtp->maxargs)
18 ▎ ▎ rc = CMD_RET_USAGE;
17 ▎
16 #if defined(CONFIG_CMD_BOOTD)
15 ▎ /* avoid "bootd" recursion */
14 ▎ else if (cmdtp->cmd == do_bootd) {
13 ▎ ▎ if (flag & CMD_FLAG_BOOTD) {
12 ▎ ▎ ▎ puts("'bootd' recursion detected\n");
11 ▎ ▎ ▎ rc = CMD_RET_FAILURE;
10 ▎ ▎ } else {
9 ▎ ▎ ▎ flag |= CMD_FLAG_BOOTD;
8 ▎ ▎ }
7 ▎ }
6 #endif
5 ▎
4 ▎ /* If OK so far, then do the command */
3 ▎ if (!rc) {
2 ▎ ▎ rc = cmd_call(cmdtp, flag, argc, argv);
1 ▎ ▎ *repeatable &= cmdtp->repeatable;
545 ▎ }
1 ▎ if (rc == CMD_RET_USAGE)
2 ▎ ▎ rc = cmd_usage(cmdtp);
3 ▎ return rc;
4 }
enum command_ret_t rc = CMD_RET_SUCCESS; 这句代码中, command_ret_t 代码如下:
8 /*
7 ▎* Error codes that commands return to cmd_process(). We use the standard 0
6 ▎* and 1 for success and failure, but add one more case - failure with a
5 ▎* request to call cmd_usage(). But the cmd_process() function handles
4 ▎* CMD_RET_USAGE itself and after calling cmd_usage() it will return 1.
3 ▎* This is just a convenience for commands to avoid them having to call
2 ▎* cmd_usage() all over the place.
1 ▎*/
127 enum command_ret_t {
1 ▎ CMD_RET_SUCCESS, /* 0 = Success */
2 ▎ CMD_RET_FAILURE, /* 1 = Failure */
3 ▎ CMD_RET_USAGE = -1, /* Failure, please report 'usage' error */
4 };
cmd_tbl_t *cmdtp; 这句中, cmd_tbl_t 代码如下:
16 struct cmd_tbl_s {
15 ▎ char *name; /* Command Name */
14 ▎ int maxargs; /* maximum number of arguments */
13 ▎ int repeatable; /* autorepeat allowed? */
12 ▎ ▎ ▎ ▎ ▎ /* Implementation function */
11 ▎ int (*cmd)(struct cmd_tbl_s *, int, int, char * const []);
10 ▎ char *usage; /* Usage message (short) */
9 #ifdef CONFIG_SYS_LONGHELP
8 ▎ char *help; /* Help message (long) */
7 #endif
6 #ifdef CONFIG_AUTO_COMPLETE
5 ▎ /* do auto completion on the arguments */
4 ▎ int (*complete)(int argc, char * const argv[], char last_char, int maxv, char *cmdv[]);
3 #endif
2 };
1
62 typedef struct cmd_tbl_s cmd_tbl_t;
这个结构体 , 就是 关于 uboot 的命令的结构体, 所有的Uboot的命令都存放在这个段中。
这个段 如下图所示。
接下来 , 我们就看一下, 关于 Uboot的命令的存储吧。
以 version 这个命令为例子。
代码如下:
14
E 13 #include <common.h> ■ 'common.h' file not found
12 #include <command.h>
11 #include <version.h>
10 #include <linux/compiler.h>
9
E 8 const char __weak version_string[] = U_BOOT_VERSION_STRING; ■ Expected ';' after top level declarator (fix available)
7
E 6 int do_version(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) ■ Unknown type name 'cmd_tbl_t'
5 {
E 4 ▎ printf("\n%s\n", version_string); ■■ Use of undeclared identifier 'version_string'
3 #ifdef CC_VERSION_STRING
2 ▎ puts(CC_VERSION_STRING "\n");
1 #endif
37 #ifdef LD_VERSION_STRING
1 ▎ puts(LD_VERSION_STRING "\n");
2 #endif
3 ▎
4 ▎ return 0;
5 }
6
E 7 U_BOOT_CMD( ■ Type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int (fix available)
E 8 ▎ version, 1, 1, do_version, ■ Expected identifier
9 ▎ "print monitor, compiler and linker version",
10 ▎ ""
11 );
主要就是这个 U_BOOT_CMD 红顶以的发展开。
它的定义在这里。
1 #define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) \
2 ▎ U_BOOT_CMD_COMPLETE(name,maxargs,rep,cmd,usage,help,NULL)
完全展开之后, 是这样的。
#define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) cmd_tbl_t __u_boot_cmd_##name __attribute__((unused, section(".u_boot_cmd"), aligned(4))) = {#name, maxargs, rep, cmd, usage, _CMD_HELP(help) _CMD_COMPLETE(comp)}
实际上 就是 它 定义了 一个 cmd_tbl_t 的结构体,并给这个结构体赋上了值。
疑问: 那么是谁把这些 命令 拷贝到这个段上去的呢?
我觉得是这样。
首先 c 文件在编译的时候,会将, 这个结构体的说明,放到 .u_boot_cmd 段中,但是 命令的实现不放这里。
然后,不是有 连接脚本吗,连接脚本会将代码中 所有 有这些段的 放到 .u_boot_cmd 段中。
接下来继续往下分析代码。
接下来是这段代码
1 ▎ /* Look up command in command table */
519 ▎ cmdtp = find_cmd(argv[0]);
1 ▎ if (cmdtp == NULL) {
2 ▎ ▎ printf("Unknown command '%s' - try 'help'\n", argv[0]);
3 ▎ ▎ return 1;
4 ▎ }
cmdtp = find_cmd(argv[0]); 这句中 find_cmd 代码如下:
20 cmd_tbl_t *find_cmd (const char *cmd)
19 {
18 ▎ int len = &__u_boot_cmd_end - &__u_boot_cmd_start;
17 ▎ return find_cmd_tbl(cmd, &__u_boot_cmd_start, len);
16 }
继续往下看。
35 /***************************************************************************
34 ▎* find command table entry for a command
33 ▎*/
32 cmd_tbl_t *find_cmd_tbl (const char *cmd, cmd_tbl_t *table, int table_len)
31 {
30 ▎ cmd_tbl_t *cmdtp;
29 ▎ cmd_tbl_t *cmdtp_temp = table; /*Init value */
28 ▎ const char *p;
27 ▎ int len;
26 ▎ int n_found = 0;
25 ▎
24 ▎ if (!cmd)
23 ▎ ▎ return NULL;
22 ▎ /*
21 ▎ ▎* Some commands allow length modifiers (like "cp.b");
20 ▎ ▎* compare command name only until first dot.
19 ▎ ▎*/
18 ▎ len = ((p = strchr(cmd, '.')) == NULL) ? strlen (cmd) : (p - cmd);
17 ▎
16 ▎ for (cmdtp = table;
15 ▎ ▎ cmdtp != table + table_len;
14 ▎ ▎ cmdtp++) {
13 ▎ ▎ if (strncmp (cmd, cmdtp->name, len) == 0) {
12 ▎ ▎ ▎ if (len == strlen (cmdtp->name))
11 ▎ ▎ ▎ ▎ return cmdtp; /* full match */
10 ▎ ▎ ▎
9 ▎ ▎ ▎ cmdtp_temp = cmdtp; /* abbreviated command ? */
8 ▎ ▎ ▎ n_found++;
7 ▎ ▎ }
6 ▎ }
5 ▎ if (n_found == 1) { /* exactly one match */
4 ▎ ▎ return cmdtp_temp;
3 ▎ }
2 ▎
1 ▎ return NULL; /* not found or ambiguous command */
136 }
这个函数就是 一条一条的找, 就不分析了,如果找到了,就返回这个结构体的头部。
继续分析代码,接下来就是 这段了。
3 ▎ /* If OK so far, then do the command */
2 ▎ if (!rc) {
1 ▎ ▎ rc = cmd_call(cmdtp, flag, argc, argv);
544 ▎ ▎ *repeatable &= cmdtp->repeatable;
1 ▎ }
代码如下:
19 ▎* Call a command function. This should be the only route in U-Boot to call
18 ▎* a command, so that we can track whether we are waiting for input or
17 ▎* executing a command.
16 ▎*
15 ▎* @param cmdtp Pointer to the command to execute
14 ▎* @param flag Some flags normally 0 (see CMD_FLAG_.. above)
13 ▎* @param argc Number of arguments (arg 0 must be the command text)
12 ▎* @param argv Arguments
11 ▎* @return 0 if command succeeded, else non-zero (CMD_RET_...)
10 ▎*/
9 static int cmd_call(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
8 {
7 ▎ int result;
6 ▎
5 ▎ result = (cmdtp->cmd)(cmdtp, flag, argc, argv);
4 ▎ if (result)
3 ▎ ▎ debug("Command failed, result=%d", result);
2 ▎ return result;
1 }
511
实际上 就是 调用了 结构体中的函数指针
这样 ,如果 按下按键的流程就分析完了,
接下来去分析 如果是等到 倒计时为0 的时候,执行流程。
那么它会执行 这段代码
run_command_list(s, -1, 0);
代码如下:
35 int run_command_list(const char *cmd, int len, int flag)
34 {
33 ▎ int need_buff = 1;
32 ▎ char *buff = (char *)cmd; /* cast away const */
31 ▎ int rcode = 0;
30 ▎
29 ▎ if (len == -1) {
28 ▎ ▎ len = strlen(cmd);
27 #ifdef CONFIG_SYS_HUSH_PARSER
26 ▎ ▎ /* hush will never change our string */
25 ▎ ▎ need_buff = 0;
24 #else
23 ▎ ▎ /* the built-in parser will change our string if it sees \n */
22 ▎ ▎ need_buff = strchr(cmd, '\n') != NULL;
21 #endif
20 ▎ }
19 ▎ if (need_buff) {
18 ▎ ▎ buff = malloc(len + 1);
17 ▎ ▎ if (!buff)
16 ▎ ▎ ▎ return 1;
15 ▎ ▎ memcpy(buff, cmd, len);
14 ▎ ▎ buff[len] = '\0';
13 ▎ }
12 #ifdef CONFIG_SYS_HUSH_PARSER
11 ▎ rcode = parse_string_outer(buff, FLAG_PARSE_SEMICOLON);
10 #else
9 ▎ /*
8 ▎ ▎* This function will overwrite any \n it sees with a \0, which
7 ▎ ▎* is why it can't work with a const char *. Here we are making
6 ▎ ▎* using of internal knowledge of this function, to avoid always
5 ▎ ▎* doing a malloc() which is actually required only in a case that
4 ▎ ▎* is pretty rare.
3 ▎ ▎*/
2 ▎ rcode = builtin_run_command_list(buff, flag);
1 ▎ if (need_buff)
1461 ▎ ▎ free(buff);
1 #endif
2 ▎
3 ▎ return rcode;
4 }
5
然后再去分析如果是 没有 按下按键的话,他是怎么解析命令的。
这个我就不分析了。这个老师也没有分析这块。