blob: 7a21fdaf7faee89fd6c12ca74b1e9ada69e185f3 [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001/*
2 * (C) Copyright 2000
3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4 *
5 * Add to readline cmdline-editing by
6 * (C) Copyright 2005
7 * JinHua Luo, GuangDong Linux Center, <luo.jinhua@gd-linux.com>
8 *
9 * SPDX-License-Identifier: GPL-2.0+
10 */
11
12/* #define DEBUG */
13
14#include <common.h>
15#include <command.h>
16#include <fdtdec.h>
17#include <hush.h>
18#include <malloc.h>
19#include <menu.h>
20#include <post.h>
21#include <version.h>
22#include <watchdog.h>
23#include <linux/ctype.h>
24
25DECLARE_GLOBAL_DATA_PTR;
26
27/*
28 * Board-specific Platform code can reimplement show_boot_progress () if needed
29 */
30void inline __show_boot_progress (int val) {}
31void show_boot_progress (int val) __attribute__((weak, alias("__show_boot_progress")));
32
33#define MAX_DELAY_STOP_STR 32
34
35#define DEBUG_PARSER 0 /* set to 1 to debug */
36
37#define debug_parser(fmt, args...) \
38 debug_cond(DEBUG_PARSER, fmt, ##args)
39
40#ifndef DEBUG_BOOTKEYS
41#define DEBUG_BOOTKEYS 0
42#endif
43#define debug_bootkeys(fmt, args...) \
44 debug_cond(DEBUG_BOOTKEYS, fmt, ##args)
45
46char console_buffer[CONFIG_SYS_CBSIZE + 1]; /* console I/O buffer */
47
48static char * delete_char (char *buffer, char *p, int *colp, int *np, int plen);
49static const char erase_seq[] = "\b \b"; /* erase sequence */
50static const char tab_seq[] = " "; /* used to expand TABs */
51
52#ifdef CONFIG_BOOT_RETRY_TIME
53static uint64_t endtime = 0; /* must be set, default is instant timeout */
54static int retry_time = -1; /* -1 so can call readline before main_loop */
55#endif
56
57#define endtick(seconds) (get_ticks() + (uint64_t)(seconds) * get_tbclk())
58
59#ifndef CONFIG_BOOT_RETRY_MIN
60#define CONFIG_BOOT_RETRY_MIN CONFIG_BOOT_RETRY_TIME
61#endif
62
63#ifdef CONFIG_MODEM_SUPPORT
64int do_mdm_init = 0;
65extern void mdm_init(void); /* defined in board.c */
66#endif
67
68/***************************************************************************
69 * Watch for 'delay' seconds for autoboot stop or autoboot delay string.
70 * returns: 0 - no key string, allow autoboot 1 - got key string, abort
71 */
72#if defined(CONFIG_BOOTDELAY)
73# if defined(CONFIG_AUTOBOOT_KEYED)
74static int abortboot_keyed(int bootdelay)
75{
76 int abort = 0;
77 uint64_t etime = endtick(bootdelay);
78 struct {
79 char* str;
80 u_int len;
81 int retry;
82 }
83 delaykey [] = {
84 { str: getenv ("bootdelaykey"), retry: 1 },
85 { str: getenv ("bootdelaykey2"), retry: 1 },
86 { str: getenv ("bootstopkey"), retry: 0 },
87 { str: getenv ("bootstopkey2"), retry: 0 },
88 };
89
90 char presskey [MAX_DELAY_STOP_STR];
91 u_int presskey_len = 0;
92 u_int presskey_max = 0;
93 u_int i;
94
95#ifndef CONFIG_ZERO_BOOTDELAY_CHECK
96 if (bootdelay == 0)
97 return 0;
98#endif
99
100# ifdef CONFIG_AUTOBOOT_PROMPT
101 printf(CONFIG_AUTOBOOT_PROMPT);
102# endif
103
104# ifdef CONFIG_AUTOBOOT_DELAY_STR
105 if (delaykey[0].str == NULL)
106 delaykey[0].str = CONFIG_AUTOBOOT_DELAY_STR;
107# endif
108# ifdef CONFIG_AUTOBOOT_DELAY_STR2
109 if (delaykey[1].str == NULL)
110 delaykey[1].str = CONFIG_AUTOBOOT_DELAY_STR2;
111# endif
112# ifdef CONFIG_AUTOBOOT_STOP_STR
113 if (delaykey[2].str == NULL)
114 delaykey[2].str = CONFIG_AUTOBOOT_STOP_STR;
115# endif
116# ifdef CONFIG_AUTOBOOT_STOP_STR2
117 if (delaykey[3].str == NULL)
118 delaykey[3].str = CONFIG_AUTOBOOT_STOP_STR2;
119# endif
120
121 for (i = 0; i < sizeof(delaykey) / sizeof(delaykey[0]); i ++) {
122 delaykey[i].len = delaykey[i].str == NULL ?
123 0 : strlen (delaykey[i].str);
124 delaykey[i].len = delaykey[i].len > MAX_DELAY_STOP_STR ?
125 MAX_DELAY_STOP_STR : delaykey[i].len;
126
127 presskey_max = presskey_max > delaykey[i].len ?
128 presskey_max : delaykey[i].len;
129
130 debug_bootkeys("%s key:<%s>\n",
131 delaykey[i].retry ? "delay" : "stop",
132 delaykey[i].str ? delaykey[i].str : "NULL");
133 }
134
135 /* In order to keep up with incoming data, check timeout only
136 * when catch up.
137 */
138 do {
139 if (tstc()) {
140 if (presskey_len < presskey_max) {
141 presskey [presskey_len ++] = getc();
142 }
143 else {
144 for (i = 0; i < presskey_max - 1; i ++)
145 presskey [i] = presskey [i + 1];
146
147 presskey [i] = getc();
148 }
149 }
150
151 for (i = 0; i < sizeof(delaykey) / sizeof(delaykey[0]); i ++) {
152 if (delaykey[i].len > 0 &&
153 presskey_len >= delaykey[i].len &&
154 memcmp (presskey + presskey_len - delaykey[i].len,
155 delaykey[i].str,
156 delaykey[i].len) == 0) {
157 debug_bootkeys("got %skey\n",
158 delaykey[i].retry ? "delay" :
159 "stop");
160
161# ifdef CONFIG_BOOT_RETRY_TIME
162 /* don't retry auto boot */
163 if (! delaykey[i].retry)
164 retry_time = -1;
165# endif
166 abort = 1;
167 }
168 }
169 } while (!abort && get_ticks() <= etime);
170
171 if (!abort)
172 debug_bootkeys("key timeout\n");
173
174#ifdef CONFIG_SILENT_CONSOLE
175 if (abort)
176 gd->flags &= ~GD_FLG_SILENT;
177#endif
178
179 return abort;
180}
181
182# else /* !defined(CONFIG_AUTOBOOT_KEYED) */
183
184#ifdef CONFIG_MENUKEY
185static int menukey = 0;
186#endif
187
188static int abortboot_normal(int bootdelay)
189{
190 int abort = 0;
191 unsigned long ts;
192 if (serial_get_quiet())
193 return 0;
194#ifdef CONFIG_MENUPROMPT
195 printf(CONFIG_MENUPROMPT);
196#else
197 if (bootdelay >= 0)
198 printf("Hit any key to stop autoboot: %2d ", bootdelay);
199#endif
200
201#if defined CONFIG_ZERO_BOOTDELAY_CHECK
202 /*
203 * Check if key already pressed
204 * Don't check if bootdelay < 0
205 */
206 if (bootdelay >= 0) {
207 if (tstc()) { /* we got a key press */
208 (void) getc(); /* consume input */
209 puts ("\b\b\b 0");
210 abort = 1; /* don't auto boot */
211 }
212 }
213#endif
214
215 while ((bootdelay > 0) && (!abort)) {
216 --bootdelay;
217 /* delay 1000 ms */
218 ts = get_timer(0);
219 do {
220 if (tstc()) { /* we got a key press */
221 abort = 1; /* don't auto boot */
222 bootdelay = 0; /* no more delay */
223# ifdef CONFIG_MENUKEY
224 menukey = getc();
225# else
226 (void) getc(); /* consume input */
227# endif
228 break;
229 }
230 udelay(10000);
231 } while (!abort && get_timer(ts) < 1000);
232
233 printf("\b\b\b%2d ", bootdelay);
234 }
235
236 putc('\n');
237
238#ifdef CONFIG_SILENT_CONSOLE
239 if (abort)
240 gd->flags &= ~GD_FLG_SILENT;
241#endif
242
243 return abort;
244}
245# endif /* CONFIG_AUTOBOOT_KEYED */
246
247static int abortboot(int bootdelay)
248{
249#ifdef CONFIG_AUTOBOOT_KEYED
250 return abortboot_keyed(bootdelay);
251#else
252 return abortboot_normal(bootdelay);
253#endif
254}
255#endif /* CONFIG_BOOTDELAY */
256
257/*
258 * Runs the given boot command securely. Specifically:
259 * - Doesn't run the command with the shell (run_command or parse_string_outer),
260 * since that's a lot of code surface that an attacker might exploit.
261 * Because of this, we don't do any argument parsing--the secure boot command
262 * has to be a full-fledged u-boot command.
263 * - Doesn't check for keypresses before booting, since that could be a
264 * security hole; also disables Ctrl-C.
265 * - Doesn't allow the command to return.
266 *
267 * Upon any failures, this function will drop into an infinite loop after
268 * printing the error message to console.
269 */
270
271#if defined(CONFIG_BOOTDELAY) && defined(CONFIG_OF_CONTROL)
272static void secure_boot_cmd(char *cmd)
273{
274 cmd_tbl_t *cmdtp;
275 int rc;
276
277 if (!cmd) {
278 printf("## Error: Secure boot command not specified\n");
279 goto err;
280 }
281
282 /* Disable Ctrl-C just in case some command is used that checks it. */
283 disable_ctrlc(1);
284
285 /* Find the command directly. */
286 cmdtp = find_cmd(cmd);
287 if (!cmdtp) {
288 printf("## Error: \"%s\" not defined\n", cmd);
289 goto err;
290 }
291
292 /* Run the command, forcing no flags and faking argc and argv. */
293 rc = (cmdtp->cmd)(cmdtp, 0, 1, &cmd);
294
295 /* Shouldn't ever return from boot command. */
296 printf("## Error: \"%s\" returned (code %d)\n", cmd, rc);
297
298err:
299 /*
300 * Not a whole lot to do here. Rebooting won't help much, since we'll
301 * just end up right back here. Just loop.
302 */
303 hang();
304}
305
306static void process_fdt_options(const void *blob)
307{
308 ulong addr;
309
310 /* Add an env variable to point to a kernel payload, if available */
311 addr = fdtdec_get_config_int(gd->fdt_blob, "kernel-offset", 0);
312 if (addr)
313 setenv_addr("kernaddr", (void *)(CONFIG_SYS_TEXT_BASE + addr));
314
315 /* Add an env variable to point to a root disk, if available */
316 addr = fdtdec_get_config_int(gd->fdt_blob, "rootdisk-offset", 0);
317 if (addr)
318 setenv_addr("rootaddr", (void *)(CONFIG_SYS_TEXT_BASE + addr));
319}
320#endif /* CONFIG_OF_CONTROL */
321
322#ifdef CONFIG_BOOTDELAY
323static void process_boot_delay(void)
324{
325#ifdef CONFIG_OF_CONTROL
326 char *env;
327#endif
328 char *s;
329 int bootdelay;
330#ifdef CONFIG_BOOTCOUNT_LIMIT
331 unsigned long bootcount = 0;
332 unsigned long bootlimit = 0;
333#endif /* CONFIG_BOOTCOUNT_LIMIT */
334
335#ifdef CONFIG_BOOTCOUNT_LIMIT
336 bootcount = bootcount_load();
337 bootcount++;
338 bootcount_store (bootcount);
339 setenv_ulong("bootcount", bootcount);
340 bootlimit = getenv_ulong("bootlimit", 10, 0);
341#endif /* CONFIG_BOOTCOUNT_LIMIT */
342
343 s = getenv ("bootdelay");
344 bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;
345
346#ifdef CONFIG_OF_CONTROL
347 bootdelay = fdtdec_get_config_int(gd->fdt_blob, "bootdelay",
348 bootdelay);
349#endif
350
351 debug ("### main_loop entered: bootdelay=%d\n\n", bootdelay);
352
353#if defined(CONFIG_MENU_SHOW)
354 bootdelay = menu_show(bootdelay);
355#endif
356# ifdef CONFIG_BOOT_RETRY_TIME
357 init_cmd_timeout ();
358# endif /* CONFIG_BOOT_RETRY_TIME */
359
360#ifdef CONFIG_POST
361 if (gd->flags & GD_FLG_POSTFAIL) {
362 s = getenv("failbootcmd");
363 }
364 else
365#endif /* CONFIG_POST */
366#ifdef CONFIG_BOOTCOUNT_LIMIT
367 if (bootlimit && (bootcount > bootlimit)) {
368 printf ("Warning: Bootlimit (%u) exceeded. Using altbootcmd.\n",
369 (unsigned)bootlimit);
370 s = getenv ("altbootcmd");
371 }
372 else
373#endif /* CONFIG_BOOTCOUNT_LIMIT */
374 s = getenv ("bootcmd");
375#ifdef CONFIG_OF_CONTROL
376 /* Allow the fdt to override the boot command */
377 env = fdtdec_get_config_string(gd->fdt_blob, "bootcmd");
378 if (env)
379 s = env;
380
381 process_fdt_options(gd->fdt_blob);
382
383 /*
384 * If the bootsecure option was chosen, use secure_boot_cmd().
385 * Always use 'env' in this case, since bootsecure requres that the
386 * bootcmd was specified in the FDT too.
387 */
388 if (fdtdec_get_config_int(gd->fdt_blob, "bootsecure", 0))
389 secure_boot_cmd(env);
390
391#endif /* CONFIG_OF_CONTROL */
392
393 debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>");
394
395 if (bootdelay != -1 && s && !abortboot(bootdelay)) {
396#if defined(CONFIG_AUTOBOOT_KEYED) && !defined(CONFIG_AUTOBOOT_KEYED_CTRLC)
397 int prev = disable_ctrlc(1); /* disable Control C checking */
398#endif
399
400 run_command_list(s, -1, 0);
401
402#if defined(CONFIG_AUTOBOOT_KEYED) && !defined(CONFIG_AUTOBOOT_KEYED_CTRLC)
403 disable_ctrlc(prev); /* restore Control C checking */
404#endif
405 }
406
407#ifdef CONFIG_MENUKEY
408 if (menukey == CONFIG_MENUKEY) {
409 s = getenv("menucmd");
410 if (s)
411 run_command_list(s, -1, 0);
412 }
413#endif /* CONFIG_MENUKEY */
414}
415#endif /* CONFIG_BOOTDELAY */
416
417void main_loop(void)
418{
419#ifndef CONFIG_SYS_HUSH_PARSER
420 static char lastcommand[CONFIG_SYS_CBSIZE] = { 0, };
421 int len;
422 int rc = 1;
423 int flag;
424#endif
425#ifdef CONFIG_PREBOOT
426 char *p;
427#endif
428
429 bootstage_mark_name(BOOTSTAGE_ID_MAIN_LOOP, "main_loop");
430
431#ifdef CONFIG_MODEM_SUPPORT
432 debug("DEBUG: main_loop: do_mdm_init=%d\n", do_mdm_init);
433 if (do_mdm_init) {
434 char *str = strdup(getenv("mdm_cmd"));
435 setenv("preboot", str); /* set or delete definition */
436 if (str != NULL)
437 free(str);
438 mdm_init(); /* wait for modem connection */
439 }
440#endif /* CONFIG_MODEM_SUPPORT */
441
442#ifdef CONFIG_VERSION_VARIABLE
443 {
444 setenv("ver", version_string); /* set version variable */
445 }
446#endif /* CONFIG_VERSION_VARIABLE */
447
448#ifdef CONFIG_SYS_HUSH_PARSER
449 u_boot_hush_start();
450#endif
451
452#if defined(CONFIG_HUSH_INIT_VAR)
453 hush_init_var();
454#endif
455
456#ifdef CONFIG_PREBOOT
457 p = getenv("preboot");
458 if (p != NULL) {
459# ifdef CONFIG_AUTOBOOT_KEYED
460 int prev = disable_ctrlc(1); /* disable Control C checking */
461# endif
462
463 run_command_list(p, -1, 0);
464
465# ifdef CONFIG_AUTOBOOT_KEYED
466 disable_ctrlc(prev); /* restore Control C checking */
467# endif
468 }
469#endif /* CONFIG_PREBOOT */
470
471#if defined(CONFIG_UPDATE_TFTP)
472 update_tftp(0UL);
473#endif /* CONFIG_UPDATE_TFTP */
474
475#ifdef CONFIG_BOOTDELAY
476 process_boot_delay();
477#endif
478 /*
479 * Main Loop for Monitor Command Processing
480 */
481#ifdef CONFIG_SYS_HUSH_PARSER
482 parse_file_outer();
483 /* This point is never reached */
484 for (;;);
485#else
486 for (;;) {
487#ifdef CONFIG_BOOT_RETRY_TIME
488 if (rc >= 0) {
489 /* Saw enough of a valid command to
490 * restart the timeout.
491 */
492 reset_cmd_timeout();
493 }
494#endif
495 len = readline (CONFIG_SYS_PROMPT);
496
497 flag = 0; /* assume no special flags for now */
498 if (len > 0)
499 strcpy (lastcommand, console_buffer);
500 else if (len == 0)
501 flag |= CMD_FLAG_REPEAT;
502#ifdef CONFIG_BOOT_RETRY_TIME
503 else if (len == -2) {
504 /* -2 means timed out, retry autoboot
505 */
506 puts ("\nTimed out waiting for command\n");
507# ifdef CONFIG_RESET_TO_RETRY
508 /* Reinit board to run initialization code again */
509 do_reset (NULL, 0, 0, NULL);
510# else
511 return; /* retry autoboot */
512# endif
513 }
514#endif
515
516 if (len == -1)
517 puts ("<INTERRUPT>\n");
518 else
519 rc = run_command(lastcommand, flag);
520
521 if (rc <= 0) {
522 /* invalid command or not repeatable, forget it */
523 lastcommand[0] = 0;
524 }
525 }
526#endif /*CONFIG_SYS_HUSH_PARSER*/
527}
528
529#ifdef CONFIG_BOOT_RETRY_TIME
530/***************************************************************************
531 * initialize command line timeout
532 */
533void init_cmd_timeout(void)
534{
535 char *s = getenv ("bootretry");
536
537 if (s != NULL)
538 retry_time = (int)simple_strtol(s, NULL, 10);
539 else
540 retry_time = CONFIG_BOOT_RETRY_TIME;
541
542 if (retry_time >= 0 && retry_time < CONFIG_BOOT_RETRY_MIN)
543 retry_time = CONFIG_BOOT_RETRY_MIN;
544}
545
546/***************************************************************************
547 * reset command line timeout to retry_time seconds
548 */
549void reset_cmd_timeout(void)
550{
551 endtime = endtick(retry_time);
552}
553#endif
554
555#ifdef CONFIG_CMDLINE_EDITING
556
557/*
558 * cmdline-editing related codes from vivi.
559 * Author: Janghoon Lyu <nandy@mizi.com>
560 */
561
562#define putnstr(str,n) do { \
563 printf ("%.*s", (int)n, str); \
564 } while (0)
565
566#define CTL_CH(c) ((c) - 'a' + 1)
567#define CTL_BACKSPACE ('\b')
568#define DEL ((char)255)
569#define DEL7 ((char)127)
570#define CREAD_HIST_CHAR ('!')
571
572#define getcmd_putch(ch) putc(ch)
573#define getcmd_getch() getc()
574#define getcmd_cbeep() getcmd_putch('\a')
575
576#define HIST_MAX 20
577#define HIST_SIZE CONFIG_SYS_CBSIZE
578
579static int hist_max;
580static int hist_add_idx;
581static int hist_cur = -1;
582static unsigned hist_num;
583
584static char *hist_list[HIST_MAX];
585static char hist_lines[HIST_MAX][HIST_SIZE + 1]; /* Save room for NULL */
586
587#define add_idx_minus_one() ((hist_add_idx == 0) ? hist_max : hist_add_idx-1)
588
589static void hist_init(void)
590{
591 int i;
592
593 hist_max = 0;
594 hist_add_idx = 0;
595 hist_cur = -1;
596 hist_num = 0;
597
598 for (i = 0; i < HIST_MAX; i++) {
599 hist_list[i] = hist_lines[i];
600 hist_list[i][0] = '\0';
601 }
602}
603
604static void cread_add_to_hist(char *line)
605{
606 strcpy(hist_list[hist_add_idx], line);
607
608 if (++hist_add_idx >= HIST_MAX)
609 hist_add_idx = 0;
610
611 if (hist_add_idx > hist_max)
612 hist_max = hist_add_idx;
613
614 hist_num++;
615}
616
617static char* hist_prev(void)
618{
619 char *ret;
620 int old_cur;
621
622 if (hist_cur < 0)
623 return NULL;
624
625 old_cur = hist_cur;
626 if (--hist_cur < 0)
627 hist_cur = hist_max;
628
629 if (hist_cur == hist_add_idx) {
630 hist_cur = old_cur;
631 ret = NULL;
632 } else
633 ret = hist_list[hist_cur];
634
635 return (ret);
636}
637
638static char* hist_next(void)
639{
640 char *ret;
641
642 if (hist_cur < 0)
643 return NULL;
644
645 if (hist_cur == hist_add_idx)
646 return NULL;
647
648 if (++hist_cur > hist_max)
649 hist_cur = 0;
650
651 if (hist_cur == hist_add_idx) {
652 ret = "";
653 } else
654 ret = hist_list[hist_cur];
655
656 return (ret);
657}
658
659#ifndef CONFIG_CMDLINE_EDITING
660static void cread_print_hist_list(void)
661{
662 int i;
663 unsigned long n;
664
665 n = hist_num - hist_max;
666
667 i = hist_add_idx + 1;
668 while (1) {
669 if (i > hist_max)
670 i = 0;
671 if (i == hist_add_idx)
672 break;
673 printf("%s\n", hist_list[i]);
674 n++;
675 i++;
676 }
677}
678#endif /* CONFIG_CMDLINE_EDITING */
679
680#define BEGINNING_OF_LINE() { \
681 while (num) { \
682 getcmd_putch(CTL_BACKSPACE); \
683 num--; \
684 } \
685}
686
687#define ERASE_TO_EOL() { \
688 if (num < eol_num) { \
689 printf("%*s", (int)(eol_num - num), ""); \
690 do { \
691 getcmd_putch(CTL_BACKSPACE); \
692 } while (--eol_num > num); \
693 } \
694}
695
696#define REFRESH_TO_EOL() { \
697 if (num < eol_num) { \
698 wlen = eol_num - num; \
699 putnstr(buf + num, wlen); \
700 num = eol_num; \
701 } \
702}
703
704static void cread_add_char(char ichar, int insert, unsigned long *num,
705 unsigned long *eol_num, char *buf, unsigned long len)
706{
707 unsigned long wlen;
708
709 /* room ??? */
710 if (insert || *num == *eol_num) {
711 if (*eol_num > len - 1) {
712 getcmd_cbeep();
713 return;
714 }
715 (*eol_num)++;
716 }
717
718 if (insert) {
719 wlen = *eol_num - *num;
720 if (wlen > 1) {
721 memmove(&buf[*num+1], &buf[*num], wlen-1);
722 }
723
724 buf[*num] = ichar;
725 putnstr(buf + *num, wlen);
726 (*num)++;
727 while (--wlen) {
728 getcmd_putch(CTL_BACKSPACE);
729 }
730 } else {
731 /* echo the character */
732 wlen = 1;
733 buf[*num] = ichar;
734 putnstr(buf + *num, wlen);
735 (*num)++;
736 }
737}
738
739static void cread_add_str(char *str, int strsize, int insert, unsigned long *num,
740 unsigned long *eol_num, char *buf, unsigned long len)
741{
742 while (strsize--) {
743 cread_add_char(*str, insert, num, eol_num, buf, len);
744 str++;
745 }
746}
747
748static int cread_line(const char *const prompt, char *buf, unsigned int *len,
749 int timeout)
750{
751 unsigned long num = 0;
752 unsigned long eol_num = 0;
753 unsigned long wlen;
754 char ichar;
755 int insert = 1;
756 int esc_len = 0;
757 char esc_save[8];
758 int init_len = strlen(buf);
759 int first = 1;
760
761 if (init_len)
762 cread_add_str(buf, init_len, 1, &num, &eol_num, buf, *len);
763
764 while (1) {
765#ifdef CONFIG_BOOT_RETRY_TIME
766 while (!tstc()) { /* while no incoming data */
767 if (retry_time >= 0 && get_ticks() > endtime)
768 return (-2); /* timed out */
769 WATCHDOG_RESET();
770 }
771#endif
772 if (first && timeout) {
773 uint64_t etime = endtick(timeout);
774
775 while (!tstc()) { /* while no incoming data */
776 if (get_ticks() >= etime)
777 return -2; /* timed out */
778 WATCHDOG_RESET();
779 }
780 first = 0;
781 }
782
783 ichar = getcmd_getch();
784
785 if ((ichar == '\n') || (ichar == '\r')) {
786 putc('\n');
787 break;
788 }
789
790 /*
791 * handle standard linux xterm esc sequences for arrow key, etc.
792 */
793 if (esc_len != 0) {
794 if (esc_len == 1) {
795 if (ichar == '[') {
796 esc_save[esc_len] = ichar;
797 esc_len = 2;
798 } else {
799 cread_add_str(esc_save, esc_len, insert,
800 &num, &eol_num, buf, *len);
801 esc_len = 0;
802 }
803 continue;
804 }
805
806 switch (ichar) {
807
808 case 'D': /* <- key */
809 ichar = CTL_CH('b');
810 esc_len = 0;
811 break;
812 case 'C': /* -> key */
813 ichar = CTL_CH('f');
814 esc_len = 0;
815 break; /* pass off to ^F handler */
816 case 'H': /* Home key */
817 ichar = CTL_CH('a');
818 esc_len = 0;
819 break; /* pass off to ^A handler */
820 case 'A': /* up arrow */
821 ichar = CTL_CH('p');
822 esc_len = 0;
823 break; /* pass off to ^P handler */
824 case 'B': /* down arrow */
825 ichar = CTL_CH('n');
826 esc_len = 0;
827 break; /* pass off to ^N handler */
828 default:
829 esc_save[esc_len++] = ichar;
830 cread_add_str(esc_save, esc_len, insert,
831 &num, &eol_num, buf, *len);
832 esc_len = 0;
833 continue;
834 }
835 }
836
837 switch (ichar) {
838 case 0x1b:
839 if (esc_len == 0) {
840 esc_save[esc_len] = ichar;
841 esc_len = 1;
842 } else {
843 puts("impossible condition #876\n");
844 esc_len = 0;
845 }
846 break;
847
848 case CTL_CH('a'):
849 BEGINNING_OF_LINE();
850 break;
851 case CTL_CH('c'): /* ^C - break */
852 *buf = '\0'; /* discard input */
853 return (-1);
854 case CTL_CH('f'):
855 if (num < eol_num) {
856 getcmd_putch(buf[num]);
857 num++;
858 }
859 break;
860 case CTL_CH('b'):
861 if (num) {
862 getcmd_putch(CTL_BACKSPACE);
863 num--;
864 }
865 break;
866 case CTL_CH('d'):
867 if (num < eol_num) {
868 wlen = eol_num - num - 1;
869 if (wlen) {
870 memmove(&buf[num], &buf[num+1], wlen);
871 putnstr(buf + num, wlen);
872 }
873
874 getcmd_putch(' ');
875 do {
876 getcmd_putch(CTL_BACKSPACE);
877 } while (wlen--);
878 eol_num--;
879 }
880 break;
881 case CTL_CH('k'):
882 ERASE_TO_EOL();
883 break;
884 case CTL_CH('e'):
885 REFRESH_TO_EOL();
886 break;
887 case CTL_CH('o'):
888 insert = !insert;
889 break;
890 case CTL_CH('x'):
891 case CTL_CH('u'):
892 BEGINNING_OF_LINE();
893 ERASE_TO_EOL();
894 break;
895 case DEL:
896 case DEL7:
897 case 8:
898 if (num) {
899 wlen = eol_num - num;
900 num--;
901 memmove(&buf[num], &buf[num+1], wlen);
902 getcmd_putch(CTL_BACKSPACE);
903 putnstr(buf + num, wlen);
904 getcmd_putch(' ');
905 do {
906 getcmd_putch(CTL_BACKSPACE);
907 } while (wlen--);
908 eol_num--;
909 }
910 break;
911 case CTL_CH('p'):
912 case CTL_CH('n'):
913 {
914 char * hline;
915
916 esc_len = 0;
917
918 if (ichar == CTL_CH('p'))
919 hline = hist_prev();
920 else
921 hline = hist_next();
922
923 if (!hline) {
924 getcmd_cbeep();
925 continue;
926 }
927
928 /* nuke the current line */
929 /* first, go home */
930 BEGINNING_OF_LINE();
931
932 /* erase to end of line */
933 ERASE_TO_EOL();
934
935 /* copy new line into place and display */
936 strcpy(buf, hline);
937 eol_num = strlen(buf);
938 REFRESH_TO_EOL();
939 continue;
940 }
941#ifdef CONFIG_AUTO_COMPLETE
942 case '\t': {
943 int num2, col;
944
945 /* do not autocomplete when in the middle */
946 if (num < eol_num) {
947 getcmd_cbeep();
948 break;
949 }
950
951 buf[num] = '\0';
952 col = strlen(prompt) + eol_num;
953 num2 = num;
954 if (cmd_auto_complete(prompt, buf, &num2, &col)) {
955 col = num2 - num;
956 num += col;
957 eol_num += col;
958 }
959 break;
960 }
961#endif
962 default:
963 cread_add_char(ichar, insert, &num, &eol_num, buf, *len);
964 break;
965 }
966 }
967 *len = eol_num;
968 buf[eol_num] = '\0'; /* lose the newline */
969
970 if (buf[0] && buf[0] != CREAD_HIST_CHAR)
971 cread_add_to_hist(buf);
972 hist_cur = hist_add_idx;
973
974 return 0;
975}
976
977#endif /* CONFIG_CMDLINE_EDITING */
978
979/****************************************************************************/
980
981/*
982 * Prompt for input and read a line.
983 * If CONFIG_BOOT_RETRY_TIME is defined and retry_time >= 0,
984 * time out when time goes past endtime (timebase time in ticks).
985 * Return: number of read characters
986 * -1 if break
987 * -2 if timed out
988 */
989int readline (const char *const prompt)
990{
991 /*
992 * If console_buffer isn't 0-length the user will be prompted to modify
993 * it instead of entering it from scratch as desired.
994 */
995 console_buffer[0] = '\0';
996
997 return readline_into_buffer(prompt, console_buffer, 0);
998}
999
1000
1001int readline_into_buffer(const char *const prompt, char *buffer, int timeout)
1002{
1003 char *p = buffer;
1004#ifdef CONFIG_CMDLINE_EDITING
1005 unsigned int len = CONFIG_SYS_CBSIZE;
1006 int rc;
1007 static int initted = 0;
1008
1009 /*
1010 * History uses a global array which is not
1011 * writable until after relocation to RAM.
1012 * Revert to non-history version if still
1013 * running from flash.
1014 */
1015 if (gd->flags & GD_FLG_RELOC) {
1016 if (!initted) {
1017 hist_init();
1018 initted = 1;
1019 }
1020
1021 if (prompt)
1022 puts (prompt);
1023
1024 rc = cread_line(prompt, p, &len, timeout);
1025 return rc < 0 ? rc : len;
1026
1027 } else {
1028#endif /* CONFIG_CMDLINE_EDITING */
1029 char * p_buf = p;
1030 int n = 0; /* buffer index */
1031 int plen = 0; /* prompt length */
1032 int col; /* output column cnt */
1033 char c;
1034
1035 /* print prompt */
1036 if (prompt) {
1037 plen = strlen (prompt);
1038 puts (prompt);
1039 }
1040 col = plen;
1041
1042 for (;;) {
1043#ifdef CONFIG_BOOT_RETRY_TIME
1044 while (!tstc()) { /* while no incoming data */
1045 if (retry_time >= 0 && get_ticks() > endtime)
1046 return (-2); /* timed out */
1047 WATCHDOG_RESET();
1048 }
1049#endif
1050 WATCHDOG_RESET(); /* Trigger watchdog, if needed */
1051
1052#ifdef CONFIG_SHOW_ACTIVITY
1053 while (!tstc()) {
1054 show_activity(0);
1055 WATCHDOG_RESET();
1056 }
1057#endif
1058 c = getc();
1059
1060 /*
1061 * Special character handling
1062 */
1063 switch (c) {
1064 case '\r': /* Enter */
1065 case '\n':
1066 *p = '\0';
1067 puts ("\r\n");
1068 return p - p_buf;
1069
1070 case '\0': /* nul */
1071 continue;
1072
1073 case 0x03: /* ^C - break */
1074 p_buf[0] = '\0'; /* discard input */
1075 return -1;
1076
1077 case 0x15: /* ^U - erase line */
1078 while (col > plen) {
1079 puts (erase_seq);
1080 --col;
1081 }
1082 p = p_buf;
1083 n = 0;
1084 continue;
1085
1086 case 0x17: /* ^W - erase word */
1087 p=delete_char(p_buf, p, &col, &n, plen);
1088 while ((n > 0) && (*p != ' ')) {
1089 p=delete_char(p_buf, p, &col, &n, plen);
1090 }
1091 continue;
1092
1093 case 0x08: /* ^H - backspace */
1094 case 0x7F: /* DEL - backspace */
1095 p=delete_char(p_buf, p, &col, &n, plen);
1096 continue;
1097
1098 default:
1099 /*
1100 * Must be a normal character then
1101 */
1102 if (n < CONFIG_SYS_CBSIZE-2) {
1103 if (c == '\t') { /* expand TABs */
1104#ifdef CONFIG_AUTO_COMPLETE
1105 /* if auto completion triggered just continue */
1106 *p = '\0';
1107 if (cmd_auto_complete(prompt, console_buffer, &n, &col)) {
1108 p = p_buf + n; /* reset */
1109 continue;
1110 }
1111#endif
1112 puts (tab_seq+(col&07));
1113 col += 8 - (col&07);
1114 } else {
1115 char buf[2];
1116
1117 /*
1118 * Echo input using puts() to force an
1119 * LCD flush if we are using an LCD
1120 */
1121 ++col;
1122 buf[0] = c;
1123 buf[1] = '\0';
1124 puts(buf);
1125 }
1126 *p++ = c;
1127 ++n;
1128 } else { /* Buffer full */
1129 putc ('\a');
1130 }
1131 }
1132 }
1133#ifdef CONFIG_CMDLINE_EDITING
1134 }
1135#endif
1136}
1137
1138/****************************************************************************/
1139
1140static char * delete_char (char *buffer, char *p, int *colp, int *np, int plen)
1141{
1142 char *s;
1143
1144 if (*np == 0) {
1145 return (p);
1146 }
1147
1148 if (*(--p) == '\t') { /* will retype the whole line */
1149 while (*colp > plen) {
1150 puts (erase_seq);
1151 (*colp)--;
1152 }
1153 for (s=buffer; s<p; ++s) {
1154 if (*s == '\t') {
1155 puts (tab_seq+((*colp) & 07));
1156 *colp += 8 - ((*colp) & 07);
1157 } else {
1158 ++(*colp);
1159 putc (*s);
1160 }
1161 }
1162 } else {
1163 puts (erase_seq);
1164 (*colp)--;
1165 }
1166 (*np)--;
1167 return (p);
1168}
1169
1170/****************************************************************************/
1171
1172int parse_line (char *line, char *argv[])
1173{
1174 int nargs = 0;
1175
1176 debug_parser("parse_line: \"%s\"\n", line);
1177 while (nargs < CONFIG_SYS_MAXARGS) {
1178
1179 /* skip any white space */
1180 while (isblank(*line))
1181 ++line;
1182
1183 if (*line == '\0') { /* end of line, no more args */
1184 argv[nargs] = NULL;
1185 debug_parser("parse_line: nargs=%d\n", nargs);
1186 return nargs;
1187 }
1188
1189 argv[nargs++] = line; /* begin of argument string */
1190
1191 /* find end of string */
1192 while (*line && !isblank(*line))
1193 ++line;
1194
1195 if (*line == '\0') { /* end of line, no more args */
1196 argv[nargs] = NULL;
1197 debug_parser("parse_line: nargs=%d\n", nargs);
1198 return nargs;
1199 }
1200
1201 *line++ = '\0'; /* terminate current arg */
1202 }
1203
1204 printf ("** Too many args (max. %d) **\n", CONFIG_SYS_MAXARGS);
1205
1206 debug_parser("parse_line: nargs=%d\n", nargs);
1207 return (nargs);
1208}
1209
1210/****************************************************************************/
1211
1212#ifndef CONFIG_SYS_HUSH_PARSER
1213static void process_macros (const char *input, char *output)
1214{
1215 char c, prev;
1216 const char *varname_start = NULL;
1217 int inputcnt = strlen (input);
1218 int outputcnt = CONFIG_SYS_CBSIZE;
1219 int state = 0; /* 0 = waiting for '$' */
1220
1221 /* 1 = waiting for '(' or '{' */
1222 /* 2 = waiting for ')' or '}' */
1223 /* 3 = waiting for ''' */
1224 char *output_start = output;
1225
1226 debug_parser("[PROCESS_MACROS] INPUT len %zd: \"%s\"\n", strlen(input),
1227 input);
1228
1229 prev = '\0'; /* previous character */
1230
1231 while (inputcnt && outputcnt) {
1232 c = *input++;
1233 inputcnt--;
1234
1235 if (state != 3) {
1236 /* remove one level of escape characters */
1237 if ((c == '\\') && (prev != '\\')) {
1238 if (inputcnt-- == 0)
1239 break;
1240 prev = c;
1241 c = *input++;
1242 }
1243 }
1244
1245 switch (state) {
1246 case 0: /* Waiting for (unescaped) $ */
1247 if ((c == '\'') && (prev != '\\')) {
1248 state = 3;
1249 break;
1250 }
1251 if ((c == '$') && (prev != '\\')) {
1252 state++;
1253 } else {
1254 *(output++) = c;
1255 outputcnt--;
1256 }
1257 break;
1258 case 1: /* Waiting for ( */
1259 if (c == '(' || c == '{') {
1260 state++;
1261 varname_start = input;
1262 } else {
1263 state = 0;
1264 *(output++) = '$';
1265 outputcnt--;
1266
1267 if (outputcnt) {
1268 *(output++) = c;
1269 outputcnt--;
1270 }
1271 }
1272 break;
1273 case 2: /* Waiting for ) */
1274 if (c == ')' || c == '}') {
1275 int i;
1276 char envname[CONFIG_SYS_CBSIZE], *envval;
1277 int envcnt = input - varname_start - 1; /* Varname # of chars */
1278
1279 /* Get the varname */
1280 for (i = 0; i < envcnt; i++) {
1281 envname[i] = varname_start[i];
1282 }
1283 envname[i] = 0;
1284
1285 /* Get its value */
1286 envval = getenv (envname);
1287
1288 /* Copy into the line if it exists */
1289 if (envval != NULL)
1290 while ((*envval) && outputcnt) {
1291 *(output++) = *(envval++);
1292 outputcnt--;
1293 }
1294 /* Look for another '$' */
1295 state = 0;
1296 }
1297 break;
1298 case 3: /* Waiting for ' */
1299 if ((c == '\'') && (prev != '\\')) {
1300 state = 0;
1301 } else {
1302 *(output++) = c;
1303 outputcnt--;
1304 }
1305 break;
1306 }
1307 prev = c;
1308 }
1309
1310 if (outputcnt)
1311 *output = 0;
1312 else
1313 *(output - 1) = 0;
1314
1315 debug_parser("[PROCESS_MACROS] OUTPUT len %zd: \"%s\"\n",
1316 strlen(output_start), output_start);
1317}
1318
1319/****************************************************************************
1320 * returns:
1321 * 1 - command executed, repeatable
1322 * 0 - command executed but not repeatable, interrupted commands are
1323 * always considered not repeatable
1324 * -1 - not executed (unrecognized, bootd recursion or too many args)
1325 * (If cmd is NULL or "" or longer than CONFIG_SYS_CBSIZE-1 it is
1326 * considered unrecognized)
1327 *
1328 * WARNING:
1329 *
1330 * We must create a temporary copy of the command since the command we get
1331 * may be the result from getenv(), which returns a pointer directly to
1332 * the environment data, which may change magicly when the command we run
1333 * creates or modifies environment variables (like "bootp" does).
1334 */
1335static int builtin_run_command(const char *cmd, int flag)
1336{
1337 char cmdbuf[CONFIG_SYS_CBSIZE]; /* working copy of cmd */
1338 char *token; /* start of token in cmdbuf */
1339 char *sep; /* end of token (separator) in cmdbuf */
1340 char finaltoken[CONFIG_SYS_CBSIZE];
1341 char *str = cmdbuf;
1342 char *argv[CONFIG_SYS_MAXARGS + 1]; /* NULL terminated */
1343 int argc, inquotes;
1344 int repeatable = 1;
1345 int rc = 0;
1346
1347 debug_parser("[RUN_COMMAND] cmd[%p]=\"", cmd);
1348 if (DEBUG_PARSER) {
1349 /* use puts - string may be loooong */
1350 puts(cmd ? cmd : "NULL");
1351 puts("\"\n");
1352 }
1353 clear_ctrlc(); /* forget any previous Control C */
1354
1355 if (!cmd || !*cmd) {
1356 return -1; /* empty command */
1357 }
1358
1359 if (strlen(cmd) >= CONFIG_SYS_CBSIZE) {
1360 puts ("## Command too long!\n");
1361 return -1;
1362 }
1363
1364 strcpy (cmdbuf, cmd);
1365
1366 /* Process separators and check for invalid
1367 * repeatable commands
1368 */
1369
1370 debug_parser("[PROCESS_SEPARATORS] %s\n", cmd);
1371 while (*str) {
1372
1373 /*
1374 * Find separator, or string end
1375 * Allow simple escape of ';' by writing "\;"
1376 */
1377 for (inquotes = 0, sep = str; *sep; sep++) {
1378 if ((*sep=='\'') &&
1379 (*(sep-1) != '\\'))
1380 inquotes=!inquotes;
1381
1382 if (!inquotes &&
1383 (*sep == ';') && /* separator */
1384 ( sep != str) && /* past string start */
1385 (*(sep-1) != '\\')) /* and NOT escaped */
1386 break;
1387 }
1388
1389 /*
1390 * Limit the token to data between separators
1391 */
1392 token = str;
1393 if (*sep) {
1394 str = sep + 1; /* start of command for next pass */
1395 *sep = '\0';
1396 }
1397 else
1398 str = sep; /* no more commands for next pass */
1399 debug_parser("token: \"%s\"\n", token);
1400
1401 /* find macros in this token and replace them */
1402 process_macros (token, finaltoken);
1403
1404 /* Extract arguments */
1405 if ((argc = parse_line (finaltoken, argv)) == 0) {
1406 rc = -1; /* no command at all */
1407 continue;
1408 }
1409
1410 if (cmd_process(flag, argc, argv, &repeatable, NULL))
1411 rc = -1;
1412
1413 /* Did the user stop this? */
1414 if (had_ctrlc ())
1415 return -1; /* if stopped then not repeatable */
1416 }
1417
1418 return rc ? rc : repeatable;
1419}
1420#endif
1421
1422/*
1423 * Run a command using the selected parser.
1424 *
1425 * @param cmd Command to run
1426 * @param flag Execution flags (CMD_FLAG_...)
1427 * @return 0 on success, or != 0 on error.
1428 */
1429int run_command(const char *cmd, int flag)
1430{
1431#ifndef CONFIG_SYS_HUSH_PARSER
1432 /*
1433 * builtin_run_command can return 0 or 1 for success, so clean up
1434 * its result.
1435 */
1436 if (builtin_run_command(cmd, flag) == -1)
1437 return 1;
1438
1439 return 0;
1440#else
1441 return parse_string_outer(cmd,
1442 FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP);
1443#endif
1444}
1445
1446#ifndef CONFIG_SYS_HUSH_PARSER
1447/**
1448 * Execute a list of command separated by ; or \n using the built-in parser.
1449 *
1450 * This function cannot take a const char * for the command, since if it
1451 * finds newlines in the string, it replaces them with \0.
1452 *
1453 * @param cmd String containing list of commands
1454 * @param flag Execution flags (CMD_FLAG_...)
1455 * @return 0 on success, or != 0 on error.
1456 */
1457static int builtin_run_command_list(char *cmd, int flag)
1458{
1459 char *line, *next;
1460 int rcode = 0;
1461
1462 /*
1463 * Break into individual lines, and execute each line; terminate on
1464 * error.
1465 */
1466 line = next = cmd;
1467 while (*next) {
1468 if (*next == '\n') {
1469 *next = '\0';
1470 /* run only non-empty commands */
1471 if (*line) {
1472 debug("** exec: \"%s\"\n", line);
1473 if (builtin_run_command(line, 0) < 0) {
1474 rcode = 1;
1475 break;
1476 }
1477 }
1478 line = next + 1;
1479 }
1480 ++next;
1481 }
1482 if (rcode == 0 && *line)
1483 rcode = (builtin_run_command(line, 0) >= 0);
1484
1485 return rcode;
1486}
1487#endif
1488
1489int run_command_list(const char *cmd, int len, int flag)
1490{
1491 int need_buff = 1;
1492 char *buff = (char *)cmd; /* cast away const */
1493 int rcode = 0;
1494
1495 if (len == -1) {
1496 len = strlen(cmd);
1497#ifdef CONFIG_SYS_HUSH_PARSER
1498 /* hush will never change our string */
1499 need_buff = 0;
1500#else
1501 /* the built-in parser will change our string if it sees \n */
1502 need_buff = strchr(cmd, '\n') != NULL;
1503#endif
1504 }
1505 if (need_buff) {
1506 buff = malloc(len + 1);
1507 if (!buff)
1508 return 1;
1509 memcpy(buff, cmd, len);
1510 buff[len] = '\0';
1511 }
1512#ifdef CONFIG_SYS_HUSH_PARSER
1513 rcode = parse_string_outer(buff, FLAG_PARSE_SEMICOLON);
1514#else
1515 /*
1516 * This function will overwrite any \n it sees with a \0, which
1517 * is why it can't work with a const char *. Here we are making
1518 * using of internal knowledge of this function, to avoid always
1519 * doing a malloc() which is actually required only in a case that
1520 * is pretty rare.
1521 */
1522 rcode = builtin_run_command_list(buff, flag);
1523 if (need_buff)
1524 free(buff);
1525#endif
1526
1527 return rcode;
1528}
1529
1530/****************************************************************************/
1531
1532#if defined(CONFIG_CMD_RUN)
1533int do_run (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
1534{
1535 int i;
1536
1537 if (argc < 2)
1538 return CMD_RET_USAGE;
1539
1540 for (i=1; i<argc; ++i) {
1541 char *arg;
1542
1543 if ((arg = getenv (argv[i])) == NULL) {
1544 printf ("## Error: \"%s\" not defined\n", argv[i]);
1545 return 1;
1546 }
1547
1548 if (run_command(arg, flag) != 0)
1549 return 1;
1550 }
1551 return 0;
1552}
1553#endif