blob: e5173d7284130f70144eea55df2ec9777cde2728 [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 Denk4c9ca782006-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 *
wdenkc6097192002-11-03 00:24:07 +00009 * See file CREDITS for list of people who contributed to this
10 * project.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License as
14 * published by the Free Software Foundation; either version 2 of
15 * the License, or (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
25 * MA 02111-1307 USA
26 */
27
wdenk9dd2b882002-12-03 21:28:10 +000028/* #define DEBUG */
29
wdenkc6097192002-11-03 00:24:07 +000030#include <common.h>
wdenkc6097192002-11-03 00:24:07 +000031#include <command.h>
Che-Liang Chiou0b5e5a32012-10-25 16:31:07 +000032#include <fdtdec.h>
wdenkc6097192002-11-03 00:24:07 +000033#include <hush.h>
Simon Glassb2b687f2013-05-15 06:23:59 +000034#include <malloc.h>
35#include <menu.h>
wdenk0a658552003-08-05 17:43:17 +000036#include <post.h>
Simon Glassb2b687f2013-05-15 06:23:59 +000037#include <version.h>
38#include <watchdog.h>
Jason Hobbscafa1aa2011-08-23 11:06:54 +000039#include <linux/ctype.h>
wdenk0a658552003-08-05 17:43:17 +000040
Wolfgang Denk6405a152006-03-31 18:32:53 +020041DECLARE_GLOBAL_DATA_PTR;
Wolfgang Denk6405a152006-03-31 18:32:53 +020042
Heiko Schocher8a8ec532007-07-13 09:54:17 +020043/*
44 * Board-specific Platform code can reimplement show_boot_progress () if needed
45 */
46void inline __show_boot_progress (int val) {}
Emil Medveace7cc82009-05-12 13:48:32 -050047void show_boot_progress (int val) __attribute__((weak, alias("__show_boot_progress")));
Heiko Schocher8a8ec532007-07-13 09:54:17 +020048
wdenkc6097192002-11-03 00:24:07 +000049#define MAX_DELAY_STOP_STR 32
50
wdenkc6097192002-11-03 00:24:07 +000051#undef DEBUG_PARSER
52
John Schmollerc01e7202010-03-12 09:49:23 -060053char console_buffer[CONFIG_SYS_CBSIZE + 1]; /* console I/O buffer */
wdenkc6097192002-11-03 00:24:07 +000054
Stefan Roese59ff5a52006-07-27 16:11:19 +020055static char * delete_char (char *buffer, char *p, int *colp, int *np, int plen);
Mike Frysingerd5c319c2010-12-22 09:40:45 -050056static const char erase_seq[] = "\b \b"; /* erase sequence */
57static const char tab_seq[] = " "; /* used to expand TABs */
wdenkc6097192002-11-03 00:24:07 +000058
59#ifdef CONFIG_BOOT_RETRY_TIME
60static uint64_t endtime = 0; /* must be set, default is instant timeout */
61static int retry_time = -1; /* -1 so can call readline before main_loop */
62#endif
63
64#define endtick(seconds) (get_ticks() + (uint64_t)(seconds) * get_tbclk())
65
66#ifndef CONFIG_BOOT_RETRY_MIN
67#define CONFIG_BOOT_RETRY_MIN CONFIG_BOOT_RETRY_TIME
68#endif
69
70#ifdef CONFIG_MODEM_SUPPORT
71int do_mdm_init = 0;
72extern void mdm_init(void); /* defined in board.c */
73#endif
74
75/***************************************************************************
76 * Watch for 'delay' seconds for autoboot stop or autoboot delay string.
Jason Hobbsa56febb2011-08-31 05:37:24 +000077 * returns: 0 - no key string, allow autoboot 1 - got key string, abort
wdenkc6097192002-11-03 00:24:07 +000078 */
Joe Hershberger66eb8fc2013-02-08 10:28:00 +000079#if defined(CONFIG_BOOTDELAY)
wdenkc6097192002-11-03 00:24:07 +000080# if defined(CONFIG_AUTOBOOT_KEYED)
Simon Glasse71c1e62013-05-15 06:23:55 +000081static int abortboot_keyed(int bootdelay)
wdenkc6097192002-11-03 00:24:07 +000082{
83 int abort = 0;
84 uint64_t etime = endtick(bootdelay);
Wolfgang Denk9c82c682006-10-28 00:38:39 +020085 struct {
wdenkc6097192002-11-03 00:24:07 +000086 char* str;
87 u_int len;
88 int retry;
89 }
Wolfgang Denk9c82c682006-10-28 00:38:39 +020090 delaykey [] = {
wdenkc6097192002-11-03 00:24:07 +000091 { str: getenv ("bootdelaykey"), retry: 1 },
92 { str: getenv ("bootdelaykey2"), retry: 1 },
93 { str: getenv ("bootstopkey"), retry: 0 },
94 { str: getenv ("bootstopkey2"), retry: 0 },
95 };
96
97 char presskey [MAX_DELAY_STOP_STR];
98 u_int presskey_len = 0;
99 u_int presskey_max = 0;
100 u_int i;
101
Dirk Eibachc82b4ea2012-04-26 01:49:33 +0000102#ifndef CONFIG_ZERO_BOOTDELAY_CHECK
103 if (bootdelay == 0)
104 return 0;
105#endif
106
wdenkc6097192002-11-03 00:24:07 +0000107# ifdef CONFIG_AUTOBOOT_PROMPT
Stefan Roese37628252008-08-06 14:05:38 +0200108 printf(CONFIG_AUTOBOOT_PROMPT);
wdenkc6097192002-11-03 00:24:07 +0000109# endif
110
111# ifdef CONFIG_AUTOBOOT_DELAY_STR
112 if (delaykey[0].str == NULL)
113 delaykey[0].str = CONFIG_AUTOBOOT_DELAY_STR;
114# endif
115# ifdef CONFIG_AUTOBOOT_DELAY_STR2
116 if (delaykey[1].str == NULL)
117 delaykey[1].str = CONFIG_AUTOBOOT_DELAY_STR2;
118# endif
119# ifdef CONFIG_AUTOBOOT_STOP_STR
120 if (delaykey[2].str == NULL)
121 delaykey[2].str = CONFIG_AUTOBOOT_STOP_STR;
122# endif
123# ifdef CONFIG_AUTOBOOT_STOP_STR2
124 if (delaykey[3].str == NULL)
125 delaykey[3].str = CONFIG_AUTOBOOT_STOP_STR2;
126# endif
127
128 for (i = 0; i < sizeof(delaykey) / sizeof(delaykey[0]); i ++) {
129 delaykey[i].len = delaykey[i].str == NULL ?
130 0 : strlen (delaykey[i].str);
131 delaykey[i].len = delaykey[i].len > MAX_DELAY_STOP_STR ?
132 MAX_DELAY_STOP_STR : delaykey[i].len;
133
134 presskey_max = presskey_max > delaykey[i].len ?
135 presskey_max : delaykey[i].len;
136
137# if DEBUG_BOOTKEYS
138 printf("%s key:<%s>\n",
139 delaykey[i].retry ? "delay" : "stop",
140 delaykey[i].str ? delaykey[i].str : "NULL");
141# endif
142 }
143
144 /* In order to keep up with incoming data, check timeout only
145 * when catch up.
146 */
Peter Korsgaard6499fd62008-12-10 16:24:16 +0100147 do {
148 if (tstc()) {
149 if (presskey_len < presskey_max) {
150 presskey [presskey_len ++] = getc();
151 }
152 else {
153 for (i = 0; i < presskey_max - 1; i ++)
154 presskey [i] = presskey [i + 1];
155
156 presskey [i] = getc();
157 }
158 }
159
wdenkc6097192002-11-03 00:24:07 +0000160 for (i = 0; i < sizeof(delaykey) / sizeof(delaykey[0]); i ++) {
161 if (delaykey[i].len > 0 &&
162 presskey_len >= delaykey[i].len &&
163 memcmp (presskey + presskey_len - delaykey[i].len,
wdenk57b2d802003-06-27 21:31:46 +0000164 delaykey[i].str,
wdenkc6097192002-11-03 00:24:07 +0000165 delaykey[i].len) == 0) {
166# if DEBUG_BOOTKEYS
167 printf("got %skey\n",
168 delaykey[i].retry ? "delay" : "stop");
169# endif
170
171# ifdef CONFIG_BOOT_RETRY_TIME
172 /* don't retry auto boot */
173 if (! delaykey[i].retry)
174 retry_time = -1;
175# endif
176 abort = 1;
177 }
178 }
Peter Korsgaard6499fd62008-12-10 16:24:16 +0100179 } while (!abort && get_ticks() <= etime);
wdenkc6097192002-11-03 00:24:07 +0000180
wdenkc6097192002-11-03 00:24:07 +0000181# if DEBUG_BOOTKEYS
182 if (!abort)
Ladislav Michl83fc7e52007-04-25 16:01:26 +0200183 puts("key timeout\n");
wdenkc6097192002-11-03 00:24:07 +0000184# endif
185
dzu6605c842003-10-24 13:14:45 +0000186#ifdef CONFIG_SILENT_CONSOLE
Ladislav Michl6c6a38a2007-04-25 16:01:26 +0200187 if (abort)
188 gd->flags &= ~GD_FLG_SILENT;
dzu6605c842003-10-24 13:14:45 +0000189#endif
190
wdenkc6097192002-11-03 00:24:07 +0000191 return abort;
192}
193
194# else /* !defined(CONFIG_AUTOBOOT_KEYED) */
195
wdenk452cfd62002-11-19 11:04:11 +0000196#ifdef CONFIG_MENUKEY
197static int menukey = 0;
198#endif
199
Simon Glasse71c1e62013-05-15 06:23:55 +0000200static int abortboot_normal(int bootdelay)
wdenkc6097192002-11-03 00:24:07 +0000201{
202 int abort = 0;
Jim Lin56014a42013-01-24 01:05:55 +0000203 unsigned long ts;
wdenkc6097192002-11-03 00:24:07 +0000204
wdenk452cfd62002-11-19 11:04:11 +0000205#ifdef CONFIG_MENUPROMPT
Stefan Roese37628252008-08-06 14:05:38 +0200206 printf(CONFIG_MENUPROMPT);
wdenk452cfd62002-11-19 11:04:11 +0000207#else
Joe Hershberger96ccaf32012-08-17 10:53:12 +0000208 if (bootdelay >= 0)
209 printf("Hit any key to stop autoboot: %2d ", bootdelay);
wdenk452cfd62002-11-19 11:04:11 +0000210#endif
wdenkc6097192002-11-03 00:24:07 +0000211
212#if defined CONFIG_ZERO_BOOTDELAY_CHECK
wdenk57b2d802003-06-27 21:31:46 +0000213 /*
214 * Check if key already pressed
215 * Don't check if bootdelay < 0
216 */
wdenkc6097192002-11-03 00:24:07 +0000217 if (bootdelay >= 0) {
218 if (tstc()) { /* we got a key press */
219 (void) getc(); /* consume input */
wdenk42c05472004-03-23 22:14:11 +0000220 puts ("\b\b\b 0");
Ladislav Michl6c6a38a2007-04-25 16:01:26 +0200221 abort = 1; /* don't auto boot */
wdenkc6097192002-11-03 00:24:07 +0000222 }
wdenk57b2d802003-06-27 21:31:46 +0000223 }
wdenkc6097192002-11-03 00:24:07 +0000224#endif
225
wdenk808532a2003-10-10 10:05:42 +0000226 while ((bootdelay > 0) && (!abort)) {
wdenkc6097192002-11-03 00:24:07 +0000227 --bootdelay;
Jim Lin56014a42013-01-24 01:05:55 +0000228 /* delay 1000 ms */
229 ts = get_timer(0);
230 do {
wdenkc6097192002-11-03 00:24:07 +0000231 if (tstc()) { /* we got a key press */
232 abort = 1; /* don't auto boot */
233 bootdelay = 0; /* no more delay */
wdenk452cfd62002-11-19 11:04:11 +0000234# ifdef CONFIG_MENUKEY
235 menukey = getc();
236# else
wdenkc6097192002-11-03 00:24:07 +0000237 (void) getc(); /* consume input */
wdenk452cfd62002-11-19 11:04:11 +0000238# endif
wdenkc6097192002-11-03 00:24:07 +0000239 break;
240 }
Ladislav Michl83fc7e52007-04-25 16:01:26 +0200241 udelay(10000);
Jim Lin56014a42013-01-24 01:05:55 +0000242 } while (!abort && get_timer(ts) < 1000);
wdenkc6097192002-11-03 00:24:07 +0000243
Ladislav Michl83fc7e52007-04-25 16:01:26 +0200244 printf("\b\b\b%2d ", bootdelay);
wdenkc6097192002-11-03 00:24:07 +0000245 }
246
Ladislav Michl83fc7e52007-04-25 16:01:26 +0200247 putc('\n');
wdenkc6097192002-11-03 00:24:07 +0000248
wdenk808532a2003-10-10 10:05:42 +0000249#ifdef CONFIG_SILENT_CONSOLE
Ladislav Michl6c6a38a2007-04-25 16:01:26 +0200250 if (abort)
251 gd->flags &= ~GD_FLG_SILENT;
wdenk808532a2003-10-10 10:05:42 +0000252#endif
253
wdenkc6097192002-11-03 00:24:07 +0000254 return abort;
255}
256# endif /* CONFIG_AUTOBOOT_KEYED */
Simon Glasse71c1e62013-05-15 06:23:55 +0000257
258static int abortboot(int bootdelay)
259{
260#ifdef CONFIG_AUTOBOOT_KEYED
261 return abortboot_keyed(bootdelay);
262#else
263 return abortboot_normal(bootdelay);
264#endif
265}
Joe Hershberger66eb8fc2013-02-08 10:28:00 +0000266#endif /* CONFIG_BOOTDELAY */
wdenkc6097192002-11-03 00:24:07 +0000267
Doug Anderson07b81142012-10-25 16:31:09 +0000268/*
269 * Runs the given boot command securely. Specifically:
270 * - Doesn't run the command with the shell (run_command or parse_string_outer),
271 * since that's a lot of code surface that an attacker might exploit.
272 * Because of this, we don't do any argument parsing--the secure boot command
273 * has to be a full-fledged u-boot command.
274 * - Doesn't check for keypresses before booting, since that could be a
275 * security hole; also disables Ctrl-C.
276 * - Doesn't allow the command to return.
277 *
278 * Upon any failures, this function will drop into an infinite loop after
279 * printing the error message to console.
280 */
281
Joe Hershberger66eb8fc2013-02-08 10:28:00 +0000282#if defined(CONFIG_BOOTDELAY) && defined(CONFIG_OF_CONTROL)
Doug Anderson07b81142012-10-25 16:31:09 +0000283static void secure_boot_cmd(char *cmd)
284{
285 cmd_tbl_t *cmdtp;
286 int rc;
287
288 if (!cmd) {
289 printf("## Error: Secure boot command not specified\n");
290 goto err;
291 }
292
293 /* Disable Ctrl-C just in case some command is used that checks it. */
294 disable_ctrlc(1);
295
296 /* Find the command directly. */
297 cmdtp = find_cmd(cmd);
298 if (!cmdtp) {
299 printf("## Error: \"%s\" not defined\n", cmd);
300 goto err;
301 }
302
303 /* Run the command, forcing no flags and faking argc and argv. */
304 rc = (cmdtp->cmd)(cmdtp, 0, 1, &cmd);
305
306 /* Shouldn't ever return from boot command. */
307 printf("## Error: \"%s\" returned (code %d)\n", cmd, rc);
308
309err:
310 /*
311 * Not a whole lot to do here. Rebooting won't help much, since we'll
312 * just end up right back here. Just loop.
313 */
314 hang();
315}
316
Simon Glass057f6802012-10-25 16:31:11 +0000317static void process_fdt_options(const void *blob)
318{
319 ulong addr;
320
321 /* Add an env variable to point to a kernel payload, if available */
322 addr = fdtdec_get_config_int(gd->fdt_blob, "kernel-offset", 0);
323 if (addr)
324 setenv_addr("kernaddr", (void *)(CONFIG_SYS_TEXT_BASE + addr));
325
326 /* Add an env variable to point to a root disk, if available */
327 addr = fdtdec_get_config_int(gd->fdt_blob, "rootdisk-offset", 0);
328 if (addr)
329 setenv_addr("rootaddr", (void *)(CONFIG_SYS_TEXT_BASE + addr));
330}
Doug Anderson07b81142012-10-25 16:31:09 +0000331#endif /* CONFIG_OF_CONTROL */
332
Simon Glassde6f0c42013-05-15 06:23:56 +0000333#ifdef CONFIG_BOOTDELAY
334static void process_boot_delay(void)
wdenkc6097192002-11-03 00:24:07 +0000335{
Simon Glassde6f0c42013-05-15 06:23:56 +0000336#ifdef CONFIG_OF_CONTROL
Che-Liang Chiou0b5e5a32012-10-25 16:31:07 +0000337 char *env;
338#endif
wdenkc6097192002-11-03 00:24:07 +0000339 char *s;
340 int bootdelay;
wdenk0a658552003-08-05 17:43:17 +0000341#ifdef CONFIG_BOOTCOUNT_LIMIT
342 unsigned long bootcount = 0;
343 unsigned long bootlimit = 0;
wdenk0a658552003-08-05 17:43:17 +0000344#endif /* CONFIG_BOOTCOUNT_LIMIT */
wdenkc6097192002-11-03 00:24:07 +0000345
wdenk0a658552003-08-05 17:43:17 +0000346#ifdef CONFIG_BOOTCOUNT_LIMIT
347 bootcount = bootcount_load();
348 bootcount++;
349 bootcount_store (bootcount);
Simon Glass962cf722013-05-15 06:23:57 +0000350 setenv_ulong("bootcount", bootcount);
351 bootlimit = getenv_ulong("bootlimit", 10, 0);
wdenk0a658552003-08-05 17:43:17 +0000352#endif /* CONFIG_BOOTCOUNT_LIMIT */
353
wdenkc6097192002-11-03 00:24:07 +0000354 s = getenv ("bootdelay");
355 bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;
356
wdenk9dd2b882002-12-03 21:28:10 +0000357 debug ("### main_loop entered: bootdelay=%d\n\n", bootdelay);
wdenkc6097192002-11-03 00:24:07 +0000358
Heiko Schocherb4c1df82012-01-16 21:13:35 +0000359#if defined(CONFIG_MENU_SHOW)
360 bootdelay = menu_show(bootdelay);
361#endif
wdenkc6097192002-11-03 00:24:07 +0000362# ifdef CONFIG_BOOT_RETRY_TIME
wdenkb00ec162003-06-19 23:40:20 +0000363 init_cmd_timeout ();
wdenkc6097192002-11-03 00:24:07 +0000364# endif /* CONFIG_BOOT_RETRY_TIME */
365
Yuri Tikhonovd773efb2008-02-04 14:11:03 +0100366#ifdef CONFIG_POST
367 if (gd->flags & GD_FLG_POSTFAIL) {
368 s = getenv("failbootcmd");
369 }
370 else
371#endif /* CONFIG_POST */
wdenk0a658552003-08-05 17:43:17 +0000372#ifdef CONFIG_BOOTCOUNT_LIMIT
373 if (bootlimit && (bootcount > bootlimit)) {
374 printf ("Warning: Bootlimit (%u) exceeded. Using altbootcmd.\n",
375 (unsigned)bootlimit);
376 s = getenv ("altbootcmd");
377 }
378 else
379#endif /* CONFIG_BOOTCOUNT_LIMIT */
380 s = getenv ("bootcmd");
Che-Liang Chiou0b5e5a32012-10-25 16:31:07 +0000381#ifdef CONFIG_OF_CONTROL
382 /* Allow the fdt to override the boot command */
383 env = fdtdec_get_config_string(gd->fdt_blob, "bootcmd");
384 if (env)
385 s = env;
Doug Anderson07b81142012-10-25 16:31:09 +0000386
Simon Glass057f6802012-10-25 16:31:11 +0000387 process_fdt_options(gd->fdt_blob);
388
Doug Anderson07b81142012-10-25 16:31:09 +0000389 /*
390 * If the bootsecure option was chosen, use secure_boot_cmd().
391 * Always use 'env' in this case, since bootsecure requres that the
392 * bootcmd was specified in the FDT too.
393 */
394 if (fdtdec_get_config_int(gd->fdt_blob, "bootsecure", 0))
395 secure_boot_cmd(env);
396
Che-Liang Chiou0b5e5a32012-10-25 16:31:07 +0000397#endif /* CONFIG_OF_CONTROL */
wdenk9dd2b882002-12-03 21:28:10 +0000398
399 debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>");
400
Joe Hershberger96ccaf32012-08-17 10:53:12 +0000401 if (bootdelay != -1 && s && !abortboot(bootdelay)) {
Simon Glassde6f0c42013-05-15 06:23:56 +0000402#ifdef CONFIG_AUTOBOOT_KEYED
wdenkc6097192002-11-03 00:24:07 +0000403 int prev = disable_ctrlc(1); /* disable Control C checking */
Simon Glassde6f0c42013-05-15 06:23:56 +0000404#endif
wdenkc6097192002-11-03 00:24:07 +0000405
Simon Glassd0eb9402012-03-30 21:30:56 +0000406 run_command_list(s, -1, 0);
wdenkc6097192002-11-03 00:24:07 +0000407
Simon Glassde6f0c42013-05-15 06:23:56 +0000408#ifdef CONFIG_AUTOBOOT_KEYED
wdenkc6097192002-11-03 00:24:07 +0000409 disable_ctrlc(prev); /* restore Control C checking */
Simon Glassde6f0c42013-05-15 06:23:56 +0000410#endif
wdenkc6097192002-11-03 00:24:07 +0000411 }
wdenk452cfd62002-11-19 11:04:11 +0000412
Simon Glassde6f0c42013-05-15 06:23:56 +0000413#ifdef CONFIG_MENUKEY
wdenk9dd2b882002-12-03 21:28:10 +0000414 if (menukey == CONFIG_MENUKEY) {
Jason Hobbs3b403b72011-06-23 08:27:30 +0000415 s = getenv("menucmd");
Jason Hobbsa56febb2011-08-31 05:37:24 +0000416 if (s)
Simon Glassd0eb9402012-03-30 21:30:56 +0000417 run_command_list(s, -1, 0);
wdenk452cfd62002-11-19 11:04:11 +0000418 }
419#endif /* CONFIG_MENUKEY */
Simon Glassde6f0c42013-05-15 06:23:56 +0000420}
Wolfgang Denkb0b104a2010-06-13 18:28:54 +0200421#endif /* CONFIG_BOOTDELAY */
wdenk452cfd62002-11-19 11:04:11 +0000422
Simon Glassde6f0c42013-05-15 06:23:56 +0000423void main_loop(void)
424{
425#ifndef CONFIG_SYS_HUSH_PARSER
426 static char lastcommand[CONFIG_SYS_CBSIZE] = { 0, };
427 int len;
428 int rc = 1;
429 int flag;
430#endif
431#ifdef CONFIG_PREBOOT
432 char *p;
433#endif
434
435 bootstage_mark_name(BOOTSTAGE_ID_MAIN_LOOP, "main_loop");
436
437#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-VILLARD03836942008-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-VILLARD03836942008-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 */
wdenk42c05472004-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)
wdenk42c05472004-03-23 22:14:11 +0000523 puts ("<INTERRUPT>\n");
wdenkc6097192002-11-03 00:24:07 +0000524 else
Simon Glassbf8c5b02012-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-VILLARD03836942008-10-16 15:01:15 +0200532#endif /*CONFIG_SYS_HUSH_PARSER*/
wdenkc6097192002-11-03 00:24:07 +0000533}
534
wdenkb00ec162003-06-19 23:40:20 +0000535#ifdef CONFIG_BOOT_RETRY_TIME
536/***************************************************************************
Wolfgang Denk9c82c682006-10-28 00:38:39 +0200537 * initialize command line timeout
wdenkb00ec162003-06-19 23:40:20 +0000538 */
539void init_cmd_timeout(void)
540{
541 char *s = getenv ("bootretry");
542
543 if (s != NULL)
wdenk444f22b2003-12-07 21:39:28 +0000544 retry_time = (int)simple_strtol(s, NULL, 10);
wdenkb00ec162003-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 Denk4c9ca782006-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 Denk4c9ca782006-07-21 11:33:45 +0200568#define putnstr(str,n) do { \
Andrew Klossnere4ad4542008-07-07 06:41:14 -0700569 printf ("%.*s", (int)n, str); \
Wolfgang Denk4c9ca782006-07-21 11:33:45 +0200570 } while (0)
Wolfgang Denk4c9ca782006-07-21 11:33:45 +0200571
572#define CTL_CH(c) ((c) - 'a' + 1)
Wolfgang Denk4c9ca782006-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 Tyser7e0e5ca2010-09-29 13:30:56 -0500583#define HIST_SIZE CONFIG_SYS_CBSIZE
Wolfgang Denk4c9ca782006-07-21 11:33:45 +0200584
Kim Phillipsb052b602012-10-29 13:34:32 +0000585static int hist_max;
586static int hist_add_idx;
Wolfgang Denk4c9ca782006-07-21 11:33:45 +0200587static int hist_cur = -1;
Kim Phillipsb052b602012-10-29 13:34:32 +0000588static unsigned hist_num;
Wolfgang Denk4c9ca782006-07-21 11:33:45 +0200589
Kim Phillipsb052b602012-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 Denk4c9ca782006-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 Roese59ff5a52006-07-27 16:11:19 +0200665#ifndef CONFIG_CMDLINE_EDITING
Wolfgang Denk4c9ca782006-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 Roese59ff5a52006-07-27 16:11:19 +0200684#endif /* CONFIG_CMDLINE_EDITING */
Wolfgang Denk4c9ca782006-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 Frysinger3952bea2010-07-23 05:28:15 -0400695 printf("%*s", (int)(eol_num - num), ""); \
696 do { \
Wolfgang Denk4c9ca782006-07-21 11:33:45 +0200697 getcmd_putch(CTL_BACKSPACE); \
Mike Frysinger3952bea2010-07-23 05:28:15 -0400698 } while (--eol_num > num); \
Wolfgang Denk4c9ca782006-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 Schocher0eab4d52012-01-16 21:13:05 +0000754static int cread_line(const char *const prompt, char *buf, unsigned int *len,
755 int timeout)
Wolfgang Denk4c9ca782006-07-21 11:33:45 +0200756{
757 unsigned long num = 0;
758 unsigned long eol_num = 0;
Wolfgang Denk4c9ca782006-07-21 11:33:45 +0200759 unsigned long wlen;
760 char ichar;
761 int insert = 1;
762 int esc_len = 0;
Wolfgang Denk4c9ca782006-07-21 11:33:45 +0200763 char esc_save[8];
Peter Tyser8ad15a92009-10-25 15:12:54 -0500764 int init_len = strlen(buf);
Heiko Schocher0eab4d52012-01-16 21:13:05 +0000765 int first = 1;
Peter Tyser8ad15a92009-10-25 15:12:54 -0500766
767 if (init_len)
768 cread_add_str(buf, init_len, 1, &num, &eol_num, buf, *len);
Wolfgang Denk4c9ca782006-07-21 11:33:45 +0200769
770 while (1) {
Andreas Engel3a0ba102008-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 Scharsig11247552010-04-09 19:02:38 +0200775 WATCHDOG_RESET();
Andreas Engel3a0ba102008-01-09 17:10:56 +0100776 }
777#endif
Heiko Schocher0eab4d52012-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 Engel3a0ba102008-01-09 17:10:56 +0100788
Wolfgang Denk4c9ca782006-07-21 11:33:45 +0200789 ichar = getcmd_getch();
790
791 if ((ichar == '\n') || (ichar == '\r')) {
Wolfgang Denk92549de2006-07-21 11:34:34 +0200792 putc('\n');
Wolfgang Denk4c9ca782006-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 Denk92549de2006-07-21 11:34:34 +0200849 puts("impossible condition #876\n");
Wolfgang Denk4c9ca782006-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-VILLARD6366f002007-12-22 15:52:58 +0100897 case CTL_CH('u'):
Wolfgang Denk4c9ca782006-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-VILLARD6366f002007-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 Denk4c9ca782006-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 Tyser03e46c42009-10-25 15:12:53 -0500980 return 0;
Wolfgang Denk4c9ca782006-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 Tyser8ad15a92009-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 Schocher0eab4d52012-01-16 21:13:05 +00001003 return readline_into_buffer(prompt, console_buffer, 0);
James Yang20ffa972008-01-09 11:17:49 -06001004}
1005
1006
Heiko Schocher0eab4d52012-01-16 21:13:05 +00001007int readline_into_buffer(const char *const prompt, char *buffer, int timeout)
James Yang20ffa972008-01-09 11:17:49 -06001008{
1009 char *p = buffer;
Wolfgang Denk4c9ca782006-07-21 11:33:45 +02001010#ifdef CONFIG_CMDLINE_EDITING
Peter Tyser7e0e5ca2010-09-29 13:30:56 -05001011 unsigned int len = CONFIG_SYS_CBSIZE;
Stefan Roesedc5ff702006-08-07 15:08:44 +02001012 int rc;
Wolfgang Denk4c9ca782006-07-21 11:33:45 +02001013 static int initted = 0;
1014
James Yangb83983f2008-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 Tyserc144e012009-10-25 15:12:52 -05001027 if (prompt)
1028 puts (prompt);
James Yangb83983f2008-05-05 10:22:53 -05001029
Heiko Schocher0eab4d52012-01-16 21:13:05 +00001030 rc = cread_line(prompt, p, &len, timeout);
James Yangb83983f2008-05-05 10:22:53 -05001031 return rc < 0 ? rc : len;
1032
1033 } else {
1034#endif /* CONFIG_CMDLINE_EDITING */
Kumar Galae225b172008-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 Scharsig11247552010-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 Scharsig11247552010-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 Glasse30a5f72013-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 Glasse30a5f72013-05-15 06:23:58 +00001074 return p - p_buf;
wdenkc6097192002-11-03 00:24:07 +00001075
Simon Glasse30a5f72013-05-15 06:23:58 +00001076 case '\0': /* nul */
wdenk8d4d1f62004-03-23 22:37:33 +00001077 continue;
1078
Simon Glasse30a5f72013-05-15 06:23:58 +00001079 case 0x03: /* ^C - break */
James Yang20ffa972008-01-09 11:17:49 -06001080 p_buf[0] = '\0'; /* discard input */
Simon Glasse30a5f72013-05-15 06:23:58 +00001081 return -1;
wdenkc6097192002-11-03 00:24:07 +00001082
Simon Glasse30a5f72013-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 Yang20ffa972008-01-09 11:17:49 -06001088 p = p_buf;
wdenkc6097192002-11-03 00:24:07 +00001089 n = 0;
1090 continue;
1091
Simon Glasse30a5f72013-05-15 06:23:58 +00001092 case 0x17: /* ^W - erase word */
James Yang20ffa972008-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 Yang20ffa972008-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 Glasse30a5f72013-05-15 06:23:58 +00001099 case 0x08: /* ^H - backspace */
1100 case 0x7F: /* DEL - backspace */
James Yang20ffa972008-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-VILLARD03836942008-10-16 15:01:15 +02001108 if (n < CONFIG_SYS_CBSIZE-2) {
Simon Glasse30a5f72013-05-15 06:23:58 +00001109 if (c == '\t') { /* expand TABs */
wdenk3902d702004-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 Yang20ffa972008-01-09 11:17:49 -06001114 p = p_buf + n; /* reset */
wdenk3902d702004-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 Glassef45ffd2012-10-30 13:40:18 +00001121 char buf[2];
1122
1123 /*
Simon Glasse30a5f72013-05-15 06:23:58 +00001124 * Echo input using puts() to force an
Simon Glassef45ffd2012-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 Yangb83983f2008-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
1182#ifdef DEBUG_PARSER
1183 printf ("parse_line: \"%s\"\n", line);
1184#endif
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +02001185 while (nargs < CONFIG_SYS_MAXARGS) {
wdenkc6097192002-11-03 00:24:07 +00001186
1187 /* skip any white space */
Jason Hobbscafa1aa2011-08-23 11:06:54 +00001188 while (isblank(*line))
wdenkc6097192002-11-03 00:24:07 +00001189 ++line;
wdenkc6097192002-11-03 00:24:07 +00001190
1191 if (*line == '\0') { /* end of line, no more args */
1192 argv[nargs] = NULL;
1193#ifdef DEBUG_PARSER
1194 printf ("parse_line: nargs=%d\n", nargs);
1195#endif
1196 return (nargs);
1197 }
1198
1199 argv[nargs++] = line; /* begin of argument string */
1200
1201 /* find end of string */
Jason Hobbscafa1aa2011-08-23 11:06:54 +00001202 while (*line && !isblank(*line))
wdenkc6097192002-11-03 00:24:07 +00001203 ++line;
wdenkc6097192002-11-03 00:24:07 +00001204
1205 if (*line == '\0') { /* end of line, no more args */
1206 argv[nargs] = NULL;
1207#ifdef DEBUG_PARSER
1208 printf ("parse_line: nargs=%d\n", nargs);
1209#endif
1210 return (nargs);
1211 }
1212
1213 *line++ = '\0'; /* terminate current arg */
1214 }
1215
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +02001216 printf ("** Too many args (max. %d) **\n", CONFIG_SYS_MAXARGS);
wdenkc6097192002-11-03 00:24:07 +00001217
1218#ifdef DEBUG_PARSER
1219 printf ("parse_line: nargs=%d\n", nargs);
1220#endif
1221 return (nargs);
1222}
1223
1224/****************************************************************************/
1225
Simon Glass82c21322012-02-14 19:59:22 +00001226#ifndef CONFIG_SYS_HUSH_PARSER
wdenkc6097192002-11-03 00:24:07 +00001227static void process_macros (const char *input, char *output)
1228{
1229 char c, prev;
1230 const char *varname_start = NULL;
Wolfgang Denk9c82c682006-10-28 00:38:39 +02001231 int inputcnt = strlen (input);
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +02001232 int outputcnt = CONFIG_SYS_CBSIZE;
Wolfgang Denk9c82c682006-10-28 00:38:39 +02001233 int state = 0; /* 0 = waiting for '$' */
1234
1235 /* 1 = waiting for '(' or '{' */
1236 /* 2 = waiting for ')' or '}' */
1237 /* 3 = waiting for ''' */
wdenkc6097192002-11-03 00:24:07 +00001238#ifdef DEBUG_PARSER
1239 char *output_start = output;
1240
Wolfgang Denk9c82c682006-10-28 00:38:39 +02001241 printf ("[PROCESS_MACROS] INPUT len %d: \"%s\"\n", strlen (input),
1242 input);
wdenkc6097192002-11-03 00:24:07 +00001243#endif
1244
Wolfgang Denk9c82c682006-10-28 00:38:39 +02001245 prev = '\0'; /* previous character */
wdenkc6097192002-11-03 00:24:07 +00001246
1247 while (inputcnt && outputcnt) {
wdenk57b2d802003-06-27 21:31:46 +00001248 c = *input++;
Wolfgang Denk9c82c682006-10-28 00:38:39 +02001249 inputcnt--;
wdenkc6097192002-11-03 00:24:07 +00001250
Wolfgang Denk9c82c682006-10-28 00:38:39 +02001251 if (state != 3) {
1252 /* remove one level of escape characters */
1253 if ((c == '\\') && (prev != '\\')) {
1254 if (inputcnt-- == 0)
1255 break;
1256 prev = c;
1257 c = *input++;
1258 }
wdenkc6097192002-11-03 00:24:07 +00001259 }
wdenkc6097192002-11-03 00:24:07 +00001260
Wolfgang Denk9c82c682006-10-28 00:38:39 +02001261 switch (state) {
1262 case 0: /* Waiting for (unescaped) $ */
1263 if ((c == '\'') && (prev != '\\')) {
1264 state = 3;
1265 break;
1266 }
1267 if ((c == '$') && (prev != '\\')) {
1268 state++;
1269 } else {
wdenkc6097192002-11-03 00:24:07 +00001270 *(output++) = c;
1271 outputcnt--;
1272 }
Wolfgang Denk9c82c682006-10-28 00:38:39 +02001273 break;
1274 case 1: /* Waiting for ( */
1275 if (c == '(' || c == '{') {
1276 state++;
1277 varname_start = input;
1278 } else {
1279 state = 0;
1280 *(output++) = '$';
1281 outputcnt--;
wdenkc6097192002-11-03 00:24:07 +00001282
Wolfgang Denk9c82c682006-10-28 00:38:39 +02001283 if (outputcnt) {
1284 *(output++) = c;
1285 outputcnt--;
1286 }
wdenkc6097192002-11-03 00:24:07 +00001287 }
Wolfgang Denk9c82c682006-10-28 00:38:39 +02001288 break;
1289 case 2: /* Waiting for ) */
1290 if (c == ')' || c == '}') {
1291 int i;
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +02001292 char envname[CONFIG_SYS_CBSIZE], *envval;
Wolfgang Denk9c82c682006-10-28 00:38:39 +02001293 int envcnt = input - varname_start - 1; /* Varname # of chars */
wdenkc6097192002-11-03 00:24:07 +00001294
Wolfgang Denk9c82c682006-10-28 00:38:39 +02001295 /* Get the varname */
1296 for (i = 0; i < envcnt; i++) {
1297 envname[i] = varname_start[i];
wdenkc6097192002-11-03 00:24:07 +00001298 }
Wolfgang Denk9c82c682006-10-28 00:38:39 +02001299 envname[i] = 0;
1300
1301 /* Get its value */
1302 envval = getenv (envname);
1303
1304 /* Copy into the line if it exists */
1305 if (envval != NULL)
1306 while ((*envval) && outputcnt) {
1307 *(output++) = *(envval++);
1308 outputcnt--;
1309 }
1310 /* Look for another '$' */
1311 state = 0;
1312 }
1313 break;
1314 case 3: /* Waiting for ' */
1315 if ((c == '\'') && (prev != '\\')) {
1316 state = 0;
1317 } else {
1318 *(output++) = c;
1319 outputcnt--;
1320 }
1321 break;
wdenkc6097192002-11-03 00:24:07 +00001322 }
Wolfgang Denk9c82c682006-10-28 00:38:39 +02001323 prev = c;
wdenkc6097192002-11-03 00:24:07 +00001324 }
1325
1326 if (outputcnt)
1327 *output = 0;
Bartlomiej Siekacadc8e82007-05-27 17:04:18 +02001328 else
1329 *(output - 1) = 0;
wdenkc6097192002-11-03 00:24:07 +00001330
1331#ifdef DEBUG_PARSER
1332 printf ("[PROCESS_MACROS] OUTPUT len %d: \"%s\"\n",
Wolfgang Denk9c82c682006-10-28 00:38:39 +02001333 strlen (output_start), output_start);
wdenkc6097192002-11-03 00:24:07 +00001334#endif
1335}
1336
1337/****************************************************************************
1338 * returns:
1339 * 1 - command executed, repeatable
1340 * 0 - command executed but not repeatable, interrupted commands are
1341 * always considered not repeatable
1342 * -1 - not executed (unrecognized, bootd recursion or too many args)
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +02001343 * (If cmd is NULL or "" or longer than CONFIG_SYS_CBSIZE-1 it is
wdenkc6097192002-11-03 00:24:07 +00001344 * considered unrecognized)
1345 *
1346 * WARNING:
1347 *
1348 * We must create a temporary copy of the command since the command we get
1349 * may be the result from getenv(), which returns a pointer directly to
1350 * the environment data, which may change magicly when the command we run
1351 * creates or modifies environment variables (like "bootp" does).
1352 */
Simon Glassbf8c5b02012-02-14 19:59:21 +00001353static int builtin_run_command(const char *cmd, int flag)
wdenkc6097192002-11-03 00:24:07 +00001354{
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +02001355 char cmdbuf[CONFIG_SYS_CBSIZE]; /* working copy of cmd */
wdenkc6097192002-11-03 00:24:07 +00001356 char *token; /* start of token in cmdbuf */
1357 char *sep; /* end of token (separator) in cmdbuf */
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +02001358 char finaltoken[CONFIG_SYS_CBSIZE];
wdenkc6097192002-11-03 00:24:07 +00001359 char *str = cmdbuf;
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +02001360 char *argv[CONFIG_SYS_MAXARGS + 1]; /* NULL terminated */
wdenkf4688a22003-05-28 08:06:31 +00001361 int argc, inquotes;
wdenkc6097192002-11-03 00:24:07 +00001362 int repeatable = 1;
wdenkf4688a22003-05-28 08:06:31 +00001363 int rc = 0;
wdenkc6097192002-11-03 00:24:07 +00001364
1365#ifdef DEBUG_PARSER
1366 printf ("[RUN_COMMAND] cmd[%p]=\"", cmd);
1367 puts (cmd ? cmd : "NULL"); /* use puts - string may be loooong */
1368 puts ("\"\n");
1369#endif
1370
1371 clear_ctrlc(); /* forget any previous Control C */
1372
1373 if (!cmd || !*cmd) {
1374 return -1; /* empty command */
1375 }
1376
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +02001377 if (strlen(cmd) >= CONFIG_SYS_CBSIZE) {
wdenkc6097192002-11-03 00:24:07 +00001378 puts ("## Command too long!\n");
1379 return -1;
1380 }
1381
1382 strcpy (cmdbuf, cmd);
1383
1384 /* Process separators and check for invalid
1385 * repeatable commands
1386 */
1387
1388#ifdef DEBUG_PARSER
1389 printf ("[PROCESS_SEPARATORS] %s\n", cmd);
1390#endif
1391 while (*str) {
1392
1393 /*
1394 * Find separator, or string end
1395 * Allow simple escape of ';' by writing "\;"
1396 */
wdenk654868c2003-01-02 23:57:29 +00001397 for (inquotes = 0, sep = str; *sep; sep++) {
1398 if ((*sep=='\'') &&
1399 (*(sep-1) != '\\'))
1400 inquotes=!inquotes;
1401
1402 if (!inquotes &&
1403 (*sep == ';') && /* separator */
wdenkc6097192002-11-03 00:24:07 +00001404 ( sep != str) && /* past string start */
1405 (*(sep-1) != '\\')) /* and NOT escaped */
1406 break;
1407 }
1408
1409 /*
1410 * Limit the token to data between separators
1411 */
1412 token = str;
1413 if (*sep) {
1414 str = sep + 1; /* start of command for next pass */
1415 *sep = '\0';
1416 }
1417 else
1418 str = sep; /* no more commands for next pass */
1419#ifdef DEBUG_PARSER
1420 printf ("token: \"%s\"\n", token);
1421#endif
1422
1423 /* find macros in this token and replace them */
1424 process_macros (token, finaltoken);
1425
1426 /* Extract arguments */
Wolfgang Denkd44e7bb2006-03-12 02:20:55 +01001427 if ((argc = parse_line (finaltoken, argv)) == 0) {
1428 rc = -1; /* no command at all */
1429 continue;
1430 }
wdenkc6097192002-11-03 00:24:07 +00001431
Richard Genoud94ff0672012-12-03 06:28:28 +00001432 if (cmd_process(flag, argc, argv, &repeatable, NULL))
Timo Ketola9ba54722012-04-22 23:57:27 +00001433 rc = -1;
wdenkc6097192002-11-03 00:24:07 +00001434
1435 /* Did the user stop this? */
1436 if (had_ctrlc ())
Detlev Zundeleeab5a12007-05-23 18:47:48 +02001437 return -1; /* if stopped then not repeatable */
wdenkc6097192002-11-03 00:24:07 +00001438 }
1439
wdenkf4688a22003-05-28 08:06:31 +00001440 return rc ? rc : repeatable;
wdenkc6097192002-11-03 00:24:07 +00001441}
Simon Glass82c21322012-02-14 19:59:22 +00001442#endif
wdenkc6097192002-11-03 00:24:07 +00001443
Simon Glassbf8c5b02012-02-14 19:59:21 +00001444/*
1445 * Run a command using the selected parser.
1446 *
1447 * @param cmd Command to run
1448 * @param flag Execution flags (CMD_FLAG_...)
1449 * @return 0 on success, or != 0 on error.
1450 */
1451int run_command(const char *cmd, int flag)
1452{
1453#ifndef CONFIG_SYS_HUSH_PARSER
1454 /*
1455 * builtin_run_command can return 0 or 1 for success, so clean up
1456 * its result.
1457 */
1458 if (builtin_run_command(cmd, flag) == -1)
1459 return 1;
1460
1461 return 0;
1462#else
1463 return parse_string_outer(cmd,
1464 FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP);
1465#endif
1466}
1467
Simon Glassa6642e02012-03-30 21:30:55 +00001468#ifndef CONFIG_SYS_HUSH_PARSER
1469/**
1470 * Execute a list of command separated by ; or \n using the built-in parser.
1471 *
1472 * This function cannot take a const char * for the command, since if it
1473 * finds newlines in the string, it replaces them with \0.
1474 *
1475 * @param cmd String containing list of commands
1476 * @param flag Execution flags (CMD_FLAG_...)
1477 * @return 0 on success, or != 0 on error.
1478 */
1479static int builtin_run_command_list(char *cmd, int flag)
1480{
1481 char *line, *next;
1482 int rcode = 0;
1483
1484 /*
1485 * Break into individual lines, and execute each line; terminate on
1486 * error.
1487 */
1488 line = next = cmd;
1489 while (*next) {
1490 if (*next == '\n') {
1491 *next = '\0';
1492 /* run only non-empty commands */
1493 if (*line) {
1494 debug("** exec: \"%s\"\n", line);
1495 if (builtin_run_command(line, 0) < 0) {
1496 rcode = 1;
1497 break;
1498 }
1499 }
1500 line = next + 1;
1501 }
1502 ++next;
1503 }
1504 if (rcode == 0 && *line)
1505 rcode = (builtin_run_command(line, 0) >= 0);
1506
1507 return rcode;
1508}
1509#endif
1510
1511int run_command_list(const char *cmd, int len, int flag)
1512{
1513 int need_buff = 1;
1514 char *buff = (char *)cmd; /* cast away const */
1515 int rcode = 0;
1516
1517 if (len == -1) {
1518 len = strlen(cmd);
1519#ifdef CONFIG_SYS_HUSH_PARSER
1520 /* hush will never change our string */
1521 need_buff = 0;
1522#else
1523 /* the built-in parser will change our string if it sees \n */
1524 need_buff = strchr(cmd, '\n') != NULL;
1525#endif
1526 }
1527 if (need_buff) {
1528 buff = malloc(len + 1);
1529 if (!buff)
1530 return 1;
1531 memcpy(buff, cmd, len);
1532 buff[len] = '\0';
1533 }
1534#ifdef CONFIG_SYS_HUSH_PARSER
1535 rcode = parse_string_outer(buff, FLAG_PARSE_SEMICOLON);
1536#else
1537 /*
1538 * This function will overwrite any \n it sees with a \0, which
1539 * is why it can't work with a const char *. Here we are making
1540 * using of internal knowledge of this function, to avoid always
1541 * doing a malloc() which is actually required only in a case that
1542 * is pretty rare.
1543 */
1544 rcode = builtin_run_command_list(buff, flag);
1545 if (need_buff)
1546 free(buff);
1547#endif
1548
1549 return rcode;
1550}
1551
wdenkc6097192002-11-03 00:24:07 +00001552/****************************************************************************/
1553
Jon Loeliger052fc842007-07-08 18:10:08 -05001554#if defined(CONFIG_CMD_RUN)
Wolfgang Denk6262d0212010-06-28 22:00:46 +02001555int do_run (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
wdenkc6097192002-11-03 00:24:07 +00001556{
1557 int i;
wdenkc6097192002-11-03 00:24:07 +00001558
Wolfgang Denk3b683112010-07-17 01:06:04 +02001559 if (argc < 2)
Simon Glassa06dfc72011-12-10 08:44:01 +00001560 return CMD_RET_USAGE;
wdenkc6097192002-11-03 00:24:07 +00001561
1562 for (i=1; i<argc; ++i) {
wdenkb02744a2003-04-05 00:53:31 +00001563 char *arg;
1564
1565 if ((arg = getenv (argv[i])) == NULL) {
1566 printf ("## Error: \"%s\" not defined\n", argv[i]);
1567 return 1;
1568 }
Jason Hobbsa56febb2011-08-31 05:37:24 +00001569
Simon Glass8161d042012-02-14 19:59:20 +00001570 if (run_command(arg, flag) != 0)
wdenkb02744a2003-04-05 00:53:31 +00001571 return 1;
wdenkc6097192002-11-03 00:24:07 +00001572 }
wdenkb02744a2003-04-05 00:53:31 +00001573 return 0;
wdenkc6097192002-11-03 00:24:07 +00001574}
Jon Loeligerd704d912007-07-10 11:02:44 -05001575#endif