blob: 6d1c3a9fadb0da00f93541464beabd5a7db8b41c [file] [log] [blame]
wdenkc6097192002-11-03 00:24:07 +00001/*
2 * (C) Copyright 2000
3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4 *
Wolfgang Denk501090a2006-07-21 11:33:45 +02005 * Add to readline cmdline-editing by
6 * (C) Copyright 2005
7 * JinHua Luo, GuangDong Linux Center, <luo.jinhua@gd-linux.com>
8 *
Wolfgang Denk1a459662013-07-08 09:37:19 +02009 * SPDX-License-Identifier: GPL-2.0+
wdenkc6097192002-11-03 00:24:07 +000010 */
11
wdenka6c7ad22002-12-03 21:28:10 +000012/* #define DEBUG */
13
wdenkc6097192002-11-03 00:24:07 +000014#include <common.h>
Simon Glass18d66532014-04-10 20:01:25 -060015#include <cli.h>
wdenkc6097192002-11-03 00:24:07 +000016#include <command.h>
Che-Liang Chiou224b72e2012-10-25 16:31:07 +000017#include <fdtdec.h>
Simon Glasseca86fa2014-04-10 20:01:24 -060018#include <cli_hush.h>
Simon Glassfbcdf322013-05-15 06:23:59 +000019#include <malloc.h>
Heiko Schocher317d6c52012-01-16 21:13:35 +000020#include <menu.h>
Simon Glassfbcdf322013-05-15 06:23:59 +000021#include <post.h>
22#include <version.h>
23#include <watchdog.h>
24#include <linux/ctype.h>
wdenkbdccc4f2003-08-05 17:43:17 +000025
Wolfgang Denkd87080b2006-03-31 18:32:53 +020026DECLARE_GLOBAL_DATA_PTR;
Wolfgang Denkd87080b2006-03-31 18:32:53 +020027
Heiko Schocherfad63402007-07-13 09:54:17 +020028/*
29 * Board-specific Platform code can reimplement show_boot_progress () if needed
30 */
31void inline __show_boot_progress (int val) {}
Emil Medve5e2c08c2009-05-12 13:48:32 -050032void show_boot_progress (int val) __attribute__((weak, alias("__show_boot_progress")));
Heiko Schocherfad63402007-07-13 09:54:17 +020033
wdenkc6097192002-11-03 00:24:07 +000034#define MAX_DELAY_STOP_STR 32
35
Simon Glass3e408872013-05-15 06:24:00 +000036#define DEBUG_PARSER 0 /* set to 1 to debug */
37
38#define debug_parser(fmt, args...) \
39 debug_cond(DEBUG_PARSER, fmt, ##args)
40
Simon Glassd34d1862013-05-15 06:24:01 +000041#ifndef DEBUG_BOOTKEYS
42#define DEBUG_BOOTKEYS 0
43#endif
44#define debug_bootkeys(fmt, args...) \
45 debug_cond(DEBUG_BOOTKEYS, fmt, ##args)
wdenkc6097192002-11-03 00:24:07 +000046
John Schmoller6475b9f2010-03-12 09:49:23 -060047char console_buffer[CONFIG_SYS_CBSIZE + 1]; /* console I/O buffer */
wdenkc6097192002-11-03 00:24:07 +000048
Stefan Roese3ca91222006-07-27 16:11:19 +020049static char * delete_char (char *buffer, char *p, int *colp, int *np, int plen);
Mike Frysinger82359ae2010-12-22 09:40:45 -050050static const char erase_seq[] = "\b \b"; /* erase sequence */
51static const char tab_seq[] = " "; /* used to expand TABs */
wdenkc6097192002-11-03 00:24:07 +000052
53#ifdef CONFIG_BOOT_RETRY_TIME
54static uint64_t endtime = 0; /* must be set, default is instant timeout */
55static int retry_time = -1; /* -1 so can call readline before main_loop */
56#endif
57
58#define endtick(seconds) (get_ticks() + (uint64_t)(seconds) * get_tbclk())
59
60#ifndef CONFIG_BOOT_RETRY_MIN
61#define CONFIG_BOOT_RETRY_MIN CONFIG_BOOT_RETRY_TIME
62#endif
63
64#ifdef CONFIG_MODEM_SUPPORT
65int do_mdm_init = 0;
66extern void mdm_init(void); /* defined in board.c */
67#endif
68
69/***************************************************************************
70 * Watch for 'delay' seconds for autoboot stop or autoboot delay string.
Jason Hobbsc8a20792011-08-31 05:37:24 +000071 * returns: 0 - no key string, allow autoboot 1 - got key string, abort
wdenkc6097192002-11-03 00:24:07 +000072 */
Joe Hershbergerd5145442013-02-08 10:28:00 +000073#if defined(CONFIG_BOOTDELAY)
wdenkc6097192002-11-03 00:24:07 +000074# if defined(CONFIG_AUTOBOOT_KEYED)
Simon Glass063ae002013-05-15 06:23:55 +000075static int abortboot_keyed(int bootdelay)
wdenkc6097192002-11-03 00:24:07 +000076{
77 int abort = 0;
78 uint64_t etime = endtick(bootdelay);
Wolfgang Denk19973b62006-10-28 00:38:39 +020079 struct {
wdenkc6097192002-11-03 00:24:07 +000080 char* str;
81 u_int len;
82 int retry;
83 }
Wolfgang Denk19973b62006-10-28 00:38:39 +020084 delaykey [] = {
wdenkc6097192002-11-03 00:24:07 +000085 { str: getenv ("bootdelaykey"), retry: 1 },
86 { str: getenv ("bootdelaykey2"), retry: 1 },
87 { str: getenv ("bootstopkey"), retry: 0 },
88 { str: getenv ("bootstopkey2"), retry: 0 },
89 };
90
91 char presskey [MAX_DELAY_STOP_STR];
92 u_int presskey_len = 0;
93 u_int presskey_max = 0;
94 u_int i;
95
Dirk Eibacha5aae0a2012-04-26 01:49:33 +000096#ifndef CONFIG_ZERO_BOOTDELAY_CHECK
97 if (bootdelay == 0)
98 return 0;
99#endif
100
wdenkc6097192002-11-03 00:24:07 +0000101# ifdef CONFIG_AUTOBOOT_PROMPT
Stefan Roesef2302d42008-08-06 14:05:38 +0200102 printf(CONFIG_AUTOBOOT_PROMPT);
wdenkc6097192002-11-03 00:24:07 +0000103# endif
104
105# ifdef CONFIG_AUTOBOOT_DELAY_STR
106 if (delaykey[0].str == NULL)
107 delaykey[0].str = CONFIG_AUTOBOOT_DELAY_STR;
108# endif
109# ifdef CONFIG_AUTOBOOT_DELAY_STR2
110 if (delaykey[1].str == NULL)
111 delaykey[1].str = CONFIG_AUTOBOOT_DELAY_STR2;
112# endif
113# ifdef CONFIG_AUTOBOOT_STOP_STR
114 if (delaykey[2].str == NULL)
115 delaykey[2].str = CONFIG_AUTOBOOT_STOP_STR;
116# endif
117# ifdef CONFIG_AUTOBOOT_STOP_STR2
118 if (delaykey[3].str == NULL)
119 delaykey[3].str = CONFIG_AUTOBOOT_STOP_STR2;
120# endif
121
122 for (i = 0; i < sizeof(delaykey) / sizeof(delaykey[0]); i ++) {
123 delaykey[i].len = delaykey[i].str == NULL ?
124 0 : strlen (delaykey[i].str);
125 delaykey[i].len = delaykey[i].len > MAX_DELAY_STOP_STR ?
126 MAX_DELAY_STOP_STR : delaykey[i].len;
127
128 presskey_max = presskey_max > delaykey[i].len ?
129 presskey_max : delaykey[i].len;
130
Simon Glassd34d1862013-05-15 06:24:01 +0000131 debug_bootkeys("%s key:<%s>\n",
132 delaykey[i].retry ? "delay" : "stop",
133 delaykey[i].str ? delaykey[i].str : "NULL");
wdenkc6097192002-11-03 00:24:07 +0000134 }
135
136 /* In order to keep up with incoming data, check timeout only
137 * when catch up.
138 */
Peter Korsgaardc3284b02008-12-10 16:24:16 +0100139 do {
140 if (tstc()) {
141 if (presskey_len < presskey_max) {
142 presskey [presskey_len ++] = getc();
143 }
144 else {
145 for (i = 0; i < presskey_max - 1; i ++)
146 presskey [i] = presskey [i + 1];
147
148 presskey [i] = getc();
149 }
150 }
151
wdenkc6097192002-11-03 00:24:07 +0000152 for (i = 0; i < sizeof(delaykey) / sizeof(delaykey[0]); i ++) {
153 if (delaykey[i].len > 0 &&
154 presskey_len >= delaykey[i].len &&
155 memcmp (presskey + presskey_len - delaykey[i].len,
wdenk8bde7f72003-06-27 21:31:46 +0000156 delaykey[i].str,
wdenkc6097192002-11-03 00:24:07 +0000157 delaykey[i].len) == 0) {
Simon Glassd34d1862013-05-15 06:24:01 +0000158 debug_bootkeys("got %skey\n",
159 delaykey[i].retry ? "delay" :
160 "stop");
wdenkc6097192002-11-03 00:24:07 +0000161
162# ifdef CONFIG_BOOT_RETRY_TIME
163 /* don't retry auto boot */
164 if (! delaykey[i].retry)
165 retry_time = -1;
166# endif
167 abort = 1;
168 }
169 }
Peter Korsgaardc3284b02008-12-10 16:24:16 +0100170 } while (!abort && get_ticks() <= etime);
wdenkc6097192002-11-03 00:24:07 +0000171
wdenkc6097192002-11-03 00:24:07 +0000172 if (!abort)
Simon Glassd34d1862013-05-15 06:24:01 +0000173 debug_bootkeys("key timeout\n");
wdenkc6097192002-11-03 00:24:07 +0000174
dzu8cb81432003-10-24 13:14:45 +0000175#ifdef CONFIG_SILENT_CONSOLE
Ladislav Michl4ec5bd52007-04-25 16:01:26 +0200176 if (abort)
177 gd->flags &= ~GD_FLG_SILENT;
dzu8cb81432003-10-24 13:14:45 +0000178#endif
179
wdenkc6097192002-11-03 00:24:07 +0000180 return abort;
181}
182
183# else /* !defined(CONFIG_AUTOBOOT_KEYED) */
184
wdenkc7de8292002-11-19 11:04:11 +0000185#ifdef CONFIG_MENUKEY
186static int menukey = 0;
187#endif
188
Simon Glass063ae002013-05-15 06:23:55 +0000189static int abortboot_normal(int bootdelay)
wdenkc6097192002-11-03 00:24:07 +0000190{
191 int abort = 0;
Jim Linb2f3e0e2013-01-24 01:05:55 +0000192 unsigned long ts;
wdenkc6097192002-11-03 00:24:07 +0000193
wdenkc7de8292002-11-19 11:04:11 +0000194#ifdef CONFIG_MENUPROMPT
Stefan Roesef2302d42008-08-06 14:05:38 +0200195 printf(CONFIG_MENUPROMPT);
wdenkc7de8292002-11-19 11:04:11 +0000196#else
Joe Hershberger93d72122012-08-17 10:53:12 +0000197 if (bootdelay >= 0)
198 printf("Hit any key to stop autoboot: %2d ", bootdelay);
wdenkc7de8292002-11-19 11:04:11 +0000199#endif
wdenkc6097192002-11-03 00:24:07 +0000200
201#if defined CONFIG_ZERO_BOOTDELAY_CHECK
wdenk8bde7f72003-06-27 21:31:46 +0000202 /*
203 * Check if key already pressed
204 * Don't check if bootdelay < 0
205 */
wdenkc6097192002-11-03 00:24:07 +0000206 if (bootdelay >= 0) {
207 if (tstc()) { /* we got a key press */
208 (void) getc(); /* consume input */
wdenk4b9206e2004-03-23 22:14:11 +0000209 puts ("\b\b\b 0");
Ladislav Michl4ec5bd52007-04-25 16:01:26 +0200210 abort = 1; /* don't auto boot */
wdenkc6097192002-11-03 00:24:07 +0000211 }
wdenk8bde7f72003-06-27 21:31:46 +0000212 }
wdenkc6097192002-11-03 00:24:07 +0000213#endif
214
wdenkf72da342003-10-10 10:05:42 +0000215 while ((bootdelay > 0) && (!abort)) {
wdenkc6097192002-11-03 00:24:07 +0000216 --bootdelay;
Jim Linb2f3e0e2013-01-24 01:05:55 +0000217 /* delay 1000 ms */
218 ts = get_timer(0);
219 do {
wdenkc6097192002-11-03 00:24:07 +0000220 if (tstc()) { /* we got a key press */
221 abort = 1; /* don't auto boot */
222 bootdelay = 0; /* no more delay */
wdenkc7de8292002-11-19 11:04:11 +0000223# ifdef CONFIG_MENUKEY
224 menukey = getc();
225# else
wdenkc6097192002-11-03 00:24:07 +0000226 (void) getc(); /* consume input */
wdenkc7de8292002-11-19 11:04:11 +0000227# endif
wdenkc6097192002-11-03 00:24:07 +0000228 break;
229 }
Ladislav Michlada4d402007-04-25 16:01:26 +0200230 udelay(10000);
Jim Linb2f3e0e2013-01-24 01:05:55 +0000231 } while (!abort && get_timer(ts) < 1000);
wdenkc6097192002-11-03 00:24:07 +0000232
Ladislav Michlada4d402007-04-25 16:01:26 +0200233 printf("\b\b\b%2d ", bootdelay);
wdenkc6097192002-11-03 00:24:07 +0000234 }
235
Ladislav Michlada4d402007-04-25 16:01:26 +0200236 putc('\n');
wdenkc6097192002-11-03 00:24:07 +0000237
wdenkf72da342003-10-10 10:05:42 +0000238#ifdef CONFIG_SILENT_CONSOLE
Ladislav Michl4ec5bd52007-04-25 16:01:26 +0200239 if (abort)
240 gd->flags &= ~GD_FLG_SILENT;
wdenkf72da342003-10-10 10:05:42 +0000241#endif
242
wdenkc6097192002-11-03 00:24:07 +0000243 return abort;
244}
245# endif /* CONFIG_AUTOBOOT_KEYED */
Simon Glass063ae002013-05-15 06:23:55 +0000246
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}
Joe Hershbergerd5145442013-02-08 10:28:00 +0000255#endif /* CONFIG_BOOTDELAY */
wdenkc6097192002-11-03 00:24:07 +0000256
Doug Anderson67e1ea22012-10-25 16:31:09 +0000257/*
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
Joe Hershbergerd5145442013-02-08 10:28:00 +0000271#if defined(CONFIG_BOOTDELAY) && defined(CONFIG_OF_CONTROL)
Doug Anderson67e1ea22012-10-25 16:31:09 +0000272static 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
Simon Glassfcabc242012-10-25 16:31:11 +0000306static 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}
Doug Anderson67e1ea22012-10-25 16:31:09 +0000320#endif /* CONFIG_OF_CONTROL */
321
Simon Glassbc2b4c22013-05-15 06:23:56 +0000322#ifdef CONFIG_BOOTDELAY
323static void process_boot_delay(void)
wdenkc6097192002-11-03 00:24:07 +0000324{
Simon Glassbc2b4c22013-05-15 06:23:56 +0000325#ifdef CONFIG_OF_CONTROL
Che-Liang Chiou224b72e2012-10-25 16:31:07 +0000326 char *env;
327#endif
wdenkc6097192002-11-03 00:24:07 +0000328 char *s;
329 int bootdelay;
wdenkbdccc4f2003-08-05 17:43:17 +0000330#ifdef CONFIG_BOOTCOUNT_LIMIT
331 unsigned long bootcount = 0;
332 unsigned long bootlimit = 0;
wdenkbdccc4f2003-08-05 17:43:17 +0000333#endif /* CONFIG_BOOTCOUNT_LIMIT */
wdenkc6097192002-11-03 00:24:07 +0000334
wdenkbdccc4f2003-08-05 17:43:17 +0000335#ifdef CONFIG_BOOTCOUNT_LIMIT
336 bootcount = bootcount_load();
337 bootcount++;
338 bootcount_store (bootcount);
Simon Glassf2abca82013-05-15 06:23:57 +0000339 setenv_ulong("bootcount", bootcount);
340 bootlimit = getenv_ulong("bootlimit", 10, 0);
wdenkbdccc4f2003-08-05 17:43:17 +0000341#endif /* CONFIG_BOOTCOUNT_LIMIT */
342
wdenkc6097192002-11-03 00:24:07 +0000343 s = getenv ("bootdelay");
344 bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;
345
Stephen Warren99bd5442013-05-14 08:02:56 +0000346#ifdef CONFIG_OF_CONTROL
347 bootdelay = fdtdec_get_config_int(gd->fdt_blob, "bootdelay",
348 bootdelay);
349#endif
350
wdenka6c7ad22002-12-03 21:28:10 +0000351 debug ("### main_loop entered: bootdelay=%d\n\n", bootdelay);
wdenkc6097192002-11-03 00:24:07 +0000352
Heiko Schocher317d6c52012-01-16 21:13:35 +0000353#if defined(CONFIG_MENU_SHOW)
354 bootdelay = menu_show(bootdelay);
355#endif
wdenkc6097192002-11-03 00:24:07 +0000356# ifdef CONFIG_BOOT_RETRY_TIME
wdenk6dd652f2003-06-19 23:40:20 +0000357 init_cmd_timeout ();
wdenkc6097192002-11-03 00:24:07 +0000358# endif /* CONFIG_BOOT_RETRY_TIME */
359
Yuri Tikhonovb428f6a2008-02-04 14:11:03 +0100360#ifdef CONFIG_POST
361 if (gd->flags & GD_FLG_POSTFAIL) {
362 s = getenv("failbootcmd");
363 }
364 else
365#endif /* CONFIG_POST */
wdenkbdccc4f2003-08-05 17:43:17 +0000366#ifdef CONFIG_BOOTCOUNT_LIMIT
367 if (bootlimit && (bootcount > bootlimit)) {
368 printf ("Warning: Bootlimit (%u) exceeded. Using altbootcmd.\n",
Wolfgang Denk93e14592013-10-04 17:43:24 +0200369 (unsigned)bootlimit);
wdenkbdccc4f2003-08-05 17:43:17 +0000370 s = getenv ("altbootcmd");
371 }
372 else
373#endif /* CONFIG_BOOTCOUNT_LIMIT */
374 s = getenv ("bootcmd");
Che-Liang Chiou224b72e2012-10-25 16:31:07 +0000375#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;
Doug Anderson67e1ea22012-10-25 16:31:09 +0000380
Simon Glassfcabc242012-10-25 16:31:11 +0000381 process_fdt_options(gd->fdt_blob);
382
Doug Anderson67e1ea22012-10-25 16:31:09 +0000383 /*
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
Che-Liang Chiou224b72e2012-10-25 16:31:07 +0000391#endif /* CONFIG_OF_CONTROL */
wdenka6c7ad22002-12-03 21:28:10 +0000392
393 debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>");
394
Joe Hershberger93d72122012-08-17 10:53:12 +0000395 if (bootdelay != -1 && s && !abortboot(bootdelay)) {
Mark Langsdorf00ddacc2013-09-10 15:20:23 -0500396#if defined(CONFIG_AUTOBOOT_KEYED) && !defined(CONFIG_AUTOBOOT_KEYED_CTRLC)
wdenkc6097192002-11-03 00:24:07 +0000397 int prev = disable_ctrlc(1); /* disable Control C checking */
Simon Glassbc2b4c22013-05-15 06:23:56 +0000398#endif
wdenkc6097192002-11-03 00:24:07 +0000399
Simon Glass3a8a02b2012-03-30 21:30:56 +0000400 run_command_list(s, -1, 0);
wdenkc6097192002-11-03 00:24:07 +0000401
Mark Langsdorf00ddacc2013-09-10 15:20:23 -0500402#if defined(CONFIG_AUTOBOOT_KEYED) && !defined(CONFIG_AUTOBOOT_KEYED_CTRLC)
wdenkc6097192002-11-03 00:24:07 +0000403 disable_ctrlc(prev); /* restore Control C checking */
Simon Glassbc2b4c22013-05-15 06:23:56 +0000404#endif
wdenkc6097192002-11-03 00:24:07 +0000405 }
wdenkc7de8292002-11-19 11:04:11 +0000406
Simon Glassbc2b4c22013-05-15 06:23:56 +0000407#ifdef CONFIG_MENUKEY
wdenka6c7ad22002-12-03 21:28:10 +0000408 if (menukey == CONFIG_MENUKEY) {
Jason Hobbs370d1e32011-06-23 08:27:30 +0000409 s = getenv("menucmd");
Jason Hobbsc8a20792011-08-31 05:37:24 +0000410 if (s)
Simon Glass3a8a02b2012-03-30 21:30:56 +0000411 run_command_list(s, -1, 0);
wdenkc7de8292002-11-19 11:04:11 +0000412 }
413#endif /* CONFIG_MENUKEY */
Simon Glassbc2b4c22013-05-15 06:23:56 +0000414}
Wolfgang Denk953b7e62010-06-13 18:28:54 +0200415#endif /* CONFIG_BOOTDELAY */
wdenkc7de8292002-11-19 11:04:11 +0000416
Simon Glassbc2b4c22013-05-15 06:23:56 +0000417void 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
Simon Glass0f605c12014-03-22 17:14:51 -0600431#ifndef CONFIG_SYS_GENERIC_BOARD
432 puts("Warning: Your board does not use generic board. Please read\n");
433 puts("doc/README.generic-board and take action. Boards not\n");
434 puts("upgraded by the late 2014 may break or be removed.\n");
435#endif
436
Simon Glassbc2b4c22013-05-15 06:23:56 +0000437#ifdef CONFIG_MODEM_SUPPORT
438 debug("DEBUG: main_loop: do_mdm_init=%d\n", do_mdm_init);
439 if (do_mdm_init) {
440 char *str = strdup(getenv("mdm_cmd"));
441 setenv("preboot", str); /* set or delete definition */
442 if (str != NULL)
443 free(str);
444 mdm_init(); /* wait for modem connection */
445 }
446#endif /* CONFIG_MODEM_SUPPORT */
447
448#ifdef CONFIG_VERSION_VARIABLE
449 {
450 setenv("ver", version_string); /* set version variable */
451 }
452#endif /* CONFIG_VERSION_VARIABLE */
453
454#ifdef CONFIG_SYS_HUSH_PARSER
455 u_boot_hush_start();
456#endif
457
458#if defined(CONFIG_HUSH_INIT_VAR)
459 hush_init_var();
460#endif
461
462#ifdef CONFIG_PREBOOT
463 p = getenv("preboot");
464 if (p != NULL) {
465# ifdef CONFIG_AUTOBOOT_KEYED
466 int prev = disable_ctrlc(1); /* disable Control C checking */
467# endif
468
469 run_command_list(p, -1, 0);
470
471# ifdef CONFIG_AUTOBOOT_KEYED
472 disable_ctrlc(prev); /* restore Control C checking */
473# endif
474 }
475#endif /* CONFIG_PREBOOT */
476
477#if defined(CONFIG_UPDATE_TFTP)
478 update_tftp(0UL);
479#endif /* CONFIG_UPDATE_TFTP */
480
481#ifdef CONFIG_BOOTDELAY
482 process_boot_delay();
483#endif
wdenkc6097192002-11-03 00:24:07 +0000484 /*
485 * Main Loop for Monitor Command Processing
486 */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200487#ifdef CONFIG_SYS_HUSH_PARSER
wdenkc6097192002-11-03 00:24:07 +0000488 parse_file_outer();
489 /* This point is never reached */
490 for (;;);
491#else
492 for (;;) {
493#ifdef CONFIG_BOOT_RETRY_TIME
494 if (rc >= 0) {
495 /* Saw enough of a valid command to
496 * restart the timeout.
497 */
498 reset_cmd_timeout();
499 }
500#endif
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200501 len = readline (CONFIG_SYS_PROMPT);
wdenkc6097192002-11-03 00:24:07 +0000502
503 flag = 0; /* assume no special flags for now */
504 if (len > 0)
505 strcpy (lastcommand, console_buffer);
506 else if (len == 0)
507 flag |= CMD_FLAG_REPEAT;
508#ifdef CONFIG_BOOT_RETRY_TIME
509 else if (len == -2) {
510 /* -2 means timed out, retry autoboot
511 */
wdenk4b9206e2004-03-23 22:14:11 +0000512 puts ("\nTimed out waiting for command\n");
wdenkc6097192002-11-03 00:24:07 +0000513# ifdef CONFIG_RESET_TO_RETRY
514 /* Reinit board to run initialization code again */
515 do_reset (NULL, 0, 0, NULL);
516# else
517 return; /* retry autoboot */
518# endif
519 }
520#endif
521
522 if (len == -1)
wdenk4b9206e2004-03-23 22:14:11 +0000523 puts ("<INTERRUPT>\n");
wdenkc6097192002-11-03 00:24:07 +0000524 else
Simon Glass53071532012-02-14 19:59:21 +0000525 rc = run_command(lastcommand, flag);
wdenkc6097192002-11-03 00:24:07 +0000526
527 if (rc <= 0) {
528 /* invalid command or not repeatable, forget it */
529 lastcommand[0] = 0;
530 }
531 }
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200532#endif /*CONFIG_SYS_HUSH_PARSER*/
wdenkc6097192002-11-03 00:24:07 +0000533}
534
wdenk6dd652f2003-06-19 23:40:20 +0000535#ifdef CONFIG_BOOT_RETRY_TIME
536/***************************************************************************
Wolfgang Denk19973b62006-10-28 00:38:39 +0200537 * initialize command line timeout
wdenk6dd652f2003-06-19 23:40:20 +0000538 */
539void init_cmd_timeout(void)
540{
541 char *s = getenv ("bootretry");
542
543 if (s != NULL)
wdenkb028f712003-12-07 21:39:28 +0000544 retry_time = (int)simple_strtol(s, NULL, 10);
wdenk6dd652f2003-06-19 23:40:20 +0000545 else
546 retry_time = CONFIG_BOOT_RETRY_TIME;
547
548 if (retry_time >= 0 && retry_time < CONFIG_BOOT_RETRY_MIN)
549 retry_time = CONFIG_BOOT_RETRY_MIN;
550}
551
wdenkc6097192002-11-03 00:24:07 +0000552/***************************************************************************
553 * reset command line timeout to retry_time seconds
554 */
wdenkc6097192002-11-03 00:24:07 +0000555void reset_cmd_timeout(void)
556{
557 endtime = endtick(retry_time);
558}
559#endif
560
Wolfgang Denk501090a2006-07-21 11:33:45 +0200561#ifdef CONFIG_CMDLINE_EDITING
562
563/*
564 * cmdline-editing related codes from vivi.
565 * Author: Janghoon Lyu <nandy@mizi.com>
566 */
567
Wolfgang Denk501090a2006-07-21 11:33:45 +0200568#define putnstr(str,n) do { \
Andrew Klossnerdc4b0b32008-07-07 06:41:14 -0700569 printf ("%.*s", (int)n, str); \
Wolfgang Denk501090a2006-07-21 11:33:45 +0200570 } while (0)
Wolfgang Denk501090a2006-07-21 11:33:45 +0200571
572#define CTL_CH(c) ((c) - 'a' + 1)
Wolfgang Denk501090a2006-07-21 11:33:45 +0200573#define CTL_BACKSPACE ('\b')
574#define DEL ((char)255)
575#define DEL7 ((char)127)
576#define CREAD_HIST_CHAR ('!')
577
578#define getcmd_putch(ch) putc(ch)
579#define getcmd_getch() getc()
580#define getcmd_cbeep() getcmd_putch('\a')
581
582#define HIST_MAX 20
Peter Tyser8804ae32010-09-29 13:30:56 -0500583#define HIST_SIZE CONFIG_SYS_CBSIZE
Wolfgang Denk501090a2006-07-21 11:33:45 +0200584
Kim Phillips199adb62012-10-29 13:34:32 +0000585static int hist_max;
586static int hist_add_idx;
Wolfgang Denk501090a2006-07-21 11:33:45 +0200587static int hist_cur = -1;
Kim Phillips199adb62012-10-29 13:34:32 +0000588static unsigned hist_num;
Wolfgang Denk501090a2006-07-21 11:33:45 +0200589
Kim Phillips199adb62012-10-29 13:34:32 +0000590static char *hist_list[HIST_MAX];
591static char hist_lines[HIST_MAX][HIST_SIZE + 1]; /* Save room for NULL */
Wolfgang Denk501090a2006-07-21 11:33:45 +0200592
593#define add_idx_minus_one() ((hist_add_idx == 0) ? hist_max : hist_add_idx-1)
594
595static void hist_init(void)
596{
597 int i;
598
599 hist_max = 0;
600 hist_add_idx = 0;
601 hist_cur = -1;
602 hist_num = 0;
603
604 for (i = 0; i < HIST_MAX; i++) {
605 hist_list[i] = hist_lines[i];
606 hist_list[i][0] = '\0';
607 }
608}
609
610static void cread_add_to_hist(char *line)
611{
612 strcpy(hist_list[hist_add_idx], line);
613
614 if (++hist_add_idx >= HIST_MAX)
615 hist_add_idx = 0;
616
617 if (hist_add_idx > hist_max)
618 hist_max = hist_add_idx;
619
620 hist_num++;
621}
622
623static char* hist_prev(void)
624{
625 char *ret;
626 int old_cur;
627
628 if (hist_cur < 0)
629 return NULL;
630
631 old_cur = hist_cur;
632 if (--hist_cur < 0)
633 hist_cur = hist_max;
634
635 if (hist_cur == hist_add_idx) {
636 hist_cur = old_cur;
637 ret = NULL;
638 } else
639 ret = hist_list[hist_cur];
640
641 return (ret);
642}
643
644static char* hist_next(void)
645{
646 char *ret;
647
648 if (hist_cur < 0)
649 return NULL;
650
651 if (hist_cur == hist_add_idx)
652 return NULL;
653
654 if (++hist_cur > hist_max)
655 hist_cur = 0;
656
657 if (hist_cur == hist_add_idx) {
658 ret = "";
659 } else
660 ret = hist_list[hist_cur];
661
662 return (ret);
663}
664
Stefan Roese3ca91222006-07-27 16:11:19 +0200665#ifndef CONFIG_CMDLINE_EDITING
Wolfgang Denk501090a2006-07-21 11:33:45 +0200666static void cread_print_hist_list(void)
667{
668 int i;
669 unsigned long n;
670
671 n = hist_num - hist_max;
672
673 i = hist_add_idx + 1;
674 while (1) {
675 if (i > hist_max)
676 i = 0;
677 if (i == hist_add_idx)
678 break;
679 printf("%s\n", hist_list[i]);
680 n++;
681 i++;
682 }
683}
Stefan Roese3ca91222006-07-27 16:11:19 +0200684#endif /* CONFIG_CMDLINE_EDITING */
Wolfgang Denk501090a2006-07-21 11:33:45 +0200685
686#define BEGINNING_OF_LINE() { \
687 while (num) { \
688 getcmd_putch(CTL_BACKSPACE); \
689 num--; \
690 } \
691}
692
693#define ERASE_TO_EOL() { \
694 if (num < eol_num) { \
Mike Frysinger8faba482010-07-23 05:28:15 -0400695 printf("%*s", (int)(eol_num - num), ""); \
696 do { \
Wolfgang Denk501090a2006-07-21 11:33:45 +0200697 getcmd_putch(CTL_BACKSPACE); \
Mike Frysinger8faba482010-07-23 05:28:15 -0400698 } while (--eol_num > num); \
Wolfgang Denk501090a2006-07-21 11:33:45 +0200699 } \
700}
701
702#define REFRESH_TO_EOL() { \
703 if (num < eol_num) { \
704 wlen = eol_num - num; \
705 putnstr(buf + num, wlen); \
706 num = eol_num; \
707 } \
708}
709
710static void cread_add_char(char ichar, int insert, unsigned long *num,
711 unsigned long *eol_num, char *buf, unsigned long len)
712{
713 unsigned long wlen;
714
715 /* room ??? */
716 if (insert || *num == *eol_num) {
717 if (*eol_num > len - 1) {
718 getcmd_cbeep();
719 return;
720 }
721 (*eol_num)++;
722 }
723
724 if (insert) {
725 wlen = *eol_num - *num;
726 if (wlen > 1) {
727 memmove(&buf[*num+1], &buf[*num], wlen-1);
728 }
729
730 buf[*num] = ichar;
731 putnstr(buf + *num, wlen);
732 (*num)++;
733 while (--wlen) {
734 getcmd_putch(CTL_BACKSPACE);
735 }
736 } else {
737 /* echo the character */
738 wlen = 1;
739 buf[*num] = ichar;
740 putnstr(buf + *num, wlen);
741 (*num)++;
742 }
743}
744
745static void cread_add_str(char *str, int strsize, int insert, unsigned long *num,
746 unsigned long *eol_num, char *buf, unsigned long len)
747{
748 while (strsize--) {
749 cread_add_char(*str, insert, num, eol_num, buf, len);
750 str++;
751 }
752}
753
Heiko Schocher9c348312012-01-16 21:13:05 +0000754static int cread_line(const char *const prompt, char *buf, unsigned int *len,
755 int timeout)
Wolfgang Denk501090a2006-07-21 11:33:45 +0200756{
757 unsigned long num = 0;
758 unsigned long eol_num = 0;
Wolfgang Denk501090a2006-07-21 11:33:45 +0200759 unsigned long wlen;
760 char ichar;
761 int insert = 1;
762 int esc_len = 0;
Wolfgang Denk501090a2006-07-21 11:33:45 +0200763 char esc_save[8];
Peter Tyserecc55002009-10-25 15:12:54 -0500764 int init_len = strlen(buf);
Heiko Schocher9c348312012-01-16 21:13:05 +0000765 int first = 1;
Peter Tyserecc55002009-10-25 15:12:54 -0500766
767 if (init_len)
768 cread_add_str(buf, init_len, 1, &num, &eol_num, buf, *len);
Wolfgang Denk501090a2006-07-21 11:33:45 +0200769
770 while (1) {
Andreas Engel00ac50e2008-01-09 17:10:56 +0100771#ifdef CONFIG_BOOT_RETRY_TIME
772 while (!tstc()) { /* while no incoming data */
773 if (retry_time >= 0 && get_ticks() > endtime)
774 return (-2); /* timed out */
Jens Scharsig30dc1652010-04-09 19:02:38 +0200775 WATCHDOG_RESET();
Andreas Engel00ac50e2008-01-09 17:10:56 +0100776 }
777#endif
Heiko Schocher9c348312012-01-16 21:13:05 +0000778 if (first && timeout) {
779 uint64_t etime = endtick(timeout);
780
781 while (!tstc()) { /* while no incoming data */
782 if (get_ticks() >= etime)
783 return -2; /* timed out */
784 WATCHDOG_RESET();
785 }
786 first = 0;
787 }
Andreas Engel00ac50e2008-01-09 17:10:56 +0100788
Wolfgang Denk501090a2006-07-21 11:33:45 +0200789 ichar = getcmd_getch();
790
791 if ((ichar == '\n') || (ichar == '\r')) {
Wolfgang Denkdd9f06f2006-07-21 11:34:34 +0200792 putc('\n');
Wolfgang Denk501090a2006-07-21 11:33:45 +0200793 break;
794 }
795
796 /*
797 * handle standard linux xterm esc sequences for arrow key, etc.
798 */
799 if (esc_len != 0) {
800 if (esc_len == 1) {
801 if (ichar == '[') {
802 esc_save[esc_len] = ichar;
803 esc_len = 2;
804 } else {
805 cread_add_str(esc_save, esc_len, insert,
806 &num, &eol_num, buf, *len);
807 esc_len = 0;
808 }
809 continue;
810 }
811
812 switch (ichar) {
813
814 case 'D': /* <- key */
815 ichar = CTL_CH('b');
816 esc_len = 0;
817 break;
818 case 'C': /* -> key */
819 ichar = CTL_CH('f');
820 esc_len = 0;
821 break; /* pass off to ^F handler */
822 case 'H': /* Home key */
823 ichar = CTL_CH('a');
824 esc_len = 0;
825 break; /* pass off to ^A handler */
826 case 'A': /* up arrow */
827 ichar = CTL_CH('p');
828 esc_len = 0;
829 break; /* pass off to ^P handler */
830 case 'B': /* down arrow */
831 ichar = CTL_CH('n');
832 esc_len = 0;
833 break; /* pass off to ^N handler */
834 default:
835 esc_save[esc_len++] = ichar;
836 cread_add_str(esc_save, esc_len, insert,
837 &num, &eol_num, buf, *len);
838 esc_len = 0;
839 continue;
840 }
841 }
842
843 switch (ichar) {
844 case 0x1b:
845 if (esc_len == 0) {
846 esc_save[esc_len] = ichar;
847 esc_len = 1;
848 } else {
Wolfgang Denkdd9f06f2006-07-21 11:34:34 +0200849 puts("impossible condition #876\n");
Wolfgang Denk501090a2006-07-21 11:33:45 +0200850 esc_len = 0;
851 }
852 break;
853
854 case CTL_CH('a'):
855 BEGINNING_OF_LINE();
856 break;
857 case CTL_CH('c'): /* ^C - break */
858 *buf = '\0'; /* discard input */
859 return (-1);
860 case CTL_CH('f'):
861 if (num < eol_num) {
862 getcmd_putch(buf[num]);
863 num++;
864 }
865 break;
866 case CTL_CH('b'):
867 if (num) {
868 getcmd_putch(CTL_BACKSPACE);
869 num--;
870 }
871 break;
872 case CTL_CH('d'):
873 if (num < eol_num) {
874 wlen = eol_num - num - 1;
875 if (wlen) {
876 memmove(&buf[num], &buf[num+1], wlen);
877 putnstr(buf + num, wlen);
878 }
879
880 getcmd_putch(' ');
881 do {
882 getcmd_putch(CTL_BACKSPACE);
883 } while (wlen--);
884 eol_num--;
885 }
886 break;
887 case CTL_CH('k'):
888 ERASE_TO_EOL();
889 break;
890 case CTL_CH('e'):
891 REFRESH_TO_EOL();
892 break;
893 case CTL_CH('o'):
894 insert = !insert;
895 break;
896 case CTL_CH('x'):
Jean-Christophe PLAGNIOL-VILLARD23d0baf2007-12-22 15:52:58 +0100897 case CTL_CH('u'):
Wolfgang Denk501090a2006-07-21 11:33:45 +0200898 BEGINNING_OF_LINE();
899 ERASE_TO_EOL();
900 break;
901 case DEL:
902 case DEL7:
903 case 8:
904 if (num) {
905 wlen = eol_num - num;
906 num--;
907 memmove(&buf[num], &buf[num+1], wlen);
908 getcmd_putch(CTL_BACKSPACE);
909 putnstr(buf + num, wlen);
910 getcmd_putch(' ');
911 do {
912 getcmd_putch(CTL_BACKSPACE);
913 } while (wlen--);
914 eol_num--;
915 }
916 break;
917 case CTL_CH('p'):
918 case CTL_CH('n'):
919 {
920 char * hline;
921
922 esc_len = 0;
923
924 if (ichar == CTL_CH('p'))
925 hline = hist_prev();
926 else
927 hline = hist_next();
928
929 if (!hline) {
930 getcmd_cbeep();
931 continue;
932 }
933
934 /* nuke the current line */
935 /* first, go home */
936 BEGINNING_OF_LINE();
937
938 /* erase to end of line */
939 ERASE_TO_EOL();
940
941 /* copy new line into place and display */
942 strcpy(buf, hline);
943 eol_num = strlen(buf);
944 REFRESH_TO_EOL();
945 continue;
946 }
Jean-Christophe PLAGNIOL-VILLARD23d0baf2007-12-22 15:52:58 +0100947#ifdef CONFIG_AUTO_COMPLETE
948 case '\t': {
949 int num2, col;
950
951 /* do not autocomplete when in the middle */
952 if (num < eol_num) {
953 getcmd_cbeep();
954 break;
955 }
956
957 buf[num] = '\0';
958 col = strlen(prompt) + eol_num;
959 num2 = num;
960 if (cmd_auto_complete(prompt, buf, &num2, &col)) {
961 col = num2 - num;
962 num += col;
963 eol_num += col;
964 }
965 break;
966 }
967#endif
Wolfgang Denk501090a2006-07-21 11:33:45 +0200968 default:
969 cread_add_char(ichar, insert, &num, &eol_num, buf, *len);
970 break;
971 }
972 }
973 *len = eol_num;
974 buf[eol_num] = '\0'; /* lose the newline */
975
976 if (buf[0] && buf[0] != CREAD_HIST_CHAR)
977 cread_add_to_hist(buf);
978 hist_cur = hist_add_idx;
979
Peter Tyserf9239432009-10-25 15:12:53 -0500980 return 0;
Wolfgang Denk501090a2006-07-21 11:33:45 +0200981}
982
983#endif /* CONFIG_CMDLINE_EDITING */
984
wdenkc6097192002-11-03 00:24:07 +0000985/****************************************************************************/
986
987/*
988 * Prompt for input and read a line.
989 * If CONFIG_BOOT_RETRY_TIME is defined and retry_time >= 0,
990 * time out when time goes past endtime (timebase time in ticks).
991 * Return: number of read characters
992 * -1 if break
993 * -2 if timed out
994 */
995int readline (const char *const prompt)
996{
Peter Tyserecc55002009-10-25 15:12:54 -0500997 /*
998 * If console_buffer isn't 0-length the user will be prompted to modify
999 * it instead of entering it from scratch as desired.
1000 */
1001 console_buffer[0] = '\0';
1002
Heiko Schocher9c348312012-01-16 21:13:05 +00001003 return readline_into_buffer(prompt, console_buffer, 0);
James Yang6636b622008-01-09 11:17:49 -06001004}
1005
1006
Heiko Schocher9c348312012-01-16 21:13:05 +00001007int readline_into_buffer(const char *const prompt, char *buffer, int timeout)
James Yang6636b622008-01-09 11:17:49 -06001008{
1009 char *p = buffer;
Wolfgang Denk501090a2006-07-21 11:33:45 +02001010#ifdef CONFIG_CMDLINE_EDITING
Peter Tyser8804ae32010-09-29 13:30:56 -05001011 unsigned int len = CONFIG_SYS_CBSIZE;
Stefan Roesed8f961b2006-08-07 15:08:44 +02001012 int rc;
Wolfgang Denk501090a2006-07-21 11:33:45 +02001013 static int initted = 0;
1014
James Yang597f6c22008-05-05 10:22:53 -05001015 /*
1016 * History uses a global array which is not
1017 * writable until after relocation to RAM.
1018 * Revert to non-history version if still
1019 * running from flash.
1020 */
1021 if (gd->flags & GD_FLG_RELOC) {
1022 if (!initted) {
1023 hist_init();
1024 initted = 1;
1025 }
1026
Peter Tysere491a712009-10-25 15:12:52 -05001027 if (prompt)
1028 puts (prompt);
James Yang597f6c22008-05-05 10:22:53 -05001029
Heiko Schocher9c348312012-01-16 21:13:05 +00001030 rc = cread_line(prompt, p, &len, timeout);
James Yang597f6c22008-05-05 10:22:53 -05001031 return rc < 0 ? rc : len;
1032
1033 } else {
1034#endif /* CONFIG_CMDLINE_EDITING */
Kumar Gala0ec59522008-01-10 02:22:05 -06001035 char * p_buf = p;
wdenkc6097192002-11-03 00:24:07 +00001036 int n = 0; /* buffer index */
1037 int plen = 0; /* prompt length */
1038 int col; /* output column cnt */
1039 char c;
1040
1041 /* print prompt */
1042 if (prompt) {
1043 plen = strlen (prompt);
1044 puts (prompt);
1045 }
1046 col = plen;
1047
1048 for (;;) {
1049#ifdef CONFIG_BOOT_RETRY_TIME
1050 while (!tstc()) { /* while no incoming data */
1051 if (retry_time >= 0 && get_ticks() > endtime)
1052 return (-2); /* timed out */
Jens Scharsig30dc1652010-04-09 19:02:38 +02001053 WATCHDOG_RESET();
wdenkc6097192002-11-03 00:24:07 +00001054 }
1055#endif
1056 WATCHDOG_RESET(); /* Trigger watchdog, if needed */
1057
1058#ifdef CONFIG_SHOW_ACTIVITY
1059 while (!tstc()) {
wdenkc6097192002-11-03 00:24:07 +00001060 show_activity(0);
Jens Scharsig30dc1652010-04-09 19:02:38 +02001061 WATCHDOG_RESET();
wdenkc6097192002-11-03 00:24:07 +00001062 }
1063#endif
1064 c = getc();
1065
1066 /*
1067 * Special character handling
1068 */
1069 switch (c) {
Simon Glass49333812013-05-15 06:23:58 +00001070 case '\r': /* Enter */
wdenkc6097192002-11-03 00:24:07 +00001071 case '\n':
1072 *p = '\0';
1073 puts ("\r\n");
Simon Glass49333812013-05-15 06:23:58 +00001074 return p - p_buf;
wdenkc6097192002-11-03 00:24:07 +00001075
Simon Glass49333812013-05-15 06:23:58 +00001076 case '\0': /* nul */
wdenk27aa8182004-03-23 22:37:33 +00001077 continue;
1078
Simon Glass49333812013-05-15 06:23:58 +00001079 case 0x03: /* ^C - break */
James Yang6636b622008-01-09 11:17:49 -06001080 p_buf[0] = '\0'; /* discard input */
Simon Glass49333812013-05-15 06:23:58 +00001081 return -1;
wdenkc6097192002-11-03 00:24:07 +00001082
Simon Glass49333812013-05-15 06:23:58 +00001083 case 0x15: /* ^U - erase line */
wdenkc6097192002-11-03 00:24:07 +00001084 while (col > plen) {
1085 puts (erase_seq);
1086 --col;
1087 }
James Yang6636b622008-01-09 11:17:49 -06001088 p = p_buf;
wdenkc6097192002-11-03 00:24:07 +00001089 n = 0;
1090 continue;
1091
Simon Glass49333812013-05-15 06:23:58 +00001092 case 0x17: /* ^W - erase word */
James Yang6636b622008-01-09 11:17:49 -06001093 p=delete_char(p_buf, p, &col, &n, plen);
wdenkc6097192002-11-03 00:24:07 +00001094 while ((n > 0) && (*p != ' ')) {
James Yang6636b622008-01-09 11:17:49 -06001095 p=delete_char(p_buf, p, &col, &n, plen);
wdenkc6097192002-11-03 00:24:07 +00001096 }
1097 continue;
1098
Simon Glass49333812013-05-15 06:23:58 +00001099 case 0x08: /* ^H - backspace */
1100 case 0x7F: /* DEL - backspace */
James Yang6636b622008-01-09 11:17:49 -06001101 p=delete_char(p_buf, p, &col, &n, plen);
wdenkc6097192002-11-03 00:24:07 +00001102 continue;
1103
1104 default:
1105 /*
1106 * Must be a normal character then
1107 */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001108 if (n < CONFIG_SYS_CBSIZE-2) {
Simon Glass49333812013-05-15 06:23:58 +00001109 if (c == '\t') { /* expand TABs */
wdenk04a85b32004-04-15 18:22:41 +00001110#ifdef CONFIG_AUTO_COMPLETE
1111 /* if auto completion triggered just continue */
1112 *p = '\0';
1113 if (cmd_auto_complete(prompt, console_buffer, &n, &col)) {
James Yang6636b622008-01-09 11:17:49 -06001114 p = p_buf + n; /* reset */
wdenk04a85b32004-04-15 18:22:41 +00001115 continue;
1116 }
1117#endif
wdenkc6097192002-11-03 00:24:07 +00001118 puts (tab_seq+(col&07));
1119 col += 8 - (col&07);
1120 } else {
Simon Glass9a8efc42012-10-30 13:40:18 +00001121 char buf[2];
1122
1123 /*
Simon Glass49333812013-05-15 06:23:58 +00001124 * Echo input using puts() to force an
Simon Glass9a8efc42012-10-30 13:40:18 +00001125 * LCD flush if we are using an LCD
1126 */
1127 ++col;
1128 buf[0] = c;
1129 buf[1] = '\0';
1130 puts(buf);
wdenkc6097192002-11-03 00:24:07 +00001131 }
1132 *p++ = c;
1133 ++n;
1134 } else { /* Buffer full */
1135 putc ('\a');
1136 }
1137 }
1138 }
James Yang597f6c22008-05-05 10:22:53 -05001139#ifdef CONFIG_CMDLINE_EDITING
1140 }
1141#endif
wdenkc6097192002-11-03 00:24:07 +00001142}
1143
1144/****************************************************************************/
1145
1146static char * delete_char (char *buffer, char *p, int *colp, int *np, int plen)
1147{
1148 char *s;
1149
1150 if (*np == 0) {
1151 return (p);
1152 }
1153
1154 if (*(--p) == '\t') { /* will retype the whole line */
1155 while (*colp > plen) {
1156 puts (erase_seq);
1157 (*colp)--;
1158 }
1159 for (s=buffer; s<p; ++s) {
1160 if (*s == '\t') {
1161 puts (tab_seq+((*colp) & 07));
1162 *colp += 8 - ((*colp) & 07);
1163 } else {
1164 ++(*colp);
1165 putc (*s);
1166 }
1167 }
1168 } else {
1169 puts (erase_seq);
1170 (*colp)--;
1171 }
1172 (*np)--;
1173 return (p);
1174}
1175
1176/****************************************************************************/
1177
1178int parse_line (char *line, char *argv[])
1179{
1180 int nargs = 0;
1181
Simon Glass3e408872013-05-15 06:24:00 +00001182 debug_parser("parse_line: \"%s\"\n", line);
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001183 while (nargs < CONFIG_SYS_MAXARGS) {
wdenkc6097192002-11-03 00:24:07 +00001184
1185 /* skip any white space */
Jason Hobbs4d91a6e2011-08-23 11:06:54 +00001186 while (isblank(*line))
wdenkc6097192002-11-03 00:24:07 +00001187 ++line;
wdenkc6097192002-11-03 00:24:07 +00001188
1189 if (*line == '\0') { /* end of line, no more args */
1190 argv[nargs] = NULL;
Simon Glass3e408872013-05-15 06:24:00 +00001191 debug_parser("parse_line: nargs=%d\n", nargs);
1192 return nargs;
wdenkc6097192002-11-03 00:24:07 +00001193 }
1194
1195 argv[nargs++] = line; /* begin of argument string */
1196
1197 /* find end of string */
Jason Hobbs4d91a6e2011-08-23 11:06:54 +00001198 while (*line && !isblank(*line))
wdenkc6097192002-11-03 00:24:07 +00001199 ++line;
wdenkc6097192002-11-03 00:24:07 +00001200
1201 if (*line == '\0') { /* end of line, no more args */
1202 argv[nargs] = NULL;
Simon Glass3e408872013-05-15 06:24:00 +00001203 debug_parser("parse_line: nargs=%d\n", nargs);
1204 return nargs;
wdenkc6097192002-11-03 00:24:07 +00001205 }
1206
1207 *line++ = '\0'; /* terminate current arg */
1208 }
1209
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001210 printf ("** Too many args (max. %d) **\n", CONFIG_SYS_MAXARGS);
wdenkc6097192002-11-03 00:24:07 +00001211
Simon Glass3e408872013-05-15 06:24:00 +00001212 debug_parser("parse_line: nargs=%d\n", nargs);
wdenkc6097192002-11-03 00:24:07 +00001213 return (nargs);
1214}
1215
1216/****************************************************************************/
1217
Simon Glass7fed89e2012-02-14 19:59:22 +00001218#ifndef CONFIG_SYS_HUSH_PARSER
wdenkc6097192002-11-03 00:24:07 +00001219static void process_macros (const char *input, char *output)
1220{
1221 char c, prev;
1222 const char *varname_start = NULL;
Wolfgang Denk19973b62006-10-28 00:38:39 +02001223 int inputcnt = strlen (input);
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001224 int outputcnt = CONFIG_SYS_CBSIZE;
Wolfgang Denk19973b62006-10-28 00:38:39 +02001225 int state = 0; /* 0 = waiting for '$' */
1226
1227 /* 1 = waiting for '(' or '{' */
1228 /* 2 = waiting for ')' or '}' */
1229 /* 3 = waiting for ''' */
wdenkc6097192002-11-03 00:24:07 +00001230 char *output_start = output;
1231
Simon Glass3e408872013-05-15 06:24:00 +00001232 debug_parser("[PROCESS_MACROS] INPUT len %zd: \"%s\"\n", strlen(input),
1233 input);
wdenkc6097192002-11-03 00:24:07 +00001234
Wolfgang Denk19973b62006-10-28 00:38:39 +02001235 prev = '\0'; /* previous character */
wdenkc6097192002-11-03 00:24:07 +00001236
1237 while (inputcnt && outputcnt) {
wdenk8bde7f72003-06-27 21:31:46 +00001238 c = *input++;
Wolfgang Denk19973b62006-10-28 00:38:39 +02001239 inputcnt--;
wdenkc6097192002-11-03 00:24:07 +00001240
Wolfgang Denk19973b62006-10-28 00:38:39 +02001241 if (state != 3) {
1242 /* remove one level of escape characters */
1243 if ((c == '\\') && (prev != '\\')) {
1244 if (inputcnt-- == 0)
1245 break;
1246 prev = c;
1247 c = *input++;
1248 }
wdenka25f8622003-01-02 23:57:29 +00001249 }
wdenkc6097192002-11-03 00:24:07 +00001250
Wolfgang Denk19973b62006-10-28 00:38:39 +02001251 switch (state) {
1252 case 0: /* Waiting for (unescaped) $ */
1253 if ((c == '\'') && (prev != '\\')) {
1254 state = 3;
1255 break;
1256 }
1257 if ((c == '$') && (prev != '\\')) {
1258 state++;
1259 } else {
wdenkc6097192002-11-03 00:24:07 +00001260 *(output++) = c;
1261 outputcnt--;
1262 }
Wolfgang Denk19973b62006-10-28 00:38:39 +02001263 break;
1264 case 1: /* Waiting for ( */
1265 if (c == '(' || c == '{') {
1266 state++;
1267 varname_start = input;
1268 } else {
1269 state = 0;
1270 *(output++) = '$';
1271 outputcnt--;
wdenkc6097192002-11-03 00:24:07 +00001272
Wolfgang Denk19973b62006-10-28 00:38:39 +02001273 if (outputcnt) {
1274 *(output++) = c;
wdenkc6097192002-11-03 00:24:07 +00001275 outputcnt--;
1276 }
Wolfgang Denk19973b62006-10-28 00:38:39 +02001277 }
1278 break;
1279 case 2: /* Waiting for ) */
1280 if (c == ')' || c == '}') {
1281 int i;
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001282 char envname[CONFIG_SYS_CBSIZE], *envval;
Wolfgang Denk19973b62006-10-28 00:38:39 +02001283 int envcnt = input - varname_start - 1; /* Varname # of chars */
1284
1285 /* Get the varname */
1286 for (i = 0; i < envcnt; i++) {
1287 envname[i] = varname_start[i];
1288 }
1289 envname[i] = 0;
1290
1291 /* Get its value */
1292 envval = getenv (envname);
1293
1294 /* Copy into the line if it exists */
1295 if (envval != NULL)
1296 while ((*envval) && outputcnt) {
1297 *(output++) = *(envval++);
1298 outputcnt--;
1299 }
1300 /* Look for another '$' */
1301 state = 0;
1302 }
1303 break;
1304 case 3: /* Waiting for ' */
1305 if ((c == '\'') && (prev != '\\')) {
1306 state = 0;
1307 } else {
1308 *(output++) = c;
1309 outputcnt--;
1310 }
1311 break;
wdenkc6097192002-11-03 00:24:07 +00001312 }
Wolfgang Denk19973b62006-10-28 00:38:39 +02001313 prev = c;
wdenkc6097192002-11-03 00:24:07 +00001314 }
1315
1316 if (outputcnt)
1317 *output = 0;
Bartlomiej Sieka9160b962007-05-27 17:04:18 +02001318 else
1319 *(output - 1) = 0;
wdenkc6097192002-11-03 00:24:07 +00001320
Simon Glass3e408872013-05-15 06:24:00 +00001321 debug_parser("[PROCESS_MACROS] OUTPUT len %zd: \"%s\"\n",
1322 strlen(output_start), output_start);
wdenkc6097192002-11-03 00:24:07 +00001323}
1324
1325/****************************************************************************
1326 * returns:
1327 * 1 - command executed, repeatable
1328 * 0 - command executed but not repeatable, interrupted commands are
1329 * always considered not repeatable
1330 * -1 - not executed (unrecognized, bootd recursion or too many args)
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001331 * (If cmd is NULL or "" or longer than CONFIG_SYS_CBSIZE-1 it is
wdenkc6097192002-11-03 00:24:07 +00001332 * considered unrecognized)
1333 *
1334 * WARNING:
1335 *
1336 * We must create a temporary copy of the command since the command we get
1337 * may be the result from getenv(), which returns a pointer directly to
1338 * the environment data, which may change magicly when the command we run
1339 * creates or modifies environment variables (like "bootp" does).
1340 */
Simon Glass53071532012-02-14 19:59:21 +00001341static int builtin_run_command(const char *cmd, int flag)
wdenkc6097192002-11-03 00:24:07 +00001342{
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001343 char cmdbuf[CONFIG_SYS_CBSIZE]; /* working copy of cmd */
wdenkc6097192002-11-03 00:24:07 +00001344 char *token; /* start of token in cmdbuf */
1345 char *sep; /* end of token (separator) in cmdbuf */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001346 char finaltoken[CONFIG_SYS_CBSIZE];
wdenkc6097192002-11-03 00:24:07 +00001347 char *str = cmdbuf;
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001348 char *argv[CONFIG_SYS_MAXARGS + 1]; /* NULL terminated */
wdenkf07771c2003-05-28 08:06:31 +00001349 int argc, inquotes;
wdenkc6097192002-11-03 00:24:07 +00001350 int repeatable = 1;
wdenkf07771c2003-05-28 08:06:31 +00001351 int rc = 0;
wdenkc6097192002-11-03 00:24:07 +00001352
Simon Glass3e408872013-05-15 06:24:00 +00001353 debug_parser("[RUN_COMMAND] cmd[%p]=\"", cmd);
1354 if (DEBUG_PARSER) {
1355 /* use puts - string may be loooong */
1356 puts(cmd ? cmd : "NULL");
1357 puts("\"\n");
1358 }
wdenkc6097192002-11-03 00:24:07 +00001359 clear_ctrlc(); /* forget any previous Control C */
1360
1361 if (!cmd || !*cmd) {
1362 return -1; /* empty command */
1363 }
1364
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001365 if (strlen(cmd) >= CONFIG_SYS_CBSIZE) {
wdenkc6097192002-11-03 00:24:07 +00001366 puts ("## Command too long!\n");
1367 return -1;
1368 }
1369
1370 strcpy (cmdbuf, cmd);
1371
1372 /* Process separators and check for invalid
1373 * repeatable commands
1374 */
1375
Simon Glass3e408872013-05-15 06:24:00 +00001376 debug_parser("[PROCESS_SEPARATORS] %s\n", cmd);
wdenkc6097192002-11-03 00:24:07 +00001377 while (*str) {
1378
1379 /*
1380 * Find separator, or string end
1381 * Allow simple escape of ';' by writing "\;"
1382 */
wdenka25f8622003-01-02 23:57:29 +00001383 for (inquotes = 0, sep = str; *sep; sep++) {
1384 if ((*sep=='\'') &&
1385 (*(sep-1) != '\\'))
1386 inquotes=!inquotes;
1387
1388 if (!inquotes &&
1389 (*sep == ';') && /* separator */
wdenkc6097192002-11-03 00:24:07 +00001390 ( sep != str) && /* past string start */
1391 (*(sep-1) != '\\')) /* and NOT escaped */
1392 break;
1393 }
1394
1395 /*
1396 * Limit the token to data between separators
1397 */
1398 token = str;
1399 if (*sep) {
1400 str = sep + 1; /* start of command for next pass */
1401 *sep = '\0';
1402 }
1403 else
1404 str = sep; /* no more commands for next pass */
Simon Glass3e408872013-05-15 06:24:00 +00001405 debug_parser("token: \"%s\"\n", token);
wdenkc6097192002-11-03 00:24:07 +00001406
1407 /* find macros in this token and replace them */
1408 process_macros (token, finaltoken);
1409
1410 /* Extract arguments */
Wolfgang Denk1264b402006-03-12 02:20:55 +01001411 if ((argc = parse_line (finaltoken, argv)) == 0) {
1412 rc = -1; /* no command at all */
1413 continue;
1414 }
wdenkc6097192002-11-03 00:24:07 +00001415
Richard Genoud34765e82012-12-03 06:28:28 +00001416 if (cmd_process(flag, argc, argv, &repeatable, NULL))
Timo Ketola030fca52012-04-22 23:57:27 +00001417 rc = -1;
wdenkc6097192002-11-03 00:24:07 +00001418
1419 /* Did the user stop this? */
1420 if (had_ctrlc ())
Detlev Zundel5afb2022007-05-23 18:47:48 +02001421 return -1; /* if stopped then not repeatable */
wdenkc6097192002-11-03 00:24:07 +00001422 }
1423
wdenkf07771c2003-05-28 08:06:31 +00001424 return rc ? rc : repeatable;
wdenkc6097192002-11-03 00:24:07 +00001425}
Simon Glass7fed89e2012-02-14 19:59:22 +00001426#endif
wdenkc6097192002-11-03 00:24:07 +00001427
Simon Glass53071532012-02-14 19:59:21 +00001428/*
1429 * Run a command using the selected parser.
1430 *
1431 * @param cmd Command to run
1432 * @param flag Execution flags (CMD_FLAG_...)
1433 * @return 0 on success, or != 0 on error.
1434 */
1435int run_command(const char *cmd, int flag)
1436{
1437#ifndef CONFIG_SYS_HUSH_PARSER
1438 /*
1439 * builtin_run_command can return 0 or 1 for success, so clean up
1440 * its result.
1441 */
1442 if (builtin_run_command(cmd, flag) == -1)
1443 return 1;
1444
1445 return 0;
1446#else
1447 return parse_string_outer(cmd,
1448 FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP);
1449#endif
1450}
1451
Simon Glassd51004a2012-03-30 21:30:55 +00001452#ifndef CONFIG_SYS_HUSH_PARSER
1453/**
1454 * Execute a list of command separated by ; or \n using the built-in parser.
1455 *
1456 * This function cannot take a const char * for the command, since if it
1457 * finds newlines in the string, it replaces them with \0.
1458 *
1459 * @param cmd String containing list of commands
1460 * @param flag Execution flags (CMD_FLAG_...)
1461 * @return 0 on success, or != 0 on error.
1462 */
1463static int builtin_run_command_list(char *cmd, int flag)
1464{
1465 char *line, *next;
1466 int rcode = 0;
1467
1468 /*
1469 * Break into individual lines, and execute each line; terminate on
1470 * error.
1471 */
1472 line = next = cmd;
1473 while (*next) {
1474 if (*next == '\n') {
1475 *next = '\0';
1476 /* run only non-empty commands */
1477 if (*line) {
1478 debug("** exec: \"%s\"\n", line);
1479 if (builtin_run_command(line, 0) < 0) {
1480 rcode = 1;
1481 break;
1482 }
1483 }
1484 line = next + 1;
1485 }
1486 ++next;
1487 }
1488 if (rcode == 0 && *line)
1489 rcode = (builtin_run_command(line, 0) >= 0);
1490
1491 return rcode;
1492}
1493#endif
1494
1495int run_command_list(const char *cmd, int len, int flag)
1496{
1497 int need_buff = 1;
1498 char *buff = (char *)cmd; /* cast away const */
1499 int rcode = 0;
1500
1501 if (len == -1) {
1502 len = strlen(cmd);
1503#ifdef CONFIG_SYS_HUSH_PARSER
1504 /* hush will never change our string */
1505 need_buff = 0;
1506#else
1507 /* the built-in parser will change our string if it sees \n */
1508 need_buff = strchr(cmd, '\n') != NULL;
1509#endif
1510 }
1511 if (need_buff) {
1512 buff = malloc(len + 1);
1513 if (!buff)
1514 return 1;
1515 memcpy(buff, cmd, len);
1516 buff[len] = '\0';
1517 }
1518#ifdef CONFIG_SYS_HUSH_PARSER
1519 rcode = parse_string_outer(buff, FLAG_PARSE_SEMICOLON);
1520#else
1521 /*
1522 * This function will overwrite any \n it sees with a \0, which
1523 * is why it can't work with a const char *. Here we are making
1524 * using of internal knowledge of this function, to avoid always
1525 * doing a malloc() which is actually required only in a case that
1526 * is pretty rare.
1527 */
1528 rcode = builtin_run_command_list(buff, flag);
1529 if (need_buff)
1530 free(buff);
1531#endif
1532
1533 return rcode;
1534}
1535
wdenkc6097192002-11-03 00:24:07 +00001536/****************************************************************************/
1537
Jon Loeligerc3517f92007-07-08 18:10:08 -05001538#if defined(CONFIG_CMD_RUN)
Wolfgang Denk54841ab2010-06-28 22:00:46 +02001539int do_run (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
wdenkc6097192002-11-03 00:24:07 +00001540{
1541 int i;
wdenkc6097192002-11-03 00:24:07 +00001542
Wolfgang Denk47e26b12010-07-17 01:06:04 +02001543 if (argc < 2)
Simon Glass4c12eeb2011-12-10 08:44:01 +00001544 return CMD_RET_USAGE;
wdenkc6097192002-11-03 00:24:07 +00001545
1546 for (i=1; i<argc; ++i) {
wdenk3e386912003-04-05 00:53:31 +00001547 char *arg;
1548
1549 if ((arg = getenv (argv[i])) == NULL) {
1550 printf ("## Error: \"%s\" not defined\n", argv[i]);
1551 return 1;
1552 }
Jason Hobbsc8a20792011-08-31 05:37:24 +00001553
Simon Glass1992dbf2013-10-25 23:01:32 -06001554 if (run_command_list(arg, -1, flag) != 0)
wdenk3e386912003-04-05 00:53:31 +00001555 return 1;
wdenkc6097192002-11-03 00:24:07 +00001556 }
wdenk3e386912003-04-05 00:53:31 +00001557 return 0;
wdenkc6097192002-11-03 00:24:07 +00001558}
Jon Loeliger90253172007-07-10 11:02:44 -05001559#endif